* Makefile.in (cse.o): Depend on TARGET_H.
[official-gcc.git] / gcc / config / m68hc11 / m68hc11.c
blob0a50c4cc2e641b55b9d5903c196552cec95b6f77
1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@nerim.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
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.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
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 "tm_p.h"
43 #include "regs.h"
44 #include "hard-reg-set.h"
45 #include "real.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 "toplev.h"
54 #include "basic-block.h"
55 #include "function.h"
56 #include "ggc.h"
57 #include "reload.h"
58 #include "target.h"
59 #include "target-def.h"
61 static void print_options PARAMS ((FILE *));
62 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
63 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
64 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
65 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
66 int));
67 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
68 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
69 static int must_parenthesize PARAMS ((rtx));
70 static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
71 static int m68hc11_rtx_costs_1 PARAMS ((rtx, enum rtx_code, enum rtx_code));
72 static bool m68hc11_rtx_costs PARAMS ((rtx, int, int, int *));
73 static int m68hc11_auto_inc_p PARAMS ((rtx));
74 static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
75 const struct attribute_spec m68hc11_attribute_table[];
77 void create_regs_rtx PARAMS ((void));
79 static void asm_print_register PARAMS ((FILE *, int));
80 static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
81 static void m68hc11_asm_out_constructor PARAMS ((rtx, int));
82 static void m68hc11_asm_out_destructor PARAMS ((rtx, int));
83 static void m68hc11_encode_section_info PARAMS((tree, int));
84 static int autoinc_mode PARAMS((rtx));
85 static int m68hc11_make_autoinc_notes PARAMS((rtx *, void *));
87 /* Must be set to 1 to produce debug messages. */
88 int debug_m6811 = 0;
90 extern FILE *asm_out_file;
92 rtx ix_reg;
93 rtx iy_reg;
94 rtx d_reg;
95 rtx m68hc11_soft_tmp_reg;
96 static GTY(()) rtx stack_push_word;
97 static GTY(()) rtx stack_pop_word;
98 static GTY(()) rtx z_reg;
99 static GTY(()) rtx z_reg_qi;
100 static int regs_inited = 0;
102 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
103 int current_function_interrupt;
105 /* Set to 1 by expand_prologue() when the function is a trap handler. */
106 int current_function_trap;
108 /* Set to 1 when the current function is placed in 68HC12 banked
109 memory and must return with rtc. */
110 int current_function_far;
112 /* Min offset that is valid for the indirect addressing mode. */
113 HOST_WIDE_INT m68hc11_min_offset = 0;
115 /* Max offset that is valid for the indirect addressing mode. */
116 HOST_WIDE_INT m68hc11_max_offset = 256;
118 /* The class value for base registers. */
119 enum reg_class m68hc11_base_reg_class = A_REGS;
121 /* The class value for index registers. This is NO_REGS for 68HC11. */
122 enum reg_class m68hc11_index_reg_class = NO_REGS;
124 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
126 /* Tables that tell whether a given hard register is valid for
127 a base or an index register. It is filled at init time depending
128 on the target processor. */
129 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
130 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
132 /* A correction offset which is applied to the stack pointer.
133 This is 1 for 68HC11 and 0 for 68HC12. */
134 int m68hc11_sp_correction;
136 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
137 rtx m68hc11_compare_op0;
138 rtx m68hc11_compare_op1;
141 const struct processor_costs *m68hc11_cost;
143 /* Costs for a 68HC11. */
144 static const struct processor_costs m6811_cost = {
145 /* add */
146 COSTS_N_INSNS (2),
147 /* logical */
148 COSTS_N_INSNS (2),
149 /* non-constant shift */
150 COSTS_N_INSNS (20),
151 /* shiftQI const */
152 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
153 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
154 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
156 /* shiftHI const */
157 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
158 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
159 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
160 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
161 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
162 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
164 /* mulQI */
165 COSTS_N_INSNS (20),
166 /* mulHI */
167 COSTS_N_INSNS (20 * 4),
168 /* mulSI */
169 COSTS_N_INSNS (20 * 16),
170 /* divQI */
171 COSTS_N_INSNS (20),
172 /* divHI */
173 COSTS_N_INSNS (80),
174 /* divSI */
175 COSTS_N_INSNS (100)
178 /* Costs for a 68HC12. */
179 static const struct processor_costs m6812_cost = {
180 /* add */
181 COSTS_N_INSNS (2),
182 /* logical */
183 COSTS_N_INSNS (2),
184 /* non-constant shift */
185 COSTS_N_INSNS (20),
186 /* shiftQI const */
187 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
188 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
189 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
191 /* shiftHI const */
192 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
193 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
194 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
195 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
196 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
197 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
199 /* mulQI */
200 COSTS_N_INSNS (3),
201 /* mulHI */
202 COSTS_N_INSNS (3),
203 /* mulSI */
204 COSTS_N_INSNS (3 * 4),
205 /* divQI */
206 COSTS_N_INSNS (12),
207 /* divHI */
208 COSTS_N_INSNS (12),
209 /* divSI */
210 COSTS_N_INSNS (100)
213 /* Machine specific options */
215 const char *m68hc11_regparm_string;
216 const char *m68hc11_reg_alloc_order;
217 const char *m68hc11_soft_reg_count;
219 static int nb_soft_regs;
221 /* Initialize the GCC target structure. */
222 #undef TARGET_ATTRIBUTE_TABLE
223 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
225 #undef TARGET_ASM_ALIGNED_HI_OP
226 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
228 #undef TARGET_ASM_FUNCTION_EPILOGUE
229 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
231 #undef TARGET_ENCODE_SECTION_INFO
232 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
234 #undef TARGET_RTX_COSTS
235 #define TARGET_RTX_COSTS m68hc11_rtx_costs
237 struct gcc_target targetm = TARGET_INITIALIZER;
240 m68hc11_override_options ()
242 memset (m68hc11_reg_valid_for_index, 0,
243 sizeof (m68hc11_reg_valid_for_index));
244 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
246 /* Compilation with -fpic generates a wrong code. */
247 if (flag_pic)
249 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
250 (flag_pic > 1) ? "PIC" : "pic");
251 flag_pic = 0;
254 /* Configure for a 68hc11 processor. */
255 if (TARGET_M6811)
257 /* If gcc was built for a 68hc12, invalidate that because
258 a -m68hc11 option was specified on the command line. */
259 if (TARGET_DEFAULT != MASK_M6811)
260 target_flags &= ~TARGET_DEFAULT;
262 if (!TARGET_M6812)
263 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
264 m68hc11_cost = &m6811_cost;
265 m68hc11_min_offset = 0;
266 m68hc11_max_offset = 256;
267 m68hc11_index_reg_class = NO_REGS;
268 m68hc11_base_reg_class = A_REGS;
269 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
270 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
271 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
272 m68hc11_sp_correction = 1;
273 m68hc11_tmp_regs_class = D_REGS;
274 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
275 m68hc11_soft_reg_count = "4";
278 /* Configure for a 68hc12 processor. */
279 if (TARGET_M6812)
281 m68hc11_cost = &m6812_cost;
282 m68hc11_min_offset = -65536;
283 m68hc11_max_offset = 65536;
284 m68hc11_index_reg_class = D_REGS;
285 m68hc11_base_reg_class = A_OR_SP_REGS;
286 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
287 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
288 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
289 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
290 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
291 m68hc11_sp_correction = 0;
292 m68hc11_tmp_regs_class = TMP_REGS;
293 target_flags &= ~MASK_M6811;
294 target_flags |= MASK_NO_DIRECT_MODE | MASK_MIN_MAX;
295 if (m68hc11_soft_reg_count == 0)
296 m68hc11_soft_reg_count = "0";
298 if (TARGET_LONG_CALLS)
299 current_function_far = 1;
301 return 0;
305 void
306 m68hc11_conditional_register_usage ()
308 int i;
309 int cnt = atoi (m68hc11_soft_reg_count);
311 if (cnt < 0)
312 cnt = 0;
313 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
314 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
316 nb_soft_regs = cnt;
317 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
319 fixed_regs[i] = 1;
320 call_used_regs[i] = 1;
323 /* For 68HC12, the Z register emulation is not necessary when the
324 frame pointer is not used. The frame pointer is eliminated and
325 replaced by the stack register (which is a BASE_REG_CLASS). */
326 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
328 fixed_regs[HARD_Z_REGNUM] = 1;
333 /* Reload and register operations. */
335 static const char *const reg_class_names[] = REG_CLASS_NAMES;
338 void
339 create_regs_rtx ()
341 /* regs_inited = 1; */
342 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
343 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
344 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
345 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
347 stack_push_word = gen_rtx (MEM, HImode,
348 gen_rtx (PRE_DEC, HImode,
349 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
350 stack_pop_word = gen_rtx (MEM, HImode,
351 gen_rtx (POST_INC, HImode,
352 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
356 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
357 - 8 bit values are stored anywhere (except the SP register).
358 - 16 bit values can be stored in any register whose mode is 16
359 - 32 bit values can be stored in D, X registers or in a soft register
360 (except the last one because we need 2 soft registers)
361 - Values whose size is > 32 bit are not stored in real hard
362 registers. They may be stored in soft registers if there are
363 enough of them. */
365 hard_regno_mode_ok (regno, mode)
366 int regno;
367 enum machine_mode mode;
369 switch (GET_MODE_SIZE (mode))
371 case 8:
372 return S_REGNO_P (regno) && nb_soft_regs >= 4;
374 case 4:
375 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
377 case 2:
378 return G_REGNO_P (regno);
380 case 1:
381 /* We have to accept a QImode in X or Y registers. Otherwise, the
382 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
383 in the insns. Reload fails if the insn rejects the register class 'a'
384 as well as if it accepts it. Patterns that failed were
385 zero_extend_qihi2 and iorqi3. */
387 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
389 default:
390 return 0;
394 enum reg_class
395 preferred_reload_class (operand, class)
396 rtx operand;
397 enum reg_class class;
399 enum machine_mode mode;
401 mode = GET_MODE (operand);
403 if (debug_m6811)
405 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
408 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
409 return m68hc11_base_reg_class;
411 if (class >= S_REGS && (GET_CODE (operand) == MEM
412 || GET_CODE (operand) == CONST_INT))
414 /* S_REGS class must not be used. The movhi template does not
415 work to move a memory to a soft register.
416 Restrict to a hard reg. */
417 switch (class)
419 default:
420 case G_REGS:
421 case D_OR_A_OR_S_REGS:
422 class = A_OR_D_REGS;
423 break;
424 case A_OR_S_REGS:
425 class = A_REGS;
426 break;
427 case D_OR_SP_OR_S_REGS:
428 class = D_OR_SP_REGS;
429 break;
430 case D_OR_Y_OR_S_REGS:
431 class = D_OR_Y_REGS;
432 break;
433 case D_OR_X_OR_S_REGS:
434 class = D_OR_X_REGS;
435 break;
436 case SP_OR_S_REGS:
437 class = SP_REGS;
438 break;
439 case Y_OR_S_REGS:
440 class = Y_REGS;
441 break;
442 case X_OR_S_REGS:
443 class = X_REGS;
444 break;
445 case D_OR_S_REGS:
446 class = D_REGS;
449 else if (class == Y_REGS && GET_CODE (operand) == MEM)
451 class = Y_REGS;
453 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
455 class = D_OR_X_REGS;
457 else if (class >= S_REGS && S_REG_P (operand))
459 switch (class)
461 default:
462 case G_REGS:
463 case D_OR_A_OR_S_REGS:
464 class = A_OR_D_REGS;
465 break;
466 case A_OR_S_REGS:
467 class = A_REGS;
468 break;
469 case D_OR_SP_OR_S_REGS:
470 class = D_OR_SP_REGS;
471 break;
472 case D_OR_Y_OR_S_REGS:
473 class = D_OR_Y_REGS;
474 break;
475 case D_OR_X_OR_S_REGS:
476 class = D_OR_X_REGS;
477 break;
478 case SP_OR_S_REGS:
479 class = SP_REGS;
480 break;
481 case Y_OR_S_REGS:
482 class = Y_REGS;
483 break;
484 case X_OR_S_REGS:
485 class = X_REGS;
486 break;
487 case D_OR_S_REGS:
488 class = D_REGS;
491 else if (class >= S_REGS)
493 if (debug_m6811)
495 printf ("Class = %s for: ", reg_class_names[class]);
496 fflush (stdout);
497 debug_rtx (operand);
501 if (debug_m6811)
503 printf (" => class=%s\n", reg_class_names[class]);
504 fflush (stdout);
505 debug_rtx (operand);
508 return class;
511 /* Return 1 if the operand is a valid indexed addressing mode.
512 For 68hc11: n,r with n in [0..255] and r in A_REGS class
513 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
514 static int
515 register_indirect_p (operand, mode, strict)
516 rtx operand;
517 enum machine_mode mode;
518 int strict;
520 rtx base, offset;
522 switch (GET_CODE (operand))
524 case POST_INC:
525 case PRE_INC:
526 case POST_DEC:
527 case PRE_DEC:
528 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
529 return register_indirect_p (XEXP (operand, 0), mode, strict);
530 return 0;
532 case PLUS:
533 base = XEXP (operand, 0);
534 if (GET_CODE (base) == MEM)
535 return 0;
537 offset = XEXP (operand, 1);
538 if (GET_CODE (offset) == MEM)
539 return 0;
541 if (GET_CODE (base) == REG)
543 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
544 return 0;
546 if (strict == 0)
547 return 1;
549 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
551 if (GET_CODE (offset) == REG)
553 if (!VALID_CONSTANT_OFFSET_P (base, mode))
554 return 0;
556 if (strict == 0)
557 return 1;
559 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
561 return 0;
563 case REG:
564 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
566 case CONST_INT:
567 if (TARGET_M6811)
568 return 0;
570 return VALID_CONSTANT_OFFSET_P (operand, mode);
572 default:
573 return 0;
577 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
578 a 68HC12 1-byte index addressing mode. */
580 m68hc11_small_indexed_indirect_p (operand, mode)
581 rtx operand;
582 enum machine_mode mode;
584 rtx base, offset;
586 if (GET_CODE (operand) == REG && reload_in_progress
587 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
588 && reg_equiv_memory_loc[REGNO (operand)])
590 operand = reg_equiv_memory_loc[REGNO (operand)];
591 operand = eliminate_regs (operand, 0, NULL_RTX);
594 if (GET_CODE (operand) != MEM)
595 return 0;
597 operand = XEXP (operand, 0);
598 if (CONSTANT_ADDRESS_P (operand))
599 return 1;
601 if (PUSH_POP_ADDRESS_P (operand))
602 return 1;
604 if (!register_indirect_p (operand, mode, reload_completed))
605 return 0;
607 if (TARGET_M6812 && GET_CODE (operand) == PLUS
608 && (reload_completed | reload_in_progress))
610 base = XEXP (operand, 0);
611 offset = XEXP (operand, 1);
613 /* The offset can be a symbol address and this is too big
614 for the operand constraint. */
615 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
616 return 0;
618 if (GET_CODE (base) == CONST_INT)
619 offset = base;
621 switch (GET_MODE_SIZE (mode))
623 case 8:
624 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
625 return 0;
626 break;
628 case 4:
629 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
630 return 0;
631 break;
633 default:
634 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
635 return 0;
636 break;
639 return 1;
643 m68hc11_register_indirect_p (operand, mode)
644 rtx operand;
645 enum machine_mode mode;
647 if (GET_CODE (operand) != MEM)
648 return 0;
650 operand = XEXP (operand, 0);
651 return register_indirect_p (operand, mode,
652 (reload_completed | reload_in_progress));
655 static int
656 go_if_legitimate_address_internal (operand, mode, strict)
657 rtx operand;
658 enum machine_mode mode;
659 int strict;
661 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
663 /* Reject the global variables if they are too wide. This forces
664 a load of their address in a register and generates smaller code. */
665 if (GET_MODE_SIZE (mode) == 8)
666 return 0;
668 return 1;
670 if (register_indirect_p (operand, mode, strict))
672 return 1;
674 if (PUSH_POP_ADDRESS_P (operand))
676 return 1;
678 if (symbolic_memory_operand (operand, mode))
680 return 1;
682 return 0;
686 m68hc11_go_if_legitimate_address (operand, mode, strict)
687 rtx operand;
688 enum machine_mode mode;
689 int strict;
691 int result;
693 if (debug_m6811)
695 printf ("Checking: ");
696 fflush (stdout);
697 debug_rtx (operand);
700 result = go_if_legitimate_address_internal (operand, mode, strict);
702 if (debug_m6811)
704 printf (" -> %s\n", result == 0 ? "NO" : "YES");
707 if (result == 0)
709 if (debug_m6811)
711 printf ("go_if_legitimate%s, ret 0: %d:",
712 (strict ? "_strict" : ""), mode);
713 fflush (stdout);
714 debug_rtx (operand);
717 return result;
721 m68hc11_legitimize_address (operand, old_operand, mode)
722 rtx *operand ATTRIBUTE_UNUSED;
723 rtx old_operand ATTRIBUTE_UNUSED;
724 enum machine_mode mode ATTRIBUTE_UNUSED;
726 return 0;
731 m68hc11_reload_operands (operands)
732 rtx operands[];
734 enum machine_mode mode;
736 if (regs_inited == 0)
737 create_regs_rtx ();
739 mode = GET_MODE (operands[1]);
741 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
742 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
744 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
745 rtx base = XEXP (XEXP (operands[1], 0), 0);
747 if (GET_CODE (base) != REG)
749 rtx tmp = base;
750 base = big_offset;
751 big_offset = tmp;
754 /* If the offset is out of range, we have to compute the address
755 with a separate add instruction. We try to do with with an 8-bit
756 add on the A register. This is possible only if the lowest part
757 of the offset (ie, big_offset % 256) is a valid constant offset
758 with respect to the mode. If it's not, we have to generate a
759 16-bit add on the D register. From:
761 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
763 we generate:
765 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
766 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
767 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
768 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
770 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
771 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
774 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
776 int vh, vl;
777 rtx reg = operands[0];
778 rtx offset;
779 int val = INTVAL (big_offset);
782 /* We use the 'operands[0]' as a scratch register to compute the
783 address. Make sure 'base' is in that register. */
784 if (!rtx_equal_p (base, operands[0]))
786 emit_move_insn (reg, base);
789 if (val > 0)
791 vh = val >> 8;
792 vl = val & 0x0FF;
794 else
796 vh = (val >> 8) & 0x0FF;
797 vl = val & 0x0FF;
800 /* Create the lowest part offset that still remains to be added.
801 If it's not a valid offset, do a 16-bit add. */
802 offset = GEN_INT (vl);
803 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
805 emit_insn (gen_rtx (SET, VOIDmode, reg,
806 gen_rtx (PLUS, HImode, reg, big_offset)));
807 offset = const0_rtx;
809 else
811 emit_insn (gen_rtx (SET, VOIDmode, reg,
812 gen_rtx (PLUS, HImode, reg,
813 GEN_INT (vh << 8))));
815 emit_move_insn (operands[0],
816 gen_rtx (MEM, GET_MODE (operands[1]),
817 gen_rtx (PLUS, Pmode, reg, offset)));
818 return 1;
822 /* Use the normal gen_movhi pattern. */
823 return 0;
826 void
827 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
828 const char *name;
829 enum rtx_code code;
830 enum machine_mode dmode;
831 enum machine_mode smode;
832 int noperands;
833 rtx *operands;
835 rtx ret;
836 rtx insns;
837 rtx libcall;
838 rtx equiv;
840 start_sequence ();
841 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
842 switch (noperands)
844 case 2:
845 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
846 dmode, 1, operands[1], smode);
847 equiv = gen_rtx (code, dmode, operands[1]);
848 break;
850 case 3:
851 ret = emit_library_call_value (libcall, NULL_RTX,
852 LCT_CONST, dmode, 2,
853 operands[1], smode, operands[2],
854 smode);
855 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
856 break;
858 default:
859 abort ();
862 insns = get_insns ();
863 end_sequence ();
864 emit_libcall_block (insns, operands[0], ret, equiv);
867 /* Returns true if X is a PRE/POST increment decrement
868 (same as auto_inc_p() in rtlanal.c but do not take into
869 account the stack). */
870 static int
871 m68hc11_auto_inc_p (x)
872 rtx x;
874 return GET_CODE (x) == PRE_DEC
875 || GET_CODE (x) == POST_INC
876 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
880 /* Predicates for machine description. */
883 memory_reload_operand (operand, mode)
884 rtx operand;
885 enum machine_mode mode ATTRIBUTE_UNUSED;
887 return GET_CODE (operand) == MEM
888 && GET_CODE (XEXP (operand, 0)) == PLUS
889 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
890 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
891 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
892 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
896 tst_operand (operand, mode)
897 rtx operand;
898 enum machine_mode mode;
900 if (GET_CODE (operand) == MEM && reload_completed == 0)
902 rtx addr = XEXP (operand, 0);
903 if (m68hc11_auto_inc_p (addr))
904 return 0;
906 return nonimmediate_operand (operand, mode);
910 cmp_operand (operand, mode)
911 rtx operand;
912 enum machine_mode mode;
914 if (GET_CODE (operand) == MEM)
916 rtx addr = XEXP (operand, 0);
917 if (m68hc11_auto_inc_p (addr))
918 return 0;
920 return general_operand (operand, mode);
924 non_push_operand (operand, mode)
925 rtx operand;
926 enum machine_mode mode;
928 if (general_operand (operand, mode) == 0)
929 return 0;
931 if (push_operand (operand, mode) == 1)
932 return 0;
933 return 1;
937 reg_or_some_mem_operand (operand, mode)
938 rtx operand;
939 enum machine_mode mode;
941 if (GET_CODE (operand) == MEM)
943 rtx op = XEXP (operand, 0);
945 if (symbolic_memory_operand (op, mode))
946 return 1;
948 if (IS_STACK_PUSH (operand))
949 return 1;
951 if (m68hc11_register_indirect_p (operand, mode))
952 return 1;
954 return 0;
957 return register_operand (operand, mode);
961 m68hc11_symbolic_p (operand, mode)
962 rtx operand;
963 enum machine_mode mode;
965 if (GET_CODE (operand) == MEM)
967 rtx op = XEXP (operand, 0);
969 if (symbolic_memory_operand (op, mode))
970 return 1;
972 return 0;
976 m68hc11_indirect_p (operand, mode)
977 rtx operand;
978 enum machine_mode mode;
980 if (GET_CODE (operand) == MEM)
982 rtx op = XEXP (operand, 0);
984 if (symbolic_memory_operand (op, mode))
985 return 0;
987 if (reload_in_progress)
988 return 1;
990 operand = XEXP (operand, 0);
991 return register_indirect_p (operand, mode, reload_completed);
993 return 0;
997 stack_register_operand (operand, mode)
998 rtx operand;
999 enum machine_mode mode ATTRIBUTE_UNUSED;
1001 return SP_REG_P (operand);
1005 d_register_operand (operand, mode)
1006 rtx operand;
1007 enum machine_mode mode ATTRIBUTE_UNUSED;
1009 if (GET_CODE (operand) == SUBREG)
1010 operand = XEXP (operand, 0);
1012 return GET_CODE (operand) == REG
1013 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1014 || REGNO (operand) == HARD_D_REGNUM
1015 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
1019 hard_addr_reg_operand (operand, mode)
1020 rtx operand;
1021 enum machine_mode mode ATTRIBUTE_UNUSED;
1023 if (GET_CODE (operand) == SUBREG)
1024 operand = XEXP (operand, 0);
1026 return GET_CODE (operand) == REG
1027 && (REGNO (operand) == HARD_X_REGNUM
1028 || REGNO (operand) == HARD_Y_REGNUM
1029 || REGNO (operand) == HARD_Z_REGNUM);
1033 hard_reg_operand (operand, mode)
1034 rtx operand;
1035 enum machine_mode mode ATTRIBUTE_UNUSED;
1037 if (GET_CODE (operand) == SUBREG)
1038 operand = XEXP (operand, 0);
1040 return GET_CODE (operand) == REG
1041 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1042 || H_REGNO_P (REGNO (operand)));
1046 memory_indexed_operand (operand, mode)
1047 rtx operand;
1048 enum machine_mode mode ATTRIBUTE_UNUSED;
1050 if (GET_CODE (operand) != MEM)
1051 return 0;
1053 operand = XEXP (operand, 0);
1054 if (GET_CODE (operand) == PLUS)
1056 if (GET_CODE (XEXP (operand, 0)) == REG)
1057 operand = XEXP (operand, 0);
1058 else if (GET_CODE (XEXP (operand, 1)) == REG)
1059 operand = XEXP (operand, 1);
1061 return GET_CODE (operand) == REG
1062 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1063 || A_REGNO_P (REGNO (operand)));
1067 push_pop_operand_p (operand)
1068 rtx operand;
1070 if (GET_CODE (operand) != MEM)
1072 return 0;
1074 operand = XEXP (operand, 0);
1075 return PUSH_POP_ADDRESS_P (operand);
1078 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1079 reference and a constant. */
1082 symbolic_memory_operand (op, mode)
1083 register rtx op;
1084 enum machine_mode mode;
1086 switch (GET_CODE (op))
1088 case SYMBOL_REF:
1089 case LABEL_REF:
1090 return 1;
1092 case CONST:
1093 op = XEXP (op, 0);
1094 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1095 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1096 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1098 /* ??? This clause seems to be irrelevant. */
1099 case CONST_DOUBLE:
1100 return GET_MODE (op) == mode;
1102 case PLUS:
1103 return symbolic_memory_operand (XEXP (op, 0), mode)
1104 && symbolic_memory_operand (XEXP (op, 1), mode);
1106 default:
1107 return 0;
1112 m68hc11_logical_operator (op, mode)
1113 register rtx op;
1114 enum machine_mode mode ATTRIBUTE_UNUSED;
1116 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1120 m68hc11_arith_operator (op, mode)
1121 register rtx op;
1122 enum machine_mode mode ATTRIBUTE_UNUSED;
1124 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1125 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1126 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1127 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1128 || GET_CODE (op) == ROTATERT;
1132 m68hc11_non_shift_operator (op, mode)
1133 register rtx op;
1134 enum machine_mode mode ATTRIBUTE_UNUSED;
1136 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1137 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1142 m68hc11_unary_operator (op, mode)
1143 register rtx op;
1144 enum machine_mode mode ATTRIBUTE_UNUSED;
1146 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1147 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1150 /* Emit the code to build the trampoline used to call a nested function.
1152 68HC11 68HC12
1154 ldy #&CXT movw #&CXT,*_.d1
1155 sty *_.d1 jmp FNADDR
1156 jmp FNADDR
1159 void
1160 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
1161 rtx tramp;
1162 rtx fnaddr;
1163 rtx cxt;
1165 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1167 /* Skip the '*'. */
1168 if (*static_chain_reg == '*')
1169 static_chain_reg++;
1170 if (TARGET_M6811)
1172 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1173 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1174 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1175 GEN_INT (0x18df));
1176 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1177 gen_rtx_CONST (QImode,
1178 gen_rtx_SYMBOL_REF (Pmode,
1179 static_chain_reg)));
1180 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1181 GEN_INT (0x7e));
1182 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1184 else
1186 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1187 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1188 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1189 gen_rtx_CONST (HImode,
1190 gen_rtx_SYMBOL_REF (Pmode,
1191 static_chain_reg)));
1192 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1193 GEN_INT (0x06));
1194 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1198 /* Declaration of types. */
1200 const struct attribute_spec m68hc11_attribute_table[] =
1202 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1203 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1204 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1205 { NULL, 0, 0, false, false, false, NULL }
1208 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1209 arguments as in struct attribute_spec.handler. */
1210 static tree
1211 m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
1212 tree *node;
1213 tree name;
1214 tree args ATTRIBUTE_UNUSED;
1215 int flags ATTRIBUTE_UNUSED;
1216 bool *no_add_attrs;
1218 if (TREE_CODE (*node) != FUNCTION_TYPE
1219 && TREE_CODE (*node) != FIELD_DECL
1220 && TREE_CODE (*node) != TYPE_DECL)
1222 warning ("`%s' attribute only applies to functions",
1223 IDENTIFIER_POINTER (name));
1224 *no_add_attrs = true;
1227 return NULL_TREE;
1230 /* We want to recognize trap handlers so that we handle calls to traps
1231 in a special manner (by issuing the trap). This information is stored
1232 in SYMBOL_REF_FLAG. */
1234 static void
1235 m68hc11_encode_section_info (decl, first)
1236 tree decl;
1237 int first ATTRIBUTE_UNUSED;
1239 tree func_attr;
1240 int trap_handler;
1241 rtx rtl;
1243 if (TREE_CODE (decl) != FUNCTION_DECL)
1244 return;
1246 rtl = DECL_RTL (decl);
1248 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1249 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1250 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
1254 /* Argument support functions. */
1256 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1257 Arrays are passed by references and other types by value.
1259 SCz: I tried to pass DImode by reference but it seems that this
1260 does not work very well. */
1262 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1263 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1264 enum machine_mode mode ATTRIBUTE_UNUSED;
1265 tree type;
1266 int named ATTRIBUTE_UNUSED;
1268 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1269 /* Consider complex values as aggregates, so care for TCmode. */
1270 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1271 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1275 /* Define the offset between two registers, one to be eliminated, and the
1276 other its replacement, at the start of a routine. */
1278 m68hc11_initial_elimination_offset (from, to)
1279 int from;
1280 int to;
1282 int trap_handler;
1283 tree func_attr;
1284 int size;
1285 int regno;
1287 /* For a trap handler, we must take into account the registers which
1288 are pushed on the stack during the trap (except the PC). */
1289 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1290 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1291 if (trap_handler && from == ARG_POINTER_REGNUM)
1292 size = 7;
1294 /* For a function using 'call/rtc' we must take into account the
1295 page register which is pushed in the call. */
1296 else if (current_function_far && from == ARG_POINTER_REGNUM)
1297 size = 1;
1298 else
1299 size = 0;
1301 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1303 /* 2 is for the saved frame.
1304 1 is for the 'sts' correction when creating the frame. */
1305 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1308 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1310 return m68hc11_sp_correction;
1313 /* Push any 2 byte pseudo hard registers that we need to save. */
1314 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1316 if (regs_ever_live[regno] && !call_used_regs[regno])
1318 size += 2;
1322 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1324 return get_frame_size () + size;
1327 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1329 return size;
1331 return 0;
1334 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1335 for a call to a function whose data type is FNTYPE.
1336 For a library call, FNTYPE is 0. */
1338 void
1339 m68hc11_init_cumulative_args (cum, fntype, libname)
1340 CUMULATIVE_ARGS *cum;
1341 tree fntype;
1342 rtx libname;
1344 tree ret_type;
1346 z_replacement_completed = 0;
1347 cum->words = 0;
1348 cum->nregs = 0;
1350 /* For a library call, we must find out the type of the return value.
1351 When the return value is bigger than 4 bytes, it is returned in
1352 memory. In that case, the first argument of the library call is a
1353 pointer to the memory location. Because the first argument is passed in
1354 register D, we have to identify this, so that the first function
1355 parameter is not passed in D either. */
1356 if (fntype == 0)
1358 const char *name;
1359 size_t len;
1361 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1362 return;
1364 /* If the library ends in 'di' or in 'df', we assume it's
1365 returning some DImode or some DFmode which are 64-bit wide. */
1366 name = XSTR (libname, 0);
1367 len = strlen (name);
1368 if (len > 3
1369 && ((name[len - 2] == 'd'
1370 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1371 || (name[len - 3] == 'd'
1372 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1374 /* We are in. Mark the first parameter register as already used. */
1375 cum->words = 1;
1376 cum->nregs = 1;
1378 return;
1381 ret_type = TREE_TYPE (fntype);
1383 if (ret_type && aggregate_value_p (ret_type))
1385 cum->words = 1;
1386 cum->nregs = 1;
1390 /* Update the data in CUM to advance over an argument
1391 of mode MODE and data type TYPE.
1392 (TYPE is null for libcalls where that information may not be available.) */
1394 void
1395 m68hc11_function_arg_advance (cum, mode, type, named)
1396 CUMULATIVE_ARGS *cum;
1397 enum machine_mode mode;
1398 tree type;
1399 int named ATTRIBUTE_UNUSED;
1401 if (mode != BLKmode)
1403 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1405 cum->nregs = 2;
1406 cum->words = GET_MODE_SIZE (mode);
1408 else
1410 cum->words += GET_MODE_SIZE (mode);
1411 if (cum->words <= HARD_REG_SIZE)
1412 cum->nregs = 1;
1415 else
1417 cum->words += int_size_in_bytes (type);
1419 return;
1422 /* Define where to put the arguments to a function.
1423 Value is zero to push the argument on the stack,
1424 or a hard register in which to store the argument.
1426 MODE is the argument's machine mode.
1427 TYPE is the data type of the argument (as a tree).
1428 This is null for libcalls where that information may
1429 not be available.
1430 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1431 the preceding args and about the function being called.
1432 NAMED is nonzero if this argument is a named parameter
1433 (otherwise it is an extra parameter matching an ellipsis). */
1435 struct rtx_def *
1436 m68hc11_function_arg (cum, mode, type, named)
1437 const CUMULATIVE_ARGS *cum;
1438 enum machine_mode mode;
1439 tree type ATTRIBUTE_UNUSED;
1440 int named ATTRIBUTE_UNUSED;
1442 if (cum->words != 0)
1444 return NULL_RTX;
1447 if (mode != BLKmode)
1449 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1450 return gen_rtx (REG, mode, HARD_X_REGNUM);
1452 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1454 return NULL_RTX;
1456 return gen_rtx (REG, mode, HARD_D_REGNUM);
1458 return NULL_RTX;
1462 m68hc11_va_arg (valist, type)
1463 tree valist;
1464 tree type;
1466 tree addr_tree, t;
1467 HOST_WIDE_INT align;
1468 HOST_WIDE_INT rounded_size;
1469 rtx addr;
1470 int pad_direction;
1472 /* Compute the rounded size of the type. */
1473 align = PARM_BOUNDARY / BITS_PER_UNIT;
1474 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1476 /* Get AP. */
1477 addr_tree = valist;
1478 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
1480 if (pad_direction == downward)
1482 /* Small args are padded downward. */
1484 HOST_WIDE_INT adj;
1485 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1486 if (rounded_size > align)
1487 adj = rounded_size;
1489 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1490 build_int_2 (rounded_size - adj, 0));
1493 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1494 addr = copy_to_reg (addr);
1496 /* Compute new value for AP. */
1497 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1498 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1499 build_int_2 (rounded_size, 0)));
1500 TREE_SIDE_EFFECTS (t) = 1;
1501 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1503 return addr;
1506 /* If defined, a C expression which determines whether, and in which direction,
1507 to pad out an argument with extra space. The value should be of type
1508 `enum direction': either `upward' to pad above the argument,
1509 `downward' to pad below, or `none' to inhibit padding.
1511 Structures are stored left shifted in their argument slot. */
1513 m68hc11_function_arg_padding (mode, type)
1514 enum machine_mode mode;
1515 tree type;
1517 if (type != 0 && AGGREGATE_TYPE_P (type))
1518 return upward;
1520 /* This is the default definition. */
1521 return (!BYTES_BIG_ENDIAN
1522 ? upward
1523 : ((mode == BLKmode
1524 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1525 && int_size_in_bytes (type) <
1526 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1527 PARM_BOUNDARY) ? downward : upward));
1531 /* Function prologue and epilogue. */
1533 /* Emit a move after the reload pass has completed. This is used to
1534 emit the prologue and epilogue. */
1535 static void
1536 emit_move_after_reload (to, from, scratch)
1537 rtx to, from, scratch;
1539 rtx insn;
1541 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1543 insn = emit_move_insn (to, from);
1545 else
1547 emit_move_insn (scratch, from);
1548 insn = emit_move_insn (to, scratch);
1551 /* Put a REG_INC note to tell the flow analysis that the instruction
1552 is necessary. */
1553 if (IS_STACK_PUSH (to))
1555 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1556 XEXP (XEXP (to, 0), 0),
1557 REG_NOTES (insn));
1559 else if (IS_STACK_POP (from))
1561 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1562 XEXP (XEXP (from, 0), 0),
1563 REG_NOTES (insn));
1566 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1567 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1568 The problem is that we are lying to gcc and use `txs' for x = sp
1569 (which is not really true because txs is really x = sp + 1). */
1570 else if (TARGET_M6811 && SP_REG_P (from))
1572 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1573 from,
1574 REG_NOTES (insn));
1579 m68hc11_total_frame_size ()
1581 int size;
1582 int regno;
1584 size = get_frame_size ();
1585 if (current_function_interrupt)
1587 size += 3 * HARD_REG_SIZE;
1589 if (frame_pointer_needed)
1590 size += HARD_REG_SIZE;
1592 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1593 if (regs_ever_live[regno] && !call_used_regs[regno])
1594 size += HARD_REG_SIZE;
1596 return size;
1599 static void
1600 m68hc11_output_function_epilogue (out, size)
1601 FILE *out ATTRIBUTE_UNUSED;
1602 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1604 /* We catch the function epilogue generation to have a chance
1605 to clear the z_replacement_completed flag. */
1606 z_replacement_completed = 0;
1609 void
1610 expand_prologue ()
1612 tree func_attr;
1613 int size;
1614 int regno;
1615 rtx scratch;
1617 if (reload_completed != 1)
1618 abort ();
1620 size = get_frame_size ();
1622 create_regs_rtx ();
1624 /* Generate specific prologue for interrupt handlers. */
1625 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1626 current_function_interrupt = lookup_attribute ("interrupt",
1627 func_attr) != NULL_TREE;
1628 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1630 /* Get the scratch register to build the frame and push registers.
1631 If the first argument is a 32-bit quantity, the D+X registers
1632 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1633 For 68HC12, this scratch register is not used. */
1634 if (current_function_args_info.nregs == 2)
1635 scratch = iy_reg;
1636 else
1637 scratch = ix_reg;
1639 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1640 Other soft registers in page0 need not to be saved because they
1641 will be restored by C functions. For a trap handler, we don't
1642 need to preserve these registers because this is a synchronous call. */
1643 if (current_function_interrupt)
1645 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1646 emit_move_after_reload (stack_push_word,
1647 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1648 emit_move_after_reload (stack_push_word,
1649 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1650 scratch);
1653 /* Save current stack frame. */
1654 if (frame_pointer_needed)
1655 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1657 /* Allocate local variables. */
1658 if (TARGET_M6812 && (size > 4 || size == 3))
1660 emit_insn (gen_addhi3 (stack_pointer_rtx,
1661 stack_pointer_rtx, GEN_INT (-size)));
1663 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1665 rtx insn;
1667 insn = gen_rtx_PARALLEL
1668 (VOIDmode,
1669 gen_rtvec (2,
1670 gen_rtx_SET (VOIDmode,
1671 stack_pointer_rtx,
1672 gen_rtx_PLUS (HImode,
1673 stack_pointer_rtx,
1674 GEN_INT (-size))),
1675 gen_rtx_CLOBBER (VOIDmode, scratch)));
1676 emit_insn (insn);
1678 else
1680 int i;
1682 /* Allocate by pushing scratch values. */
1683 for (i = 2; i <= size; i += 2)
1684 emit_move_after_reload (stack_push_word, ix_reg, 0);
1686 if (size & 1)
1687 emit_insn (gen_addhi3 (stack_pointer_rtx,
1688 stack_pointer_rtx, GEN_INT (-1)));
1691 /* Create the frame pointer. */
1692 if (frame_pointer_needed)
1693 emit_move_after_reload (hard_frame_pointer_rtx,
1694 stack_pointer_rtx, scratch);
1696 /* Push any 2 byte pseudo hard registers that we need to save. */
1697 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1699 if (regs_ever_live[regno] && !call_used_regs[regno])
1701 emit_move_after_reload (stack_push_word,
1702 gen_rtx (REG, HImode, regno), scratch);
1707 void
1708 expand_epilogue ()
1710 int size;
1711 register int regno;
1712 int return_size;
1713 rtx scratch;
1715 if (reload_completed != 1)
1716 abort ();
1718 size = get_frame_size ();
1720 /* If we are returning a value in two registers, we have to preserve the
1721 X register and use the Y register to restore the stack and the saved
1722 registers. Otherwise, use X because it's faster (and smaller). */
1723 if (current_function_return_rtx == 0)
1724 return_size = 0;
1725 else if (GET_CODE (current_function_return_rtx) == MEM)
1726 return_size = HARD_REG_SIZE;
1727 else
1728 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1730 if (return_size > HARD_REG_SIZE)
1731 scratch = iy_reg;
1732 else
1733 scratch = ix_reg;
1735 /* Pop any 2 byte pseudo hard registers that we saved. */
1736 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1738 if (regs_ever_live[regno] && !call_used_regs[regno])
1740 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1741 stack_pop_word, scratch);
1745 /* de-allocate auto variables */
1746 if (TARGET_M6812 && (size > 4 || size == 3))
1748 emit_insn (gen_addhi3 (stack_pointer_rtx,
1749 stack_pointer_rtx, GEN_INT (size)));
1751 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1753 rtx insn;
1755 insn = gen_rtx_PARALLEL
1756 (VOIDmode,
1757 gen_rtvec (2,
1758 gen_rtx_SET (VOIDmode,
1759 stack_pointer_rtx,
1760 gen_rtx_PLUS (HImode,
1761 stack_pointer_rtx,
1762 GEN_INT (size))),
1763 gen_rtx_CLOBBER (VOIDmode, scratch)));
1764 emit_insn (insn);
1766 else
1768 int i;
1770 for (i = 2; i <= size; i += 2)
1771 emit_move_after_reload (scratch, stack_pop_word, scratch);
1772 if (size & 1)
1773 emit_insn (gen_addhi3 (stack_pointer_rtx,
1774 stack_pointer_rtx, GEN_INT (1)));
1777 /* Restore previous frame pointer. */
1778 if (frame_pointer_needed)
1779 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1781 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1782 if (current_function_interrupt)
1784 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1785 stack_pop_word, scratch);
1786 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1787 stack_pop_word, scratch);
1788 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1791 /* If the trap handler returns some value, copy the value
1792 in D, X onto the stack so that the rti will pop the return value
1793 correctly. */
1794 else if (current_function_trap && return_size != 0)
1796 rtx addr_reg = stack_pointer_rtx;
1798 if (!TARGET_M6812)
1800 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1801 addr_reg = scratch;
1803 emit_move_after_reload (gen_rtx (MEM, HImode,
1804 gen_rtx (PLUS, HImode, addr_reg,
1805 GEN_INT (1))), d_reg, 0);
1806 if (return_size > HARD_REG_SIZE)
1807 emit_move_after_reload (gen_rtx (MEM, HImode,
1808 gen_rtx (PLUS, HImode, addr_reg,
1809 GEN_INT (3))), ix_reg, 0);
1812 emit_jump_insn (gen_return ());
1816 /* Low and High part extraction for 68HC11. These routines are
1817 similar to gen_lowpart and gen_highpart but they have been
1818 fixed to work for constants and 68HC11 specific registers. */
1821 m68hc11_gen_lowpart (mode, x)
1822 enum machine_mode mode;
1823 rtx x;
1825 /* We assume that the low part of an auto-inc mode is the same with
1826 the mode changed and that the caller split the larger mode in the
1827 correct order. */
1828 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1830 return gen_rtx (MEM, mode, XEXP (x, 0));
1833 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1834 floating-point constant. A CONST_DOUBLE is used whenever the
1835 constant requires more than one word in order to be adequately
1836 represented. */
1837 if (GET_CODE (x) == CONST_DOUBLE)
1839 long l[2];
1841 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1843 REAL_VALUE_TYPE r;
1845 if (GET_MODE (x) == SFmode)
1847 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1848 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1850 else
1852 rtx first, second;
1854 split_double (x, &first, &second);
1855 return second;
1857 if (mode == SImode)
1858 return GEN_INT (l[0]);
1860 return gen_int_mode (l[0], HImode);
1862 else
1864 l[0] = CONST_DOUBLE_LOW (x);
1866 if (mode == SImode)
1867 return GEN_INT (l[0]);
1868 else if (mode == HImode && GET_MODE (x) == SFmode)
1869 return gen_int_mode (l[0], HImode);
1870 else
1871 abort ();
1874 if (mode == QImode && D_REG_P (x))
1875 return gen_rtx (REG, mode, HARD_B_REGNUM);
1877 /* gen_lowpart crashes when it is called with a SUBREG. */
1878 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1880 if (mode == SImode)
1881 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1882 else if (mode == HImode)
1883 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1884 else
1885 abort ();
1887 x = gen_lowpart (mode, x);
1889 /* Return a different rtx to avoid to share it in several insns
1890 (when used by a split pattern). Sharing addresses within
1891 a MEM breaks the Z register replacement (and reloading). */
1892 if (GET_CODE (x) == MEM)
1893 x = copy_rtx (x);
1894 return x;
1898 m68hc11_gen_highpart (mode, x)
1899 enum machine_mode mode;
1900 rtx x;
1902 /* We assume that the high part of an auto-inc mode is the same with
1903 the mode changed and that the caller split the larger mode in the
1904 correct order. */
1905 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1907 return gen_rtx (MEM, mode, XEXP (x, 0));
1910 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1911 floating-point constant. A CONST_DOUBLE is used whenever the
1912 constant requires more than one word in order to be adequately
1913 represented. */
1914 if (GET_CODE (x) == CONST_DOUBLE)
1916 long l[2];
1918 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1920 REAL_VALUE_TYPE r;
1922 if (GET_MODE (x) == SFmode)
1924 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1925 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1927 else
1929 rtx first, second;
1931 split_double (x, &first, &second);
1932 return first;
1934 if (mode == SImode)
1935 return GEN_INT (l[1]);
1937 return gen_int_mode ((l[1] >> 16), HImode);
1939 else
1941 l[1] = CONST_DOUBLE_HIGH (x);
1944 if (mode == SImode)
1945 return GEN_INT (l[1]);
1946 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1947 return gen_int_mode ((l[0] >> 16), HImode);
1948 else
1949 abort ();
1951 if (GET_CODE (x) == CONST_INT)
1953 HOST_WIDE_INT val = INTVAL (x);
1955 if (mode == QImode)
1957 return gen_int_mode (val >> 8, QImode);
1959 else if (mode == HImode)
1961 return gen_int_mode (val >> 16, HImode);
1964 if (mode == QImode && D_REG_P (x))
1965 return gen_rtx (REG, mode, HARD_A_REGNUM);
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))
1973 int pos;
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]));
1983 /* gen_highpart crashes when it is called with a SUBREG. */
1984 if (GET_CODE (x) == SUBREG)
1986 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1988 if (GET_CODE (x) == REG)
1990 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1991 return gen_rtx (REG, mode, REGNO (x));
1992 else
1993 return gen_rtx_SUBREG (mode, x, 0);
1996 if (GET_CODE (x) == MEM)
1998 x = change_address (x, mode, 0);
2000 /* Return a different rtx to avoid to share it in several insns
2001 (when used by a split pattern). Sharing addresses within
2002 a MEM breaks the Z register replacement (and reloading). */
2003 if (GET_CODE (x) == MEM)
2004 x = copy_rtx (x);
2005 return x;
2007 abort ();
2011 /* Obscure register manipulation. */
2013 /* Finds backward in the instructions to see if register 'reg' is
2014 dead. This is used when generating code to see if we can use 'reg'
2015 as a scratch register. This allows us to choose a better generation
2016 of code when we know that some register dies or can be clobbered. */
2019 dead_register_here (x, reg)
2020 rtx x;
2021 rtx reg;
2023 rtx x_reg;
2024 rtx p;
2026 if (D_REG_P (reg))
2027 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
2028 else
2029 x_reg = 0;
2031 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2032 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
2034 rtx body;
2036 body = PATTERN (p);
2038 if (GET_CODE (body) == CALL_INSN)
2039 break;
2040 if (GET_CODE (body) == JUMP_INSN)
2041 break;
2043 if (GET_CODE (body) == SET)
2045 rtx dst = XEXP (body, 0);
2047 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2048 break;
2049 if (x_reg && rtx_equal_p (dst, x_reg))
2050 break;
2052 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2053 return 1;
2055 else if (reg_mentioned_p (reg, p)
2056 || (x_reg && reg_mentioned_p (x_reg, p)))
2057 break;
2060 /* Scan forward to see if the register is set in some insns and never
2061 used since then. */
2062 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2064 rtx body;
2066 if (GET_CODE (p) == CODE_LABEL
2067 || GET_CODE (p) == JUMP_INSN
2068 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2069 break;
2071 if (GET_CODE (p) != INSN)
2072 continue;
2074 body = PATTERN (p);
2075 if (GET_CODE (body) == SET)
2077 rtx src = XEXP (body, 1);
2078 rtx dst = XEXP (body, 0);
2080 if (GET_CODE (dst) == REG
2081 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2082 return 1;
2085 /* Register is used (may be in source or in dest). */
2086 if (reg_mentioned_p (reg, p)
2087 || (x_reg != 0 && GET_MODE (p) == SImode
2088 && reg_mentioned_p (x_reg, p)))
2089 break;
2091 return p == 0 ? 1 : 0;
2095 /* Code generation operations called from machine description file. */
2097 /* Print the name of register 'regno' in the assembly file. */
2098 static void
2099 asm_print_register (file, regno)
2100 FILE *file;
2101 int regno;
2103 const char *name = reg_names[regno];
2105 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2106 name++;
2108 fprintf (file, "%s", name);
2111 /* A C compound statement to output to stdio stream STREAM the
2112 assembler syntax for an instruction operand X. X is an RTL
2113 expression.
2115 CODE is a value that can be used to specify one of several ways
2116 of printing the operand. It is used when identical operands
2117 must be printed differently depending on the context. CODE
2118 comes from the `%' specification that was used to request
2119 printing of the operand. If the specification was just `%DIGIT'
2120 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2121 is the ASCII code for LTR.
2123 If X is a register, this macro should print the register's name.
2124 The names can be found in an array `reg_names' whose type is
2125 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2127 When the machine description has a specification `%PUNCT' (a `%'
2128 followed by a punctuation character), this macro is called with
2129 a null pointer for X and the punctuation character for CODE.
2131 The M68HC11 specific codes are:
2133 'b' for the low part of the operand.
2134 'h' for the high part of the operand
2135 The 'b' or 'h' modifiers have no effect if the operand has
2136 the QImode and is not a S_REG_P (soft register). If the
2137 operand is a hard register, these two modifiers have no effect.
2138 't' generate the temporary scratch register. The operand is
2139 ignored.
2140 'T' generate the low-part temporary scratch register. The operand is
2141 ignored. */
2143 void
2144 print_operand (file, op, letter)
2145 FILE *file;
2146 rtx op;
2147 int letter;
2149 if (letter == 't')
2151 asm_print_register (file, SOFT_TMP_REGNUM);
2152 return;
2154 else if (letter == 'T')
2156 asm_print_register (file, SOFT_TMP_REGNUM);
2157 fprintf (file, "+1");
2158 return;
2160 else if (letter == '#')
2162 asm_fprintf (file, "%0I");
2165 if (GET_CODE (op) == REG)
2167 if (letter == 'b' && S_REG_P (op))
2169 asm_print_register (file, REGNO (op));
2170 fprintf (file, "+1");
2172 else
2174 asm_print_register (file, REGNO (op));
2176 return;
2179 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2181 if (letter == 'b')
2182 asm_fprintf (file, "%0I%%lo(");
2183 else
2184 asm_fprintf (file, "%0I%%hi(");
2186 output_addr_const (file, op);
2187 fprintf (file, ")");
2188 return;
2191 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2192 are specified. If we already have a QImode, there is nothing to do. */
2193 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2195 if (letter == 'b')
2197 op = m68hc11_gen_lowpart (QImode, op);
2199 else if (letter == 'h')
2201 op = m68hc11_gen_highpart (QImode, op);
2205 if (GET_CODE (op) == MEM)
2207 rtx base = XEXP (op, 0);
2208 switch (GET_CODE (base))
2210 case PRE_DEC:
2211 if (TARGET_M6812)
2213 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2214 asm_print_register (file, REGNO (XEXP (base, 0)));
2216 else
2217 abort ();
2218 break;
2220 case POST_DEC:
2221 if (TARGET_M6812)
2223 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2224 asm_print_register (file, REGNO (XEXP (base, 0)));
2225 fprintf (file, "-");
2227 else
2228 abort ();
2229 break;
2231 case POST_INC:
2232 if (TARGET_M6812)
2234 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2235 asm_print_register (file, REGNO (XEXP (base, 0)));
2236 fprintf (file, "+");
2238 else
2239 abort ();
2240 break;
2242 case PRE_INC:
2243 if (TARGET_M6812)
2245 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2246 asm_print_register (file, REGNO (XEXP (base, 0)));
2248 else
2249 abort ();
2250 break;
2252 default:
2253 output_address (base);
2254 break;
2257 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2259 REAL_VALUE_TYPE r;
2260 long l;
2262 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2263 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2264 asm_fprintf (file, "%I0x%lx", l);
2266 else if (GET_CODE (op) == CONST_DOUBLE
2267 && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode))
2269 char dstr[30];
2271 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2272 sizeof (dstr), 0, 1);
2273 asm_fprintf (file, "%I0r%s", dstr);
2275 else
2277 int need_parenthesize = 0;
2279 if (letter != 'i')
2280 asm_fprintf (file, "%0I");
2281 else
2282 need_parenthesize = must_parenthesize (op);
2284 if (need_parenthesize)
2285 fprintf (file, "(");
2287 output_addr_const (file, op);
2288 if (need_parenthesize)
2289 fprintf (file, ")");
2293 /* Returns true if the operand 'op' must be printed with parenthesis
2294 arround it. This must be done only if there is a symbol whose name
2295 is a processor register. */
2296 static int
2297 must_parenthesize (op)
2298 rtx op;
2300 const char *name;
2302 switch (GET_CODE (op))
2304 case SYMBOL_REF:
2305 name = XSTR (op, 0);
2306 /* Avoid a conflict between symbol name and a possible
2307 register. */
2308 return (strcasecmp (name, "a") == 0
2309 || strcasecmp (name, "b") == 0
2310 || strcasecmp (name, "d") == 0
2311 || strcasecmp (name, "x") == 0
2312 || strcasecmp (name, "y") == 0
2313 || strcasecmp (name, "ix") == 0
2314 || strcasecmp (name, "iy") == 0
2315 || strcasecmp (name, "pc") == 0
2316 || strcasecmp (name, "sp") == 0
2317 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2319 case PLUS:
2320 case MINUS:
2321 return must_parenthesize (XEXP (op, 0))
2322 || must_parenthesize (XEXP (op, 1));
2324 case MEM:
2325 case CONST:
2326 case ZERO_EXTEND:
2327 case SIGN_EXTEND:
2328 return must_parenthesize (XEXP (op, 0));
2330 case CONST_DOUBLE:
2331 case CONST_INT:
2332 case LABEL_REF:
2333 case CODE_LABEL:
2334 default:
2335 return 0;
2339 /* A C compound statement to output to stdio stream STREAM the
2340 assembler syntax for an instruction operand that is a memory
2341 reference whose address is ADDR. ADDR is an RTL expression. */
2343 void
2344 print_operand_address (file, addr)
2345 FILE *file;
2346 rtx addr;
2348 rtx base;
2349 rtx offset;
2350 int need_parenthesis = 0;
2352 switch (GET_CODE (addr))
2354 case REG:
2355 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2356 abort ();
2358 fprintf (file, "0,");
2359 asm_print_register (file, REGNO (addr));
2360 break;
2362 case MEM:
2363 base = XEXP (addr, 0);
2364 switch (GET_CODE (base))
2366 case PRE_DEC:
2367 if (TARGET_M6812)
2369 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2370 asm_print_register (file, REGNO (XEXP (base, 0)));
2372 else
2373 abort ();
2374 break;
2376 case POST_DEC:
2377 if (TARGET_M6812)
2379 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2380 asm_print_register (file, REGNO (XEXP (base, 0)));
2381 fprintf (file, "-");
2383 else
2384 abort ();
2385 break;
2387 case POST_INC:
2388 if (TARGET_M6812)
2390 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2391 asm_print_register (file, REGNO (XEXP (base, 0)));
2392 fprintf (file, "+");
2394 else
2395 abort ();
2396 break;
2398 case PRE_INC:
2399 if (TARGET_M6812)
2401 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2402 asm_print_register (file, REGNO (XEXP (base, 0)));
2404 else
2405 abort ();
2406 break;
2408 default:
2409 need_parenthesis = must_parenthesize (base);
2410 if (need_parenthesis)
2411 fprintf (file, "(");
2413 output_addr_const (file, base);
2414 if (need_parenthesis)
2415 fprintf (file, ")");
2416 break;
2418 break;
2420 case PLUS:
2421 base = XEXP (addr, 0);
2422 offset = XEXP (addr, 1);
2423 if (!G_REG_P (base) && G_REG_P (offset))
2425 base = XEXP (addr, 1);
2426 offset = XEXP (addr, 0);
2428 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2430 need_parenthesis = must_parenthesize (addr);
2432 if (need_parenthesis)
2433 fprintf (file, "(");
2435 output_addr_const (file, base);
2436 fprintf (file, "+");
2437 output_addr_const (file, offset);
2438 if (need_parenthesis)
2439 fprintf (file, ")");
2441 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2443 if (REG_P (offset))
2445 if (TARGET_M6812)
2447 asm_print_register (file, REGNO (offset));
2448 fprintf (file, ",");
2449 asm_print_register (file, REGNO (base));
2451 else
2452 abort ();
2454 else
2456 need_parenthesis = must_parenthesize (offset);
2457 if (need_parenthesis)
2458 fprintf (file, "(");
2460 output_addr_const (file, offset);
2461 if (need_parenthesis)
2462 fprintf (file, ")");
2463 fprintf (file, ",");
2464 asm_print_register (file, REGNO (base));
2467 else
2469 abort ();
2471 break;
2473 default:
2474 if (GET_CODE (addr) == CONST_INT
2475 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2477 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2479 else
2481 need_parenthesis = must_parenthesize (addr);
2482 if (need_parenthesis)
2483 fprintf (file, "(");
2485 output_addr_const (file, addr);
2486 if (need_parenthesis)
2487 fprintf (file, ")");
2489 break;
2494 /* Splitting of some instructions. */
2496 static rtx
2497 m68hc11_expand_compare (code, op0, op1)
2498 enum rtx_code code;
2499 rtx op0, op1;
2501 rtx ret = 0;
2503 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2504 abort ();
2505 else
2507 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2508 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2509 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2512 return ret;
2516 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2517 enum rtx_code code;
2518 rtx op0, op1, label;
2520 rtx tmp;
2522 switch (GET_MODE (op0))
2524 case QImode:
2525 case HImode:
2526 tmp = m68hc11_expand_compare (code, op0, op1);
2527 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2528 gen_rtx_LABEL_REF (VOIDmode, label),
2529 pc_rtx);
2530 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2531 return 0;
2532 #if 0
2534 /* SCz: from i386.c */
2535 case SFmode:
2536 case DFmode:
2537 /* Don't expand the comparison early, so that we get better code
2538 when jump or whoever decides to reverse the comparison. */
2540 rtvec vec;
2541 int use_fcomi;
2543 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2544 &m68hc11_compare_op1);
2546 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2547 m68hc11_compare_op0, m68hc11_compare_op1);
2548 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2549 gen_rtx_LABEL_REF (VOIDmode, label),
2550 pc_rtx);
2551 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2553 use_fcomi = ix86_use_fcomi_compare (code);
2554 vec = rtvec_alloc (3 + !use_fcomi);
2555 RTVEC_ELT (vec, 0) = tmp;
2556 RTVEC_ELT (vec, 1)
2557 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2558 RTVEC_ELT (vec, 2)
2559 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2560 if (!use_fcomi)
2561 RTVEC_ELT (vec, 3)
2562 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2564 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2565 return;
2567 #endif
2569 case SImode:
2570 /* Expand SImode branch into multiple compare+branch. */
2572 rtx lo[2], hi[2], label2;
2573 enum rtx_code code1, code2, code3;
2575 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2577 tmp = op0;
2578 op0 = op1;
2579 op1 = tmp;
2580 code = swap_condition (code);
2582 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2583 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2584 hi[0] = m68hc11_gen_highpart (HImode, op0);
2585 hi[1] = m68hc11_gen_highpart (HImode, op1);
2587 /* Otherwise, if we are doing less-than, op1 is a constant and the
2588 low word is zero, then we can just examine the high word. */
2590 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2591 && (code == LT || code == LTU))
2593 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2594 label);
2597 /* Otherwise, we need two or three jumps. */
2599 label2 = gen_label_rtx ();
2601 code1 = code;
2602 code2 = swap_condition (code);
2603 code3 = unsigned_condition (code);
2605 switch (code)
2607 case LT:
2608 case GT:
2609 case LTU:
2610 case GTU:
2611 break;
2613 case LE:
2614 code1 = LT;
2615 code2 = GT;
2616 break;
2617 case GE:
2618 code1 = GT;
2619 code2 = LT;
2620 break;
2621 case LEU:
2622 code1 = LTU;
2623 code2 = GTU;
2624 break;
2625 case GEU:
2626 code1 = GTU;
2627 code2 = LTU;
2628 break;
2630 case EQ:
2631 code1 = NIL;
2632 code2 = NE;
2633 break;
2634 case NE:
2635 code2 = NIL;
2636 break;
2638 default:
2639 abort ();
2643 * a < b =>
2644 * if (hi(a) < hi(b)) goto true;
2645 * if (hi(a) > hi(b)) goto false;
2646 * if (lo(a) < lo(b)) goto true;
2647 * false:
2649 if (code1 != NIL)
2650 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2651 if (code2 != NIL)
2652 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2654 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2656 if (code2 != NIL)
2657 emit_label (label2);
2658 return 0;
2661 default:
2662 abort ();
2664 return 0;
2667 /* Return the increment/decrement mode of a MEM if it is such.
2668 Return CONST if it is anything else. */
2669 static int
2670 autoinc_mode (x)
2671 rtx x;
2673 if (GET_CODE (x) != MEM)
2674 return CONST;
2676 x = XEXP (x, 0);
2677 if (GET_CODE (x) == PRE_INC
2678 || GET_CODE (x) == PRE_DEC
2679 || GET_CODE (x) == POST_INC
2680 || GET_CODE (x) == POST_DEC)
2681 return GET_CODE (x);
2683 return CONST;
2686 static int
2687 m68hc11_make_autoinc_notes (x, data)
2688 rtx *x;
2689 void *data;
2691 rtx insn;
2693 switch (GET_CODE (*x))
2695 case PRE_DEC:
2696 case PRE_INC:
2697 case POST_DEC:
2698 case POST_INC:
2699 insn = (rtx) data;
2700 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2701 REG_NOTES (insn));
2702 return -1;
2704 default:
2705 return 0;
2709 /* Split a DI, SI or HI move into several smaller move operations.
2710 The scratch register 'scratch' is used as a temporary to load
2711 store intermediate values. It must be a hard register. */
2712 void
2713 m68hc11_split_move (to, from, scratch)
2714 rtx to, from, scratch;
2716 rtx low_to, low_from;
2717 rtx high_to, high_from;
2718 rtx insn;
2719 enum machine_mode mode;
2720 int offset = 0;
2721 int autoinc_from = autoinc_mode (from);
2722 int autoinc_to = autoinc_mode (to);
2724 mode = GET_MODE (to);
2726 /* If the TO and FROM contain autoinc modes that are not compatible
2727 together (one pop and the other a push), we must change one to
2728 an offsetable operand and generate an appropriate add at the end. */
2729 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2731 rtx reg;
2732 int code;
2734 /* The source uses an autoinc mode which is not compatible with
2735 a split (this would result in a word swap). */
2736 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2738 code = GET_CODE (XEXP (from, 0));
2739 reg = XEXP (XEXP (from, 0), 0);
2740 offset = GET_MODE_SIZE (GET_MODE (from));
2741 if (code == POST_DEC)
2742 offset = -offset;
2744 if (code == PRE_INC)
2745 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2747 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2748 if (code == POST_DEC)
2749 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2750 return;
2753 /* Likewise for destination. */
2754 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2756 code = GET_CODE (XEXP (to, 0));
2757 reg = XEXP (XEXP (to, 0), 0);
2758 offset = GET_MODE_SIZE (GET_MODE (to));
2759 if (code == POST_DEC)
2760 offset = -offset;
2762 if (code == PRE_INC)
2763 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2765 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2766 if (code == POST_DEC)
2767 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2768 return;
2771 /* The source and destination auto increment modes must be compatible
2772 with each other: same direction. */
2773 if ((autoinc_to != autoinc_from
2774 && autoinc_to != CONST && autoinc_from != CONST)
2775 /* The destination address register must not be used within
2776 the source operand because the source address would change
2777 while doing the copy. */
2778 || (autoinc_to != CONST
2779 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2780 && !IS_STACK_PUSH (to)))
2782 /* Must change the destination. */
2783 code = GET_CODE (XEXP (to, 0));
2784 reg = XEXP (XEXP (to, 0), 0);
2785 offset = GET_MODE_SIZE (GET_MODE (to));
2786 if (code == PRE_DEC || code == POST_DEC)
2787 offset = -offset;
2789 if (code == PRE_DEC || code == PRE_INC)
2790 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2791 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2792 if (code == POST_DEC || code == POST_INC)
2793 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2795 return;
2798 /* Likewise, the source address register must not be used within
2799 the destination operand. */
2800 if (autoinc_from != CONST
2801 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2802 && !IS_STACK_PUSH (to))
2804 /* Must change the source. */
2805 code = GET_CODE (XEXP (from, 0));
2806 reg = XEXP (XEXP (from, 0), 0);
2807 offset = GET_MODE_SIZE (GET_MODE (from));
2808 if (code == PRE_DEC || code == POST_DEC)
2809 offset = -offset;
2811 if (code == PRE_DEC || code == PRE_INC)
2812 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2813 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2814 if (code == POST_DEC || code == POST_INC)
2815 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2817 return;
2821 if (GET_MODE_SIZE (mode) == 8)
2822 mode = SImode;
2823 else if (GET_MODE_SIZE (mode) == 4)
2824 mode = HImode;
2825 else
2826 mode = QImode;
2828 if (TARGET_M6812
2829 && IS_STACK_PUSH (to)
2830 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2832 if (mode == SImode)
2834 offset = 4;
2836 else if (mode == HImode)
2838 offset = 2;
2840 else
2841 offset = 0;
2844 low_to = m68hc11_gen_lowpart (mode, to);
2845 high_to = m68hc11_gen_highpart (mode, to);
2847 low_from = m68hc11_gen_lowpart (mode, from);
2848 if (mode == SImode && GET_CODE (from) == CONST_INT)
2850 if (INTVAL (from) >= 0)
2851 high_from = const0_rtx;
2852 else
2853 high_from = constm1_rtx;
2855 else
2856 high_from = m68hc11_gen_highpart (mode, from);
2858 if (offset)
2860 high_from = adjust_address (high_from, mode, offset);
2861 low_from = high_from;
2864 /* When copying with a POST_INC mode, we must copy the
2865 high part and then the low part to guarantee a correct
2866 32/64-bit copy. */
2867 if (TARGET_M6812
2868 && GET_MODE_SIZE (mode) >= 2
2869 && autoinc_from != autoinc_to
2870 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2872 rtx swap;
2874 swap = low_to;
2875 low_to = high_to;
2876 high_to = swap;
2878 swap = low_from;
2879 low_from = high_from;
2880 high_from = swap;
2882 if (mode == SImode)
2884 m68hc11_split_move (low_to, low_from, scratch);
2885 m68hc11_split_move (high_to, high_from, scratch);
2887 else if (H_REG_P (to) || H_REG_P (from)
2888 || (low_from == const0_rtx
2889 && high_from == const0_rtx
2890 && ! push_operand (to, GET_MODE (to))
2891 && ! H_REG_P (scratch))
2892 || (TARGET_M6812
2893 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2894 || m68hc11_small_indexed_indirect_p (from,
2895 GET_MODE (from)))
2896 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2897 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2899 insn = emit_move_insn (low_to, low_from);
2900 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2902 insn = emit_move_insn (high_to, high_from);
2903 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2905 else
2907 insn = emit_move_insn (scratch, low_from);
2908 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2909 insn = emit_move_insn (low_to, scratch);
2910 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2912 insn = emit_move_insn (scratch, high_from);
2913 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2914 insn = emit_move_insn (high_to, scratch);
2915 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2919 static rtx
2920 simplify_logical (mode, code, operand, result)
2921 enum machine_mode mode;
2922 int code;
2923 rtx operand;
2924 rtx *result;
2926 int val;
2927 int mask;
2929 *result = 0;
2930 if (GET_CODE (operand) != CONST_INT)
2931 return operand;
2933 if (mode == HImode)
2934 mask = 0x0ffff;
2935 else
2936 mask = 0x0ff;
2938 val = INTVAL (operand);
2939 switch (code)
2941 case IOR:
2942 if ((val & mask) == 0)
2943 return 0;
2944 if ((val & mask) == mask)
2945 *result = constm1_rtx;
2946 break;
2948 case AND:
2949 if ((val & mask) == 0)
2950 *result = const0_rtx;
2951 if ((val & mask) == mask)
2952 return 0;
2953 break;
2955 case XOR:
2956 if ((val & mask) == 0)
2957 return 0;
2958 break;
2960 return operand;
2963 static void
2964 m68hc11_emit_logical (mode, code, operands)
2965 enum machine_mode mode;
2966 int code;
2967 rtx *operands;
2969 rtx result;
2970 int need_copy;
2972 need_copy = (rtx_equal_p (operands[0], operands[1])
2973 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2975 operands[1] = simplify_logical (mode, code, operands[1], &result);
2976 operands[2] = simplify_logical (mode, code, operands[2], &result);
2978 if (result && GET_CODE (result) == CONST_INT)
2980 if (!H_REG_P (operands[0]) && operands[3]
2981 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2983 emit_move_insn (operands[3], result);
2984 emit_move_insn (operands[0], operands[3]);
2986 else
2988 emit_move_insn (operands[0], result);
2991 else if (operands[1] != 0 && operands[2] != 0)
2993 rtx insn;
2995 if (!H_REG_P (operands[0]) && operands[3])
2997 emit_move_insn (operands[3], operands[1]);
2998 emit_insn (gen_rtx (SET, mode,
2999 operands[3],
3000 gen_rtx (code, mode,
3001 operands[3], operands[2])));
3002 insn = emit_move_insn (operands[0], operands[3]);
3004 else
3006 insn = emit_insn (gen_rtx (SET, mode,
3007 operands[0],
3008 gen_rtx (code, mode,
3009 operands[0], operands[2])));
3013 /* The logical operation is similar to a copy. */
3014 else if (need_copy)
3016 rtx src;
3018 if (GET_CODE (operands[1]) == CONST_INT)
3019 src = operands[2];
3020 else
3021 src = operands[1];
3023 if (!H_REG_P (operands[0]) && !H_REG_P (src))
3025 emit_move_insn (operands[3], src);
3026 emit_move_insn (operands[0], operands[3]);
3028 else
3030 emit_move_insn (operands[0], src);
3035 void
3036 m68hc11_split_logical (mode, code, operands)
3037 enum machine_mode mode;
3038 int code;
3039 rtx *operands;
3041 rtx low[4];
3042 rtx high[4];
3044 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3045 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3046 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3048 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3050 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3052 if (INTVAL (operands[1]) >= 0)
3053 high[1] = const0_rtx;
3054 else
3055 high[1] = constm1_rtx;
3057 else
3058 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3060 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3062 if (INTVAL (operands[2]) >= 0)
3063 high[2] = const0_rtx;
3064 else
3065 high[2] = constm1_rtx;
3067 else
3068 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3070 low[3] = operands[3];
3071 high[3] = operands[3];
3072 if (mode == SImode)
3074 m68hc11_split_logical (HImode, code, low);
3075 m68hc11_split_logical (HImode, code, high);
3076 return;
3079 m68hc11_emit_logical (mode, code, low);
3080 m68hc11_emit_logical (mode, code, high);
3084 /* Code generation. */
3086 void
3087 m68hc11_output_swap (insn, operands)
3088 rtx insn ATTRIBUTE_UNUSED;
3089 rtx operands[];
3091 /* We have to be careful with the cc_status. An address register swap
3092 is generated for some comparison. The comparison is made with D
3093 but the branch really uses the address register. See the split
3094 pattern for compare. The xgdx/xgdy preserve the flags but after
3095 the exchange, the flags will reflect to the value of X and not D.
3096 Tell this by setting the cc_status according to the cc_prev_status. */
3097 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3099 if (cc_prev_status.value1 != 0
3100 && (D_REG_P (cc_prev_status.value1)
3101 || X_REG_P (cc_prev_status.value1)))
3103 cc_status = cc_prev_status;
3104 if (D_REG_P (cc_status.value1))
3105 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3106 HARD_X_REGNUM);
3107 else
3108 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3109 HARD_D_REGNUM);
3111 else
3112 CC_STATUS_INIT;
3114 output_asm_insn ("xgdx", operands);
3116 else
3118 if (cc_prev_status.value1 != 0
3119 && (D_REG_P (cc_prev_status.value1)
3120 || Y_REG_P (cc_prev_status.value1)))
3122 cc_status = cc_prev_status;
3123 if (D_REG_P (cc_status.value1))
3124 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3125 HARD_Y_REGNUM);
3126 else
3127 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3128 HARD_D_REGNUM);
3130 else
3131 CC_STATUS_INIT;
3133 output_asm_insn ("xgdy", operands);
3137 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3138 This is used to decide whether a move that set flags should be used
3139 instead. */
3141 next_insn_test_reg (insn, reg)
3142 rtx insn;
3143 rtx reg;
3145 rtx body;
3147 insn = next_nonnote_insn (insn);
3148 if (GET_CODE (insn) != INSN)
3149 return 0;
3151 body = PATTERN (insn);
3152 if (sets_cc0_p (body) != 1)
3153 return 0;
3155 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3156 return 0;
3158 return 1;
3161 /* Generate the code to move a 16-bit operand into another one. */
3163 void
3164 m68hc11_gen_movhi (insn, operands)
3165 rtx insn;
3166 rtx *operands;
3168 int reg;
3170 /* Move a register or memory to the same location.
3171 This is possible because such insn can appear
3172 in a non-optimizing mode. */
3173 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3175 cc_status = cc_prev_status;
3176 return;
3179 if (TARGET_M6812)
3181 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3183 cc_status = cc_prev_status;
3184 switch (REGNO (operands[1]))
3186 case HARD_X_REGNUM:
3187 case HARD_Y_REGNUM:
3188 case HARD_D_REGNUM:
3189 output_asm_insn ("psh%1", operands);
3190 break;
3191 case HARD_SP_REGNUM:
3192 output_asm_insn ("sts\t-2,sp", operands);
3193 break;
3194 default:
3195 abort ();
3197 return;
3199 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3201 cc_status = cc_prev_status;
3202 switch (REGNO (operands[0]))
3204 case HARD_X_REGNUM:
3205 case HARD_Y_REGNUM:
3206 case HARD_D_REGNUM:
3207 output_asm_insn ("pul%0", operands);
3208 break;
3209 default:
3210 abort ();
3212 return;
3214 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3216 m68hc11_notice_keep_cc (operands[0]);
3217 output_asm_insn ("tfr\t%1,%0", operands);
3219 else if (H_REG_P (operands[0]))
3221 if (SP_REG_P (operands[0]))
3222 output_asm_insn ("lds\t%1", operands);
3223 else
3224 output_asm_insn ("ld%0\t%1", operands);
3226 else if (H_REG_P (operands[1]))
3228 if (SP_REG_P (operands[1]))
3229 output_asm_insn ("sts\t%0", operands);
3230 else
3231 output_asm_insn ("st%1\t%0", operands);
3233 else
3235 rtx from = operands[1];
3236 rtx to = operands[0];
3238 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3239 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3240 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3241 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3243 rtx ops[3];
3245 if (operands[2])
3247 ops[0] = operands[2];
3248 ops[1] = from;
3249 ops[2] = 0;
3250 m68hc11_gen_movhi (insn, ops);
3251 ops[0] = to;
3252 ops[1] = operands[2];
3253 m68hc11_gen_movhi (insn, ops);
3255 else
3257 /* !!!! SCz wrong here. */
3258 fatal_insn ("move insn not handled", insn);
3261 else
3263 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3265 output_asm_insn ("clr\t%h0", operands);
3266 output_asm_insn ("clr\t%b0", operands);
3268 else
3270 m68hc11_notice_keep_cc (operands[0]);
3271 output_asm_insn ("movw\t%1,%0", operands);
3275 return;
3278 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3280 cc_status = cc_prev_status;
3281 switch (REGNO (operands[0]))
3283 case HARD_X_REGNUM:
3284 case HARD_Y_REGNUM:
3285 output_asm_insn ("pul%0", operands);
3286 break;
3287 case HARD_D_REGNUM:
3288 output_asm_insn ("pula", operands);
3289 output_asm_insn ("pulb", operands);
3290 break;
3291 default:
3292 abort ();
3294 return;
3296 /* Some moves to a hard register are special. Not all of them
3297 are really supported and we have to use a temporary
3298 location to provide them (either the stack of a temp var). */
3299 if (H_REG_P (operands[0]))
3301 switch (REGNO (operands[0]))
3303 case HARD_D_REGNUM:
3304 if (X_REG_P (operands[1]))
3306 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3308 m68hc11_output_swap (insn, operands);
3310 else if (next_insn_test_reg (insn, operands[0]))
3312 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3314 else
3316 m68hc11_notice_keep_cc (operands[0]);
3317 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3320 else if (Y_REG_P (operands[1]))
3322 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3324 m68hc11_output_swap (insn, operands);
3326 else
3328 /* %t means *ZTMP scratch register. */
3329 output_asm_insn ("sty\t%t1", operands);
3330 output_asm_insn ("ldd\t%t1", operands);
3333 else if (SP_REG_P (operands[1]))
3335 CC_STATUS_INIT;
3336 if (ix_reg == 0)
3337 create_regs_rtx ();
3338 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3339 output_asm_insn ("xgdx", operands);
3340 output_asm_insn ("tsx", operands);
3341 output_asm_insn ("xgdx", operands);
3343 else if (IS_STACK_POP (operands[1]))
3345 output_asm_insn ("pula\n\tpulb", operands);
3347 else if (GET_CODE (operands[1]) == CONST_INT
3348 && INTVAL (operands[1]) == 0)
3350 output_asm_insn ("clra\n\tclrb", operands);
3352 else
3354 output_asm_insn ("ldd\t%1", operands);
3356 break;
3358 case HARD_X_REGNUM:
3359 if (D_REG_P (operands[1]))
3361 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3363 m68hc11_output_swap (insn, operands);
3365 else if (next_insn_test_reg (insn, operands[0]))
3367 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3369 else
3371 m68hc11_notice_keep_cc (operands[0]);
3372 output_asm_insn ("pshb", operands);
3373 output_asm_insn ("psha", operands);
3374 output_asm_insn ("pulx", operands);
3377 else if (Y_REG_P (operands[1]))
3379 /* When both D and Y are dead, use the sequence xgdy, xgdx
3380 to move Y into X. The D and Y registers are modified. */
3381 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3382 && dead_register_here (insn, d_reg))
3384 output_asm_insn ("xgdy", operands);
3385 output_asm_insn ("xgdx", operands);
3386 CC_STATUS_INIT;
3388 else
3390 output_asm_insn ("sty\t%t1", operands);
3391 output_asm_insn ("ldx\t%t1", operands);
3394 else if (SP_REG_P (operands[1]))
3396 /* tsx, tsy preserve the flags */
3397 cc_status = cc_prev_status;
3398 output_asm_insn ("tsx", operands);
3400 else
3402 output_asm_insn ("ldx\t%1", operands);
3404 break;
3406 case HARD_Y_REGNUM:
3407 if (D_REG_P (operands[1]))
3409 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3411 m68hc11_output_swap (insn, operands);
3413 else
3415 output_asm_insn ("std\t%t1", operands);
3416 output_asm_insn ("ldy\t%t1", operands);
3419 else if (X_REG_P (operands[1]))
3421 /* When both D and X are dead, use the sequence xgdx, xgdy
3422 to move X into Y. The D and X registers are modified. */
3423 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3424 && dead_register_here (insn, d_reg))
3426 output_asm_insn ("xgdx", operands);
3427 output_asm_insn ("xgdy", operands);
3428 CC_STATUS_INIT;
3430 else
3432 output_asm_insn ("stx\t%t1", operands);
3433 output_asm_insn ("ldy\t%t1", operands);
3436 else if (SP_REG_P (operands[1]))
3438 /* tsx, tsy preserve the flags */
3439 cc_status = cc_prev_status;
3440 output_asm_insn ("tsy", operands);
3442 else
3444 output_asm_insn ("ldy\t%1", operands);
3446 break;
3448 case HARD_SP_REGNUM:
3449 if (D_REG_P (operands[1]))
3451 m68hc11_notice_keep_cc (operands[0]);
3452 output_asm_insn ("xgdx", operands);
3453 output_asm_insn ("txs", operands);
3454 output_asm_insn ("xgdx", operands);
3456 else if (X_REG_P (operands[1]))
3458 /* tys, txs preserve the flags */
3459 cc_status = cc_prev_status;
3460 output_asm_insn ("txs", operands);
3462 else if (Y_REG_P (operands[1]))
3464 /* tys, txs preserve the flags */
3465 cc_status = cc_prev_status;
3466 output_asm_insn ("tys", operands);
3468 else
3470 /* lds sets the flags but the des does not. */
3471 CC_STATUS_INIT;
3472 output_asm_insn ("lds\t%1", operands);
3473 output_asm_insn ("des", operands);
3475 break;
3477 default:
3478 fatal_insn ("invalid register in the move instruction", insn);
3479 break;
3481 return;
3483 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3484 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3486 output_asm_insn ("sts\t%0", operands);
3487 return;
3490 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3492 cc_status = cc_prev_status;
3493 switch (REGNO (operands[1]))
3495 case HARD_X_REGNUM:
3496 case HARD_Y_REGNUM:
3497 output_asm_insn ("psh%1", operands);
3498 break;
3499 case HARD_D_REGNUM:
3500 output_asm_insn ("pshb", operands);
3501 output_asm_insn ("psha", operands);
3502 break;
3503 default:
3504 abort ();
3506 return;
3509 /* Operand 1 must be a hard register. */
3510 if (!H_REG_P (operands[1]))
3512 fatal_insn ("invalid operand in the instruction", insn);
3515 reg = REGNO (operands[1]);
3516 switch (reg)
3518 case HARD_D_REGNUM:
3519 output_asm_insn ("std\t%0", operands);
3520 break;
3522 case HARD_X_REGNUM:
3523 output_asm_insn ("stx\t%0", operands);
3524 break;
3526 case HARD_Y_REGNUM:
3527 output_asm_insn ("sty\t%0", operands);
3528 break;
3530 case HARD_SP_REGNUM:
3531 if (ix_reg == 0)
3532 create_regs_rtx ();
3534 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3536 output_asm_insn ("pshx", operands);
3537 output_asm_insn ("tsx", operands);
3538 output_asm_insn ("inx", operands);
3539 output_asm_insn ("inx", operands);
3540 output_asm_insn ("stx\t%0", operands);
3541 output_asm_insn ("pulx", operands);
3544 else if (reg_mentioned_p (ix_reg, operands[0]))
3546 output_asm_insn ("sty\t%t0", operands);
3547 output_asm_insn ("tsy", operands);
3548 output_asm_insn ("sty\t%0", operands);
3549 output_asm_insn ("ldy\t%t0", operands);
3551 else
3553 output_asm_insn ("stx\t%t0", operands);
3554 output_asm_insn ("tsx", operands);
3555 output_asm_insn ("stx\t%0", operands);
3556 output_asm_insn ("ldx\t%t0", operands);
3558 CC_STATUS_INIT;
3559 break;
3561 default:
3562 fatal_insn ("invalid register in the move instruction", insn);
3563 break;
3567 void
3568 m68hc11_gen_movqi (insn, operands)
3569 rtx insn;
3570 rtx *operands;
3572 /* Move a register or memory to the same location.
3573 This is possible because such insn can appear
3574 in a non-optimizing mode. */
3575 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3577 cc_status = cc_prev_status;
3578 return;
3581 if (TARGET_M6812)
3584 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3586 m68hc11_notice_keep_cc (operands[0]);
3587 output_asm_insn ("tfr\t%1,%0", operands);
3589 else if (H_REG_P (operands[0]))
3591 if (Q_REG_P (operands[0]))
3592 output_asm_insn ("lda%0\t%b1", operands);
3593 else if (D_REG_P (operands[0]))
3594 output_asm_insn ("ldab\t%b1", operands);
3595 else
3596 goto m6811_move;
3598 else if (H_REG_P (operands[1]))
3600 if (Q_REG_P (operands[1]))
3601 output_asm_insn ("sta%1\t%b0", operands);
3602 else if (D_REG_P (operands[1]))
3603 output_asm_insn ("stab\t%b0", operands);
3604 else
3605 goto m6811_move;
3607 else
3609 rtx from = operands[1];
3610 rtx to = operands[0];
3612 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3613 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3614 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3615 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3617 rtx ops[3];
3619 if (operands[2])
3621 ops[0] = operands[2];
3622 ops[1] = from;
3623 ops[2] = 0;
3624 m68hc11_gen_movqi (insn, ops);
3625 ops[0] = to;
3626 ops[1] = operands[2];
3627 m68hc11_gen_movqi (insn, ops);
3629 else
3631 /* !!!! SCz wrong here. */
3632 fatal_insn ("move insn not handled", insn);
3635 else
3637 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3639 output_asm_insn ("clr\t%b0", operands);
3641 else
3643 m68hc11_notice_keep_cc (operands[0]);
3644 output_asm_insn ("movb\t%b1,%b0", operands);
3648 return;
3651 m6811_move:
3652 if (H_REG_P (operands[0]))
3654 switch (REGNO (operands[0]))
3656 case HARD_B_REGNUM:
3657 case HARD_D_REGNUM:
3658 if (X_REG_P (operands[1]))
3660 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3662 m68hc11_output_swap (insn, operands);
3664 else
3666 output_asm_insn ("stx\t%t1", operands);
3667 output_asm_insn ("ldab\t%T0", operands);
3670 else if (Y_REG_P (operands[1]))
3672 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3674 m68hc11_output_swap (insn, operands);
3676 else
3678 output_asm_insn ("sty\t%t1", operands);
3679 output_asm_insn ("ldab\t%T0", operands);
3682 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3683 && !DA_REG_P (operands[1]))
3685 output_asm_insn ("ldab\t%b1", operands);
3687 else if (DA_REG_P (operands[1]))
3689 output_asm_insn ("tab", operands);
3691 else
3693 cc_status = cc_prev_status;
3694 return;
3696 break;
3698 case HARD_A_REGNUM:
3699 if (X_REG_P (operands[1]))
3701 output_asm_insn ("stx\t%t1", operands);
3702 output_asm_insn ("ldaa\t%T0", operands);
3704 else if (Y_REG_P (operands[1]))
3706 output_asm_insn ("sty\t%t1", operands);
3707 output_asm_insn ("ldaa\t%T0", operands);
3709 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3710 && !DA_REG_P (operands[1]))
3712 output_asm_insn ("ldaa\t%b1", operands);
3714 else if (!DA_REG_P (operands[1]))
3716 output_asm_insn ("tba", operands);
3718 else
3720 cc_status = cc_prev_status;
3722 break;
3724 case HARD_X_REGNUM:
3725 if (D_REG_P (operands[1]))
3727 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3729 m68hc11_output_swap (insn, operands);
3731 else
3733 output_asm_insn ("stab\t%T1", operands);
3734 output_asm_insn ("ldx\t%t1", operands);
3736 CC_STATUS_INIT;
3738 else if (Y_REG_P (operands[1]))
3740 output_asm_insn ("sty\t%t0", operands);
3741 output_asm_insn ("ldx\t%t0", operands);
3743 else if (GET_CODE (operands[1]) == CONST_INT)
3745 output_asm_insn ("ldx\t%1", operands);
3747 else if (dead_register_here (insn, d_reg))
3749 output_asm_insn ("ldab\t%b1", operands);
3750 output_asm_insn ("xgdx", operands);
3752 else if (!reg_mentioned_p (operands[0], operands[1]))
3754 output_asm_insn ("xgdx", operands);
3755 output_asm_insn ("ldab\t%b1", operands);
3756 output_asm_insn ("xgdx", operands);
3758 else
3760 output_asm_insn ("pshb", operands);
3761 output_asm_insn ("ldab\t%b1", operands);
3762 output_asm_insn ("stab\t%T1", operands);
3763 output_asm_insn ("ldx\t%t1", operands);
3764 output_asm_insn ("pulb", operands);
3765 CC_STATUS_INIT;
3767 break;
3769 case HARD_Y_REGNUM:
3770 if (D_REG_P (operands[1]))
3772 output_asm_insn ("stab\t%T1", operands);
3773 output_asm_insn ("ldy\t%t1", operands);
3774 CC_STATUS_INIT;
3776 else if (X_REG_P (operands[1]))
3778 output_asm_insn ("stx\t%t1", operands);
3779 output_asm_insn ("ldy\t%t1", operands);
3780 CC_STATUS_INIT;
3782 else if (GET_CODE (operands[1]) == CONST_INT)
3784 output_asm_insn ("ldy\t%1", operands);
3786 else if (dead_register_here (insn, d_reg))
3788 output_asm_insn ("ldab\t%b1", operands);
3789 output_asm_insn ("xgdy", operands);
3791 else if (!reg_mentioned_p (operands[0], operands[1]))
3793 output_asm_insn ("xgdy", operands);
3794 output_asm_insn ("ldab\t%b1", operands);
3795 output_asm_insn ("xgdy", operands);
3797 else
3799 output_asm_insn ("pshb", operands);
3800 output_asm_insn ("ldab\t%b1", operands);
3801 output_asm_insn ("stab\t%T1", operands);
3802 output_asm_insn ("ldy\t%t1", operands);
3803 output_asm_insn ("pulb", operands);
3804 CC_STATUS_INIT;
3806 break;
3808 default:
3809 fatal_insn ("invalid register in the instruction", insn);
3810 break;
3813 else if (H_REG_P (operands[1]))
3815 switch (REGNO (operands[1]))
3817 case HARD_D_REGNUM:
3818 case HARD_B_REGNUM:
3819 output_asm_insn ("stab\t%b0", operands);
3820 break;
3822 case HARD_A_REGNUM:
3823 output_asm_insn ("staa\t%b0", operands);
3824 break;
3826 case HARD_X_REGNUM:
3827 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3828 break;
3830 case HARD_Y_REGNUM:
3831 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3832 break;
3834 default:
3835 fatal_insn ("invalid register in the move instruction", insn);
3836 break;
3838 return;
3840 else
3842 fatal_insn ("operand 1 must be a hard register", insn);
3846 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3847 The source and destination must be D or A and the shift must
3848 be a constant. */
3849 void
3850 m68hc11_gen_rotate (code, insn, operands)
3851 enum rtx_code code;
3852 rtx insn;
3853 rtx operands[];
3855 int val;
3857 if (GET_CODE (operands[2]) != CONST_INT
3858 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3859 fatal_insn ("invalid rotate insn", insn);
3861 val = INTVAL (operands[2]);
3862 if (code == ROTATERT)
3863 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3865 if (GET_MODE (operands[0]) != QImode)
3866 CC_STATUS_INIT;
3868 /* Rotate by 8-bits if the shift is within [5..11]. */
3869 if (val >= 5 && val <= 11)
3871 if (TARGET_M6812)
3872 output_asm_insn ("exg\ta,b", operands);
3873 else
3875 output_asm_insn ("psha", operands);
3876 output_asm_insn ("tba", operands);
3877 output_asm_insn ("pulb", operands);
3879 val -= 8;
3882 /* If the shift is big, invert the rotation. */
3883 else if (val >= 12)
3885 val = val - 16;
3888 if (val > 0)
3890 /* Set the carry to bit-15, but don't change D yet. */
3891 if (GET_MODE (operands[0]) != QImode)
3893 output_asm_insn ("asra", operands);
3894 output_asm_insn ("rola", operands);
3897 while (--val >= 0)
3899 /* Rotate B first to move the carry to bit-0. */
3900 if (D_REG_P (operands[0]))
3901 output_asm_insn ("rolb", operands);
3903 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3904 output_asm_insn ("rola", operands);
3907 else
3909 /* Set the carry to bit-8 of D. */
3910 if (val != 0 && GET_MODE (operands[0]) != QImode)
3912 output_asm_insn ("tap", operands);
3915 while (++val <= 0)
3917 /* Rotate B first to move the carry to bit-7. */
3918 if (D_REG_P (operands[0]))
3919 output_asm_insn ("rorb", operands);
3921 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3922 output_asm_insn ("rora", operands);
3929 /* Store in cc_status the expressions that the condition codes will
3930 describe after execution of an instruction whose pattern is EXP.
3931 Do not alter them if the instruction would not alter the cc's. */
3933 void
3934 m68hc11_notice_update_cc (exp, insn)
3935 rtx exp;
3936 rtx insn ATTRIBUTE_UNUSED;
3938 /* recognize SET insn's. */
3939 if (GET_CODE (exp) == SET)
3941 /* Jumps do not alter the cc's. */
3942 if (SET_DEST (exp) == pc_rtx)
3945 /* NOTE: most instructions don't affect the carry bit, but the
3946 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3947 the conditions.h header. */
3949 /* Function calls clobber the cc's. */
3950 else if (GET_CODE (SET_SRC (exp)) == CALL)
3952 CC_STATUS_INIT;
3955 /* Tests and compares set the cc's in predictable ways. */
3956 else if (SET_DEST (exp) == cc0_rtx)
3958 cc_status.flags = 0;
3959 cc_status.value1 = XEXP (exp, 0);
3960 cc_status.value2 = XEXP (exp, 1);
3962 else
3964 /* All other instructions affect the condition codes. */
3965 cc_status.flags = 0;
3966 cc_status.value1 = XEXP (exp, 0);
3967 cc_status.value2 = XEXP (exp, 1);
3970 else
3972 /* Default action if we haven't recognized something
3973 and returned earlier. */
3974 CC_STATUS_INIT;
3977 if (cc_status.value2 != 0)
3978 switch (GET_CODE (cc_status.value2))
3980 /* These logical operations can generate several insns.
3981 The flags are setup according to what is generated. */
3982 case IOR:
3983 case XOR:
3984 case AND:
3985 break;
3987 /* The (not ...) generates several 'com' instructions for
3988 non QImode. We have to invalidate the flags. */
3989 case NOT:
3990 if (GET_MODE (cc_status.value2) != QImode)
3991 CC_STATUS_INIT;
3992 break;
3994 case PLUS:
3995 case MINUS:
3996 case MULT:
3997 case DIV:
3998 case UDIV:
3999 case MOD:
4000 case UMOD:
4001 case NEG:
4002 if (GET_MODE (cc_status.value2) != VOIDmode)
4003 cc_status.flags |= CC_NO_OVERFLOW;
4004 break;
4006 /* The asl sets the overflow bit in such a way that this
4007 makes the flags unusable for a next compare insn. */
4008 case ASHIFT:
4009 case ROTATE:
4010 case ROTATERT:
4011 if (GET_MODE (cc_status.value2) != VOIDmode)
4012 cc_status.flags |= CC_NO_OVERFLOW;
4013 break;
4015 /* A load/store instruction does not affect the carry. */
4016 case MEM:
4017 case SYMBOL_REF:
4018 case REG:
4019 case CONST_INT:
4020 cc_status.flags |= CC_NO_OVERFLOW;
4021 break;
4023 default:
4024 break;
4026 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
4027 && cc_status.value2
4028 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
4029 cc_status.value2 = 0;
4032 /* The current instruction does not affect the flags but changes
4033 the register 'reg'. See if the previous flags can be kept for the
4034 next instruction to avoid a comparison. */
4035 void
4036 m68hc11_notice_keep_cc (reg)
4037 rtx reg;
4039 if (reg == 0
4040 || cc_prev_status.value1 == 0
4041 || rtx_equal_p (reg, cc_prev_status.value1)
4042 || (cc_prev_status.value2
4043 && reg_mentioned_p (reg, cc_prev_status.value2)))
4044 CC_STATUS_INIT;
4045 else
4046 cc_status = cc_prev_status;
4051 /* Machine Specific Reorg. */
4053 /* Z register replacement:
4055 GCC treats the Z register as an index base address register like
4056 X or Y. In general, it uses it during reload to compute the address
4057 of some operand. This helps the reload pass to avoid to fall into the
4058 register spill failure.
4060 The Z register is in the A_REGS class. In the machine description,
4061 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4063 It can appear everywhere an X or Y register can appear, except for
4064 some templates in the clobber section (when a clobber of X or Y is asked).
4065 For a given instruction, the template must ensure that no more than
4066 2 'A' registers are used. Otherwise, the register replacement is not
4067 possible.
4069 To replace the Z register, the algorithm is not terrific:
4070 1. Insns that do not use the Z register are not changed
4071 2. When a Z register is used, we scan forward the insns to see
4072 a potential register to use: either X or Y and sometimes D.
4073 We stop when a call, a label or a branch is seen, or when we
4074 detect that both X and Y are used (probably at different times, but it does
4075 not matter).
4076 3. The register that will be used for the replacement of Z is saved
4077 in a .page0 register or on the stack. If the first instruction that
4078 used Z, uses Z as an input, the value is loaded from another .page0
4079 register. The replacement register is pushed on the stack in the
4080 rare cases where a compare insn uses Z and we couldn't find if X/Y
4081 are dead.
4082 4. The Z register is replaced in all instructions until we reach
4083 the end of the Z-block, as detected by step 2.
4084 5. If we detect that Z is still alive, its value is saved.
4085 If the replacement register is alive, its old value is loaded.
4087 The Z register can be disabled with -ffixed-z.
4090 struct replace_info
4092 rtx first;
4093 rtx replace_reg;
4094 int need_save_z;
4095 int must_load_z;
4096 int must_save_reg;
4097 int must_restore_reg;
4098 rtx last;
4099 int regno;
4100 int x_used;
4101 int y_used;
4102 int can_use_d;
4103 int found_call;
4104 int z_died;
4105 int z_set_count;
4106 rtx z_value;
4107 int must_push_reg;
4108 int save_before_last;
4109 int z_loaded_with_sp;
4112 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
4113 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
4114 static void m68hc11_z_replacement PARAMS ((rtx));
4115 static void m68hc11_reassign_regs PARAMS ((rtx));
4117 int z_replacement_completed = 0;
4119 /* Analyze the insn to find out which replacement register to use and
4120 the boundaries of the replacement.
4121 Returns 0 if we reached the last insn to be replaced, 1 if we can
4122 continue replacement in next insns. */
4124 static int
4125 m68hc11_check_z_replacement (insn, info)
4126 rtx insn;
4127 struct replace_info *info;
4129 int this_insn_uses_ix;
4130 int this_insn_uses_iy;
4131 int this_insn_uses_z;
4132 int this_insn_uses_z_in_dst;
4133 int this_insn_uses_d;
4134 rtx body;
4135 int z_dies_here;
4137 /* A call is said to clobber the Z register, we don't need
4138 to save the value of Z. We also don't need to restore
4139 the replacement register (unless it is used by the call). */
4140 if (GET_CODE (insn) == CALL_INSN)
4142 body = PATTERN (insn);
4144 info->can_use_d = 0;
4146 /* If the call is an indirect call with Z, we have to use the
4147 Y register because X can be used as an input (D+X).
4148 We also must not save Z nor restore Y. */
4149 if (reg_mentioned_p (z_reg, body))
4151 insn = NEXT_INSN (insn);
4152 info->x_used = 1;
4153 info->y_used = 0;
4154 info->found_call = 1;
4155 info->must_restore_reg = 0;
4156 info->last = NEXT_INSN (insn);
4158 info->need_save_z = 0;
4159 return 0;
4161 if (GET_CODE (insn) == CODE_LABEL
4162 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4163 return 0;
4165 if (GET_CODE (insn) == JUMP_INSN)
4167 if (reg_mentioned_p (z_reg, insn) == 0)
4168 return 0;
4170 info->can_use_d = 0;
4171 info->must_save_reg = 0;
4172 info->must_restore_reg = 0;
4173 info->need_save_z = 0;
4174 info->last = NEXT_INSN (insn);
4175 return 0;
4177 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4179 return 1;
4182 /* Z register dies here. */
4183 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4185 body = PATTERN (insn);
4186 if (GET_CODE (body) == SET)
4188 rtx src = XEXP (body, 1);
4189 rtx dst = XEXP (body, 0);
4191 /* Condition code is set here. We have to restore the X/Y and
4192 save into Z before any test/compare insn because once we save/restore
4193 we can change the condition codes. When the compare insn uses Z and
4194 we can't use X/Y, the comparison is made with the *ZREG soft register
4195 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4196 if (dst == cc0_rtx)
4198 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4199 || (GET_CODE (src) == COMPARE &&
4200 (rtx_equal_p (XEXP (src, 0), z_reg)
4201 || rtx_equal_p (XEXP (src, 1), z_reg))))
4203 if (insn == info->first)
4205 info->must_load_z = 0;
4206 info->must_save_reg = 0;
4207 info->must_restore_reg = 0;
4208 info->need_save_z = 0;
4209 info->found_call = 1;
4210 info->regno = SOFT_Z_REGNUM;
4211 info->last = insn;
4213 return 0;
4215 if (reg_mentioned_p (z_reg, src) == 0)
4217 info->can_use_d = 0;
4218 return 0;
4221 if (insn != info->first)
4222 return 0;
4224 /* Compare insn which uses Z. We have to save/restore the X/Y
4225 register without modifying the condition codes. For this
4226 we have to use a push/pop insn. */
4227 info->must_push_reg = 1;
4228 info->last = insn;
4231 /* Z reg is set to something new. We don't need to load it. */
4232 if (Z_REG_P (dst))
4234 if (!reg_mentioned_p (z_reg, src))
4236 /* Z reg is used before being set. Treat this as
4237 a new sequence of Z register replacement. */
4238 if (insn != info->first)
4240 return 0;
4242 info->must_load_z = 0;
4244 info->z_set_count++;
4245 info->z_value = src;
4246 if (SP_REG_P (src))
4247 info->z_loaded_with_sp = 1;
4249 else if (reg_mentioned_p (z_reg, dst))
4250 info->can_use_d = 0;
4252 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4253 | reg_mentioned_p (d_reg, dst);
4254 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4255 | reg_mentioned_p (ix_reg, dst);
4256 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4257 | reg_mentioned_p (iy_reg, dst);
4258 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4260 /* If z is used as an address operand (like (MEM (reg z))),
4261 we can't replace it with d. */
4262 if (this_insn_uses_z && !Z_REG_P (src)
4263 && !(m68hc11_arith_operator (src, GET_MODE (src))
4264 && Z_REG_P (XEXP (src, 0))
4265 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4266 && insn == info->first
4267 && dead_register_here (insn, d_reg)))
4268 info->can_use_d = 0;
4270 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4271 if (TARGET_M6812 && !z_dies_here
4272 && ((this_insn_uses_z && side_effects_p (src))
4273 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4275 info->need_save_z = 1;
4276 info->z_set_count++;
4278 this_insn_uses_z |= this_insn_uses_z_in_dst;
4280 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4282 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4285 if (this_insn_uses_d)
4286 info->can_use_d = 0;
4288 /* IX and IY are used at the same time, we have to restore
4289 the value of the scratch register before this insn. */
4290 if (this_insn_uses_ix && this_insn_uses_iy)
4292 return 0;
4295 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4296 info->can_use_d = 0;
4298 if (info->x_used == 0 && this_insn_uses_ix)
4300 if (info->y_used)
4302 /* We have a (set (REG:HI X) (REG:HI Z)).
4303 Since we use Z as the replacement register, this insn
4304 is no longer necessary. We turn it into a note. We must
4305 not reload the old value of X. */
4306 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4308 if (z_dies_here)
4310 info->need_save_z = 0;
4311 info->z_died = 1;
4313 info->must_save_reg = 0;
4314 info->must_restore_reg = 0;
4315 info->found_call = 1;
4316 info->can_use_d = 0;
4317 PUT_CODE (insn, NOTE);
4318 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4319 NOTE_SOURCE_FILE (insn) = 0;
4320 info->last = NEXT_INSN (insn);
4321 return 0;
4324 if (X_REG_P (dst)
4325 && (rtx_equal_p (src, z_reg)
4326 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4328 if (z_dies_here)
4330 info->need_save_z = 0;
4331 info->z_died = 1;
4333 info->last = NEXT_INSN (insn);
4334 info->must_save_reg = 0;
4335 info->must_restore_reg = 0;
4337 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4338 && !reg_mentioned_p (ix_reg, src))
4340 if (z_dies_here)
4342 info->z_died = 1;
4343 info->need_save_z = 0;
4345 else if (TARGET_M6812 && side_effects_p (src))
4347 info->last = 0;
4348 info->must_restore_reg = 0;
4349 return 0;
4351 else
4353 info->save_before_last = 1;
4355 info->must_restore_reg = 0;
4356 info->last = NEXT_INSN (insn);
4358 else if (info->can_use_d)
4360 info->last = NEXT_INSN (insn);
4361 info->x_used = 1;
4363 return 0;
4365 info->x_used = 1;
4366 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4367 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4369 info->need_save_z = 0;
4370 info->z_died = 1;
4371 info->last = NEXT_INSN (insn);
4372 info->regno = HARD_X_REGNUM;
4373 info->must_save_reg = 0;
4374 info->must_restore_reg = 0;
4375 return 0;
4377 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4379 info->regno = HARD_X_REGNUM;
4380 info->must_restore_reg = 0;
4381 info->must_save_reg = 0;
4382 return 0;
4385 if (info->y_used == 0 && this_insn_uses_iy)
4387 if (info->x_used)
4389 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4391 if (z_dies_here)
4393 info->need_save_z = 0;
4394 info->z_died = 1;
4396 info->must_save_reg = 0;
4397 info->must_restore_reg = 0;
4398 info->found_call = 1;
4399 info->can_use_d = 0;
4400 PUT_CODE (insn, NOTE);
4401 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4402 NOTE_SOURCE_FILE (insn) = 0;
4403 info->last = NEXT_INSN (insn);
4404 return 0;
4407 if (Y_REG_P (dst)
4408 && (rtx_equal_p (src, z_reg)
4409 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4411 if (z_dies_here)
4413 info->z_died = 1;
4414 info->need_save_z = 0;
4416 info->last = NEXT_INSN (insn);
4417 info->must_save_reg = 0;
4418 info->must_restore_reg = 0;
4420 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4421 && !reg_mentioned_p (iy_reg, src))
4423 if (z_dies_here)
4425 info->z_died = 1;
4426 info->need_save_z = 0;
4428 else if (TARGET_M6812 && side_effects_p (src))
4430 info->last = 0;
4431 info->must_restore_reg = 0;
4432 return 0;
4434 else
4436 info->save_before_last = 1;
4438 info->must_restore_reg = 0;
4439 info->last = NEXT_INSN (insn);
4441 else if (info->can_use_d)
4443 info->last = NEXT_INSN (insn);
4444 info->y_used = 1;
4447 return 0;
4449 info->y_used = 1;
4450 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4451 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4453 info->need_save_z = 0;
4454 info->z_died = 1;
4455 info->last = NEXT_INSN (insn);
4456 info->regno = HARD_Y_REGNUM;
4457 info->must_save_reg = 0;
4458 info->must_restore_reg = 0;
4459 return 0;
4461 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4463 info->regno = HARD_Y_REGNUM;
4464 info->must_restore_reg = 0;
4465 info->must_save_reg = 0;
4466 return 0;
4469 if (z_dies_here)
4471 info->need_save_z = 0;
4472 info->z_died = 1;
4473 if (info->last == 0)
4474 info->last = NEXT_INSN (insn);
4475 return 0;
4477 return info->last != NULL_RTX ? 0 : 1;
4479 if (GET_CODE (body) == PARALLEL)
4481 int i;
4482 char ix_clobber = 0;
4483 char iy_clobber = 0;
4484 char z_clobber = 0;
4485 this_insn_uses_iy = 0;
4486 this_insn_uses_ix = 0;
4487 this_insn_uses_z = 0;
4489 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4491 rtx x;
4492 int uses_ix, uses_iy, uses_z;
4494 x = XVECEXP (body, 0, i);
4496 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4497 info->can_use_d = 0;
4499 uses_ix = reg_mentioned_p (ix_reg, x);
4500 uses_iy = reg_mentioned_p (iy_reg, x);
4501 uses_z = reg_mentioned_p (z_reg, x);
4502 if (GET_CODE (x) == CLOBBER)
4504 ix_clobber |= uses_ix;
4505 iy_clobber |= uses_iy;
4506 z_clobber |= uses_z;
4508 else
4510 this_insn_uses_ix |= uses_ix;
4511 this_insn_uses_iy |= uses_iy;
4512 this_insn_uses_z |= uses_z;
4514 if (uses_z && GET_CODE (x) == SET)
4516 rtx dst = XEXP (x, 0);
4518 if (Z_REG_P (dst))
4519 info->z_set_count++;
4521 if (TARGET_M6812 && uses_z && side_effects_p (x))
4522 info->need_save_z = 1;
4524 if (z_clobber)
4525 info->need_save_z = 0;
4527 if (debug_m6811)
4529 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4530 this_insn_uses_ix, this_insn_uses_iy,
4531 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4532 debug_rtx (insn);
4534 if (this_insn_uses_z)
4535 info->can_use_d = 0;
4537 if (z_clobber && info->first != insn)
4539 info->need_save_z = 0;
4540 info->last = insn;
4541 return 0;
4543 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4545 if (this_insn_uses_z == 0 && insn == info->first)
4547 info->must_load_z = 0;
4549 if (dead_register_here (insn, d_reg))
4551 info->regno = HARD_D_REGNUM;
4552 info->must_save_reg = 0;
4553 info->must_restore_reg = 0;
4555 else if (dead_register_here (insn, ix_reg))
4557 info->regno = HARD_X_REGNUM;
4558 info->must_save_reg = 0;
4559 info->must_restore_reg = 0;
4561 else if (dead_register_here (insn, iy_reg))
4563 info->regno = HARD_Y_REGNUM;
4564 info->must_save_reg = 0;
4565 info->must_restore_reg = 0;
4567 if (info->regno >= 0)
4569 info->last = NEXT_INSN (insn);
4570 return 0;
4572 if (this_insn_uses_ix == 0)
4574 info->regno = HARD_X_REGNUM;
4575 info->must_save_reg = 1;
4576 info->must_restore_reg = 1;
4578 else if (this_insn_uses_iy == 0)
4580 info->regno = HARD_Y_REGNUM;
4581 info->must_save_reg = 1;
4582 info->must_restore_reg = 1;
4584 else
4586 info->regno = HARD_D_REGNUM;
4587 info->must_save_reg = 1;
4588 info->must_restore_reg = 1;
4590 info->last = NEXT_INSN (insn);
4591 return 0;
4594 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4595 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4597 if (this_insn_uses_z)
4599 if (info->y_used == 0 && iy_clobber)
4601 info->regno = HARD_Y_REGNUM;
4602 info->must_save_reg = 0;
4603 info->must_restore_reg = 0;
4605 if (info->first != insn
4606 && ((info->y_used && ix_clobber)
4607 || (info->x_used && iy_clobber)))
4608 info->last = insn;
4609 else
4610 info->last = NEXT_INSN (insn);
4611 info->save_before_last = 1;
4613 return 0;
4615 if (this_insn_uses_ix && this_insn_uses_iy)
4617 if (this_insn_uses_z)
4619 fatal_insn ("cannot do z-register replacement", insn);
4621 return 0;
4623 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4625 if (info->y_used)
4627 return 0;
4629 info->x_used = 1;
4630 if (iy_clobber || z_clobber)
4632 info->last = NEXT_INSN (insn);
4633 info->save_before_last = 1;
4634 return 0;
4638 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4640 if (info->x_used)
4642 return 0;
4644 info->y_used = 1;
4645 if (ix_clobber || z_clobber)
4647 info->last = NEXT_INSN (insn);
4648 info->save_before_last = 1;
4649 return 0;
4652 if (z_dies_here)
4654 info->z_died = 1;
4655 info->need_save_z = 0;
4657 return 1;
4659 if (GET_CODE (body) == CLOBBER)
4662 /* IX and IY are used at the same time, we have to restore
4663 the value of the scratch register before this insn. */
4664 if (this_insn_uses_ix && this_insn_uses_iy)
4666 return 0;
4668 if (info->x_used == 0 && this_insn_uses_ix)
4670 if (info->y_used)
4672 return 0;
4674 info->x_used = 1;
4676 if (info->y_used == 0 && this_insn_uses_iy)
4678 if (info->x_used)
4680 return 0;
4682 info->y_used = 1;
4684 return 1;
4686 return 1;
4689 static void
4690 m68hc11_find_z_replacement (insn, info)
4691 rtx insn;
4692 struct replace_info *info;
4694 int reg;
4696 info->replace_reg = NULL_RTX;
4697 info->must_load_z = 1;
4698 info->need_save_z = 1;
4699 info->must_save_reg = 1;
4700 info->must_restore_reg = 1;
4701 info->first = insn;
4702 info->x_used = 0;
4703 info->y_used = 0;
4704 info->can_use_d = TARGET_M6811 ? 1 : 0;
4705 info->found_call = 0;
4706 info->z_died = 0;
4707 info->last = 0;
4708 info->regno = -1;
4709 info->z_set_count = 0;
4710 info->z_value = NULL_RTX;
4711 info->must_push_reg = 0;
4712 info->save_before_last = 0;
4713 info->z_loaded_with_sp = 0;
4715 /* Scan the insn forward to find an address register that is not used.
4716 Stop when:
4717 - the flow of the program changes,
4718 - when we detect that both X and Y are necessary,
4719 - when the Z register dies,
4720 - when the condition codes are set. */
4722 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4724 if (m68hc11_check_z_replacement (insn, info) == 0)
4725 break;
4728 /* May be we can use Y or X if they contain the same value as Z.
4729 This happens very often after the reload. */
4730 if (info->z_set_count == 1)
4732 rtx p = info->first;
4733 rtx v = 0;
4735 if (info->x_used)
4737 v = find_last_value (iy_reg, &p, insn, 1);
4739 else if (info->y_used)
4741 v = find_last_value (ix_reg, &p, insn, 1);
4743 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4745 if (info->x_used)
4746 info->regno = HARD_Y_REGNUM;
4747 else
4748 info->regno = HARD_X_REGNUM;
4749 info->must_load_z = 0;
4750 info->must_save_reg = 0;
4751 info->must_restore_reg = 0;
4752 info->found_call = 1;
4755 if (info->z_set_count == 0)
4756 info->need_save_z = 0;
4758 if (insn == 0)
4759 info->need_save_z = 0;
4761 if (info->last == 0)
4762 info->last = insn;
4764 if (info->regno >= 0)
4766 reg = info->regno;
4767 info->replace_reg = gen_rtx (REG, HImode, reg);
4769 else if (info->can_use_d)
4771 reg = HARD_D_REGNUM;
4772 info->replace_reg = d_reg;
4774 else if (info->x_used)
4776 reg = HARD_Y_REGNUM;
4777 info->replace_reg = iy_reg;
4779 else
4781 reg = HARD_X_REGNUM;
4782 info->replace_reg = ix_reg;
4784 info->regno = reg;
4786 if (info->must_save_reg && info->must_restore_reg)
4788 if (insn && dead_register_here (insn, info->replace_reg))
4790 info->must_save_reg = 0;
4791 info->must_restore_reg = 0;
4796 /* The insn uses the Z register. Find a replacement register for it
4797 (either X or Y) and replace it in the insn and the next ones until
4798 the flow changes or the replacement register is used. Instructions
4799 are emited before and after the Z-block to preserve the value of
4800 Z and of the replacement register. */
4802 static void
4803 m68hc11_z_replacement (insn)
4804 rtx insn;
4806 rtx replace_reg_qi;
4807 rtx replace_reg;
4808 struct replace_info info;
4810 /* Find trivial case where we only need to replace z with the
4811 equivalent soft register. */
4812 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4814 rtx body = PATTERN (insn);
4815 rtx src = XEXP (body, 1);
4816 rtx dst = XEXP (body, 0);
4818 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4820 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4821 return;
4823 else if (Z_REG_P (src)
4824 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4826 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4827 return;
4829 else if (D_REG_P (dst)
4830 && m68hc11_arith_operator (src, GET_MODE (src))
4831 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4833 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4834 return;
4836 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4837 && INTVAL (src) == 0)
4839 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4840 /* Force it to be re-recognized. */
4841 INSN_CODE (insn) = -1;
4842 return;
4846 m68hc11_find_z_replacement (insn, &info);
4848 replace_reg = info.replace_reg;
4849 replace_reg_qi = NULL_RTX;
4851 /* Save the X register in a .page0 location. */
4852 if (info.must_save_reg && !info.must_push_reg)
4854 rtx dst;
4856 if (info.must_push_reg && 0)
4857 dst = gen_rtx (MEM, HImode,
4858 gen_rtx (PRE_DEC, HImode,
4859 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4860 else
4861 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4863 emit_insn_before (gen_movhi (dst,
4864 gen_rtx (REG, HImode, info.regno)), insn);
4866 if (info.must_load_z && !info.must_push_reg)
4868 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4869 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4870 insn);
4874 /* Replace all occurrence of Z by replace_reg.
4875 Stop when the last instruction to replace is reached.
4876 Also stop when we detect a change in the flow (but it's not
4877 necessary; just safeguard). */
4879 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4881 rtx body;
4883 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4884 break;
4886 if (GET_CODE (insn) != INSN
4887 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4888 continue;
4890 body = PATTERN (insn);
4891 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4892 || GET_CODE (body) == ASM_OPERANDS
4893 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4895 rtx note;
4897 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4899 printf ("Reg mentioned here...:\n");
4900 fflush (stdout);
4901 debug_rtx (insn);
4904 /* Stack pointer was decremented by 2 due to the push.
4905 Correct that by adding 2 to the destination. */
4906 if (info.must_push_reg
4907 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4909 rtx src, dst;
4911 src = SET_SRC (body);
4912 dst = SET_DEST (body);
4913 if (SP_REG_P (src) && Z_REG_P (dst))
4914 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4917 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4918 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4920 INSN_CODE (insn) = -1;
4921 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4922 fatal_insn ("cannot do z-register replacement", insn);
4925 /* Likewise for (REG:QI Z). */
4926 if (reg_mentioned_p (z_reg, insn))
4928 if (replace_reg_qi == NULL_RTX)
4929 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4930 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4933 /* If there is a REG_INC note on Z, replace it with a
4934 REG_INC note on the replacement register. This is necessary
4935 to make sure that the flow pass will identify the change
4936 and it will not remove a possible insn that saves Z. */
4937 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4939 if (REG_NOTE_KIND (note) == REG_INC
4940 && GET_CODE (XEXP (note, 0)) == REG
4941 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4943 XEXP (note, 0) = replace_reg;
4947 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4948 break;
4951 /* Save Z before restoring the old value. */
4952 if (insn && info.need_save_z && !info.must_push_reg)
4954 rtx save_pos_insn = insn;
4956 /* If Z is clobber by the last insn, we have to save its value
4957 before the last instruction. */
4958 if (info.save_before_last)
4959 save_pos_insn = PREV_INSN (save_pos_insn);
4961 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4962 gen_rtx (REG, HImode, info.regno)),
4963 save_pos_insn);
4966 if (info.must_push_reg && info.last)
4968 rtx new_body, body;
4970 body = PATTERN (info.last);
4971 new_body = gen_rtx (PARALLEL, VOIDmode,
4972 gen_rtvec (3, body,
4973 gen_rtx (USE, VOIDmode,
4974 replace_reg),
4975 gen_rtx (USE, VOIDmode,
4976 gen_rtx (REG, HImode,
4977 SOFT_Z_REGNUM))));
4978 PATTERN (info.last) = new_body;
4980 /* Force recognition on insn since we changed it. */
4981 INSN_CODE (insn) = -1;
4983 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4985 fatal_insn ("invalid Z register replacement for insn", insn);
4987 insn = NEXT_INSN (info.last);
4990 /* Restore replacement register unless it was died. */
4991 if (insn && info.must_restore_reg && !info.must_push_reg)
4993 rtx dst;
4995 if (info.must_push_reg && 0)
4996 dst = gen_rtx (MEM, HImode,
4997 gen_rtx (POST_INC, HImode,
4998 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4999 else
5000 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
5002 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
5003 dst), insn);
5009 /* Scan all the insn and re-affects some registers
5010 - The Z register (if it was used), is affected to X or Y depending
5011 on the instruction. */
5013 static void
5014 m68hc11_reassign_regs (first)
5015 rtx first;
5017 rtx insn;
5019 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
5020 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
5021 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5022 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
5024 /* Scan all insns to replace Z by X or Y preserving the old value
5025 of X/Y and restoring it afterward. */
5027 for (insn = first; insn; insn = NEXT_INSN (insn))
5029 rtx body;
5031 if (GET_CODE (insn) == CODE_LABEL
5032 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
5033 continue;
5035 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
5036 continue;
5038 body = PATTERN (insn);
5039 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5040 continue;
5042 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5043 || GET_CODE (body) == ASM_OPERANDS
5044 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5045 continue;
5047 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5048 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5051 /* If Z appears in this insn, replace it in the current insn
5052 and the next ones until the flow changes or we have to
5053 restore back the replacement register. */
5055 if (reg_mentioned_p (z_reg, body))
5057 m68hc11_z_replacement (insn);
5060 else
5062 printf ("insn not handled by Z replacement:\n");
5063 fflush (stdout);
5064 debug_rtx (insn);
5070 void
5071 m68hc11_reorg (first)
5072 rtx first;
5074 int split_done = 0;
5075 rtx insn;
5077 z_replacement_completed = 0;
5078 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5080 /* Some RTX are shared at this point. This breaks the Z register
5081 replacement, unshare everything. */
5082 unshare_all_rtl_again (first);
5084 /* Force a split of all splitable insn. This is necessary for the
5085 Z register replacement mechanism because we end up with basic insns. */
5086 split_all_insns_noflow ();
5087 split_done = 1;
5089 z_replacement_completed = 1;
5090 m68hc11_reassign_regs (first);
5092 if (optimize)
5093 compute_bb_for_insn ();
5095 /* After some splitting, there are some oportunities for CSE pass.
5096 This happens quite often when 32-bit or above patterns are split. */
5097 if (optimize > 0 && split_done)
5099 reload_cse_regs (first);
5102 /* Re-create the REG_DEAD notes. These notes are used in the machine
5103 description to use the best assembly directives. */
5104 if (optimize)
5106 /* Before recomputing the REG_DEAD notes, remove all of them.
5107 This is necessary because the reload_cse_regs() pass can
5108 have replaced some (MEM) with a register. In that case,
5109 the REG_DEAD that could exist for that register may become
5110 wrong. */
5111 for (insn = first; insn; insn = NEXT_INSN (insn))
5113 if (INSN_P (insn))
5115 rtx *pnote;
5117 pnote = &REG_NOTES (insn);
5118 while (*pnote != 0)
5120 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5121 *pnote = XEXP (*pnote, 1);
5122 else
5123 pnote = &XEXP (*pnote, 1);
5128 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
5131 z_replacement_completed = 2;
5133 /* If optimizing, then go ahead and split insns that must be
5134 split after Z register replacement. This gives more opportunities
5135 for peephole (in particular for consecutives xgdx/xgdy). */
5136 if (optimize > 0)
5137 split_all_insns_noflow ();
5139 /* Once insns are split after the z_replacement_completed == 2,
5140 we must not re-run the life_analysis. The xgdx/xgdy patterns
5141 are not recognized and the life_analysis pass removes some
5142 insns because it thinks some (SETs) are noops or made to dead
5143 stores (which is false due to the swap).
5145 Do a simple pass to eliminate the noop set that the final
5146 split could generate (because it was easier for split definition). */
5148 rtx insn;
5150 for (insn = first; insn; insn = NEXT_INSN (insn))
5152 rtx body;
5154 if (INSN_DELETED_P (insn))
5155 continue;
5156 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
5157 continue;
5159 /* Remove the (set (R) (R)) insns generated by some splits. */
5160 body = PATTERN (insn);
5161 if (GET_CODE (body) == SET
5162 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5164 PUT_CODE (insn, NOTE);
5165 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5166 NOTE_SOURCE_FILE (insn) = 0;
5167 continue;
5174 /* Cost functions. */
5176 /* Cost of moving memory. */
5178 m68hc11_memory_move_cost (mode, class, in)
5179 enum machine_mode mode;
5180 enum reg_class class;
5181 int in ATTRIBUTE_UNUSED;
5183 if (class <= H_REGS && class > NO_REGS)
5185 if (GET_MODE_SIZE (mode) <= 2)
5186 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5187 else
5188 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5190 else
5192 if (GET_MODE_SIZE (mode) <= 2)
5193 return COSTS_N_INSNS (3);
5194 else
5195 return COSTS_N_INSNS (4);
5200 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5201 Reload does not check the constraint of set insns when the two registers
5202 have a move cost of 2. Setting a higher cost will force reload to check
5203 the constraints. */
5205 m68hc11_register_move_cost (mode, from, to)
5206 enum machine_mode mode;
5207 enum reg_class from;
5208 enum reg_class to;
5210 /* All costs are symmetric, so reduce cases by putting the
5211 lower number class as the destination. */
5212 if (from < to)
5214 enum reg_class tmp = to;
5215 to = from, from = tmp;
5217 if (to >= S_REGS)
5218 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5219 else if (from <= S_REGS)
5220 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5221 else
5222 return COSTS_N_INSNS (2);
5226 /* Provide the costs of an addressing mode that contains ADDR.
5227 If ADDR is not a valid address, its cost is irrelevant. */
5230 m68hc11_address_cost (addr)
5231 rtx addr;
5233 int cost = 4;
5235 switch (GET_CODE (addr))
5237 case REG:
5238 /* Make the cost of hard registers and specially SP, FP small. */
5239 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5240 cost = 0;
5241 else
5242 cost = 1;
5243 break;
5245 case SYMBOL_REF:
5246 cost = 8;
5247 break;
5249 case LABEL_REF:
5250 case CONST:
5251 cost = 0;
5252 break;
5254 case PLUS:
5256 register rtx plus0 = XEXP (addr, 0);
5257 register rtx plus1 = XEXP (addr, 1);
5259 if (GET_CODE (plus0) != REG)
5260 break;
5262 switch (GET_CODE (plus1))
5264 case CONST_INT:
5265 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5266 || INTVAL (plus1) < m68hc11_min_offset)
5267 cost = 3;
5268 else if (INTVAL (plus1) >= m68hc11_max_offset)
5269 cost = 2;
5270 else
5271 cost = 1;
5272 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5273 cost += 0;
5274 else
5275 cost += 1;
5276 break;
5278 case SYMBOL_REF:
5279 cost = 8;
5280 break;
5282 case CONST:
5283 case LABEL_REF:
5284 cost = 0;
5285 break;
5287 default:
5288 break;
5290 break;
5292 case PRE_DEC:
5293 case PRE_INC:
5294 if (SP_REG_P (XEXP (addr, 0)))
5295 cost = 1;
5296 break;
5298 default:
5299 break;
5301 if (debug_m6811)
5303 printf ("Address cost: %d for :", cost);
5304 fflush (stdout);
5305 debug_rtx (addr);
5308 return cost;
5311 static int
5312 m68hc11_shift_cost (mode, x, shift)
5313 enum machine_mode mode;
5314 rtx x;
5315 int shift;
5317 int total;
5319 total = rtx_cost (x, SET);
5320 if (mode == QImode)
5321 total += m68hc11_cost->shiftQI_const[shift % 8];
5322 else if (mode == HImode)
5323 total += m68hc11_cost->shiftHI_const[shift % 16];
5324 else if (shift == 8 || shift == 16 || shift == 32)
5325 total += m68hc11_cost->shiftHI_const[8];
5326 else if (shift != 0 && shift != 16 && shift != 32)
5328 total += m68hc11_cost->shiftHI_const[1] * shift;
5331 /* For SI and others, the cost is higher. */
5332 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5333 total *= GET_MODE_SIZE (mode) / 2;
5335 /* When optimizing for size, make shift more costly so that
5336 multiplications are preferred. */
5337 if (optimize_size && (shift % 8) != 0)
5338 total *= 2;
5340 return total;
5343 static int
5344 m68hc11_rtx_costs_1 (x, code, outer_code)
5345 rtx x;
5346 enum rtx_code code;
5347 enum rtx_code outer_code ATTRIBUTE_UNUSED;
5349 enum machine_mode mode = GET_MODE (x);
5350 int extra_cost = 0;
5351 int total;
5353 switch (code)
5355 case ROTATE:
5356 case ROTATERT:
5357 case ASHIFT:
5358 case LSHIFTRT:
5359 case ASHIFTRT:
5360 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5362 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5365 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5366 total += m68hc11_cost->shift_var;
5367 return total;
5369 case AND:
5370 case XOR:
5371 case IOR:
5372 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5373 total += m68hc11_cost->logical;
5375 /* Logical instructions are byte instructions only. */
5376 total *= GET_MODE_SIZE (mode);
5377 return total;
5379 case MINUS:
5380 case PLUS:
5381 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5382 total += m68hc11_cost->add;
5383 if (GET_MODE_SIZE (mode) > 2)
5385 total *= GET_MODE_SIZE (mode) / 2;
5387 return total;
5389 case UDIV:
5390 case DIV:
5391 case MOD:
5392 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5393 switch (mode)
5395 case QImode:
5396 total += m68hc11_cost->divQI;
5397 break;
5399 case HImode:
5400 total += m68hc11_cost->divHI;
5401 break;
5403 case SImode:
5404 default:
5405 total += m68hc11_cost->divSI;
5406 break;
5408 return total;
5410 case MULT:
5411 /* mul instruction produces 16-bit result. */
5412 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5413 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5414 return m68hc11_cost->multQI
5415 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5416 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5418 /* emul instruction produces 32-bit result for 68HC12. */
5419 if (TARGET_M6812 && mode == SImode
5420 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5421 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5422 return m68hc11_cost->multHI
5423 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5424 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5426 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5427 switch (mode)
5429 case QImode:
5430 total += m68hc11_cost->multQI;
5431 break;
5433 case HImode:
5434 total += m68hc11_cost->multHI;
5435 break;
5437 case SImode:
5438 default:
5439 total += m68hc11_cost->multSI;
5440 break;
5442 return total;
5444 case NEG:
5445 case SIGN_EXTEND:
5446 extra_cost = COSTS_N_INSNS (2);
5448 /* Fall through */
5449 case NOT:
5450 case COMPARE:
5451 case ABS:
5452 case ZERO_EXTEND:
5453 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5454 if (mode == QImode)
5456 return total + COSTS_N_INSNS (1);
5458 if (mode == HImode)
5460 return total + COSTS_N_INSNS (2);
5462 if (mode == SImode)
5464 return total + COSTS_N_INSNS (4);
5466 return total + COSTS_N_INSNS (8);
5468 case IF_THEN_ELSE:
5469 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5470 return COSTS_N_INSNS (1);
5472 return COSTS_N_INSNS (1);
5474 default:
5475 return COSTS_N_INSNS (4);
5479 static bool
5480 m68hc11_rtx_costs (x, code, outer_code, total)
5481 rtx x;
5482 int code, outer_code;
5483 int *total;
5485 switch (code)
5487 /* Constants are cheap. Moving them in registers must be avoided
5488 because most instructions do not handle two register operands. */
5489 case CONST_INT:
5490 case CONST:
5491 case LABEL_REF:
5492 case SYMBOL_REF:
5493 case CONST_DOUBLE:
5494 /* Logical and arithmetic operations with a constant operand are
5495 better because they are not supported with two registers. */
5496 /* 'clr' is slow */
5497 if (outer_code == SET && x == const0_rtx)
5498 /* After reload, the reload_cse pass checks the cost to change
5499 a SET into a PLUS. Make const0 cheap then. */
5500 *total = 1 - reload_completed;
5501 else
5502 *total = 0;
5503 return true;
5505 if (outer_code == SET)
5506 *total = 1 - reload_completed;
5508 case ROTATE:
5509 case ROTATERT:
5510 case ASHIFT:
5511 case LSHIFTRT:
5512 case ASHIFTRT:
5513 case MINUS:
5514 case PLUS:
5515 case AND:
5516 case XOR:
5517 case IOR:
5518 case UDIV:
5519 case DIV:
5520 case MOD:
5521 case MULT:
5522 case NEG:
5523 case SIGN_EXTEND:
5524 case NOT:
5525 case COMPARE:
5526 case ZERO_EXTEND:
5527 case IF_THEN_ELSE:
5528 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5529 return true;
5531 default:
5532 return false;
5537 /* print_options - called at the start of the code generation for a
5538 module. */
5540 extern char *asm_file_name;
5542 #include <time.h>
5543 #include <sys/types.h>
5545 static void
5546 print_options (out)
5547 FILE *out;
5549 const char *a_time;
5550 long c_time;
5551 int i;
5552 extern int save_argc;
5553 extern char **save_argv;
5555 fprintf (out, ";;; Command:\t");
5556 for (i = 0; i < save_argc; i++)
5558 fprintf (out, "%s", save_argv[i]);
5559 if (i + 1 < save_argc)
5560 fprintf (out, " ");
5562 fprintf (out, "\n");
5563 c_time = time (0);
5564 a_time = ctime (&c_time);
5565 fprintf (out, ";;; Compiled:\t%s", a_time);
5566 #ifdef __GNUC__
5567 #ifndef __VERSION__
5568 #define __VERSION__ "[unknown]"
5569 #endif
5570 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
5571 #else
5572 fprintf (out, ";;; (META)compiled by CC.\n");
5573 #endif
5576 void
5577 m68hc11_asm_file_start (out, main_file)
5578 FILE *out;
5579 const char *main_file;
5581 fprintf (out, ";;;-----------------------------------------\n");
5582 fprintf (out, ";;; Start %s gcc assembly output\n",
5583 TARGET_M6811
5584 ? "MC68HC11"
5585 : TARGET_M68S12 ? "MC68HCS12" : "MC68HC12");
5586 fprintf (out, ";;; gcc compiler %s\n", version_string);
5587 print_options (out);
5588 fprintf (out, ";;;-----------------------------------------\n");
5589 output_file_directive (out, main_file);
5591 if (TARGET_SHORT)
5592 fprintf (out, "\t.mode mshort\n");
5593 else
5594 fprintf (out, "\t.mode mlong\n");
5598 static void
5599 m68hc11_asm_out_constructor (symbol, priority)
5600 rtx symbol;
5601 int priority;
5603 default_ctor_section_asm_out_constructor (symbol, priority);
5604 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5607 static void
5608 m68hc11_asm_out_destructor (symbol, priority)
5609 rtx symbol;
5610 int priority;
5612 default_dtor_section_asm_out_destructor (symbol, priority);
5613 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5616 #include "gt-m68hc11.h"