tm.texi.in (OVERRIDE_OPTIONS): Remove documentation.
[gcc.git] / gcc / config / m68hc11 / m68hc11.c
1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 2009, 2010 Free Software Foundation, Inc.
4 Contributed by Stephane Carrez (stcarrez@nerim.fr)
5
6 This file is part of GCC.
7
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
11 any later version.
12
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>.
21
22 Note:
23 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24 on gcc 2.6.3. I have used it as a starting point for this port.
25 However, this new port is a complete re-write. Its internal
26 design is completely different. The generated code is not
27 compatible with the gcc 2.6.3 port.
28
29 The gcc 2.6.3 port is available at:
30
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
32
33 */
34
35 #include <stdio.h>
36 #include "config.h"
37 #include "system.h"
38 #include "coretypes.h"
39 #include "tm.h"
40 #include "rtl.h"
41 #include "tree.h"
42 #include "expr.h"
43 #include "tm_p.h"
44 #include "regs.h"
45 #include "hard-reg-set.h"
46 #include "insn-config.h"
47 #include "conditions.h"
48 #include "output.h"
49 #include "insn-attr.h"
50 #include "flags.h"
51 #include "recog.h"
52 #include "expr.h"
53 #include "libfuncs.h"
54 #include "diagnostic-core.h"
55 #include "toplev.h"
56 #include "basic-block.h"
57 #include "function.h"
58 #include "ggc.h"
59 #include "reload.h"
60 #include "target.h"
61 #include "target-def.h"
62 #include "df.h"
63
64 static void m68hc11_option_override (void);
65 static void emit_move_after_reload (rtx, rtx, rtx);
66 static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
67 static void m68hc11_emit_logical (enum machine_mode, enum rtx_code, rtx *);
68 static void m68hc11_reorg (void);
69 static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool);
70 static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool);
71 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
72 static int must_parenthesize (rtx);
73 static int m68hc11_address_cost (rtx, bool);
74 static int m68hc11_shift_cost (enum machine_mode, rtx, int);
75 static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
76 static bool m68hc11_rtx_costs (rtx, int, int, int *, bool);
77 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
78 static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *);
79
80 void create_regs_rtx (void);
81
82 static void asm_print_register (FILE *, int);
83 static void m68hc11_print_operand (FILE *, rtx, int);
84 static void m68hc11_print_operand_address (FILE *, rtx);
85 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
86 static void m68hc11_asm_out_constructor (rtx, int);
87 static void m68hc11_asm_out_destructor (rtx, int);
88 static void m68hc11_file_start (void);
89 static void m68hc11_encode_section_info (tree, rtx, int);
90 static const char *m68hc11_strip_name_encoding (const char* str);
91 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
92 static int autoinc_mode (rtx);
93 static int m68hc11_make_autoinc_notes (rtx *, void *);
94 static void m68hc11_init_libfuncs (void);
95 static rtx m68hc11_struct_value_rtx (tree, int);
96 static bool m68hc11_return_in_memory (const_tree, const_tree);
97 static bool m68hc11_can_eliminate (const int, const int);
98 static void m68hc11_trampoline_init (rtx, tree, rtx);
99
100 /* Must be set to 1 to produce debug messages. */
101 int debug_m6811 = 0;
102
103 extern FILE *asm_out_file;
104
105 rtx ix_reg;
106 rtx iy_reg;
107 rtx d_reg;
108 rtx m68hc11_soft_tmp_reg;
109 static GTY(()) rtx stack_push_word;
110 static GTY(()) rtx stack_pop_word;
111 static GTY(()) rtx z_reg;
112 static GTY(()) rtx z_reg_qi;
113 static int regs_inited = 0;
114
115 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
116 int current_function_interrupt;
117
118 /* Set to 1 by expand_prologue() when the function is a trap handler. */
119 int current_function_trap;
120
121 /* Set to 1 when the current function is placed in 68HC12 banked
122 memory and must return with rtc. */
123 int current_function_far;
124
125 /* Min offset that is valid for the indirect addressing mode. */
126 HOST_WIDE_INT m68hc11_min_offset = 0;
127
128 /* Max offset that is valid for the indirect addressing mode. */
129 HOST_WIDE_INT m68hc11_max_offset = 256;
130
131 /* The class value for base registers. */
132 enum reg_class m68hc11_base_reg_class = A_REGS;
133
134 /* The class value for index registers. This is NO_REGS for 68HC11. */
135 enum reg_class m68hc11_index_reg_class = NO_REGS;
136
137 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
138
139 /* Tables that tell whether a given hard register is valid for
140 a base or an index register. It is filled at init time depending
141 on the target processor. */
142 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
143 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
144
145 /* A correction offset which is applied to the stack pointer.
146 This is 1 for 68HC11 and 0 for 68HC12. */
147 int m68hc11_sp_correction;
148
149 int m68hc11_addr_mode;
150 int m68hc11_mov_addr_mode;
151 \f
152
153 const struct processor_costs *m68hc11_cost;
154
155 /* Costs for a 68HC11. */
156 static const struct processor_costs m6811_cost = {
157 /* add */
158 COSTS_N_INSNS (2),
159 /* logical */
160 COSTS_N_INSNS (2),
161 /* non-constant shift */
162 COSTS_N_INSNS (20),
163 /* shiftQI const */
164 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
165 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
166 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
167
168 /* shiftHI const */
169 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
170 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
171 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
172 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
173 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
174 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
175 },
176 /* mulQI */
177 COSTS_N_INSNS (20),
178 /* mulHI */
179 COSTS_N_INSNS (20 * 4),
180 /* mulSI */
181 COSTS_N_INSNS (20 * 16),
182 /* divQI */
183 COSTS_N_INSNS (20),
184 /* divHI */
185 COSTS_N_INSNS (80),
186 /* divSI */
187 COSTS_N_INSNS (100)
188 };
189
190 /* Costs for a 68HC12. */
191 static const struct processor_costs m6812_cost = {
192 /* add */
193 COSTS_N_INSNS (2),
194 /* logical */
195 COSTS_N_INSNS (2),
196 /* non-constant shift */
197 COSTS_N_INSNS (20),
198 /* shiftQI const */
199 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
200 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
201 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
202
203 /* shiftHI const */
204 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
205 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
206 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
207 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
208 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
209 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
210 },
211 /* mulQI */
212 COSTS_N_INSNS (3),
213 /* mulHI */
214 COSTS_N_INSNS (3),
215 /* mulSI */
216 COSTS_N_INSNS (3 * 4),
217 /* divQI */
218 COSTS_N_INSNS (12),
219 /* divHI */
220 COSTS_N_INSNS (12),
221 /* divSI */
222 COSTS_N_INSNS (100)
223 };
224 \f
225 /* M68HC11 specific attributes. */
226
227 static const struct attribute_spec m68hc11_attribute_table[] =
228 {
229 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
230 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
231 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
232 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
233 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
234 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
235 { NULL, 0, 0, false, false, false, NULL }
236 };
237 \f
238 /* Initialize the GCC target structure. */
239 #undef TARGET_ATTRIBUTE_TABLE
240 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
241
242 #undef TARGET_ASM_ALIGNED_HI_OP
243 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
244
245 #undef TARGET_PRINT_OPERAND
246 #define TARGET_PRINT_OPERAND m68hc11_print_operand
247 #undef TARGET_PRINT_OPERAND_ADDRESS
248 #define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
249
250 #undef TARGET_ASM_FUNCTION_EPILOGUE
251 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
252
253 #undef TARGET_ASM_FILE_START
254 #define TARGET_ASM_FILE_START m68hc11_file_start
255 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
256 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
257
258 #undef TARGET_DEFAULT_TARGET_FLAGS
259 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
260
261 #undef TARGET_ENCODE_SECTION_INFO
262 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
263
264 #undef TARGET_SECTION_TYPE_FLAGS
265 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
266
267 #undef TARGET_RTX_COSTS
268 #define TARGET_RTX_COSTS m68hc11_rtx_costs
269 #undef TARGET_ADDRESS_COST
270 #define TARGET_ADDRESS_COST m68hc11_address_cost
271
272 #undef TARGET_MACHINE_DEPENDENT_REORG
273 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
274
275 #undef TARGET_INIT_LIBFUNCS
276 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
277
278 #undef TARGET_STRUCT_VALUE_RTX
279 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
280 #undef TARGET_RETURN_IN_MEMORY
281 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
282 #undef TARGET_CALLEE_COPIES
283 #define TARGET_CALLEE_COPIES hook_callee_copies_named
284
285 #undef TARGET_STRIP_NAME_ENCODING
286 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
287
288 #undef TARGET_LEGITIMATE_ADDRESS_P
289 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
290
291 #undef TARGET_CAN_ELIMINATE
292 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
293
294 #undef TARGET_TRAMPOLINE_INIT
295 #define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
296
297 #undef TARGET_OPTION_OVERRIDE
298 #define TARGET_OPTION_OVERRIDE m68hc11_option_override
299
300 struct gcc_target targetm = TARGET_INITIALIZER;
301 \f
302 static void
303 m68hc11_option_override (void)
304 {
305 memset (m68hc11_reg_valid_for_index, 0,
306 sizeof (m68hc11_reg_valid_for_index));
307 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
308
309 /* Compilation with -fpic generates a wrong code. */
310 if (flag_pic)
311 {
312 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
313 (flag_pic > 1) ? "PIC" : "pic");
314 flag_pic = 0;
315 }
316
317 /* Do not enable -fweb because it breaks the 32-bit shift patterns
318 by breaking the match_dup of those patterns. The shift patterns
319 will no longer be recognized after that. */
320 flag_web = 0;
321
322 /* Configure for a 68hc11 processor. */
323 if (TARGET_M6811)
324 {
325 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
326 m68hc11_cost = &m6811_cost;
327 m68hc11_min_offset = 0;
328 m68hc11_max_offset = 256;
329 m68hc11_index_reg_class = NO_REGS;
330 m68hc11_base_reg_class = A_REGS;
331 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
332 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
333 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
334 m68hc11_sp_correction = 1;
335 m68hc11_tmp_regs_class = D_REGS;
336 m68hc11_addr_mode = ADDR_OFFSET;
337 m68hc11_mov_addr_mode = 0;
338 if (m68hc11_soft_reg_count < 0)
339 m68hc11_soft_reg_count = 4;
340 }
341
342 /* Configure for a 68hc12 processor. */
343 if (TARGET_M6812)
344 {
345 m68hc11_cost = &m6812_cost;
346 m68hc11_min_offset = -65536;
347 m68hc11_max_offset = 65536;
348 m68hc11_index_reg_class = D_REGS;
349 m68hc11_base_reg_class = A_OR_SP_REGS;
350 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
351 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
352 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
353 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
354 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
355 m68hc11_sp_correction = 0;
356 m68hc11_tmp_regs_class = TMP_REGS;
357 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
358 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
359 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
360 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
361 target_flags |= MASK_NO_DIRECT_MODE;
362 if (m68hc11_soft_reg_count < 0)
363 m68hc11_soft_reg_count = 0;
364
365 if (TARGET_LONG_CALLS)
366 current_function_far = 1;
367 }
368 }
369
370
371 void
372 m68hc11_conditional_register_usage (void)
373 {
374 int i;
375
376 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
377 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
378
379 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
380 {
381 fixed_regs[i] = 1;
382 call_used_regs[i] = 1;
383 }
384
385 /* For 68HC12, the Z register emulation is not necessary when the
386 frame pointer is not used. The frame pointer is eliminated and
387 replaced by the stack register (which is a BASE_REG_CLASS). */
388 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
389 {
390 fixed_regs[HARD_Z_REGNUM] = 1;
391 }
392 }
393 \f
394
395 /* Reload and register operations. */
396
397
398 void
399 create_regs_rtx (void)
400 {
401 /* regs_inited = 1; */
402 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
403 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
404 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
405 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
406
407 stack_push_word = gen_rtx_MEM (HImode,
408 gen_rtx_PRE_DEC (HImode,
409 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
410 stack_pop_word = gen_rtx_MEM (HImode,
411 gen_rtx_POST_INC (HImode,
412 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
413
414 }
415
416 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
417 - 8-bit values are stored anywhere (except the SP register).
418 - 16-bit values can be stored in any register whose mode is 16
419 - 32-bit values can be stored in D, X registers or in a soft register
420 (except the last one because we need 2 soft registers)
421 - Values whose size is > 32 bit are not stored in real hard
422 registers. They may be stored in soft registers if there are
423 enough of them. */
424 int
425 hard_regno_mode_ok (int regno, enum machine_mode mode)
426 {
427 switch (GET_MODE_SIZE (mode))
428 {
429 case 8:
430 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
431
432 case 4:
433 return (X_REGNO_P (regno)
434 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
435
436 case 2:
437 return G_REGNO_P (regno);
438
439 case 1:
440 /* We have to accept a QImode in X or Y registers. Otherwise, the
441 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
442 in the insns. Reload fails if the insn rejects the register class 'a'
443 as well as if it accepts it. Patterns that failed were
444 zero_extend_qihi2 and iorqi3. */
445
446 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
447
448 default:
449 return 0;
450 }
451 }
452
453 int
454 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
455 {
456 /* Don't accept renaming to Z register. We will replace it to
457 X,Y or D during machine reorg pass. */
458 if (reg2 == HARD_Z_REGNUM)
459 return 0;
460
461 /* Don't accept renaming D,X to Y register as the code will be bigger. */
462 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
463 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
464 return 0;
465
466 return 1;
467 }
468
469 enum reg_class
470 preferred_reload_class (rtx operand, enum reg_class rclass)
471 {
472 enum machine_mode mode;
473
474 mode = GET_MODE (operand);
475
476 if (debug_m6811)
477 {
478 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
479 }
480
481 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
482 return m68hc11_base_reg_class;
483
484 if (rclass >= S_REGS && (GET_CODE (operand) == MEM
485 || GET_CODE (operand) == CONST_INT))
486 {
487 /* S_REGS class must not be used. The movhi template does not
488 work to move a memory to a soft register.
489 Restrict to a hard reg. */
490 switch (rclass)
491 {
492 default:
493 case G_REGS:
494 case D_OR_A_OR_S_REGS:
495 rclass = A_OR_D_REGS;
496 break;
497 case A_OR_S_REGS:
498 rclass = A_REGS;
499 break;
500 case D_OR_SP_OR_S_REGS:
501 rclass = D_OR_SP_REGS;
502 break;
503 case D_OR_Y_OR_S_REGS:
504 rclass = D_OR_Y_REGS;
505 break;
506 case D_OR_X_OR_S_REGS:
507 rclass = D_OR_X_REGS;
508 break;
509 case SP_OR_S_REGS:
510 rclass = SP_REGS;
511 break;
512 case Y_OR_S_REGS:
513 rclass = Y_REGS;
514 break;
515 case X_OR_S_REGS:
516 rclass = X_REGS;
517 break;
518 case D_OR_S_REGS:
519 rclass = D_REGS;
520 }
521 }
522 else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
523 {
524 rclass = Y_REGS;
525 }
526 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
527 {
528 rclass = D_OR_X_REGS;
529 }
530 else if (rclass >= S_REGS && S_REG_P (operand))
531 {
532 switch (rclass)
533 {
534 default:
535 case G_REGS:
536 case D_OR_A_OR_S_REGS:
537 rclass = A_OR_D_REGS;
538 break;
539 case A_OR_S_REGS:
540 rclass = A_REGS;
541 break;
542 case D_OR_SP_OR_S_REGS:
543 rclass = D_OR_SP_REGS;
544 break;
545 case D_OR_Y_OR_S_REGS:
546 rclass = D_OR_Y_REGS;
547 break;
548 case D_OR_X_OR_S_REGS:
549 rclass = D_OR_X_REGS;
550 break;
551 case SP_OR_S_REGS:
552 rclass = SP_REGS;
553 break;
554 case Y_OR_S_REGS:
555 rclass = Y_REGS;
556 break;
557 case X_OR_S_REGS:
558 rclass = X_REGS;
559 break;
560 case D_OR_S_REGS:
561 rclass = D_REGS;
562 }
563 }
564 else if (rclass >= S_REGS)
565 {
566 if (debug_m6811)
567 {
568 printf ("Class = %s for: ", reg_class_names[rclass]);
569 fflush (stdout);
570 debug_rtx (operand);
571 }
572 }
573
574 if (debug_m6811)
575 {
576 printf (" => class=%s\n", reg_class_names[rclass]);
577 fflush (stdout);
578 debug_rtx (operand);
579 }
580
581 return rclass;
582 }
583
584 /* Return 1 if the operand is a valid indexed addressing mode.
585 For 68hc11: n,r with n in [0..255] and r in A_REGS class
586 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
587 int
588 m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
589 {
590 rtx base, offset;
591
592 switch (GET_CODE (operand))
593 {
594 case MEM:
595 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
596 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
597 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
598 return 0;
599
600 case POST_INC:
601 case PRE_INC:
602 case POST_DEC:
603 case PRE_DEC:
604 if (addr_mode & ADDR_INCDEC)
605 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
606 addr_mode & ADDR_STRICT);
607 return 0;
608
609 case PLUS:
610 base = XEXP (operand, 0);
611 if (GET_CODE (base) == MEM)
612 return 0;
613
614 offset = XEXP (operand, 1);
615 if (GET_CODE (offset) == MEM)
616 return 0;
617
618 /* Indexed addressing mode with 2 registers. */
619 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
620 {
621 if (!(addr_mode & ADDR_INDEXED))
622 return 0;
623
624 addr_mode &= ADDR_STRICT;
625 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
626 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
627 return 1;
628
629 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
630 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
631 return 1;
632
633 return 0;
634 }
635
636 if (!(addr_mode & ADDR_OFFSET))
637 return 0;
638
639 if (GET_CODE (base) == REG)
640 {
641 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
642 return 0;
643
644 if (!(addr_mode & ADDR_STRICT))
645 return 1;
646
647 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
648 }
649
650 if (GET_CODE (offset) == REG)
651 {
652 if (!VALID_CONSTANT_OFFSET_P (base, mode))
653 return 0;
654
655 if (!(addr_mode & ADDR_STRICT))
656 return 1;
657
658 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
659 }
660 return 0;
661
662 case REG:
663 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
664
665 case CONST_INT:
666 if (addr_mode & ADDR_CONST)
667 return VALID_CONSTANT_OFFSET_P (operand, mode);
668 return 0;
669
670 default:
671 return 0;
672 }
673 }
674
675 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
676 a 68HC12 1-byte index addressing mode. */
677 int
678 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
679 {
680 rtx base, offset;
681 int addr_mode;
682
683 if (GET_CODE (operand) == REG && reload_in_progress
684 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
685 && reg_equiv_memory_loc[REGNO (operand)])
686 {
687 operand = reg_equiv_memory_loc[REGNO (operand)];
688 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
689 }
690
691 if (GET_CODE (operand) != MEM)
692 return 0;
693
694 operand = XEXP (operand, 0);
695 if (CONSTANT_ADDRESS_P (operand))
696 return 1;
697
698 if (PUSH_POP_ADDRESS_P (operand))
699 return 1;
700
701 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
702 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
703 return 0;
704
705 if (TARGET_M6812 && GET_CODE (operand) == PLUS
706 && (reload_completed | reload_in_progress))
707 {
708 base = XEXP (operand, 0);
709 offset = XEXP (operand, 1);
710
711 /* The offset can be a symbol address and this is too big
712 for the operand constraint. */
713 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
714 return 0;
715
716 if (GET_CODE (base) == CONST_INT)
717 offset = base;
718
719 switch (GET_MODE_SIZE (mode))
720 {
721 case 8:
722 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
723 return 0;
724 break;
725
726 case 4:
727 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
728 return 0;
729 break;
730
731 default:
732 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
733 return 0;
734 break;
735 }
736 }
737 return 1;
738 }
739
740 int
741 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
742 {
743 int addr_mode;
744
745 if (GET_CODE (operand) == REG && reload_in_progress
746 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
747 && reg_equiv_memory_loc[REGNO (operand)])
748 {
749 operand = reg_equiv_memory_loc[REGNO (operand)];
750 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
751 }
752 if (GET_CODE (operand) != MEM)
753 return 0;
754
755 operand = XEXP (operand, 0);
756 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
757 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
758 }
759
760 static bool
761 m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
762 bool strict)
763 {
764 int addr_mode;
765
766 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
767 {
768 /* Reject the global variables if they are too wide. This forces
769 a load of their address in a register and generates smaller code. */
770 if (GET_MODE_SIZE (mode) == 8)
771 return 0;
772
773 return 1;
774 }
775 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
776 if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
777 {
778 return 1;
779 }
780 if (PUSH_POP_ADDRESS_P (operand))
781 {
782 return 1;
783 }
784 if (symbolic_memory_operand (operand, mode))
785 {
786 return 1;
787 }
788 return 0;
789 }
790
791 bool
792 m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
793 bool strict)
794 {
795 int result;
796
797 if (debug_m6811)
798 {
799 printf ("Checking: ");
800 fflush (stdout);
801 debug_rtx (operand);
802 }
803
804 result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
805
806 if (debug_m6811)
807 {
808 printf (" -> %s\n", result == 0 ? "NO" : "YES");
809 }
810
811 if (result == 0)
812 {
813 if (debug_m6811)
814 {
815 printf ("go_if_legitimate%s, ret 0: %d:",
816 (strict ? "_strict" : ""), mode);
817 fflush (stdout);
818 debug_rtx (operand);
819 }
820 }
821 return result;
822 }
823
824
825 int
826 m68hc11_reload_operands (rtx operands[])
827 {
828 enum machine_mode mode;
829
830 if (regs_inited == 0)
831 create_regs_rtx ();
832
833 mode = GET_MODE (operands[1]);
834
835 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
836 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
837 {
838 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
839 rtx base = XEXP (XEXP (operands[1], 0), 0);
840
841 if (GET_CODE (base) != REG)
842 {
843 rtx tmp = base;
844 base = big_offset;
845 big_offset = tmp;
846 }
847
848 /* If the offset is out of range, we have to compute the address
849 with a separate add instruction. We try to do this with an 8-bit
850 add on the A register. This is possible only if the lowest part
851 of the offset (i.e., big_offset % 256) is a valid constant offset
852 with respect to the mode. If it's not, we have to generate a
853 16-bit add on the D register. From:
854
855 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
856
857 we generate:
858
859 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
860 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
861 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
862 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
863
864 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
865 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
866
867 */
868 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
869 {
870 int vh, vl;
871 rtx reg = operands[0];
872 rtx offset;
873 int val = INTVAL (big_offset);
874
875
876 /* We use the 'operands[0]' as a scratch register to compute the
877 address. Make sure 'base' is in that register. */
878 if (!rtx_equal_p (base, operands[0]))
879 {
880 emit_move_insn (reg, base);
881 }
882
883 if (val > 0)
884 {
885 vh = val >> 8;
886 vl = val & 0x0FF;
887 }
888 else
889 {
890 vh = (val >> 8) & 0x0FF;
891 vl = val & 0x0FF;
892 }
893
894 /* Create the lowest part offset that still remains to be added.
895 If it's not a valid offset, do a 16-bit add. */
896 offset = GEN_INT (vl);
897 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
898 {
899 emit_insn (gen_rtx_SET (VOIDmode, reg,
900 gen_rtx_PLUS (HImode, reg, big_offset)));
901 offset = const0_rtx;
902 }
903 else
904 {
905 emit_insn (gen_rtx_SET (VOIDmode, reg,
906 gen_rtx_PLUS (HImode, reg,
907 GEN_INT (vh << 8))));
908 }
909 emit_move_insn (operands[0],
910 gen_rtx_MEM (GET_MODE (operands[1]),
911 gen_rtx_PLUS (Pmode, reg, offset)));
912 return 1;
913 }
914 }
915
916 /* Use the normal gen_movhi pattern. */
917 return 0;
918 }
919
920 void
921 m68hc11_emit_libcall (const char *name, enum rtx_code code,
922 enum machine_mode dmode, enum machine_mode smode,
923 int noperands, rtx *operands)
924 {
925 rtx ret;
926 rtx insns;
927 rtx libcall;
928 rtx equiv;
929
930 start_sequence ();
931 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
932 switch (noperands)
933 {
934 case 2:
935 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
936 dmode, 1, operands[1], smode);
937 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
938 break;
939
940 case 3:
941 ret = emit_library_call_value (libcall, NULL_RTX,
942 LCT_CONST, dmode, 2,
943 operands[1], smode, operands[2],
944 smode);
945 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
946 break;
947
948 default:
949 gcc_unreachable ();
950 }
951
952 insns = get_insns ();
953 end_sequence ();
954 emit_libcall_block (insns, operands[0], ret, equiv);
955 }
956
957 /* Returns true if X is a PRE/POST increment decrement
958 (same as auto_inc_p() in rtlanal.c but do not take into
959 account the stack). */
960 int
961 m68hc11_auto_inc_p (rtx x)
962 {
963 return GET_CODE (x) == PRE_DEC
964 || GET_CODE (x) == POST_INC
965 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
966 }
967 \f
968
969 /* Predicates for machine description. */
970
971 int
972 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
973 {
974 return GET_CODE (operand) == MEM
975 && GET_CODE (XEXP (operand, 0)) == PLUS
976 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
977 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
978 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
979 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
980 }
981
982 int
983 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
984 {
985 if (GET_CODE (operand) == MEM)
986 {
987 rtx op = XEXP (operand, 0);
988
989 if (symbolic_memory_operand (op, mode))
990 return 1;
991 }
992 return 0;
993 }
994
995 int
996 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
997 {
998 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
999 {
1000 rtx op = XEXP (operand, 0);
1001 int addr_mode;
1002
1003 if (m68hc11_page0_symbol_p (op))
1004 return 1;
1005
1006 if (symbolic_memory_operand (op, mode))
1007 return TARGET_M6812;
1008
1009 if (reload_in_progress)
1010 return 1;
1011
1012 operand = XEXP (operand, 0);
1013 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1014 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
1015 }
1016 return 0;
1017 }
1018
1019 int
1020 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1021 {
1022 if (GET_CODE (operand) != MEM)
1023 return 0;
1024
1025 operand = XEXP (operand, 0);
1026 if (GET_CODE (operand) == PLUS)
1027 {
1028 if (GET_CODE (XEXP (operand, 0)) == REG)
1029 operand = XEXP (operand, 0);
1030 else if (GET_CODE (XEXP (operand, 1)) == REG)
1031 operand = XEXP (operand, 1);
1032 }
1033 return GET_CODE (operand) == REG
1034 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1035 || A_REGNO_P (REGNO (operand)));
1036 }
1037
1038 int
1039 push_pop_operand_p (rtx operand)
1040 {
1041 if (GET_CODE (operand) != MEM)
1042 {
1043 return 0;
1044 }
1045 operand = XEXP (operand, 0);
1046 return PUSH_POP_ADDRESS_P (operand);
1047 }
1048
1049 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1050 reference and a constant. */
1051
1052 int
1053 symbolic_memory_operand (rtx op, enum machine_mode mode)
1054 {
1055 switch (GET_CODE (op))
1056 {
1057 case SYMBOL_REF:
1058 case LABEL_REF:
1059 return 1;
1060
1061 case CONST:
1062 op = XEXP (op, 0);
1063 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1064 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1065 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1066
1067 /* ??? This clause seems to be irrelevant. */
1068 case CONST_DOUBLE:
1069 return GET_MODE (op) == mode;
1070
1071 case PLUS:
1072 return symbolic_memory_operand (XEXP (op, 0), mode)
1073 && symbolic_memory_operand (XEXP (op, 1), mode);
1074
1075 default:
1076 return 0;
1077 }
1078 }
1079 \f
1080 /* Emit the code to build the trampoline used to call a nested function.
1081
1082 68HC11 68HC12
1083
1084 ldy #&CXT movw #&CXT,*_.d1
1085 sty *_.d1 jmp FNADDR
1086 jmp FNADDR
1087
1088 */
1089 static void
1090 m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
1091 {
1092 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1093 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
1094 rtx mem;
1095
1096 /* Skip the '*'. */
1097 if (*static_chain_reg == '*')
1098 static_chain_reg++;
1099 if (TARGET_M6811)
1100 {
1101 mem = adjust_address (m_tramp, HImode, 0);
1102 emit_move_insn (mem, GEN_INT (0x18ce));
1103 mem = adjust_address (m_tramp, HImode, 2);
1104 emit_move_insn (mem, cxt);
1105 mem = adjust_address (m_tramp, HImode, 4);
1106 emit_move_insn (mem, GEN_INT (0x18df));
1107 mem = adjust_address (m_tramp, QImode, 6);
1108 emit_move_insn (mem,
1109 gen_rtx_CONST (QImode,
1110 gen_rtx_SYMBOL_REF (Pmode,
1111 static_chain_reg)));
1112 mem = adjust_address (m_tramp, QImode, 7);
1113 emit_move_insn (mem, GEN_INT (0x7e));
1114 mem = adjust_address (m_tramp, HImode, 8);
1115 emit_move_insn (mem, fnaddr);
1116 }
1117 else
1118 {
1119 mem = adjust_address (m_tramp, HImode, 0);
1120 emit_move_insn (mem, GEN_INT (0x1803));
1121 mem = adjust_address (m_tramp, HImode, 2);
1122 emit_move_insn (mem, cxt);
1123 mem = adjust_address (m_tramp, HImode, 4);
1124 emit_move_insn (mem,
1125 gen_rtx_CONST (HImode,
1126 gen_rtx_SYMBOL_REF (Pmode,
1127 static_chain_reg)));
1128 mem = adjust_address (m_tramp, QImode, 6);
1129 emit_move_insn (mem, GEN_INT (0x06));
1130 mem = adjust_address (m_tramp, HImode, 7);
1131 emit_move_insn (mem, fnaddr);
1132 }
1133 }
1134 \f
1135 /* Declaration of types. */
1136
1137 /* Handle an "tiny_data" attribute; arguments as in
1138 struct attribute_spec.handler. */
1139 static tree
1140 m68hc11_handle_page0_attribute (tree *node, tree name,
1141 tree args ATTRIBUTE_UNUSED,
1142 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1143 {
1144 tree decl = *node;
1145
1146 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1147 {
1148 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1149 }
1150 else
1151 {
1152 warning (OPT_Wattributes, "%qE attribute ignored",
1153 name);
1154 *no_add_attrs = true;
1155 }
1156
1157 return NULL_TREE;
1158 }
1159
1160 /* Keep track of the symbol which has a `trap' attribute and which uses
1161 the `swi' calling convention. Since there is only one trap, we only
1162 record one such symbol. If there are several, a warning is reported. */
1163 static rtx trap_handler_symbol = 0;
1164
1165 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1166 arguments as in struct attribute_spec.handler. */
1167 static tree
1168 m68hc11_handle_fntype_attribute (tree *node, tree name,
1169 tree args ATTRIBUTE_UNUSED,
1170 int flags ATTRIBUTE_UNUSED,
1171 bool *no_add_attrs)
1172 {
1173 if (TREE_CODE (*node) != FUNCTION_TYPE
1174 && TREE_CODE (*node) != METHOD_TYPE
1175 && TREE_CODE (*node) != FIELD_DECL
1176 && TREE_CODE (*node) != TYPE_DECL)
1177 {
1178 warning (OPT_Wattributes, "%qE attribute only applies to functions",
1179 name);
1180 *no_add_attrs = true;
1181 }
1182
1183 return NULL_TREE;
1184 }
1185 /* Undo the effects of the above. */
1186
1187 static const char *
1188 m68hc11_strip_name_encoding (const char *str)
1189 {
1190 return str + (*str == '*' || *str == '@' || *str == '&');
1191 }
1192
1193 static void
1194 m68hc11_encode_label (tree decl)
1195 {
1196 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1197 int len = strlen (str);
1198 char *newstr = XALLOCAVEC (char, len + 2);
1199
1200 newstr[0] = '@';
1201 strcpy (&newstr[1], str);
1202
1203 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1204 }
1205
1206 /* Return 1 if this is a symbol in page0 */
1207 int
1208 m68hc11_page0_symbol_p (rtx x)
1209 {
1210 switch (GET_CODE (x))
1211 {
1212 case SYMBOL_REF:
1213 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1214
1215 case CONST:
1216 return m68hc11_page0_symbol_p (XEXP (x, 0));
1217
1218 case PLUS:
1219 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1220 return 0;
1221
1222 return GET_CODE (XEXP (x, 1)) == CONST_INT
1223 && INTVAL (XEXP (x, 1)) < 256
1224 && INTVAL (XEXP (x, 1)) >= 0;
1225
1226 default:
1227 return 0;
1228 }
1229 }
1230
1231 /* We want to recognize trap handlers so that we handle calls to traps
1232 in a special manner (by issuing the trap). This information is stored
1233 in SYMBOL_REF_FLAG. */
1234
1235 static void
1236 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1237 {
1238 tree func_attr;
1239 int trap_handler;
1240 int is_far = 0;
1241
1242 if (TREE_CODE (decl) == VAR_DECL)
1243 {
1244 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1245 m68hc11_encode_label (decl);
1246 return;
1247 }
1248
1249 if (TREE_CODE (decl) != FUNCTION_DECL)
1250 return;
1251
1252 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1253
1254
1255 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1256 is_far = 1;
1257 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1258 is_far = TARGET_LONG_CALLS != 0;
1259
1260 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1261 if (trap_handler && is_far)
1262 {
1263 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1264 "not compatible, ignoring %<far%>");
1265 trap_handler = 0;
1266 }
1267 if (trap_handler)
1268 {
1269 if (trap_handler_symbol != 0)
1270 warning (OPT_Wattributes, "%<trap%> attribute is already used");
1271 else
1272 trap_handler_symbol = XEXP (rtl, 0);
1273 }
1274 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1275 }
1276
1277 static unsigned int
1278 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1279 {
1280 unsigned int flags = default_section_type_flags (decl, name, reloc);
1281
1282 if (strncmp (name, ".eeprom", 7) == 0)
1283 {
1284 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1285 }
1286
1287 return flags;
1288 }
1289
1290 int
1291 m68hc11_is_far_symbol (rtx sym)
1292 {
1293 if (GET_CODE (sym) == MEM)
1294 sym = XEXP (sym, 0);
1295
1296 return SYMBOL_REF_FLAG (sym);
1297 }
1298
1299 int
1300 m68hc11_is_trap_symbol (rtx sym)
1301 {
1302 if (GET_CODE (sym) == MEM)
1303 sym = XEXP (sym, 0);
1304
1305 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1306 }
1307 \f
1308
1309 /* Argument support functions. */
1310
1311 /* Given FROM and TO register numbers, say whether this elimination is
1312 allowed. Frame pointer elimination is automatically handled.
1313
1314 All other eliminations are valid. */
1315
1316 bool
1317 m68hc11_can_eliminate (const int from, const int to)
1318 {
1319 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
1320 ? ! frame_pointer_needed
1321 : true);
1322 }
1323
1324 /* Define the offset between two registers, one to be eliminated, and the
1325 other its replacement, at the start of a routine. */
1326 int
1327 m68hc11_initial_elimination_offset (int from, int to)
1328 {
1329 int trap_handler;
1330 tree func_attr;
1331 int size;
1332 int regno;
1333
1334 /* For a trap handler, we must take into account the registers which
1335 are pushed on the stack during the trap (except the PC). */
1336 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1337 current_function_interrupt = lookup_attribute ("interrupt",
1338 func_attr) != NULL_TREE;
1339 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1340
1341 if (lookup_attribute ("far", func_attr) != 0)
1342 current_function_far = 1;
1343 else if (lookup_attribute ("near", func_attr) != 0)
1344 current_function_far = 0;
1345 else
1346 current_function_far = (TARGET_LONG_CALLS != 0
1347 && !current_function_interrupt
1348 && !trap_handler);
1349
1350 if (trap_handler && from == ARG_POINTER_REGNUM)
1351 size = 7;
1352
1353 /* For a function using 'call/rtc' we must take into account the
1354 page register which is pushed in the call. */
1355 else if (current_function_far && from == ARG_POINTER_REGNUM)
1356 size = 1;
1357 else
1358 size = 0;
1359
1360 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1361 {
1362 /* 2 is for the saved frame.
1363 1 is for the 'sts' correction when creating the frame. */
1364 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1365 }
1366
1367 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1368 {
1369 return m68hc11_sp_correction;
1370 }
1371
1372 /* Push any 2 byte pseudo hard registers that we need to save. */
1373 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1374 {
1375 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1376 {
1377 size += 2;
1378 }
1379 }
1380
1381 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1382 {
1383 return get_frame_size () + size;
1384 }
1385
1386 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1387 {
1388 return size;
1389 }
1390 return 0;
1391 }
1392
1393 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1394 for a call to a function whose data type is FNTYPE.
1395 For a library call, FNTYPE is 0. */
1396
1397 void
1398 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1399 {
1400 tree ret_type;
1401
1402 z_replacement_completed = 0;
1403 cum->words = 0;
1404 cum->nregs = 0;
1405
1406 /* For a library call, we must find out the type of the return value.
1407 When the return value is bigger than 4 bytes, it is returned in
1408 memory. In that case, the first argument of the library call is a
1409 pointer to the memory location. Because the first argument is passed in
1410 register D, we have to identify this, so that the first function
1411 parameter is not passed in D either. */
1412 if (fntype == 0)
1413 {
1414 const char *name;
1415 size_t len;
1416
1417 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1418 return;
1419
1420 /* If the library ends in 'di' or in 'df', we assume it's
1421 returning some DImode or some DFmode which are 64-bit wide. */
1422 name = XSTR (libname, 0);
1423 len = strlen (name);
1424 if (len > 3
1425 && ((name[len - 2] == 'd'
1426 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1427 || (name[len - 3] == 'd'
1428 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1429 {
1430 /* We are in. Mark the first parameter register as already used. */
1431 cum->words = 1;
1432 cum->nregs = 1;
1433 }
1434 return;
1435 }
1436
1437 ret_type = TREE_TYPE (fntype);
1438
1439 if (ret_type && aggregate_value_p (ret_type, fntype))
1440 {
1441 cum->words = 1;
1442 cum->nregs = 1;
1443 }
1444 }
1445
1446 /* Update the data in CUM to advance over an argument
1447 of mode MODE and data type TYPE.
1448 (TYPE is null for libcalls where that information may not be available.) */
1449
1450 void
1451 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1452 tree type, int named ATTRIBUTE_UNUSED)
1453 {
1454 if (mode != BLKmode)
1455 {
1456 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1457 {
1458 cum->nregs = 2;
1459 cum->words = GET_MODE_SIZE (mode);
1460 }
1461 else
1462 {
1463 cum->words += GET_MODE_SIZE (mode);
1464 if (cum->words <= HARD_REG_SIZE)
1465 cum->nregs = 1;
1466 }
1467 }
1468 else
1469 {
1470 cum->words += int_size_in_bytes (type);
1471 }
1472 return;
1473 }
1474
1475 /* Define where to put the arguments to a function.
1476 Value is zero to push the argument on the stack,
1477 or a hard register in which to store the argument.
1478
1479 MODE is the argument's machine mode.
1480 TYPE is the data type of the argument (as a tree).
1481 This is null for libcalls where that information may
1482 not be available.
1483 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1484 the preceding args and about the function being called.
1485 NAMED is nonzero if this argument is a named parameter
1486 (otherwise it is an extra parameter matching an ellipsis). */
1487
1488 struct rtx_def *
1489 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1490 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1491 {
1492 if (cum->words != 0)
1493 {
1494 return NULL_RTX;
1495 }
1496
1497 if (mode != BLKmode)
1498 {
1499 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1500 return gen_rtx_REG (mode, HARD_X_REGNUM);
1501
1502 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1503 {
1504 return NULL_RTX;
1505 }
1506 return gen_rtx_REG (mode, HARD_D_REGNUM);
1507 }
1508 return NULL_RTX;
1509 }
1510
1511 /* If defined, a C expression which determines whether, and in which direction,
1512 to pad out an argument with extra space. The value should be of type
1513 `enum direction': either `upward' to pad above the argument,
1514 `downward' to pad below, or `none' to inhibit padding.
1515
1516 Structures are stored left shifted in their argument slot. */
1517 enum direction
1518 m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
1519 {
1520 if (type != 0 && AGGREGATE_TYPE_P (type))
1521 return upward;
1522
1523 /* Fall back to the default. */
1524 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1525 }
1526 \f
1527
1528 /* Function prologue and epilogue. */
1529
1530 /* Emit a move after the reload pass has completed. This is used to
1531 emit the prologue and epilogue. */
1532 static void
1533 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1534 {
1535 rtx insn;
1536
1537 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1538 {
1539 insn = emit_move_insn (to, from);
1540 }
1541 else
1542 {
1543 emit_move_insn (scratch, from);
1544 insn = emit_move_insn (to, scratch);
1545 }
1546
1547 /* Put a REG_INC note to tell the flow analysis that the instruction
1548 is necessary. */
1549 if (IS_STACK_PUSH (to))
1550 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
1551 else if (IS_STACK_POP (from))
1552 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
1553
1554 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1555 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1556 The problem is that we are lying to gcc and use `txs' for x = sp
1557 (which is not really true because txs is really x = sp + 1). */
1558 else if (TARGET_M6811 && SP_REG_P (from))
1559 add_reg_note (insn, REG_INC, from);
1560 }
1561
1562 int
1563 m68hc11_total_frame_size (void)
1564 {
1565 int size;
1566 int regno;
1567
1568 size = get_frame_size ();
1569 if (current_function_interrupt)
1570 {
1571 size += 3 * HARD_REG_SIZE;
1572 }
1573 if (frame_pointer_needed)
1574 size += HARD_REG_SIZE;
1575
1576 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1577 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1578 size += HARD_REG_SIZE;
1579
1580 return size;
1581 }
1582
1583 static void
1584 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1585 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1586 {
1587 /* We catch the function epilogue generation to have a chance
1588 to clear the z_replacement_completed flag. */
1589 z_replacement_completed = 0;
1590 }
1591
1592 void
1593 expand_prologue (void)
1594 {
1595 tree func_attr;
1596 int size;
1597 int regno;
1598 rtx scratch;
1599
1600 gcc_assert (reload_completed == 1);
1601
1602 size = get_frame_size ();
1603
1604 create_regs_rtx ();
1605
1606 /* Generate specific prologue for interrupt handlers. */
1607 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1608 current_function_interrupt = lookup_attribute ("interrupt",
1609 func_attr) != NULL_TREE;
1610 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1611 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1612 current_function_far = 1;
1613 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1614 current_function_far = 0;
1615 else
1616 current_function_far = (TARGET_LONG_CALLS != 0
1617 && !current_function_interrupt
1618 && !current_function_trap);
1619
1620 /* Get the scratch register to build the frame and push registers.
1621 If the first argument is a 32-bit quantity, the D+X registers
1622 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1623 For 68HC12, this scratch register is not used. */
1624 if (crtl->args.info.nregs == 2)
1625 scratch = iy_reg;
1626 else
1627 scratch = ix_reg;
1628
1629 /* Save current stack frame. */
1630 if (frame_pointer_needed)
1631 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1632
1633 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1634 Other soft registers in page0 need not to be saved because they
1635 will be restored by C functions. For a trap handler, we don't
1636 need to preserve these registers because this is a synchronous call. */
1637 if (current_function_interrupt)
1638 {
1639 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1640 emit_move_after_reload (stack_push_word,
1641 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1642 emit_move_after_reload (stack_push_word,
1643 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1644 scratch);
1645 }
1646
1647 /* Allocate local variables. */
1648 if (TARGET_M6812 && (size > 4 || size == 3))
1649 {
1650 emit_insn (gen_addhi3 (stack_pointer_rtx,
1651 stack_pointer_rtx, GEN_INT (-size)));
1652 }
1653 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1654 {
1655 rtx insn;
1656
1657 insn = gen_rtx_PARALLEL
1658 (VOIDmode,
1659 gen_rtvec (2,
1660 gen_rtx_SET (VOIDmode,
1661 stack_pointer_rtx,
1662 gen_rtx_PLUS (HImode,
1663 stack_pointer_rtx,
1664 GEN_INT (-size))),
1665 gen_rtx_CLOBBER (VOIDmode, scratch)));
1666 emit_insn (insn);
1667 }
1668 else
1669 {
1670 int i;
1671
1672 /* Allocate by pushing scratch values. */
1673 for (i = 2; i <= size; i += 2)
1674 emit_move_after_reload (stack_push_word, ix_reg, 0);
1675
1676 if (size & 1)
1677 emit_insn (gen_addhi3 (stack_pointer_rtx,
1678 stack_pointer_rtx, constm1_rtx));
1679 }
1680
1681 /* Create the frame pointer. */
1682 if (frame_pointer_needed)
1683 emit_move_after_reload (hard_frame_pointer_rtx,
1684 stack_pointer_rtx, scratch);
1685
1686 /* Push any 2 byte pseudo hard registers that we need to save. */
1687 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1688 {
1689 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1690 {
1691 emit_move_after_reload (stack_push_word,
1692 gen_rtx_REG (HImode, regno), scratch);
1693 }
1694 }
1695 }
1696
1697 void
1698 expand_epilogue (void)
1699 {
1700 int size;
1701 register int regno;
1702 int return_size;
1703 rtx scratch;
1704
1705 gcc_assert (reload_completed == 1);
1706
1707 size = get_frame_size ();
1708
1709 /* If we are returning a value in two registers, we have to preserve the
1710 X register and use the Y register to restore the stack and the saved
1711 registers. Otherwise, use X because it's faster (and smaller). */
1712 if (crtl->return_rtx == 0)
1713 return_size = 0;
1714 else if (GET_CODE (crtl->return_rtx) == MEM)
1715 return_size = HARD_REG_SIZE;
1716 else
1717 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
1718
1719 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1720 scratch = iy_reg;
1721 else
1722 scratch = ix_reg;
1723
1724 /* Pop any 2 byte pseudo hard registers that we saved. */
1725 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1726 {
1727 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1728 {
1729 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1730 stack_pop_word, scratch);
1731 }
1732 }
1733
1734 /* de-allocate auto variables */
1735 if (TARGET_M6812 && (size > 4 || size == 3))
1736 {
1737 emit_insn (gen_addhi3 (stack_pointer_rtx,
1738 stack_pointer_rtx, GEN_INT (size)));
1739 }
1740 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1741 {
1742 rtx insn;
1743
1744 insn = gen_rtx_PARALLEL
1745 (VOIDmode,
1746 gen_rtvec (2,
1747 gen_rtx_SET (VOIDmode,
1748 stack_pointer_rtx,
1749 gen_rtx_PLUS (HImode,
1750 stack_pointer_rtx,
1751 GEN_INT (size))),
1752 gen_rtx_CLOBBER (VOIDmode, scratch)));
1753 emit_insn (insn);
1754 }
1755 else
1756 {
1757 int i;
1758
1759 for (i = 2; i <= size; i += 2)
1760 emit_move_after_reload (scratch, stack_pop_word, scratch);
1761 if (size & 1)
1762 emit_insn (gen_addhi3 (stack_pointer_rtx,
1763 stack_pointer_rtx, const1_rtx));
1764 }
1765
1766 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1767 if (current_function_interrupt)
1768 {
1769 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1770 stack_pop_word, scratch);
1771 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1772 stack_pop_word, scratch);
1773 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1774 }
1775
1776 /* Restore previous frame pointer. */
1777 if (frame_pointer_needed)
1778 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1779
1780 /* If the trap handler returns some value, copy the value
1781 in D, X onto the stack so that the rti will pop the return value
1782 correctly. */
1783 else if (current_function_trap && return_size != 0)
1784 {
1785 rtx addr_reg = stack_pointer_rtx;
1786
1787 if (!TARGET_M6812)
1788 {
1789 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1790 addr_reg = scratch;
1791 }
1792 emit_move_after_reload (gen_rtx_MEM (HImode,
1793 gen_rtx_PLUS (HImode, addr_reg,
1794 const1_rtx)), d_reg, 0);
1795 if (return_size > HARD_REG_SIZE)
1796 emit_move_after_reload (gen_rtx_MEM (HImode,
1797 gen_rtx_PLUS (HImode, addr_reg,
1798 GEN_INT (3))), ix_reg, 0);
1799 }
1800
1801 emit_jump_insn (gen_return ());
1802 }
1803 \f
1804
1805 /* Low and High part extraction for 68HC11. These routines are
1806 similar to gen_lowpart and gen_highpart but they have been
1807 fixed to work for constants and 68HC11 specific registers. */
1808
1809 rtx
1810 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1811 {
1812 /* We assume that the low part of an auto-inc mode is the same with
1813 the mode changed and that the caller split the larger mode in the
1814 correct order. */
1815 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1816 {
1817 return gen_rtx_MEM (mode, XEXP (x, 0));
1818 }
1819
1820 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1821 floating-point constant. A CONST_DOUBLE is used whenever the
1822 constant requires more than one word in order to be adequately
1823 represented. */
1824 if (GET_CODE (x) == CONST_DOUBLE)
1825 {
1826 long l[2];
1827
1828 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1829 {
1830 REAL_VALUE_TYPE r;
1831
1832 if (GET_MODE (x) == SFmode)
1833 {
1834 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1835 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1836 }
1837 else
1838 {
1839 rtx first, second;
1840
1841 split_double (x, &first, &second);
1842 return second;
1843 }
1844 if (mode == SImode)
1845 return GEN_INT (l[0]);
1846
1847 return gen_int_mode (l[0], HImode);
1848 }
1849 else
1850 {
1851 l[0] = CONST_DOUBLE_LOW (x);
1852 }
1853 switch (mode)
1854 {
1855 case SImode:
1856 return GEN_INT (l[0]);
1857 case HImode:
1858 gcc_assert (GET_MODE (x) == SFmode);
1859 return gen_int_mode (l[0], HImode);
1860 default:
1861 gcc_unreachable ();
1862 }
1863 }
1864
1865 if (mode == QImode && D_REG_P (x))
1866 return gen_rtx_REG (mode, HARD_B_REGNUM);
1867
1868 /* gen_lowpart crashes when it is called with a SUBREG. */
1869 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1870 {
1871 switch (mode)
1872 {
1873 case SImode:
1874 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1875 case HImode:
1876 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1877 default:
1878 gcc_unreachable ();
1879 }
1880 }
1881 x = gen_lowpart (mode, x);
1882
1883 /* Return a different rtx to avoid to share it in several insns
1884 (when used by a split pattern). Sharing addresses within
1885 a MEM breaks the Z register replacement (and reloading). */
1886 if (GET_CODE (x) == MEM)
1887 x = copy_rtx (x);
1888 return x;
1889 }
1890
1891 rtx
1892 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1893 {
1894 /* We assume that the high part of an auto-inc mode is the same with
1895 the mode changed and that the caller split the larger mode in the
1896 correct order. */
1897 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1898 {
1899 return gen_rtx_MEM (mode, XEXP (x, 0));
1900 }
1901
1902 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1903 floating-point constant. A CONST_DOUBLE is used whenever the
1904 constant requires more than one word in order to be adequately
1905 represented. */
1906 if (GET_CODE (x) == CONST_DOUBLE)
1907 {
1908 long l[2];
1909
1910 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1911 {
1912 REAL_VALUE_TYPE r;
1913
1914 if (GET_MODE (x) == SFmode)
1915 {
1916 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1917 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1918 }
1919 else
1920 {
1921 rtx first, second;
1922
1923 split_double (x, &first, &second);
1924 return first;
1925 }
1926 if (mode == SImode)
1927 return GEN_INT (l[1]);
1928
1929 return gen_int_mode ((l[1] >> 16), HImode);
1930 }
1931 else
1932 {
1933 l[1] = CONST_DOUBLE_HIGH (x);
1934 }
1935
1936 switch (mode)
1937 {
1938 case SImode:
1939 return GEN_INT (l[1]);
1940 case HImode:
1941 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1942 return gen_int_mode ((l[0] >> 16), HImode);
1943 default:
1944 gcc_unreachable ();
1945 }
1946 }
1947 if (GET_CODE (x) == CONST_INT)
1948 {
1949 HOST_WIDE_INT val = INTVAL (x);
1950
1951 if (mode == QImode)
1952 {
1953 return gen_int_mode (val >> 8, QImode);
1954 }
1955 else if (mode == HImode)
1956 {
1957 return gen_int_mode (val >> 16, HImode);
1958 }
1959 else if (mode == SImode)
1960 {
1961 return gen_int_mode (val >> 32, SImode);
1962 }
1963 }
1964 if (mode == QImode && D_REG_P (x))
1965 return gen_rtx_REG (mode, HARD_A_REGNUM);
1966
1967 /* There is no way in GCC to represent the upper part of a word register.
1968 To obtain the 8-bit upper part of a soft register, we change the
1969 reg into a mem rtx. This is possible because they are physically
1970 located in memory. There is no offset because we are big-endian. */
1971 if (mode == QImode && S_REG_P (x))
1972 {
1973 int pos;
1974
1975 /* Avoid the '*' for direct addressing mode when this
1976 addressing mode is disabled. */
1977 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1978 return gen_rtx_MEM (QImode,
1979 gen_rtx_SYMBOL_REF (Pmode,
1980 &reg_names[REGNO (x)][pos]));
1981 }
1982
1983 /* gen_highpart crashes when it is called with a SUBREG. */
1984 switch (GET_CODE (x))
1985 {
1986 case SUBREG:
1987 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
1988 case REG:
1989 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1990 return gen_rtx_REG (mode, REGNO (x));
1991 else
1992 return gen_rtx_SUBREG (mode, x, 0);
1993 case MEM:
1994 x = change_address (x, mode, 0);
1995
1996 /* Return a different rtx to avoid to share it in several insns
1997 (when used by a split pattern). Sharing addresses within
1998 a MEM breaks the Z register replacement (and reloading). */
1999 if (GET_CODE (x) == MEM)
2000 x = copy_rtx (x);
2001 return x;
2002
2003 default:
2004 gcc_unreachable ();
2005 }
2006 }
2007 \f
2008
2009 /* Obscure register manipulation. */
2010
2011 /* Finds backward in the instructions to see if register 'reg' is
2012 dead. This is used when generating code to see if we can use 'reg'
2013 as a scratch register. This allows us to choose a better generation
2014 of code when we know that some register dies or can be clobbered. */
2015
2016 int
2017 dead_register_here (rtx x, rtx reg)
2018 {
2019 rtx x_reg;
2020 rtx p;
2021
2022 if (D_REG_P (reg))
2023 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2024 else
2025 x_reg = 0;
2026
2027 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2028 if (INSN_P (p))
2029 {
2030 rtx body;
2031
2032 body = PATTERN (p);
2033
2034 if (GET_CODE (body) == CALL_INSN)
2035 break;
2036 if (GET_CODE (body) == JUMP_INSN)
2037 break;
2038
2039 if (GET_CODE (body) == SET)
2040 {
2041 rtx dst = XEXP (body, 0);
2042
2043 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2044 break;
2045 if (x_reg && rtx_equal_p (dst, x_reg))
2046 break;
2047
2048 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2049 return 1;
2050 }
2051 else if (reg_mentioned_p (reg, p)
2052 || (x_reg && reg_mentioned_p (x_reg, p)))
2053 break;
2054 }
2055
2056 /* Scan forward to see if the register is set in some insns and never
2057 used since then. */
2058 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2059 {
2060 rtx body;
2061
2062 if (GET_CODE (p) == CODE_LABEL
2063 || GET_CODE (p) == JUMP_INSN
2064 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2065 break;
2066
2067 if (GET_CODE (p) != INSN)
2068 continue;
2069
2070 body = PATTERN (p);
2071 if (GET_CODE (body) == SET)
2072 {
2073 rtx src = XEXP (body, 1);
2074 rtx dst = XEXP (body, 0);
2075
2076 if (GET_CODE (dst) == REG
2077 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2078 return 1;
2079 }
2080
2081 /* Register is used (may be in source or in dest). */
2082 if (reg_mentioned_p (reg, p)
2083 || (x_reg != 0 && GET_MODE (p) == SImode
2084 && reg_mentioned_p (x_reg, p)))
2085 break;
2086 }
2087 return p == 0 ? 1 : 0;
2088 }
2089 \f
2090
2091 /* Code generation operations called from machine description file. */
2092
2093 /* Print the name of register 'regno' in the assembly file. */
2094 static void
2095 asm_print_register (FILE *file, int regno)
2096 {
2097 const char *name = reg_names[regno];
2098
2099 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2100 name++;
2101
2102 fprintf (file, "%s", name);
2103 }
2104
2105 /* A C compound statement to output to stdio stream STREAM the
2106 assembler syntax for an instruction operand X. X is an RTL
2107 expression.
2108
2109 CODE is a value that can be used to specify one of several ways
2110 of printing the operand. It is used when identical operands
2111 must be printed differently depending on the context. CODE
2112 comes from the `%' specification that was used to request
2113 printing of the operand. If the specification was just `%DIGIT'
2114 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2115 is the ASCII code for LTR.
2116
2117 If X is a register, this macro should print the register's name.
2118 The names can be found in an array `reg_names' whose type is
2119 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2120
2121 When the machine description has a specification `%PUNCT' (a `%'
2122 followed by a punctuation character), this macro is called with
2123 a null pointer for X and the punctuation character for CODE.
2124
2125 The M68HC11 specific codes are:
2126
2127 'b' for the low part of the operand.
2128 'h' for the high part of the operand
2129 The 'b' or 'h' modifiers have no effect if the operand has
2130 the QImode and is not a S_REG_P (soft register). If the
2131 operand is a hard register, these two modifiers have no effect.
2132 't' generate the temporary scratch register. The operand is
2133 ignored.
2134 'T' generate the low-part temporary scratch register. The operand is
2135 ignored. */
2136
2137 static void
2138 m68hc11_print_operand (FILE *file, rtx op, int letter)
2139 {
2140 if (letter == 't')
2141 {
2142 asm_print_register (file, SOFT_TMP_REGNUM);
2143 return;
2144 }
2145 else if (letter == 'T')
2146 {
2147 asm_print_register (file, SOFT_TMP_REGNUM);
2148 fprintf (file, "+1");
2149 return;
2150 }
2151 else if (letter == '#')
2152 {
2153 asm_fprintf (file, "%I");
2154 }
2155
2156 if (GET_CODE (op) == REG)
2157 {
2158 if (letter == 'b' && S_REG_P (op))
2159 {
2160 asm_print_register (file, REGNO (op));
2161 fprintf (file, "+1");
2162 }
2163 else if (letter == 'b' && D_REG_P (op))
2164 {
2165 asm_print_register (file, HARD_B_REGNUM);
2166 }
2167 else
2168 {
2169 asm_print_register (file, REGNO (op));
2170 }
2171 return;
2172 }
2173
2174 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2175 {
2176 if (letter == 'b')
2177 asm_fprintf (file, "%I%%lo(");
2178 else
2179 asm_fprintf (file, "%I%%hi(");
2180
2181 output_addr_const (file, op);
2182 fprintf (file, ")");
2183 return;
2184 }
2185
2186 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2187 are specified. If we already have a QImode, there is nothing to do. */
2188 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2189 {
2190 if (letter == 'b')
2191 {
2192 op = m68hc11_gen_lowpart (QImode, op);
2193 }
2194 else if (letter == 'h')
2195 {
2196 op = m68hc11_gen_highpart (QImode, op);
2197 }
2198 }
2199
2200 if (GET_CODE (op) == MEM)
2201 {
2202 rtx base = XEXP (op, 0);
2203 switch (GET_CODE (base))
2204 {
2205 case PRE_DEC:
2206 gcc_assert (TARGET_M6812);
2207 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2208 asm_print_register (file, REGNO (XEXP (base, 0)));
2209 break;
2210
2211 case POST_DEC:
2212 gcc_assert (TARGET_M6812);
2213 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2214 asm_print_register (file, REGNO (XEXP (base, 0)));
2215 fprintf (file, "-");
2216 break;
2217
2218 case POST_INC:
2219 gcc_assert (TARGET_M6812);
2220 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2221 asm_print_register (file, REGNO (XEXP (base, 0)));
2222 fprintf (file, "+");
2223 break;
2224
2225 case PRE_INC:
2226 gcc_assert (TARGET_M6812);
2227 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2228 asm_print_register (file, REGNO (XEXP (base, 0)));
2229 break;
2230
2231 case MEM:
2232 gcc_assert (TARGET_M6812);
2233 fprintf (file, "[");
2234 print_operand_address (file, XEXP (base, 0));
2235 fprintf (file, "]");
2236 break;
2237
2238 default:
2239 if (m68hc11_page0_symbol_p (base))
2240 fprintf (file, "*");
2241
2242 output_address (base);
2243 break;
2244 }
2245 }
2246 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2247 {
2248 REAL_VALUE_TYPE r;
2249 long l;
2250
2251 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2252 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2253 asm_fprintf (file, "%I0x%lx", l);
2254 }
2255 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2256 {
2257 char dstr[30];
2258
2259 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2260 sizeof (dstr), 0, 1);
2261 asm_fprintf (file, "%I0r%s", dstr);
2262 }
2263 else
2264 {
2265 int need_parenthesize = 0;
2266
2267 if (letter != 'i')
2268 asm_fprintf (file, "%I");
2269 else
2270 need_parenthesize = must_parenthesize (op);
2271
2272 if (need_parenthesize)
2273 fprintf (file, "(");
2274
2275 output_addr_const (file, op);
2276 if (need_parenthesize)
2277 fprintf (file, ")");
2278 }
2279 }
2280
2281 /* Returns true if the operand 'op' must be printed with parenthesis
2282 around it. This must be done only if there is a symbol whose name
2283 is a processor register. */
2284 static int
2285 must_parenthesize (rtx op)
2286 {
2287 const char *name;
2288
2289 switch (GET_CODE (op))
2290 {
2291 case SYMBOL_REF:
2292 name = XSTR (op, 0);
2293 /* Avoid a conflict between symbol name and a possible
2294 register. */
2295 return (strcasecmp (name, "a") == 0
2296 || strcasecmp (name, "b") == 0
2297 || strcasecmp (name, "d") == 0
2298 || strcasecmp (name, "x") == 0
2299 || strcasecmp (name, "y") == 0
2300 || strcasecmp (name, "ix") == 0
2301 || strcasecmp (name, "iy") == 0
2302 || strcasecmp (name, "pc") == 0
2303 || strcasecmp (name, "sp") == 0
2304 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2305
2306 case PLUS:
2307 case MINUS:
2308 return must_parenthesize (XEXP (op, 0))
2309 || must_parenthesize (XEXP (op, 1));
2310
2311 case MEM:
2312 case CONST:
2313 case ZERO_EXTEND:
2314 case SIGN_EXTEND:
2315 return must_parenthesize (XEXP (op, 0));
2316
2317 case CONST_DOUBLE:
2318 case CONST_INT:
2319 case LABEL_REF:
2320 case CODE_LABEL:
2321 default:
2322 return 0;
2323 }
2324 }
2325
2326 /* A C compound statement to output to stdio stream STREAM the
2327 assembler syntax for an instruction operand that is a memory
2328 reference whose address is ADDR. ADDR is an RTL expression. */
2329
2330 static void
2331 m68hc11_print_operand_address (FILE *file, rtx addr)
2332 {
2333 rtx base;
2334 rtx offset;
2335 int need_parenthesis = 0;
2336
2337 switch (GET_CODE (addr))
2338 {
2339 case REG:
2340 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2341
2342 fprintf (file, "0,");
2343 asm_print_register (file, REGNO (addr));
2344 break;
2345
2346 case MEM:
2347 base = XEXP (addr, 0);
2348 switch (GET_CODE (base))
2349 {
2350 case PRE_DEC:
2351 gcc_assert (TARGET_M6812);
2352 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2353 asm_print_register (file, REGNO (XEXP (base, 0)));
2354 break;
2355
2356 case POST_DEC:
2357 gcc_assert (TARGET_M6812);
2358 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2359 asm_print_register (file, REGNO (XEXP (base, 0)));
2360 fprintf (file, "-");
2361 break;
2362
2363 case POST_INC:
2364 gcc_assert (TARGET_M6812);
2365 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2366 asm_print_register (file, REGNO (XEXP (base, 0)));
2367 fprintf (file, "+");
2368 break;
2369
2370 case PRE_INC:
2371 gcc_assert (TARGET_M6812);
2372 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2373 asm_print_register (file, REGNO (XEXP (base, 0)));
2374 break;
2375
2376 default:
2377 need_parenthesis = must_parenthesize (base);
2378 if (need_parenthesis)
2379 fprintf (file, "(");
2380
2381 output_addr_const (file, base);
2382 if (need_parenthesis)
2383 fprintf (file, ")");
2384 break;
2385 }
2386 break;
2387
2388 case PLUS:
2389 base = XEXP (addr, 0);
2390 offset = XEXP (addr, 1);
2391 if (!G_REG_P (base) && G_REG_P (offset))
2392 {
2393 base = XEXP (addr, 1);
2394 offset = XEXP (addr, 0);
2395 }
2396 if (CONSTANT_ADDRESS_P (base))
2397 {
2398 need_parenthesis = must_parenthesize (addr);
2399
2400 gcc_assert (CONSTANT_ADDRESS_P (offset));
2401 if (need_parenthesis)
2402 fprintf (file, "(");
2403
2404 output_addr_const (file, base);
2405 fprintf (file, "+");
2406 output_addr_const (file, offset);
2407 if (need_parenthesis)
2408 fprintf (file, ")");
2409 }
2410 else
2411 {
2412 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2413 if (REG_P (offset))
2414 {
2415 gcc_assert (TARGET_M6812);
2416 asm_print_register (file, REGNO (offset));
2417 fprintf (file, ",");
2418 asm_print_register (file, REGNO (base));
2419 }
2420 else
2421 {
2422 need_parenthesis = must_parenthesize (offset);
2423 if (need_parenthesis)
2424 fprintf (file, "(");
2425
2426 output_addr_const (file, offset);
2427 if (need_parenthesis)
2428 fprintf (file, ")");
2429 fprintf (file, ",");
2430 asm_print_register (file, REGNO (base));
2431 }
2432 }
2433 break;
2434
2435 default:
2436 if (GET_CODE (addr) == CONST_INT
2437 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2438 {
2439 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2440 }
2441 else
2442 {
2443 need_parenthesis = must_parenthesize (addr);
2444 if (need_parenthesis)
2445 fprintf (file, "(");
2446
2447 output_addr_const (file, addr);
2448 if (need_parenthesis)
2449 fprintf (file, ")");
2450 }
2451 break;
2452 }
2453 }
2454 \f
2455
2456 /* Splitting of some instructions. */
2457
2458 static rtx
2459 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2460 {
2461 rtx ret = 0;
2462
2463 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2464 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2465 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2466 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2467
2468 return ret;
2469 }
2470
2471 rtx
2472 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2473 rtx label)
2474 {
2475 rtx tmp;
2476
2477 switch (GET_MODE (op0))
2478 {
2479 case QImode:
2480 case HImode:
2481 tmp = m68hc11_expand_compare (code, op0, op1);
2482 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2483 gen_rtx_LABEL_REF (VOIDmode, label),
2484 pc_rtx);
2485 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2486 return 0;
2487 #if 0
2488
2489 /* SCz: from i386.c */
2490 case SFmode:
2491 case DFmode:
2492 /* Don't expand the comparison early, so that we get better code
2493 when jump or whoever decides to reverse the comparison. */
2494 {
2495 rtvec vec;
2496 int use_fcomi;
2497
2498 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2499 &m68hc11_compare_op1);
2500
2501 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2502 m68hc11_compare_op0, m68hc11_compare_op1);
2503 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2504 gen_rtx_LABEL_REF (VOIDmode, label),
2505 pc_rtx);
2506 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2507
2508 use_fcomi = ix86_use_fcomi_compare (code);
2509 vec = rtvec_alloc (3 + !use_fcomi);
2510 RTVEC_ELT (vec, 0) = tmp;
2511 RTVEC_ELT (vec, 1)
2512 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2513 RTVEC_ELT (vec, 2)
2514 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2515 if (!use_fcomi)
2516 RTVEC_ELT (vec, 3)
2517 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2518
2519 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2520 return;
2521 }
2522 #endif
2523
2524 case SImode:
2525 /* Expand SImode branch into multiple compare+branch. */
2526 {
2527 rtx lo[2], hi[2], label2;
2528 enum rtx_code code1, code2, code3;
2529
2530 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2531 {
2532 tmp = op0;
2533 op0 = op1;
2534 op1 = tmp;
2535 code = swap_condition (code);
2536 }
2537 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2538 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2539 hi[0] = m68hc11_gen_highpart (HImode, op0);
2540 hi[1] = m68hc11_gen_highpart (HImode, op1);
2541
2542 /* Otherwise, if we are doing less-than, op1 is a constant and the
2543 low word is zero, then we can just examine the high word. */
2544
2545 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2546 && (code == LT || code == LTU))
2547 {
2548 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2549 label);
2550 }
2551
2552 /* Otherwise, we need two or three jumps. */
2553
2554 label2 = gen_label_rtx ();
2555
2556 code1 = code;
2557 code2 = swap_condition (code);
2558 code3 = unsigned_condition (code);
2559
2560 switch (code)
2561 {
2562 case LT:
2563 case GT:
2564 case LTU:
2565 case GTU:
2566 break;
2567
2568 case LE:
2569 code1 = LT;
2570 code2 = GT;
2571 break;
2572 case GE:
2573 code1 = GT;
2574 code2 = LT;
2575 break;
2576 case LEU:
2577 code1 = LTU;
2578 code2 = GTU;
2579 break;
2580 case GEU:
2581 code1 = GTU;
2582 code2 = LTU;
2583 break;
2584
2585 case EQ:
2586 code1 = UNKNOWN;
2587 code2 = NE;
2588 break;
2589 case NE:
2590 code2 = UNKNOWN;
2591 break;
2592
2593 default:
2594 gcc_unreachable ();
2595 }
2596
2597 /*
2598 * a < b =>
2599 * if (hi(a) < hi(b)) goto true;
2600 * if (hi(a) > hi(b)) goto false;
2601 * if (lo(a) < lo(b)) goto true;
2602 * false:
2603 */
2604 if (code1 != UNKNOWN)
2605 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2606 if (code2 != UNKNOWN)
2607 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2608
2609 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2610
2611 if (code2 != UNKNOWN)
2612 emit_label (label2);
2613 return 0;
2614 }
2615
2616 default:
2617 gcc_unreachable ();
2618 }
2619 return 0;
2620 }
2621
2622 /* Return the increment/decrement mode of a MEM if it is such.
2623 Return CONST if it is anything else. */
2624 static int
2625 autoinc_mode (rtx x)
2626 {
2627 if (GET_CODE (x) != MEM)
2628 return CONST;
2629
2630 x = XEXP (x, 0);
2631 if (GET_CODE (x) == PRE_INC
2632 || GET_CODE (x) == PRE_DEC
2633 || GET_CODE (x) == POST_INC
2634 || GET_CODE (x) == POST_DEC)
2635 return GET_CODE (x);
2636
2637 return CONST;
2638 }
2639
2640 static int
2641 m68hc11_make_autoinc_notes (rtx *x, void *data)
2642 {
2643 rtx insn;
2644
2645 switch (GET_CODE (*x))
2646 {
2647 case PRE_DEC:
2648 case PRE_INC:
2649 case POST_DEC:
2650 case POST_INC:
2651 insn = (rtx) data;
2652 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2653 REG_NOTES (insn));
2654 return -1;
2655
2656 default:
2657 return 0;
2658 }
2659 }
2660
2661 /* Split a DI, SI or HI move into several smaller move operations.
2662 The scratch register 'scratch' is used as a temporary to load
2663 store intermediate values. It must be a hard register. */
2664 void
2665 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2666 {
2667 rtx low_to, low_from;
2668 rtx high_to, high_from;
2669 rtx insn;
2670 enum machine_mode mode;
2671 int offset = 0;
2672 int autoinc_from = autoinc_mode (from);
2673 int autoinc_to = autoinc_mode (to);
2674
2675 mode = GET_MODE (to);
2676
2677 /* If the TO and FROM contain autoinc modes that are not compatible
2678 together (one pop and the other a push), we must change one to
2679 an offsetable operand and generate an appropriate add at the end. */
2680 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2681 {
2682 rtx reg;
2683 int code;
2684
2685 /* The source uses an autoinc mode which is not compatible with
2686 a split (this would result in a word swap). */
2687 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2688 {
2689 code = GET_CODE (XEXP (from, 0));
2690 reg = XEXP (XEXP (from, 0), 0);
2691 offset = GET_MODE_SIZE (GET_MODE (from));
2692 if (code == POST_DEC)
2693 offset = -offset;
2694
2695 if (code == PRE_INC)
2696 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2697
2698 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2699 if (code == POST_DEC)
2700 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2701 return;
2702 }
2703
2704 /* Likewise for destination. */
2705 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2706 {
2707 code = GET_CODE (XEXP (to, 0));
2708 reg = XEXP (XEXP (to, 0), 0);
2709 offset = GET_MODE_SIZE (GET_MODE (to));
2710 if (code == POST_DEC)
2711 offset = -offset;
2712
2713 if (code == PRE_INC)
2714 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2715
2716 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2717 if (code == POST_DEC)
2718 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2719 return;
2720 }
2721
2722 /* The source and destination auto increment modes must be compatible
2723 with each other: same direction. */
2724 if ((autoinc_to != autoinc_from
2725 && autoinc_to != CONST && autoinc_from != CONST)
2726 /* The destination address register must not be used within
2727 the source operand because the source address would change
2728 while doing the copy. */
2729 || (autoinc_to != CONST
2730 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2731 && !IS_STACK_PUSH (to)))
2732 {
2733 /* Must change the destination. */
2734 code = GET_CODE (XEXP (to, 0));
2735 reg = XEXP (XEXP (to, 0), 0);
2736 offset = GET_MODE_SIZE (GET_MODE (to));
2737 if (code == PRE_DEC || code == POST_DEC)
2738 offset = -offset;
2739
2740 if (code == PRE_DEC || code == PRE_INC)
2741 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2742 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2743 if (code == POST_DEC || code == POST_INC)
2744 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2745
2746 return;
2747 }
2748
2749 /* Likewise, the source address register must not be used within
2750 the destination operand. */
2751 if (autoinc_from != CONST
2752 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2753 && !IS_STACK_PUSH (to))
2754 {
2755 /* Must change the source. */
2756 code = GET_CODE (XEXP (from, 0));
2757 reg = XEXP (XEXP (from, 0), 0);
2758 offset = GET_MODE_SIZE (GET_MODE (from));
2759 if (code == PRE_DEC || code == POST_DEC)
2760 offset = -offset;
2761
2762 if (code == PRE_DEC || code == PRE_INC)
2763 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2764 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2765 if (code == POST_DEC || code == POST_INC)
2766 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2767
2768 return;
2769 }
2770 }
2771
2772 if (GET_MODE_SIZE (mode) == 8)
2773 mode = SImode;
2774 else if (GET_MODE_SIZE (mode) == 4)
2775 mode = HImode;
2776 else
2777 mode = QImode;
2778
2779 if (TARGET_M6812
2780 && IS_STACK_PUSH (to)
2781 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2782 {
2783 if (mode == SImode)
2784 {
2785 offset = 4;
2786 }
2787 else if (mode == HImode)
2788 {
2789 offset = 2;
2790 }
2791 else
2792 offset = 0;
2793 }
2794
2795 low_to = m68hc11_gen_lowpart (mode, to);
2796 high_to = m68hc11_gen_highpart (mode, to);
2797
2798 low_from = m68hc11_gen_lowpart (mode, from);
2799 high_from = m68hc11_gen_highpart (mode, from);
2800
2801 if (offset)
2802 {
2803 high_from = adjust_address (high_from, mode, offset);
2804 low_from = high_from;
2805 }
2806
2807 /* When copying with a POST_INC mode, we must copy the
2808 high part and then the low part to guarantee a correct
2809 32/64-bit copy. */
2810 if (TARGET_M6812
2811 && GET_MODE_SIZE (mode) >= 2
2812 && autoinc_from != autoinc_to
2813 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2814 {
2815 rtx swap;
2816
2817 swap = low_to;
2818 low_to = high_to;
2819 high_to = swap;
2820
2821 swap = low_from;
2822 low_from = high_from;
2823 high_from = swap;
2824 }
2825 if (mode == SImode)
2826 {
2827 m68hc11_split_move (low_to, low_from, scratch);
2828 m68hc11_split_move (high_to, high_from, scratch);
2829 }
2830 else if (H_REG_P (to) || H_REG_P (from)
2831 || (low_from == const0_rtx
2832 && high_from == const0_rtx
2833 && ! push_operand (to, GET_MODE (to))
2834 && ! H_REG_P (scratch))
2835 || (TARGET_M6812
2836 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2837 || m68hc11_small_indexed_indirect_p (from,
2838 GET_MODE (from)))
2839 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2840 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2841 {
2842 insn = emit_move_insn (low_to, low_from);
2843 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2844
2845 insn = emit_move_insn (high_to, high_from);
2846 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2847 }
2848 else
2849 {
2850 insn = emit_move_insn (scratch, low_from);
2851 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2852 insn = emit_move_insn (low_to, scratch);
2853 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2854
2855 insn = emit_move_insn (scratch, high_from);
2856 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2857 insn = emit_move_insn (high_to, scratch);
2858 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2859 }
2860 }
2861
2862 static rtx
2863 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2864 {
2865 int val;
2866 int mask;
2867
2868 *result = 0;
2869 if (GET_CODE (operand) != CONST_INT)
2870 return operand;
2871
2872 if (mode == HImode)
2873 mask = 0x0ffff;
2874 else
2875 mask = 0x0ff;
2876
2877 val = INTVAL (operand);
2878 switch (code)
2879 {
2880 case IOR:
2881 if ((val & mask) == 0)
2882 return 0;
2883 if ((val & mask) == mask)
2884 *result = constm1_rtx;
2885 break;
2886
2887 case AND:
2888 if ((val & mask) == 0)
2889 *result = const0_rtx;
2890 if ((val & mask) == mask)
2891 return 0;
2892 break;
2893
2894 case XOR:
2895 if ((val & mask) == 0)
2896 return 0;
2897 break;
2898 }
2899 return operand;
2900 }
2901
2902 static void
2903 m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
2904 {
2905 rtx result;
2906 int need_copy;
2907
2908 need_copy = (rtx_equal_p (operands[0], operands[1])
2909 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2910
2911 operands[1] = simplify_logical (mode, code, operands[1], &result);
2912 operands[2] = simplify_logical (mode, code, operands[2], &result);
2913
2914 if (result && GET_CODE (result) == CONST_INT)
2915 {
2916 if (!H_REG_P (operands[0]) && operands[3]
2917 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2918 {
2919 emit_move_insn (operands[3], result);
2920 emit_move_insn (operands[0], operands[3]);
2921 }
2922 else
2923 {
2924 emit_move_insn (operands[0], result);
2925 }
2926 }
2927 else if (operands[1] != 0 && operands[2] != 0)
2928 {
2929 rtx insn;
2930
2931 if (!H_REG_P (operands[0]) && operands[3])
2932 {
2933 emit_move_insn (operands[3], operands[1]);
2934 emit_insn (gen_rtx_SET (mode,
2935 operands[3],
2936 gen_rtx_fmt_ee (code, mode,
2937 operands[3], operands[2])));
2938 insn = emit_move_insn (operands[0], operands[3]);
2939 }
2940 else
2941 {
2942 insn = emit_insn (gen_rtx_SET (mode,
2943 operands[0],
2944 gen_rtx_fmt_ee (code, mode,
2945 operands[0],
2946 operands[2])));
2947 }
2948 }
2949
2950 /* The logical operation is similar to a copy. */
2951 else if (need_copy)
2952 {
2953 rtx src;
2954
2955 if (GET_CODE (operands[1]) == CONST_INT)
2956 src = operands[2];
2957 else
2958 src = operands[1];
2959
2960 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2961 {
2962 emit_move_insn (operands[3], src);
2963 emit_move_insn (operands[0], operands[3]);
2964 }
2965 else
2966 {
2967 emit_move_insn (operands[0], src);
2968 }
2969 }
2970 }
2971
2972 void
2973 m68hc11_split_logical (enum machine_mode mode, enum rtx_code code,
2974 rtx *operands)
2975 {
2976 rtx low[4];
2977 rtx high[4];
2978
2979 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2980 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2981 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2982
2983 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2984 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2985 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2986
2987 low[3] = operands[3];
2988 high[3] = operands[3];
2989 if (mode == SImode)
2990 {
2991 m68hc11_split_logical (HImode, code, low);
2992 m68hc11_split_logical (HImode, code, high);
2993 return;
2994 }
2995
2996 m68hc11_emit_logical (mode, code, low);
2997 m68hc11_emit_logical (mode, code, high);
2998 }
2999 \f
3000
3001 /* Code generation. */
3002
3003 void
3004 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3005 {
3006 /* We have to be careful with the cc_status. An address register swap
3007 is generated for some comparison. The comparison is made with D
3008 but the branch really uses the address register. See the split
3009 pattern for compare. The xgdx/xgdy preserve the flags but after
3010 the exchange, the flags will reflect to the value of X and not D.
3011 Tell this by setting the cc_status according to the cc_prev_status. */
3012 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3013 {
3014 if (cc_prev_status.value1 != 0
3015 && (D_REG_P (cc_prev_status.value1)
3016 || X_REG_P (cc_prev_status.value1)))
3017 {
3018 cc_status = cc_prev_status;
3019 if (D_REG_P (cc_status.value1))
3020 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3021 HARD_X_REGNUM);
3022 else
3023 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3024 HARD_D_REGNUM);
3025 }
3026 else
3027 CC_STATUS_INIT;
3028
3029 output_asm_insn ("xgdx", operands);
3030 }
3031 else
3032 {
3033 if (cc_prev_status.value1 != 0
3034 && (D_REG_P (cc_prev_status.value1)
3035 || Y_REG_P (cc_prev_status.value1)))
3036 {
3037 cc_status = cc_prev_status;
3038 if (D_REG_P (cc_status.value1))
3039 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3040 HARD_Y_REGNUM);
3041 else
3042 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3043 HARD_D_REGNUM);
3044 }
3045 else
3046 CC_STATUS_INIT;
3047
3048 output_asm_insn ("xgdy", operands);
3049 }
3050 }
3051
3052 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3053 This is used to decide whether a move that set flags should be used
3054 instead. */
3055 int
3056 next_insn_test_reg (rtx insn, rtx reg)
3057 {
3058 rtx body;
3059
3060 insn = next_nonnote_insn (insn);
3061 if (GET_CODE (insn) != INSN)
3062 return 0;
3063
3064 body = PATTERN (insn);
3065 if (sets_cc0_p (body) != 1)
3066 return 0;
3067
3068 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3069 return 0;
3070
3071 return 1;
3072 }
3073
3074 /* Generate the code to move a 16-bit operand into another one. */
3075
3076 void
3077 m68hc11_gen_movhi (rtx insn, rtx *operands)
3078 {
3079 int reg;
3080
3081 /* Move a register or memory to the same location.
3082 This is possible because such insn can appear
3083 in a non-optimizing mode. */
3084 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3085 {
3086 cc_status = cc_prev_status;
3087 return;
3088 }
3089
3090 if (TARGET_M6812)
3091 {
3092 rtx from = operands[1];
3093 rtx to = operands[0];
3094
3095 if (IS_STACK_PUSH (to) && H_REG_P (from))
3096 {
3097 cc_status = cc_prev_status;
3098 switch (REGNO (from))
3099 {
3100 case HARD_X_REGNUM:
3101 case HARD_Y_REGNUM:
3102 case HARD_D_REGNUM:
3103 output_asm_insn ("psh%1", operands);
3104 break;
3105 case HARD_SP_REGNUM:
3106 output_asm_insn ("sts\t2,-sp", operands);
3107 break;
3108 default:
3109 gcc_unreachable ();
3110 }
3111 return;
3112 }
3113 if (IS_STACK_POP (from) && H_REG_P (to))
3114 {
3115 cc_status = cc_prev_status;
3116 switch (REGNO (to))
3117 {
3118 case HARD_X_REGNUM:
3119 case HARD_Y_REGNUM:
3120 case HARD_D_REGNUM:
3121 output_asm_insn ("pul%0", operands);
3122 break;
3123 default:
3124 gcc_unreachable ();
3125 }
3126 return;
3127 }
3128 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3129 {
3130 m68hc11_notice_keep_cc (operands[0]);
3131 output_asm_insn ("tfr\t%1,%0", operands);
3132 }
3133 else if (H_REG_P (operands[0]))
3134 {
3135 if (SP_REG_P (operands[0]))
3136 output_asm_insn ("lds\t%1", operands);
3137 else
3138 output_asm_insn ("ld%0\t%1", operands);
3139 }
3140 else if (H_REG_P (operands[1]))
3141 {
3142 if (SP_REG_P (operands[1]))
3143 output_asm_insn ("sts\t%0", operands);
3144 else
3145 output_asm_insn ("st%1\t%0", operands);
3146 }
3147
3148 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3149 instruction. We have to use a scratch register as temporary location.
3150 Trying to use a specific pattern or constrain failed. */
3151 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3152 {
3153 rtx ops[4];
3154
3155 ops[0] = to;
3156 ops[2] = from;
3157 ops[3] = 0;
3158 if (dead_register_here (insn, d_reg))
3159 ops[1] = d_reg;
3160 else if (dead_register_here (insn, ix_reg))
3161 ops[1] = ix_reg;
3162 else if (dead_register_here (insn, iy_reg))
3163 ops[1] = iy_reg;
3164 else
3165 {
3166 ops[1] = d_reg;
3167 ops[3] = d_reg;
3168 output_asm_insn ("psh%3", ops);
3169 }
3170
3171 ops[0] = to;
3172 ops[2] = from;
3173 output_asm_insn ("ld%1\t%2", ops);
3174 output_asm_insn ("st%1\t%0", ops);
3175 if (ops[3])
3176 output_asm_insn ("pul%3", ops);
3177 }
3178
3179 /* Use movw for non-null constants or when we are clearing
3180 a volatile memory reference. However, this is possible
3181 only if the memory reference has a small offset or is an
3182 absolute address. */
3183 else if (GET_CODE (from) == CONST_INT
3184 && INTVAL (from) == 0
3185 && (MEM_VOLATILE_P (to) == 0
3186 || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3187 {
3188 output_asm_insn ("clr\t%h0", operands);
3189 output_asm_insn ("clr\t%b0", operands);
3190 }
3191 else
3192 {
3193 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3194 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3195 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3196 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3197 {
3198 rtx ops[3];
3199
3200 if (operands[2])
3201 {
3202 ops[0] = operands[2];
3203 ops[1] = from;
3204 ops[2] = 0;
3205 m68hc11_gen_movhi (insn, ops);
3206 ops[0] = to;
3207 ops[1] = operands[2];
3208 m68hc11_gen_movhi (insn, ops);
3209 return;
3210 }
3211 else
3212 {
3213 /* !!!! SCz wrong here. */
3214 fatal_insn ("move insn not handled", insn);
3215 }
3216 }
3217 else
3218 {
3219 m68hc11_notice_keep_cc (operands[0]);
3220 output_asm_insn ("movw\t%1,%0", operands);
3221 }
3222 }
3223 return;
3224 }
3225
3226 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3227 {
3228 cc_status = cc_prev_status;
3229 switch (REGNO (operands[0]))
3230 {
3231 case HARD_X_REGNUM:
3232 case HARD_Y_REGNUM:
3233 output_asm_insn ("pul%0", operands);
3234 break;
3235 case HARD_D_REGNUM:
3236 output_asm_insn ("pula", operands);
3237 output_asm_insn ("pulb", operands);
3238 break;
3239 default:
3240 gcc_unreachable ();
3241 }
3242 return;
3243 }
3244 /* Some moves to a hard register are special. Not all of them
3245 are really supported and we have to use a temporary
3246 location to provide them (either the stack of a temp var). */
3247 if (H_REG_P (operands[0]))
3248 {
3249 switch (REGNO (operands[0]))
3250 {
3251 case HARD_D_REGNUM:
3252 if (X_REG_P (operands[1]))
3253 {
3254 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3255 {
3256 m68hc11_output_swap (insn, operands);
3257 }
3258 else if (next_insn_test_reg (insn, operands[0]))
3259 {
3260 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3261 }
3262 else
3263 {
3264 m68hc11_notice_keep_cc (operands[0]);
3265 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3266 }
3267 }
3268 else if (Y_REG_P (operands[1]))
3269 {
3270 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3271 {
3272 m68hc11_output_swap (insn, operands);
3273 }
3274 else
3275 {
3276 /* %t means *ZTMP scratch register. */
3277 output_asm_insn ("sty\t%t1", operands);
3278 output_asm_insn ("ldd\t%t1", operands);
3279 }
3280 }
3281 else if (SP_REG_P (operands[1]))
3282 {
3283 CC_STATUS_INIT;
3284 if (ix_reg == 0)
3285 create_regs_rtx ();
3286 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3287 output_asm_insn ("xgdx", operands);
3288 output_asm_insn ("tsx", operands);
3289 output_asm_insn ("xgdx", operands);
3290 }
3291 else if (IS_STACK_POP (operands[1]))
3292 {
3293 output_asm_insn ("pula\n\tpulb", operands);
3294 }
3295 else if (GET_CODE (operands[1]) == CONST_INT
3296 && INTVAL (operands[1]) == 0)
3297 {
3298 output_asm_insn ("clra\n\tclrb", operands);
3299 }
3300 else
3301 {
3302 output_asm_insn ("ldd\t%1", operands);
3303 }
3304 break;
3305
3306 case HARD_X_REGNUM:
3307 if (D_REG_P (operands[1]))
3308 {
3309 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3310 {
3311 m68hc11_output_swap (insn, operands);
3312 }
3313 else if (next_insn_test_reg (insn, operands[0]))
3314 {
3315 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3316 }
3317 else
3318 {
3319 m68hc11_notice_keep_cc (operands[0]);
3320 output_asm_insn ("pshb", operands);
3321 output_asm_insn ("psha", operands);
3322 output_asm_insn ("pulx", operands);
3323 }
3324 }
3325 else if (Y_REG_P (operands[1]))
3326 {
3327 /* When both D and Y are dead, use the sequence xgdy, xgdx
3328 to move Y into X. The D and Y registers are modified. */
3329 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3330 && dead_register_here (insn, d_reg))
3331 {
3332 output_asm_insn ("xgdy", operands);
3333 output_asm_insn ("xgdx", operands);
3334 CC_STATUS_INIT;
3335 }
3336 else if (!optimize_size)
3337 {
3338 output_asm_insn ("sty\t%t1", operands);
3339 output_asm_insn ("ldx\t%t1", operands);
3340 }
3341 else
3342 {
3343 CC_STATUS_INIT;
3344 output_asm_insn ("pshy", operands);
3345 output_asm_insn ("pulx", operands);
3346 }
3347 }
3348 else if (SP_REG_P (operands[1]))
3349 {
3350 /* tsx, tsy preserve the flags */
3351 cc_status = cc_prev_status;
3352 output_asm_insn ("tsx", operands);
3353 }
3354 else
3355 {
3356 output_asm_insn ("ldx\t%1", operands);
3357 }
3358 break;
3359
3360 case HARD_Y_REGNUM:
3361 if (D_REG_P (operands[1]))
3362 {
3363 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3364 {
3365 m68hc11_output_swap (insn, operands);
3366 }
3367 else
3368 {
3369 output_asm_insn ("std\t%t1", operands);
3370 output_asm_insn ("ldy\t%t1", operands);
3371 }
3372 }
3373 else if (X_REG_P (operands[1]))
3374 {
3375 /* When both D and X are dead, use the sequence xgdx, xgdy
3376 to move X into Y. The D and X registers are modified. */
3377 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3378 && dead_register_here (insn, d_reg))
3379 {
3380 output_asm_insn ("xgdx", operands);
3381 output_asm_insn ("xgdy", operands);
3382 CC_STATUS_INIT;
3383 }
3384 else if (!optimize_size)
3385 {
3386 output_asm_insn ("stx\t%t1", operands);
3387 output_asm_insn ("ldy\t%t1", operands);
3388 }
3389 else
3390 {
3391 CC_STATUS_INIT;
3392 output_asm_insn ("pshx", operands);
3393 output_asm_insn ("puly", operands);
3394 }
3395 }
3396 else if (SP_REG_P (operands[1]))
3397 {
3398 /* tsx, tsy preserve the flags */
3399 cc_status = cc_prev_status;
3400 output_asm_insn ("tsy", operands);
3401 }
3402 else
3403 {
3404 output_asm_insn ("ldy\t%1", operands);
3405 }
3406 break;
3407
3408 case HARD_SP_REGNUM:
3409 if (D_REG_P (operands[1]))
3410 {
3411 m68hc11_notice_keep_cc (operands[0]);
3412 output_asm_insn ("xgdx", operands);
3413 output_asm_insn ("txs", operands);
3414 output_asm_insn ("xgdx", operands);
3415 }
3416 else if (X_REG_P (operands[1]))
3417 {
3418 /* tys, txs preserve the flags */
3419 cc_status = cc_prev_status;
3420 output_asm_insn ("txs", operands);
3421 }
3422 else if (Y_REG_P (operands[1]))
3423 {
3424 /* tys, txs preserve the flags */
3425 cc_status = cc_prev_status;
3426 output_asm_insn ("tys", operands);
3427 }
3428 else
3429 {
3430 /* lds sets the flags but the des does not. */
3431 CC_STATUS_INIT;
3432 output_asm_insn ("lds\t%1", operands);
3433 output_asm_insn ("des", operands);
3434 }
3435 break;
3436
3437 default:
3438 fatal_insn ("invalid register in the move instruction", insn);
3439 break;
3440 }
3441 return;
3442 }
3443 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3444 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3445 {
3446 output_asm_insn ("sts\t%0", operands);
3447 return;
3448 }
3449
3450 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3451 {
3452 cc_status = cc_prev_status;
3453 switch (REGNO (operands[1]))
3454 {
3455 case HARD_X_REGNUM:
3456 case HARD_Y_REGNUM:
3457 output_asm_insn ("psh%1", operands);
3458 break;
3459 case HARD_D_REGNUM:
3460 output_asm_insn ("pshb", operands);
3461 output_asm_insn ("psha", operands);
3462 break;
3463 default:
3464 gcc_unreachable ();
3465 }
3466 return;
3467 }
3468
3469 /* Operand 1 must be a hard register. */
3470 if (!H_REG_P (operands[1]))
3471 {
3472 fatal_insn ("invalid operand in the instruction", insn);
3473 }
3474
3475 reg = REGNO (operands[1]);
3476 switch (reg)
3477 {
3478 case HARD_D_REGNUM:
3479 output_asm_insn ("std\t%0", operands);
3480 break;
3481
3482 case HARD_X_REGNUM:
3483 output_asm_insn ("stx\t%0", operands);
3484 break;
3485
3486 case HARD_Y_REGNUM:
3487 output_asm_insn ("sty\t%0", operands);
3488 break;
3489
3490 case HARD_SP_REGNUM:
3491 if (ix_reg == 0)
3492 create_regs_rtx ();
3493
3494 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3495 {
3496 output_asm_insn ("pshx", operands);
3497 output_asm_insn ("tsx", operands);
3498 output_asm_insn ("inx", operands);
3499 output_asm_insn ("inx", operands);
3500 output_asm_insn ("stx\t%0", operands);
3501 output_asm_insn ("pulx", operands);
3502 }
3503
3504 else if (reg_mentioned_p (ix_reg, operands[0]))
3505 {
3506 output_asm_insn ("sty\t%t0", operands);
3507 output_asm_insn ("tsy", operands);
3508 output_asm_insn ("sty\t%0", operands);
3509 output_asm_insn ("ldy\t%t0", operands);
3510 }
3511 else
3512 {
3513 output_asm_insn ("stx\t%t0", operands);
3514 output_asm_insn ("tsx", operands);
3515 output_asm_insn ("stx\t%0", operands);
3516 output_asm_insn ("ldx\t%t0", operands);
3517 }
3518 CC_STATUS_INIT;
3519 break;
3520
3521 default:
3522 fatal_insn ("invalid register in the move instruction", insn);
3523 break;
3524 }
3525 }
3526
3527 void
3528 m68hc11_gen_movqi (rtx insn, rtx *operands)
3529 {
3530 /* Move a register or memory to the same location.
3531 This is possible because such insn can appear
3532 in a non-optimizing mode. */
3533 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3534 {
3535 cc_status = cc_prev_status;
3536 return;
3537 }
3538
3539 if (TARGET_M6812)
3540 {
3541
3542 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3543 {
3544 m68hc11_notice_keep_cc (operands[0]);
3545 output_asm_insn ("tfr\t%1,%0", operands);
3546 }
3547 else if (H_REG_P (operands[0]))
3548 {
3549 if (IS_STACK_POP (operands[1]))
3550 output_asm_insn ("pul%b0", operands);
3551 else if (Q_REG_P (operands[0]))
3552 output_asm_insn ("lda%0\t%b1", operands);
3553 else if (D_REG_P (operands[0]))
3554 output_asm_insn ("ldab\t%b1", operands);
3555 else
3556 goto m6811_move;
3557 }
3558 else if (H_REG_P (operands[1]))
3559 {
3560 if (Q_REG_P (operands[1]))
3561 output_asm_insn ("sta%1\t%b0", operands);
3562 else if (D_REG_P (operands[1]))
3563 output_asm_insn ("stab\t%b0", operands);
3564 else
3565 goto m6811_move;
3566 }
3567 else
3568 {
3569 rtx from = operands[1];
3570 rtx to = operands[0];
3571
3572 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3573 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3574 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3575 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3576 {
3577 rtx ops[3];
3578
3579 if (operands[2])
3580 {
3581 ops[0] = operands[2];
3582 ops[1] = from;
3583 ops[2] = 0;
3584 m68hc11_gen_movqi (insn, ops);
3585 ops[0] = to;
3586 ops[1] = operands[2];
3587 m68hc11_gen_movqi (insn, ops);
3588 }
3589 else
3590 {
3591 /* !!!! SCz wrong here. */
3592 fatal_insn ("move insn not handled", insn);
3593 }
3594 }
3595 else
3596 {
3597 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3598 {
3599 output_asm_insn ("clr\t%b0", operands);
3600 }
3601 else
3602 {
3603 m68hc11_notice_keep_cc (operands[0]);
3604 output_asm_insn ("movb\t%b1,%b0", operands);
3605 }
3606 }
3607 }
3608 return;
3609 }
3610
3611 m6811_move:
3612 if (H_REG_P (operands[0]))
3613 {
3614 switch (REGNO (operands[0]))
3615 {
3616 case HARD_B_REGNUM:
3617 case HARD_D_REGNUM:
3618 if (X_REG_P (operands[1]))
3619 {
3620 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3621 {
3622 m68hc11_output_swap (insn, operands);
3623 }
3624 else
3625 {
3626 output_asm_insn ("stx\t%t1", operands);
3627 output_asm_insn ("ldab\t%T0", operands);
3628 }
3629 }
3630 else if (Y_REG_P (operands[1]))
3631 {
3632 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3633 {
3634 m68hc11_output_swap (insn, operands);
3635 }
3636 else
3637 {
3638 output_asm_insn ("sty\t%t1", operands);
3639 output_asm_insn ("ldab\t%T0", operands);
3640 }
3641 }
3642 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3643 && !DA_REG_P (operands[1]))
3644 {
3645 output_asm_insn ("ldab\t%b1", operands);
3646 }
3647 else if (DA_REG_P (operands[1]))
3648 {
3649 output_asm_insn ("tab", operands);
3650 }
3651 else
3652 {
3653 cc_status = cc_prev_status;
3654 return;
3655 }
3656 break;
3657
3658 case HARD_A_REGNUM:
3659 if (X_REG_P (operands[1]))
3660 {
3661 output_asm_insn ("stx\t%t1", operands);
3662 output_asm_insn ("ldaa\t%T0", operands);
3663 }
3664 else if (Y_REG_P (operands[1]))
3665 {
3666 output_asm_insn ("sty\t%t1", operands);
3667 output_asm_insn ("ldaa\t%T0", operands);
3668 }
3669 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3670 && !DA_REG_P (operands[1]))
3671 {
3672 output_asm_insn ("ldaa\t%b1", operands);
3673 }
3674 else if (!DA_REG_P (operands[1]))
3675 {
3676 output_asm_insn ("tba", operands);
3677 }
3678 else
3679 {
3680 cc_status = cc_prev_status;
3681 }
3682 break;
3683
3684 case HARD_X_REGNUM:
3685 if (D_REG_P (operands[1]))
3686 {
3687 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3688 {
3689 m68hc11_output_swap (insn, operands);
3690 }
3691 else
3692 {
3693 output_asm_insn ("stab\t%T1", operands);
3694 output_asm_insn ("ldx\t%t1", operands);
3695 }
3696 CC_STATUS_INIT;
3697 }
3698 else if (Y_REG_P (operands[1]))
3699 {
3700 output_asm_insn ("sty\t%t0", operands);
3701 output_asm_insn ("ldx\t%t0", operands);
3702 }
3703 else if (GET_CODE (operands[1]) == CONST_INT)
3704 {
3705 output_asm_insn ("ldx\t%1", operands);
3706 }
3707 else if (dead_register_here (insn, d_reg))
3708 {
3709 output_asm_insn ("ldab\t%b1", operands);
3710 output_asm_insn ("xgdx", operands);
3711 }
3712 else if (!reg_mentioned_p (operands[0], operands[1]))
3713 {
3714 output_asm_insn ("xgdx", operands);
3715 output_asm_insn ("ldab\t%b1", operands);
3716 output_asm_insn ("xgdx", operands);
3717 }
3718 else
3719 {
3720 output_asm_insn ("pshb", operands);
3721 output_asm_insn ("ldab\t%b1", operands);
3722 output_asm_insn ("stab\t%T1", operands);
3723 output_asm_insn ("ldx\t%t1", operands);
3724 output_asm_insn ("pulb", operands);
3725 CC_STATUS_INIT;
3726 }
3727 break;
3728
3729 case HARD_Y_REGNUM:
3730 if (D_REG_P (operands[1]))
3731 {
3732 output_asm_insn ("stab\t%T1", operands);
3733 output_asm_insn ("ldy\t%t1", operands);
3734 CC_STATUS_INIT;
3735 }
3736 else if (X_REG_P (operands[1]))
3737 {
3738 output_asm_insn ("stx\t%t1", operands);
3739 output_asm_insn ("ldy\t%t1", operands);
3740 CC_STATUS_INIT;
3741 }
3742 else if (GET_CODE (operands[1]) == CONST_INT)
3743 {
3744 output_asm_insn ("ldy\t%1", operands);
3745 }
3746 else if (dead_register_here (insn, d_reg))
3747 {
3748 output_asm_insn ("ldab\t%b1", operands);
3749 output_asm_insn ("xgdy", operands);
3750 }
3751 else if (!reg_mentioned_p (operands[0], operands[1]))
3752 {
3753 output_asm_insn ("xgdy", operands);
3754 output_asm_insn ("ldab\t%b1", operands);
3755 output_asm_insn ("xgdy", operands);
3756 }
3757 else
3758 {
3759 output_asm_insn ("pshb", operands);
3760 output_asm_insn ("ldab\t%b1", operands);
3761 output_asm_insn ("stab\t%T1", operands);
3762 output_asm_insn ("ldy\t%t1", operands);
3763 output_asm_insn ("pulb", operands);
3764 CC_STATUS_INIT;
3765 }
3766 break;
3767
3768 default:
3769 fatal_insn ("invalid register in the instruction", insn);
3770 break;
3771 }
3772 }
3773 else if (H_REG_P (operands[1]))
3774 {
3775 switch (REGNO (operands[1]))
3776 {
3777 case HARD_D_REGNUM:
3778 case HARD_B_REGNUM:
3779 output_asm_insn ("stab\t%b0", operands);
3780 break;
3781
3782 case HARD_A_REGNUM:
3783 output_asm_insn ("staa\t%b0", operands);
3784 break;
3785
3786 case HARD_X_REGNUM:
3787 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3788 break;
3789
3790 case HARD_Y_REGNUM:
3791 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3792 break;
3793
3794 default:
3795 fatal_insn ("invalid register in the move instruction", insn);
3796 break;
3797 }
3798 return;
3799 }
3800 else
3801 {
3802 fatal_insn ("operand 1 must be a hard register", insn);
3803 }
3804 }
3805
3806 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3807 The source and destination must be D or A and the shift must
3808 be a constant. */
3809 void
3810 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3811 {
3812 int val;
3813
3814 if (GET_CODE (operands[2]) != CONST_INT
3815 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3816 fatal_insn ("invalid rotate insn", insn);
3817
3818 val = INTVAL (operands[2]);
3819 if (code == ROTATERT)
3820 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3821
3822 if (GET_MODE (operands[0]) != QImode)
3823 CC_STATUS_INIT;
3824
3825 /* Rotate by 8-bits if the shift is within [5..11]. */
3826 if (val >= 5 && val <= 11)
3827 {
3828 if (TARGET_M6812)
3829 output_asm_insn ("exg\ta,b", operands);
3830 else
3831 {
3832 output_asm_insn ("psha", operands);
3833 output_asm_insn ("tba", operands);
3834 output_asm_insn ("pulb", operands);
3835 }
3836 val -= 8;
3837 }
3838
3839 /* If the shift is big, invert the rotation. */
3840 else if (val >= 12)
3841 {
3842 val = val - 16;
3843 }
3844
3845 if (val > 0)
3846 {
3847 while (--val >= 0)
3848 {
3849 /* Set the carry to bit-15, but don't change D yet. */
3850 if (GET_MODE (operands[0]) != QImode)
3851 {
3852 output_asm_insn ("asra", operands);
3853 output_asm_insn ("rola", operands);
3854 }
3855
3856 /* Rotate B first to move the carry to bit-0. */
3857 if (D_REG_P (operands[0]))
3858 output_asm_insn ("rolb", operands);
3859
3860 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3861 output_asm_insn ("rola", operands);
3862 }
3863 }
3864 else
3865 {
3866 while (++val <= 0)
3867 {
3868 /* Set the carry to bit-8 of D. */
3869 if (GET_MODE (operands[0]) != QImode)
3870 output_asm_insn ("tap", operands);
3871
3872 /* Rotate B first to move the carry to bit-7. */
3873 if (D_REG_P (operands[0]))
3874 output_asm_insn ("rorb", operands);
3875
3876 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3877 output_asm_insn ("rora", operands);
3878 }
3879 }
3880 }
3881
3882 \f
3883
3884 /* Store in cc_status the expressions that the condition codes will
3885 describe after execution of an instruction whose pattern is EXP.
3886 Do not alter them if the instruction would not alter the cc's. */
3887
3888 void
3889 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3890 {
3891 /* recognize SET insn's. */
3892 if (GET_CODE (exp) == SET)
3893 {
3894 /* Jumps do not alter the cc's. */
3895 if (SET_DEST (exp) == pc_rtx)
3896 ;
3897
3898 /* NOTE: most instructions don't affect the carry bit, but the
3899 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3900 the conditions.h header. */
3901
3902 /* Function calls clobber the cc's. */
3903 else if (GET_CODE (SET_SRC (exp)) == CALL)
3904 {
3905 CC_STATUS_INIT;
3906 }
3907
3908 /* Tests and compares set the cc's in predictable ways. */
3909 else if (SET_DEST (exp) == cc0_rtx)
3910 {
3911 cc_status.flags = 0;
3912 cc_status.value1 = XEXP (exp, 0);
3913 if (GET_CODE (XEXP (exp, 1)) == COMPARE
3914 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
3915 cc_status.value2 = XEXP (XEXP (exp, 1), 0);
3916 else
3917 cc_status.value2 = XEXP (exp, 1);
3918 }
3919 else
3920 {
3921 /* All other instructions affect the condition codes. */
3922 cc_status.flags = 0;
3923 cc_status.value1 = XEXP (exp, 0);
3924 cc_status.value2 = XEXP (exp, 1);
3925 }
3926 }
3927 else
3928 {
3929 /* Default action if we haven't recognized something
3930 and returned earlier. */
3931 CC_STATUS_INIT;
3932 }
3933
3934 if (cc_status.value2 != 0)
3935 switch (GET_CODE (cc_status.value2))
3936 {
3937 /* These logical operations can generate several insns.
3938 The flags are setup according to what is generated. */
3939 case IOR:
3940 case XOR:
3941 case AND:
3942 break;
3943
3944 /* The (not ...) generates several 'com' instructions for
3945 non QImode. We have to invalidate the flags. */
3946 case NOT:
3947 if (GET_MODE (cc_status.value2) != QImode)
3948 CC_STATUS_INIT;
3949 break;
3950
3951 case PLUS:
3952 case MINUS:
3953 case MULT:
3954 case DIV:
3955 case UDIV:
3956 case MOD:
3957 case UMOD:
3958 case NEG:
3959 if (GET_MODE (cc_status.value2) != VOIDmode)
3960 cc_status.flags |= CC_NO_OVERFLOW;
3961 break;
3962
3963 /* The asl sets the overflow bit in such a way that this
3964 makes the flags unusable for a next compare insn. */
3965 case ASHIFT:
3966 case ROTATE:
3967 case ROTATERT:
3968 if (GET_MODE (cc_status.value2) != VOIDmode)
3969 cc_status.flags |= CC_NO_OVERFLOW;
3970 break;
3971
3972 /* A load/store instruction does not affect the carry. */
3973 case MEM:
3974 case SYMBOL_REF:
3975 case REG:
3976 case CONST_INT:
3977 cc_status.flags |= CC_NO_OVERFLOW;
3978 break;
3979
3980 default:
3981 break;
3982 }
3983 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3984 && cc_status.value2
3985 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3986 cc_status.value2 = 0;
3987
3988 else if (cc_status.value1 && side_effects_p (cc_status.value1))
3989 cc_status.value1 = 0;
3990
3991 else if (cc_status.value2 && side_effects_p (cc_status.value2))
3992 cc_status.value2 = 0;
3993 }
3994
3995 /* The current instruction does not affect the flags but changes
3996 the register 'reg'. See if the previous flags can be kept for the
3997 next instruction to avoid a comparison. */
3998 void
3999 m68hc11_notice_keep_cc (rtx reg)
4000 {
4001 if (reg == 0
4002 || cc_prev_status.value1 == 0
4003 || rtx_equal_p (reg, cc_prev_status.value1)
4004 || (cc_prev_status.value2
4005 && reg_mentioned_p (reg, cc_prev_status.value2)))
4006 CC_STATUS_INIT;
4007 else
4008 cc_status = cc_prev_status;
4009 }
4010
4011 \f
4012
4013 /* Machine Specific Reorg. */
4014
4015 /* Z register replacement:
4016
4017 GCC treats the Z register as an index base address register like
4018 X or Y. In general, it uses it during reload to compute the address
4019 of some operand. This helps the reload pass to avoid to fall into the
4020 register spill failure.
4021
4022 The Z register is in the A_REGS class. In the machine description,
4023 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4024
4025 It can appear everywhere an X or Y register can appear, except for
4026 some templates in the clobber section (when a clobber of X or Y is asked).
4027 For a given instruction, the template must ensure that no more than
4028 2 'A' registers are used. Otherwise, the register replacement is not
4029 possible.
4030
4031 To replace the Z register, the algorithm is not terrific:
4032 1. Insns that do not use the Z register are not changed
4033 2. When a Z register is used, we scan forward the insns to see
4034 a potential register to use: either X or Y and sometimes D.
4035 We stop when a call, a label or a branch is seen, or when we
4036 detect that both X and Y are used (probably at different times, but it does
4037 not matter).
4038 3. The register that will be used for the replacement of Z is saved
4039 in a .page0 register or on the stack. If the first instruction that
4040 used Z, uses Z as an input, the value is loaded from another .page0
4041 register. The replacement register is pushed on the stack in the
4042 rare cases where a compare insn uses Z and we couldn't find if X/Y
4043 are dead.
4044 4. The Z register is replaced in all instructions until we reach
4045 the end of the Z-block, as detected by step 2.
4046 5. If we detect that Z is still alive, its value is saved.
4047 If the replacement register is alive, its old value is loaded.
4048
4049 The Z register can be disabled with -ffixed-z.
4050 */
4051
4052 struct replace_info
4053 {
4054 rtx first;
4055 rtx replace_reg;
4056 int need_save_z;
4057 int must_load_z;
4058 int must_save_reg;
4059 int must_restore_reg;
4060 rtx last;
4061 int regno;
4062 int x_used;
4063 int y_used;
4064 int can_use_d;
4065 int found_call;
4066 int z_died;
4067 int z_set_count;
4068 rtx z_value;
4069 int must_push_reg;
4070 int save_before_last;
4071 int z_loaded_with_sp;
4072 };
4073
4074 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4075 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4076 static void m68hc11_z_replacement (rtx);
4077 static void m68hc11_reassign_regs (rtx);
4078
4079 int z_replacement_completed = 0;
4080
4081 /* Analyze the insn to find out which replacement register to use and
4082 the boundaries of the replacement.
4083 Returns 0 if we reached the last insn to be replaced, 1 if we can
4084 continue replacement in next insns. */
4085
4086 static int
4087 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4088 {
4089 int this_insn_uses_ix;
4090 int this_insn_uses_iy;
4091 int this_insn_uses_z;
4092 int this_insn_uses_z_in_dst;
4093 int this_insn_uses_d;
4094 rtx body;
4095 int z_dies_here;
4096
4097 /* A call is said to clobber the Z register, we don't need
4098 to save the value of Z. We also don't need to restore
4099 the replacement register (unless it is used by the call). */
4100 if (GET_CODE (insn) == CALL_INSN)
4101 {
4102 body = PATTERN (insn);
4103
4104 info->can_use_d = 0;
4105
4106 /* If the call is an indirect call with Z, we have to use the
4107 Y register because X can be used as an input (D+X).
4108 We also must not save Z nor restore Y. */
4109 if (reg_mentioned_p (z_reg, body))
4110 {
4111 insn = NEXT_INSN (insn);
4112 info->x_used = 1;
4113 info->y_used = 0;
4114 info->found_call = 1;
4115 info->must_restore_reg = 0;
4116 info->last = NEXT_INSN (insn);
4117 }
4118 info->need_save_z = 0;
4119 return 0;
4120 }
4121 if (GET_CODE (insn) == CODE_LABEL
4122 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4123 return 0;
4124
4125 if (GET_CODE (insn) == JUMP_INSN)
4126 {
4127 if (reg_mentioned_p (z_reg, insn) == 0)
4128 return 0;
4129
4130 info->can_use_d = 0;
4131 info->must_save_reg = 0;
4132 info->must_restore_reg = 0;
4133 info->need_save_z = 0;
4134 info->last = NEXT_INSN (insn);
4135 return 0;
4136 }
4137 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4138 {
4139 return 1;
4140 }
4141
4142 /* Z register dies here. */
4143 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4144
4145 body = PATTERN (insn);
4146 if (GET_CODE (body) == SET)
4147 {
4148 rtx src = XEXP (body, 1);
4149 rtx dst = XEXP (body, 0);
4150
4151 /* Condition code is set here. We have to restore the X/Y and
4152 save into Z before any test/compare insn because once we save/restore
4153 we can change the condition codes. When the compare insn uses Z and
4154 we can't use X/Y, the comparison is made with the *ZREG soft register
4155 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4156 if (dst == cc0_rtx)
4157 {
4158 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4159 || (GET_CODE (src) == COMPARE &&
4160 ((rtx_equal_p (XEXP (src, 0), z_reg)
4161 && H_REG_P (XEXP (src, 1)))
4162 || (rtx_equal_p (XEXP (src, 1), z_reg)
4163 && H_REG_P (XEXP (src, 0))))))
4164 {
4165 if (insn == info->first)
4166 {
4167 info->must_load_z = 0;
4168 info->must_save_reg = 0;
4169 info->must_restore_reg = 0;
4170 info->need_save_z = 0;
4171 info->found_call = 1;
4172 info->regno = SOFT_Z_REGNUM;
4173 info->last = NEXT_INSN (insn);
4174 }
4175 return 0;
4176 }
4177 if (reg_mentioned_p (z_reg, src) == 0)
4178 {
4179 info->can_use_d = 0;
4180 return 0;
4181 }
4182
4183 if (insn != info->first)
4184 return 0;
4185
4186 /* Compare insn which uses Z. We have to save/restore the X/Y
4187 register without modifying the condition codes. For this
4188 we have to use a push/pop insn. */
4189 info->must_push_reg = 1;
4190 info->last = insn;
4191 }
4192
4193 /* Z reg is set to something new. We don't need to load it. */
4194 if (Z_REG_P (dst))
4195 {
4196 if (!reg_mentioned_p (z_reg, src))
4197 {
4198 /* Z reg is used before being set. Treat this as
4199 a new sequence of Z register replacement. */
4200 if (insn != info->first)
4201 {
4202 return 0;
4203 }
4204 info->must_load_z = 0;
4205 }
4206 info->z_set_count++;
4207 info->z_value = src;
4208 if (SP_REG_P (src))
4209 info->z_loaded_with_sp = 1;
4210 }
4211 else if (reg_mentioned_p (z_reg, dst))
4212 info->can_use_d = 0;
4213
4214 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4215 | reg_mentioned_p (d_reg, dst);
4216 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4217 | reg_mentioned_p (ix_reg, dst);
4218 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4219 | reg_mentioned_p (iy_reg, dst);
4220 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4221
4222 /* If z is used as an address operand (like (MEM (reg z))),
4223 we can't replace it with d. */
4224 if (this_insn_uses_z && !Z_REG_P (src)
4225 && !(m68hc11_arith_operator (src, GET_MODE (src))
4226 && Z_REG_P (XEXP (src, 0))
4227 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4228 && insn == info->first
4229 && dead_register_here (insn, d_reg)))
4230 info->can_use_d = 0;
4231
4232 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4233 if (TARGET_M6812 && !z_dies_here
4234 && ((this_insn_uses_z && side_effects_p (src))
4235 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4236 {
4237 info->need_save_z = 1;
4238 info->z_set_count++;
4239 }
4240 this_insn_uses_z |= this_insn_uses_z_in_dst;
4241
4242 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4243 {
4244 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4245 }
4246
4247 if (this_insn_uses_d)
4248 info->can_use_d = 0;
4249
4250 /* IX and IY are used at the same time, we have to restore
4251 the value of the scratch register before this insn. */
4252 if (this_insn_uses_ix && this_insn_uses_iy)
4253 {
4254 return 0;
4255 }
4256
4257 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4258 info->can_use_d = 0;
4259
4260 if (info->x_used == 0 && this_insn_uses_ix)
4261 {
4262 if (info->y_used)
4263 {
4264 /* We have a (set (REG:HI X) (REG:HI Z)).
4265 Since we use Z as the replacement register, this insn
4266 is no longer necessary. We turn it into a note. We must
4267 not reload the old value of X. */
4268 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4269 {
4270 if (z_dies_here)
4271 {
4272 info->need_save_z = 0;
4273 info->z_died = 1;
4274 }
4275 info->must_save_reg = 0;
4276 info->must_restore_reg = 0;
4277 info->found_call = 1;
4278 info->can_use_d = 0;
4279 SET_INSN_DELETED (insn);
4280 info->last = NEXT_INSN (insn);
4281 return 0;
4282 }
4283
4284 if (X_REG_P (dst)
4285 && (rtx_equal_p (src, z_reg)
4286 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4287 {
4288 if (z_dies_here)
4289 {
4290 info->need_save_z = 0;
4291 info->z_died = 1;
4292 }
4293 info->last = NEXT_INSN (insn);
4294 info->must_save_reg = 0;
4295 info->must_restore_reg = 0;
4296 }
4297 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4298 && !reg_mentioned_p (ix_reg, src))
4299 {
4300 if (z_dies_here)
4301 {
4302 info->z_died = 1;
4303 info->need_save_z = 0;
4304 }
4305 else if (TARGET_M6812 && side_effects_p (src))
4306 {
4307 info->last = 0;
4308 info->must_restore_reg = 0;
4309 return 0;
4310 }
4311 else
4312 {
4313 info->save_before_last = 1;
4314 }
4315 info->must_restore_reg = 0;
4316 info->last = NEXT_INSN (insn);
4317 }
4318 else if (info->can_use_d)
4319 {
4320 info->last = NEXT_INSN (insn);
4321 info->x_used = 1;
4322 }
4323 return 0;
4324 }
4325 info->x_used = 1;
4326 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4327 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4328 {
4329 info->need_save_z = 0;
4330 info->z_died = 1;
4331 info->last = NEXT_INSN (insn);
4332 info->regno = HARD_X_REGNUM;
4333 info->must_save_reg = 0;
4334 info->must_restore_reg = 0;
4335 return 0;
4336 }
4337 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4338 {
4339 info->regno = HARD_X_REGNUM;
4340 info->must_restore_reg = 0;
4341 info->must_save_reg = 0;
4342 return 0;
4343 }
4344 }
4345 if (info->y_used == 0 && this_insn_uses_iy)
4346 {
4347 if (info->x_used)
4348 {
4349 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4350 {
4351 if (z_dies_here)
4352 {
4353 info->need_save_z = 0;
4354 info->z_died = 1;
4355 }
4356 info->must_save_reg = 0;
4357 info->must_restore_reg = 0;
4358 info->found_call = 1;
4359 info->can_use_d = 0;
4360 SET_INSN_DELETED (insn);
4361 info->last = NEXT_INSN (insn);
4362 return 0;
4363 }
4364
4365 if (Y_REG_P (dst)
4366 && (rtx_equal_p (src, z_reg)
4367 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4368 {
4369 if (z_dies_here)
4370 {
4371 info->z_died = 1;
4372 info->need_save_z = 0;
4373 }
4374 info->last = NEXT_INSN (insn);
4375 info->must_save_reg = 0;
4376 info->must_restore_reg = 0;
4377 }
4378 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4379 && !reg_mentioned_p (iy_reg, src))
4380 {
4381 if (z_dies_here)
4382 {
4383 info->z_died = 1;
4384 info->need_save_z = 0;
4385 }
4386 else if (TARGET_M6812 && side_effects_p (src))
4387 {
4388 info->last = 0;
4389 info->must_restore_reg = 0;
4390 return 0;
4391 }
4392 else
4393 {
4394 info->save_before_last = 1;
4395 }
4396 info->must_restore_reg = 0;
4397 info->last = NEXT_INSN (insn);
4398 }
4399 else if (info->can_use_d)
4400 {
4401 info->last = NEXT_INSN (insn);
4402 info->y_used = 1;
4403 }
4404
4405 return 0;
4406 }
4407 info->y_used = 1;
4408 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4409 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4410 {
4411 info->need_save_z = 0;
4412 info->z_died = 1;
4413 info->last = NEXT_INSN (insn);
4414 info->regno = HARD_Y_REGNUM;
4415 info->must_save_reg = 0;
4416 info->must_restore_reg = 0;
4417 return 0;
4418 }
4419 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4420 {
4421 info->regno = HARD_Y_REGNUM;
4422 info->must_restore_reg = 0;
4423 info->must_save_reg = 0;
4424 return 0;
4425 }
4426 }
4427 if (z_dies_here)
4428 {
4429 info->need_save_z = 0;
4430 info->z_died = 1;
4431 if (info->last == 0)
4432 info->last = NEXT_INSN (insn);
4433 return 0;
4434 }
4435 return info->last != NULL_RTX ? 0 : 1;
4436 }
4437 if (GET_CODE (body) == PARALLEL)
4438 {
4439 int i;
4440 char ix_clobber = 0;
4441 char iy_clobber = 0;
4442 char z_clobber = 0;
4443 this_insn_uses_iy = 0;
4444 this_insn_uses_ix = 0;
4445 this_insn_uses_z = 0;
4446
4447 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4448 {
4449 rtx x;
4450 int uses_ix, uses_iy, uses_z;
4451
4452 x = XVECEXP (body, 0, i);
4453
4454 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4455 info->can_use_d = 0;
4456
4457 uses_ix = reg_mentioned_p (ix_reg, x);
4458 uses_iy = reg_mentioned_p (iy_reg, x);
4459 uses_z = reg_mentioned_p (z_reg, x);
4460 if (GET_CODE (x) == CLOBBER)
4461 {
4462 ix_clobber |= uses_ix;
4463 iy_clobber |= uses_iy;
4464 z_clobber |= uses_z;
4465 }
4466 else
4467 {
4468 this_insn_uses_ix |= uses_ix;
4469 this_insn_uses_iy |= uses_iy;
4470 this_insn_uses_z |= uses_z;
4471 }
4472 if (uses_z && GET_CODE (x) == SET)
4473 {
4474 rtx dst = XEXP (x, 0);
4475
4476 if (Z_REG_P (dst))
4477 info->z_set_count++;
4478 }
4479 if (TARGET_M6812 && uses_z && side_effects_p (x))
4480 info->need_save_z = 1;
4481
4482 if (z_clobber)
4483 info->need_save_z = 0;
4484 }
4485 if (debug_m6811)
4486 {
4487 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4488 this_insn_uses_ix, this_insn_uses_iy,
4489 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4490 debug_rtx (insn);
4491 }
4492 if (this_insn_uses_z)
4493 info->can_use_d = 0;
4494
4495 if (z_clobber && info->first != insn)
4496 {
4497 info->need_save_z = 0;
4498 info->last = insn;
4499 return 0;
4500 }
4501 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4502 {
4503 if (this_insn_uses_z == 0 && insn == info->first)
4504 {
4505 info->must_load_z = 0;
4506 }
4507 if (dead_register_here (insn, d_reg))
4508 {
4509 info->regno = HARD_D_REGNUM;
4510 info->must_save_reg = 0;
4511 info->must_restore_reg = 0;
4512 }
4513 else if (dead_register_here (insn, ix_reg))
4514 {
4515 info->regno = HARD_X_REGNUM;
4516 info->must_save_reg = 0;
4517 info->must_restore_reg = 0;
4518 }
4519 else if (dead_register_here (insn, iy_reg))
4520 {
4521 info->regno = HARD_Y_REGNUM;
4522 info->must_save_reg = 0;
4523 info->must_restore_reg = 0;
4524 }
4525 if (info->regno >= 0)
4526 {
4527 info->last = NEXT_INSN (insn);
4528 return 0;
4529 }
4530 if (this_insn_uses_ix == 0)
4531 {
4532 info->regno = HARD_X_REGNUM;
4533 info->must_save_reg = 1;
4534 info->must_restore_reg = 1;
4535 }
4536 else if (this_insn_uses_iy == 0)
4537 {
4538 info->regno = HARD_Y_REGNUM;
4539 info->must_save_reg = 1;
4540 info->must_restore_reg = 1;
4541 }
4542 else
4543 {
4544 info->regno = HARD_D_REGNUM;
4545 info->must_save_reg = 1;
4546 info->must_restore_reg = 1;
4547 }
4548 info->last = NEXT_INSN (insn);
4549 return 0;
4550 }
4551
4552 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4553 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4554 {
4555 if (this_insn_uses_z)
4556 {
4557 if (info->y_used == 0 && iy_clobber)
4558 {
4559 info->regno = HARD_Y_REGNUM;
4560 info->must_save_reg = 0;
4561 info->must_restore_reg = 0;
4562 }
4563 if (info->first != insn
4564 && ((info->y_used && ix_clobber)
4565 || (info->x_used && iy_clobber)))
4566 info->last = insn;
4567 else
4568 info->last = NEXT_INSN (insn);
4569 info->save_before_last = 1;
4570 }
4571 return 0;
4572 }
4573 if (this_insn_uses_ix && this_insn_uses_iy)
4574 {
4575 if (this_insn_uses_z)
4576 {
4577 fatal_insn ("cannot do z-register replacement", insn);
4578 }
4579 return 0;
4580 }
4581 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4582 {
4583 if (info->y_used)
4584 {
4585 return 0;
4586 }
4587 info->x_used = 1;
4588 if (iy_clobber || z_clobber)
4589 {
4590 info->last = NEXT_INSN (insn);
4591 info->save_before_last = 1;
4592 return 0;
4593 }
4594 }
4595
4596 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4597 {
4598 if (info->x_used)
4599 {
4600 return 0;
4601 }
4602 info->y_used = 1;
4603 if (ix_clobber || z_clobber)
4604 {
4605 info->last = NEXT_INSN (insn);
4606 info->save_before_last = 1;
4607 return 0;
4608 }
4609 }
4610 if (z_dies_here)
4611 {
4612 info->z_died = 1;
4613 info->need_save_z = 0;
4614 }
4615 return 1;
4616 }
4617 if (GET_CODE (body) == CLOBBER)
4618 {
4619
4620 /* IX and IY are used at the same time, we have to restore
4621 the value of the scratch register before this insn. */
4622 if (this_insn_uses_ix && this_insn_uses_iy)
4623 {
4624 return 0;
4625 }
4626 if (info->x_used == 0 && this_insn_uses_ix)
4627 {
4628 if (info->y_used)
4629 {
4630 return 0;
4631 }
4632 info->x_used = 1;
4633 }
4634 if (info->y_used == 0 && this_insn_uses_iy)
4635 {
4636 if (info->x_used)
4637 {
4638 return 0;
4639 }
4640 info->y_used = 1;
4641 }
4642 return 1;
4643 }
4644 return 1;
4645 }
4646
4647 static void
4648 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4649 {
4650 int reg;
4651
4652 info->replace_reg = NULL_RTX;
4653 info->must_load_z = 1;
4654 info->need_save_z = 1;
4655 info->must_save_reg = 1;
4656 info->must_restore_reg = 1;
4657 info->first = insn;
4658 info->x_used = 0;
4659 info->y_used = 0;
4660 info->can_use_d = TARGET_M6811 ? 1 : 0;
4661 info->found_call = 0;
4662 info->z_died = 0;
4663 info->last = 0;
4664 info->regno = -1;
4665 info->z_set_count = 0;
4666 info->z_value = NULL_RTX;
4667 info->must_push_reg = 0;
4668 info->save_before_last = 0;
4669 info->z_loaded_with_sp = 0;
4670
4671 /* Scan the insn forward to find an address register that is not used.
4672 Stop when:
4673 - the flow of the program changes,
4674 - when we detect that both X and Y are necessary,
4675 - when the Z register dies,
4676 - when the condition codes are set. */
4677
4678 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4679 {
4680 if (m68hc11_check_z_replacement (insn, info) == 0)
4681 break;
4682 }
4683
4684 /* May be we can use Y or X if they contain the same value as Z.
4685 This happens very often after the reload. */
4686 if (info->z_set_count == 1)
4687 {
4688 rtx p = info->first;
4689 rtx v = 0;
4690
4691 if (info->x_used)
4692 {
4693 v = find_last_value (iy_reg, &p, insn, 1);
4694 }
4695 else if (info->y_used)
4696 {
4697 v = find_last_value (ix_reg, &p, insn, 1);
4698 }
4699 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4700 {
4701 if (info->x_used)
4702 info->regno = HARD_Y_REGNUM;
4703 else
4704 info->regno = HARD_X_REGNUM;
4705 info->must_load_z = 0;
4706 info->must_save_reg = 0;
4707 info->must_restore_reg = 0;
4708 info->found_call = 1;
4709 }
4710 }
4711 if (info->z_set_count == 0)
4712 info->need_save_z = 0;
4713
4714 if (insn == 0)
4715 info->need_save_z = 0;
4716
4717 if (info->last == 0)
4718 info->last = insn;
4719
4720 if (info->regno >= 0)
4721 {
4722 reg = info->regno;
4723 info->replace_reg = gen_rtx_REG (HImode, reg);
4724 }
4725 else if (info->can_use_d)
4726 {
4727 reg = HARD_D_REGNUM;
4728 info->replace_reg = d_reg;
4729 }
4730 else if (info->x_used)
4731 {
4732 reg = HARD_Y_REGNUM;
4733 info->replace_reg = iy_reg;
4734 }
4735 else
4736 {
4737 reg = HARD_X_REGNUM;
4738 info->replace_reg = ix_reg;
4739 }
4740 info->regno = reg;
4741
4742 if (info->must_save_reg && info->must_restore_reg)
4743 {
4744 if (insn && dead_register_here (insn, info->replace_reg))
4745 {
4746 info->must_save_reg = 0;
4747 info->must_restore_reg = 0;
4748 }
4749 }
4750 }
4751
4752 /* The insn uses the Z register. Find a replacement register for it
4753 (either X or Y) and replace it in the insn and the next ones until
4754 the flow changes or the replacement register is used. Instructions
4755 are emitted before and after the Z-block to preserve the value of
4756 Z and of the replacement register. */
4757
4758 static void
4759 m68hc11_z_replacement (rtx insn)
4760 {
4761 rtx replace_reg_qi;
4762 rtx replace_reg;
4763 struct replace_info info;
4764
4765 /* Find trivial case where we only need to replace z with the
4766 equivalent soft register. */
4767 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4768 {
4769 rtx body = PATTERN (insn);
4770 rtx src = XEXP (body, 1);
4771 rtx dst = XEXP (body, 0);
4772
4773 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4774 {
4775 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4776 return;
4777 }
4778 else if (Z_REG_P (src)
4779 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4780 {
4781 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4782 return;
4783 }
4784 else if (D_REG_P (dst)
4785 && m68hc11_arith_operator (src, GET_MODE (src))
4786 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4787 {
4788 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4789 return;
4790 }
4791 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4792 && INTVAL (src) == 0)
4793 {
4794 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4795 /* Force it to be re-recognized. */
4796 INSN_CODE (insn) = -1;
4797 return;
4798 }
4799 }
4800
4801 m68hc11_find_z_replacement (insn, &info);
4802
4803 replace_reg = info.replace_reg;
4804 replace_reg_qi = NULL_RTX;
4805
4806 /* Save the X register in a .page0 location. */
4807 if (info.must_save_reg && !info.must_push_reg)
4808 {
4809 rtx dst;
4810
4811 if (info.must_push_reg && 0)
4812 dst = gen_rtx_MEM (HImode,
4813 gen_rtx_PRE_DEC (HImode,
4814 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4815 else
4816 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4817
4818 emit_insn_before (gen_movhi (dst,
4819 gen_rtx_REG (HImode, info.regno)), insn);
4820 }
4821 if (info.must_load_z && !info.must_push_reg)
4822 {
4823 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4824 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4825 insn);
4826 }
4827
4828
4829 /* Replace all occurrence of Z by replace_reg.
4830 Stop when the last instruction to replace is reached.
4831 Also stop when we detect a change in the flow (but it's not
4832 necessary; just safeguard). */
4833
4834 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4835 {
4836 rtx body;
4837
4838 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4839 break;
4840
4841 if (GET_CODE (insn) != INSN
4842 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4843 continue;
4844
4845 body = PATTERN (insn);
4846 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4847 || GET_CODE (body) == ASM_OPERANDS
4848 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4849 {
4850 rtx note;
4851
4852 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4853 {
4854 printf ("Reg mentioned here...:\n");
4855 fflush (stdout);
4856 debug_rtx (insn);
4857 }
4858
4859 /* Stack pointer was decremented by 2 due to the push.
4860 Correct that by adding 2 to the destination. */
4861 if (info.must_push_reg
4862 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4863 {
4864 rtx src, dst;
4865
4866 src = SET_SRC (body);
4867 dst = SET_DEST (body);
4868 if (SP_REG_P (src) && Z_REG_P (dst))
4869 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4870 }
4871
4872 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4873 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4874 {
4875 INSN_CODE (insn) = -1;
4876 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4877 fatal_insn ("cannot do z-register replacement", insn);
4878 }
4879
4880 /* Likewise for (REG:QI Z). */
4881 if (reg_mentioned_p (z_reg, insn))
4882 {
4883 if (replace_reg_qi == NULL_RTX)
4884 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4885 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4886 }
4887
4888 /* If there is a REG_INC note on Z, replace it with a
4889 REG_INC note on the replacement register. This is necessary
4890 to make sure that the flow pass will identify the change
4891 and it will not remove a possible insn that saves Z. */
4892 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4893 {
4894 if (REG_NOTE_KIND (note) == REG_INC
4895 && GET_CODE (XEXP (note, 0)) == REG
4896 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4897 {
4898 XEXP (note, 0) = replace_reg;
4899 }
4900 }
4901 }
4902 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4903 break;
4904 }
4905
4906 /* Save Z before restoring the old value. */
4907 if (insn && info.need_save_z && !info.must_push_reg)
4908 {
4909 rtx save_pos_insn = insn;
4910
4911 /* If Z is clobber by the last insn, we have to save its value
4912 before the last instruction. */
4913 if (info.save_before_last)
4914 save_pos_insn = PREV_INSN (save_pos_insn);
4915
4916 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4917 gen_rtx_REG (HImode, info.regno)),
4918 save_pos_insn);
4919 }
4920
4921 if (info.must_push_reg && info.last)
4922 {
4923 rtx new_body, body;
4924
4925 body = PATTERN (info.last);
4926 new_body = gen_rtx_PARALLEL (VOIDmode,
4927 gen_rtvec (3, body,
4928 gen_rtx_USE (VOIDmode,
4929 replace_reg),
4930 gen_rtx_USE (VOIDmode,
4931 gen_rtx_REG (HImode,
4932 SOFT_Z_REGNUM))));
4933 PATTERN (info.last) = new_body;
4934
4935 /* Force recognition on insn since we changed it. */
4936 INSN_CODE (insn) = -1;
4937
4938 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4939 {
4940 fatal_insn ("invalid Z register replacement for insn", insn);
4941 }
4942 insn = NEXT_INSN (info.last);
4943 }
4944
4945 /* Restore replacement register unless it was died. */
4946 if (insn && info.must_restore_reg && !info.must_push_reg)
4947 {
4948 rtx dst;
4949
4950 if (info.must_push_reg && 0)
4951 dst = gen_rtx_MEM (HImode,
4952 gen_rtx_POST_INC (HImode,
4953 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4954 else
4955 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4956
4957 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4958 dst), insn);
4959 }
4960
4961 }
4962
4963
4964 /* Scan all the insn and re-affects some registers
4965 - The Z register (if it was used), is affected to X or Y depending
4966 on the instruction. */
4967
4968 static void
4969 m68hc11_reassign_regs (rtx first)
4970 {
4971 rtx insn;
4972
4973 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4974 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4975 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4976 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4977
4978 /* Scan all insns to replace Z by X or Y preserving the old value
4979 of X/Y and restoring it afterward. */
4980
4981 for (insn = first; insn; insn = NEXT_INSN (insn))
4982 {
4983 rtx body;
4984
4985 if (GET_CODE (insn) == CODE_LABEL
4986 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4987 continue;
4988
4989 if (!INSN_P (insn))
4990 continue;
4991
4992 body = PATTERN (insn);
4993 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4994 continue;
4995
4996 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4997 || GET_CODE (body) == ASM_OPERANDS
4998 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4999 continue;
5000
5001 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5002 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5003 {
5004
5005 /* If Z appears in this insn, replace it in the current insn
5006 and the next ones until the flow changes or we have to
5007 restore back the replacement register. */
5008
5009 if (reg_mentioned_p (z_reg, body))
5010 {
5011 m68hc11_z_replacement (insn);
5012 }
5013 }
5014 else
5015 {
5016 printf ("insn not handled by Z replacement:\n");
5017 fflush (stdout);
5018 debug_rtx (insn);
5019 }
5020 }
5021 }
5022
5023
5024 /* Machine-dependent reorg pass.
5025 Specific optimizations are defined here:
5026 - this pass changes the Z register into either X or Y
5027 (it preserves X/Y previous values in a memory slot in page0).
5028
5029 When this pass is finished, the global variable
5030 'z_replacement_completed' is set to 2. */
5031
5032 static void
5033 m68hc11_reorg (void)
5034 {
5035 int split_done = 0;
5036 rtx first;
5037
5038 z_replacement_completed = 0;
5039 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5040 first = get_insns ();
5041
5042 /* Some RTX are shared at this point. This breaks the Z register
5043 replacement, unshare everything. */
5044 unshare_all_rtl_again (first);
5045
5046 /* Force a split of all splittable insn. This is necessary for the
5047 Z register replacement mechanism because we end up with basic insns. */
5048 split_all_insns_noflow ();
5049 split_done = 1;
5050
5051 z_replacement_completed = 1;
5052 m68hc11_reassign_regs (first);
5053
5054 if (optimize)
5055 compute_bb_for_insn ();
5056
5057 /* After some splitting, there are some opportunities for CSE pass.
5058 This happens quite often when 32-bit or above patterns are split. */
5059 if (optimize > 0 && split_done)
5060 {
5061 reload_cse_regs (first);
5062 }
5063
5064 /* Re-create the REG_DEAD notes. These notes are used in the machine
5065 description to use the best assembly directives. */
5066 if (optimize)
5067 {
5068 df_note_add_problem ();
5069 df_analyze ();
5070 df_remove_problem (df_note);
5071 }
5072
5073 z_replacement_completed = 2;
5074
5075 /* If optimizing, then go ahead and split insns that must be
5076 split after Z register replacement. This gives more opportunities
5077 for peephole (in particular for consecutives xgdx/xgdy). */
5078 if (optimize > 0)
5079 split_all_insns_noflow ();
5080
5081 /* Once insns are split after the z_replacement_completed == 2,
5082 we must not re-run the life_analysis. The xgdx/xgdy patterns
5083 are not recognized and the life_analysis pass removes some
5084 insns because it thinks some (SETs) are noops or made to dead
5085 stores (which is false due to the swap).
5086
5087 Do a simple pass to eliminate the noop set that the final
5088 split could generate (because it was easier for split definition). */
5089 {
5090 rtx insn;
5091
5092 for (insn = first; insn; insn = NEXT_INSN (insn))
5093 {
5094 rtx body;
5095
5096 if (INSN_DELETED_P (insn))
5097 continue;
5098 if (!INSN_P (insn))
5099 continue;
5100
5101 /* Remove the (set (R) (R)) insns generated by some splits. */
5102 body = PATTERN (insn);
5103 if (GET_CODE (body) == SET
5104 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5105 {
5106 SET_INSN_DELETED (insn);
5107 continue;
5108 }
5109 }
5110 }
5111 }
5112 \f
5113 /* Override memcpy */
5114
5115 static void
5116 m68hc11_init_libfuncs (void)
5117 {
5118 memcpy_libfunc = init_one_libfunc ("__memcpy");
5119 memcmp_libfunc = init_one_libfunc ("__memcmp");
5120 memset_libfunc = init_one_libfunc ("__memset");
5121 }
5122
5123 \f
5124
5125 /* Cost functions. */
5126
5127 /* Cost of moving memory. */
5128 int
5129 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
5130 int in ATTRIBUTE_UNUSED)
5131 {
5132 if (rclass <= H_REGS && rclass > NO_REGS)
5133 {
5134 if (GET_MODE_SIZE (mode) <= 2)
5135 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5136 else
5137 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5138 }
5139 else
5140 {
5141 if (GET_MODE_SIZE (mode) <= 2)
5142 return COSTS_N_INSNS (3);
5143 else
5144 return COSTS_N_INSNS (4);
5145 }
5146 }
5147
5148
5149 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5150 Reload does not check the constraint of set insns when the two registers
5151 have a move cost of 2. Setting a higher cost will force reload to check
5152 the constraints. */
5153 int
5154 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5155 enum reg_class to)
5156 {
5157 /* All costs are symmetric, so reduce cases by putting the
5158 lower number class as the destination. */
5159 if (from < to)
5160 {
5161 enum reg_class tmp = to;
5162 to = from, from = tmp;
5163 }
5164 if (to >= S_REGS)
5165 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5166 else if (from <= S_REGS)
5167 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5168 else
5169 return COSTS_N_INSNS (2);
5170 }
5171
5172
5173 /* Provide the costs of an addressing mode that contains ADDR.
5174 If ADDR is not a valid address, its cost is irrelevant. */
5175
5176 static int
5177 m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
5178 {
5179 int cost = 4;
5180
5181 switch (GET_CODE (addr))
5182 {
5183 case REG:
5184 /* Make the cost of hard registers and specially SP, FP small. */
5185 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5186 cost = 0;
5187 else
5188 cost = 1;
5189 break;
5190
5191 case SYMBOL_REF:
5192 cost = 8;
5193 break;
5194
5195 case LABEL_REF:
5196 case CONST:
5197 cost = 0;
5198 break;
5199
5200 case PLUS:
5201 {
5202 register rtx plus0 = XEXP (addr, 0);
5203 register rtx plus1 = XEXP (addr, 1);
5204
5205 if (GET_CODE (plus0) != REG)
5206 break;
5207
5208 switch (GET_CODE (plus1))
5209 {
5210 case CONST_INT:
5211 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5212 || INTVAL (plus1) < m68hc11_min_offset)
5213 cost = 3;
5214 else if (INTVAL (plus1) >= m68hc11_max_offset)
5215 cost = 2;
5216 else
5217 cost = 1;
5218 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5219 cost += 0;
5220 else
5221 cost += 1;
5222 break;
5223
5224 case SYMBOL_REF:
5225 cost = 8;
5226 break;
5227
5228 case CONST:
5229 case LABEL_REF:
5230 cost = 0;
5231 break;
5232
5233 default:
5234 break;
5235 }
5236 break;
5237 }
5238 case PRE_DEC:
5239 case PRE_INC:
5240 if (SP_REG_P (XEXP (addr, 0)))
5241 cost = 1;
5242 break;
5243
5244 default:
5245 break;
5246 }
5247 if (debug_m6811)
5248 {
5249 printf ("Address cost: %d for :", cost);
5250 fflush (stdout);
5251 debug_rtx (addr);
5252 }
5253
5254 return cost;
5255 }
5256
5257 static int
5258 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5259 {
5260 int total;
5261
5262 total = rtx_cost (x, SET, !optimize_size);
5263 if (mode == QImode)
5264 total += m68hc11_cost->shiftQI_const[shift % 8];
5265 else if (mode == HImode)
5266 total += m68hc11_cost->shiftHI_const[shift % 16];
5267 else if (shift == 8 || shift == 16 || shift == 32)
5268 total += m68hc11_cost->shiftHI_const[8];
5269 else if (shift != 0 && shift != 16 && shift != 32)
5270 {
5271 total += m68hc11_cost->shiftHI_const[1] * shift;
5272 }
5273
5274 /* For SI and others, the cost is higher. */
5275 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5276 total *= GET_MODE_SIZE (mode) / 2;
5277
5278 /* When optimizing for size, make shift more costly so that
5279 multiplications are preferred. */
5280 if (optimize_size && (shift % 8) != 0)
5281 total *= 2;
5282
5283 return total;
5284 }
5285
5286 static int
5287 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5288 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5289 {
5290 enum machine_mode mode = GET_MODE (x);
5291 int extra_cost = 0;
5292 int total;
5293
5294 switch (code)
5295 {
5296 case ROTATE:
5297 case ROTATERT:
5298 case ASHIFT:
5299 case LSHIFTRT:
5300 case ASHIFTRT:
5301 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5302 {
5303 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5304 }
5305
5306 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5307 total += m68hc11_cost->shift_var;
5308 return total;
5309
5310 case AND:
5311 case XOR:
5312 case IOR:
5313 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5314 total += m68hc11_cost->logical;
5315
5316 /* Logical instructions are byte instructions only. */
5317 total *= GET_MODE_SIZE (mode);
5318 return total;
5319
5320 case MINUS:
5321 case PLUS:
5322 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5323 total += m68hc11_cost->add;
5324 if (GET_MODE_SIZE (mode) > 2)
5325 {
5326 total *= GET_MODE_SIZE (mode) / 2;
5327 }
5328 return total;
5329
5330 case UDIV:
5331 case DIV:
5332 case MOD:
5333 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5334 switch (mode)
5335 {
5336 case QImode:
5337 total += m68hc11_cost->divQI;
5338 break;
5339
5340 case HImode:
5341 total += m68hc11_cost->divHI;
5342 break;
5343
5344 case SImode:
5345 default:
5346 total += m68hc11_cost->divSI;
5347 break;
5348 }
5349 return total;
5350
5351 case MULT:
5352 /* mul instruction produces 16-bit result. */
5353 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5354 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5355 return m68hc11_cost->multQI
5356 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5357 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5358
5359 /* emul instruction produces 32-bit result for 68HC12. */
5360 if (TARGET_M6812 && mode == SImode
5361 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5362 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5363 return m68hc11_cost->multHI
5364 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5365 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5366
5367 total = rtx_cost (XEXP (x, 0), code, !optimize_size)
5368 + rtx_cost (XEXP (x, 1), code, !optimize_size);
5369 switch (mode)
5370 {
5371 case QImode:
5372 total += m68hc11_cost->multQI;
5373 break;
5374
5375 case HImode:
5376 total += m68hc11_cost->multHI;
5377 break;
5378
5379 case SImode:
5380 default:
5381 total += m68hc11_cost->multSI;
5382 break;
5383 }
5384 return total;
5385
5386 case NEG:
5387 case SIGN_EXTEND:
5388 extra_cost = COSTS_N_INSNS (2);
5389
5390 /* Fall through */
5391 case NOT:
5392 case COMPARE:
5393 case ABS:
5394 case ZERO_EXTEND:
5395 case ZERO_EXTRACT:
5396 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
5397 if (mode == QImode)
5398 {
5399 return total + COSTS_N_INSNS (1);
5400 }
5401 if (mode == HImode)
5402 {
5403 return total + COSTS_N_INSNS (2);
5404 }
5405 if (mode == SImode)
5406 {
5407 return total + COSTS_N_INSNS (4);
5408 }
5409 return total + COSTS_N_INSNS (8);
5410
5411 case IF_THEN_ELSE:
5412 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5413 return COSTS_N_INSNS (1);
5414
5415 return COSTS_N_INSNS (1);
5416
5417 default:
5418 return COSTS_N_INSNS (4);
5419 }
5420 }
5421
5422 static bool
5423 m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
5424 bool speed ATTRIBUTE_UNUSED)
5425 {
5426 enum rtx_code code = (enum rtx_code) codearg;
5427 enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
5428
5429 switch (code)
5430 {
5431 /* Constants are cheap. Moving them in registers must be avoided
5432 because most instructions do not handle two register operands. */
5433 case CONST_INT:
5434 case CONST:
5435 case LABEL_REF:
5436 case SYMBOL_REF:
5437 case CONST_DOUBLE:
5438 /* Logical and arithmetic operations with a constant operand are
5439 better because they are not supported with two registers. */
5440 /* 'clr' is slow */
5441 if (outer_code == SET && x == const0_rtx)
5442 /* After reload, the reload_cse pass checks the cost to change
5443 a SET into a PLUS. Make const0 cheap then. */
5444 *total = 1 - reload_completed;
5445 else
5446 *total = 0;
5447 return true;
5448
5449 case ZERO_EXTRACT:
5450 if (outer_code != COMPARE)
5451 return false;
5452
5453 case ROTATE:
5454 case ROTATERT:
5455 case ASHIFT:
5456 case LSHIFTRT:
5457 case ASHIFTRT:
5458 case MINUS:
5459 case PLUS:
5460 case AND:
5461 case XOR:
5462 case IOR:
5463 case UDIV:
5464 case DIV:
5465 case MOD:
5466 case MULT:
5467 case NEG:
5468 case SIGN_EXTEND:
5469 case NOT:
5470 case COMPARE:
5471 case ZERO_EXTEND:
5472 case IF_THEN_ELSE:
5473 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5474 return true;
5475
5476 default:
5477 return false;
5478 }
5479 }
5480 \f
5481
5482 /* Worker function for TARGET_ASM_FILE_START. */
5483
5484 static void
5485 m68hc11_file_start (void)
5486 {
5487 default_file_start ();
5488
5489 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5490 }
5491
5492
5493 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5494
5495 static void
5496 m68hc11_asm_out_constructor (rtx symbol, int priority)
5497 {
5498 default_ctor_section_asm_out_constructor (symbol, priority);
5499 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5500 }
5501
5502 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5503
5504 static void
5505 m68hc11_asm_out_destructor (rtx symbol, int priority)
5506 {
5507 default_dtor_section_asm_out_destructor (symbol, priority);
5508 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5509 }
5510
5511 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5512
5513 static rtx
5514 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5515 int incoming ATTRIBUTE_UNUSED)
5516 {
5517 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5518 }
5519
5520 /* Return true if type TYPE should be returned in memory.
5521 Blocks and data types largers than 4 bytes cannot be returned
5522 in the register (D + X = 4). */
5523
5524 static bool
5525 m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
5526 {
5527 if (TYPE_MODE (type) == BLKmode)
5528 {
5529 HOST_WIDE_INT size = int_size_in_bytes (type);
5530 return (size == -1 || size > 4);
5531 }
5532 else
5533 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5534 }
5535
5536 #include "gt-m68hc11.h"