1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@worldnet.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)
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.
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
42 #include "hard-reg-set.h"
44 #include "insn-config.h"
45 #include "conditions.h"
47 #include "insn-attr.h"
52 #include "basic-block.h"
57 #include "target-def.h"
59 static void print_options PARAMS ((FILE *));
60 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
61 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
62 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
63 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
65 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
66 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
67 static int must_parenthesize PARAMS ((rtx));
68 static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
69 static int m68hc11_auto_inc_p PARAMS ((rtx));
70 static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
71 const struct attribute_spec m68hc11_attribute_table[];
73 void create_regs_rtx PARAMS ((void));
74 static void m68hc11_add_gc_roots PARAMS ((void));
76 static void asm_print_register PARAMS ((FILE *, int));
77 static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
78 static void m68hc11_asm_out_constructor PARAMS ((rtx, int));
79 static void m68hc11_asm_out_destructor PARAMS ((rtx, int));
81 rtx m68hc11_soft_tmp_reg;
83 /* Must be set to 1 to produce debug messages. */
86 extern FILE *asm_out_file;
94 static int regs_inited = 0;
97 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
98 int current_function_interrupt;
100 /* Set to 1 by expand_prologue() when the function is a trap handler. */
101 int current_function_trap;
103 /* Min offset that is valid for the indirect addressing mode. */
104 HOST_WIDE_INT m68hc11_min_offset = 0;
106 /* Max offset that is valid for the indirect addressing mode. */
107 HOST_WIDE_INT m68hc11_max_offset = 256;
109 /* The class value for base registers. */
110 enum reg_class m68hc11_base_reg_class = A_REGS;
112 /* The class value for index registers. This is NO_REGS for 68HC11. */
113 enum reg_class m68hc11_index_reg_class = NO_REGS;
115 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
117 /* Tables that tell whether a given hard register is valid for
118 a base or an index register. It is filled at init time depending
119 on the target processor. */
120 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
121 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
123 /* A correction offset which is applied to the stack pointer.
124 This is 1 for 68HC11 and 0 for 68HC12. */
125 int m68hc11_sp_correction;
127 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
128 rtx m68hc11_compare_op0;
129 rtx m68hc11_compare_op1;
132 const struct processor_costs *m68hc11_cost;
134 /* Costs for a 68HC11. */
135 static const struct processor_costs m6811_cost = {
140 /* non-constant shift */
143 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
144 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
145 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
148 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
149 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
150 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
151 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
152 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
153 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
158 COSTS_N_INSNS (20 * 4),
160 COSTS_N_INSNS (20 * 16),
169 /* Costs for a 68HC12. */
170 static const struct processor_costs m6812_cost = {
175 /* non-constant shift */
178 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
179 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
180 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
183 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
184 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
185 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
186 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
187 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
188 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
195 COSTS_N_INSNS (3 * 4),
204 /* Machine specific options */
206 const char *m68hc11_regparm_string;
207 const char *m68hc11_reg_alloc_order;
208 const char *m68hc11_soft_reg_count;
210 static int nb_soft_regs;
212 /* Initialize the GCC target structure. */
213 #undef TARGET_ATTRIBUTE_TABLE
214 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
216 #undef TARGET_ASM_FUNCTION_EPILOGUE
217 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
219 struct gcc_target targetm = TARGET_INITIALIZER;
222 m68hc11_override_options ()
224 m68hc11_add_gc_roots ();
226 memset (m68hc11_reg_valid_for_index, 0,
227 sizeof (m68hc11_reg_valid_for_index));
228 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
230 /* Compilation with -fpic generates a wrong code. */
233 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
234 (flag_pic > 1) ? "PIC" : "pic");
238 /* Configure for a 68hc11 processor. */
241 /* If gcc was built for a 68hc12, invalidate that because
242 a -m68hc11 option was specified on the command line. */
243 if (TARGET_DEFAULT != MASK_M6811)
244 target_flags &= ~TARGET_DEFAULT;
246 m68hc11_cost = &m6811_cost;
247 m68hc11_min_offset = 0;
248 m68hc11_max_offset = 256;
249 m68hc11_index_reg_class = NO_REGS;
250 m68hc11_base_reg_class = A_REGS;
251 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
252 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
253 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
254 m68hc11_sp_correction = 1;
255 m68hc11_tmp_regs_class = D_REGS;
256 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
257 m68hc11_soft_reg_count = "4";
260 /* Configure for a 68hc12 processor. */
263 m68hc11_cost = &m6812_cost;
264 m68hc11_min_offset = -65536;
265 m68hc11_max_offset = 65536;
266 m68hc11_index_reg_class = D_REGS;
267 m68hc11_base_reg_class = A_OR_SP_REGS;
268 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
269 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
270 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
271 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
272 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
273 m68hc11_sp_correction = 0;
274 m68hc11_tmp_regs_class = TMP_REGS;
275 target_flags &= ~MASK_M6811;
276 if (m68hc11_soft_reg_count == 0)
277 m68hc11_soft_reg_count = "2";
284 m68hc11_conditional_register_usage ()
287 int cnt = atoi (m68hc11_soft_reg_count);
291 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
292 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
295 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
298 call_used_regs[i] = 1;
303 /* Reload and register operations. */
305 static const char *const reg_class_names[] = REG_CLASS_NAMES;
311 /* regs_inited = 1; */
312 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
313 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
314 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
315 da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
316 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
318 stack_push_word = gen_rtx (MEM, HImode,
319 gen_rtx (PRE_DEC, HImode,
320 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
321 stack_pop_word = gen_rtx (MEM, HImode,
322 gen_rtx (POST_INC, HImode,
323 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
327 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
328 - 8 bit values are stored anywhere (except the SP register).
329 - 16 bit values can be stored in any register whose mode is 16
330 - 32 bit values can be stored in D, X registers or in a soft register
331 (except the last one because we need 2 soft registers)
332 - Values whose size is > 32 bit are not stored in real hard
333 registers. They may be stored in soft registers if there are
336 hard_regno_mode_ok (regno, mode)
338 enum machine_mode mode;
340 switch (GET_MODE_SIZE (mode))
343 return S_REGNO_P (regno) && nb_soft_regs >= 4;
346 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
349 return G_REGNO_P (regno);
352 /* We have to accept a QImode in X or Y registers. Otherwise, the
353 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
354 in the insns. Reload fails if the insn rejects the register class 'a'
355 as well as if it accepts it. Patterns that failed were
356 zero_extend_qihi2 and iorqi3. */
358 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
366 preferred_reload_class (operand, class)
368 enum reg_class class;
370 enum machine_mode mode;
372 mode = GET_MODE (operand);
376 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
379 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
380 return m68hc11_base_reg_class;
382 if (class >= S_REGS && (GET_CODE (operand) == MEM
383 || GET_CODE (operand) == CONST_INT))
385 /* S_REGS class must not be used. The movhi template does not
386 work to move a memory to a soft register.
387 Restrict to a hard reg. */
392 case D_OR_A_OR_S_REGS:
398 case D_OR_SP_OR_S_REGS:
399 class = D_OR_SP_REGS;
401 case D_OR_Y_OR_S_REGS:
404 case D_OR_X_OR_S_REGS:
420 else if (class == Y_REGS && GET_CODE (operand) == MEM)
424 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
428 else if (class >= S_REGS && S_REG_P (operand))
434 case D_OR_A_OR_S_REGS:
440 case D_OR_SP_OR_S_REGS:
441 class = D_OR_SP_REGS;
443 case D_OR_Y_OR_S_REGS:
446 case D_OR_X_OR_S_REGS:
462 else if (class >= S_REGS)
466 printf ("Class = %s for: ", reg_class_names[class]);
474 printf (" => class=%s\n", reg_class_names[class]);
482 /* Return 1 if the operand is a valid indexed addressing mode.
483 For 68hc11: n,r with n in [0..255] and r in A_REGS class
484 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
486 register_indirect_p (operand, mode, strict)
488 enum machine_mode mode;
493 switch (GET_CODE (operand))
499 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
500 return register_indirect_p (XEXP (operand, 0), mode, strict);
504 base = XEXP (operand, 0);
505 if (GET_CODE (base) == MEM)
508 offset = XEXP (operand, 1);
509 if (GET_CODE (offset) == MEM)
512 if (GET_CODE (base) == REG)
514 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
520 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
522 if (GET_CODE (offset) == REG)
524 if (!VALID_CONSTANT_OFFSET_P (base, mode))
530 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
535 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
542 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
543 a 68HC12 1-byte index addressing mode. */
545 m68hc11_small_indexed_indirect_p (operand, mode)
547 enum machine_mode mode;
551 if (GET_CODE (operand) != MEM)
554 operand = XEXP (operand, 0);
555 if (CONSTANT_ADDRESS_P (operand))
558 if (PUSH_POP_ADDRESS_P (operand))
561 if (!register_indirect_p (operand, mode,
562 (reload_completed | reload_in_progress)))
565 if (TARGET_M6812 && GET_CODE (operand) == PLUS
566 && (reload_completed | reload_in_progress))
568 base = XEXP (operand, 0);
569 offset = XEXP (operand, 1);
570 if (GET_CODE (base) == CONST_INT)
573 switch (GET_MODE_SIZE (mode))
576 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
581 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
586 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
595 m68hc11_register_indirect_p (operand, mode)
597 enum machine_mode mode;
599 if (GET_CODE (operand) != MEM)
602 operand = XEXP (operand, 0);
603 return register_indirect_p (operand, mode,
604 (reload_completed | reload_in_progress));
608 go_if_legitimate_address_internal (operand, mode, strict)
610 enum machine_mode mode;
613 if (CONSTANT_ADDRESS_P (operand))
615 /* Reject the global variables if they are too wide. This forces
616 a load of their address in a register and generates smaller code. */
617 if (GET_MODE_SIZE (mode) == 8)
622 if (register_indirect_p (operand, mode, strict))
626 if (PUSH_POP_ADDRESS_P (operand))
630 if (symbolic_memory_operand (operand, mode))
638 m68hc11_go_if_legitimate_address (operand, mode, strict)
640 enum machine_mode mode;
647 printf ("Checking: ");
652 result = go_if_legitimate_address_internal (operand, mode, strict);
656 printf (" -> %s\n", result == 0 ? "NO" : "YES");
663 printf ("go_if_legitimate%s, ret 0: %d:",
664 (strict ? "_strict" : ""), mode);
673 m68hc11_legitimize_address (operand, old_operand, mode)
674 rtx *operand ATTRIBUTE_UNUSED;
675 rtx old_operand ATTRIBUTE_UNUSED;
676 enum machine_mode mode ATTRIBUTE_UNUSED;
683 m68hc11_reload_operands (operands)
686 enum machine_mode mode;
688 if (regs_inited == 0)
691 mode = GET_MODE (operands[1]);
693 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
694 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
696 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
697 rtx base = XEXP (XEXP (operands[1], 0), 0);
699 if (GET_CODE (base) != REG)
706 /* If the offset is out of range, we have to compute the address
707 with a separate add instruction. We try to do with with an 8-bit
708 add on the A register. This is possible only if the lowest part
709 of the offset (ie, big_offset % 256) is a valid constant offset
710 with respect to the mode. If it's not, we have to generate a
711 16-bit add on the D register. From:
713 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
717 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
718 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
719 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
720 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
722 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
723 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
726 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
729 rtx reg = operands[0];
731 int val = INTVAL (big_offset);
734 /* We use the 'operands[0]' as a scratch register to compute the
735 address. Make sure 'base' is in that register. */
736 if (!rtx_equal_p (base, operands[0]))
738 emit_move_insn (reg, base);
748 vh = (val >> 8) & 0x0FF;
752 /* Create the lowest part offset that still remains to be added.
753 If it's not a valid offset, do a 16-bit add. */
754 offset = gen_rtx (CONST_INT, VOIDmode, vl);
755 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
757 emit_insn (gen_rtx (SET, VOIDmode, reg,
758 gen_rtx (PLUS, HImode, reg, big_offset)));
763 emit_insn (gen_rtx (SET, VOIDmode, reg,
764 gen_rtx (PLUS, HImode, reg,
766 VOIDmode, vh << 8))));
768 emit_move_insn (operands[0],
769 gen_rtx (MEM, GET_MODE (operands[1]),
770 gen_rtx (PLUS, Pmode, reg, offset)));
775 /* Use the normal gen_movhi pattern. */
780 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
783 enum machine_mode dmode;
784 enum machine_mode smode;
794 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
798 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
799 dmode, 1, operands[1], smode);
800 equiv = gen_rtx (code, dmode, operands[1]);
804 ret = emit_library_call_value (libcall, NULL_RTX,
806 operands[1], smode, operands[2],
808 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
815 insns = get_insns ();
817 emit_libcall_block (insns, operands[0], ret, equiv);
820 /* Returns true if X is a PRE/POST increment decrement
821 (same as auto_inc_p() in rtlanal.c but do not take into
822 account the stack). */
824 m68hc11_auto_inc_p (x)
827 return GET_CODE (x) == PRE_DEC
828 || GET_CODE (x) == POST_INC
829 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
833 /* Predicates for machine description. */
836 memory_reload_operand (operand, mode)
838 enum machine_mode mode ATTRIBUTE_UNUSED;
840 return GET_CODE (operand) == MEM
841 && GET_CODE (XEXP (operand, 0)) == PLUS
842 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
843 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
844 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
845 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
849 tst_operand (operand, mode)
851 enum machine_mode mode;
853 if (GET_CODE (operand) == MEM)
855 rtx addr = XEXP (operand, 0);
856 if (m68hc11_auto_inc_p (addr))
859 return nonimmediate_operand (operand, mode);
863 cmp_operand (operand, mode)
865 enum machine_mode mode;
867 if (GET_CODE (operand) == MEM)
869 rtx addr = XEXP (operand, 0);
870 if (m68hc11_auto_inc_p (addr))
873 return general_operand (operand, mode);
877 non_push_operand (operand, mode)
879 enum machine_mode mode;
881 if (general_operand (operand, mode) == 0)
884 if (push_operand (operand, mode) == 1)
890 reg_or_some_mem_operand (operand, mode)
892 enum machine_mode mode;
894 if (GET_CODE (operand) == MEM)
896 rtx op = XEXP (operand, 0);
898 if (symbolic_memory_operand (op, mode))
901 if (IS_STACK_PUSH (operand))
904 if (m68hc11_register_indirect_p (operand, mode))
910 return register_operand (operand, mode);
914 stack_register_operand (operand, mode)
916 enum machine_mode mode ATTRIBUTE_UNUSED;
918 return SP_REG_P (operand);
922 d_register_operand (operand, mode)
924 enum machine_mode mode ATTRIBUTE_UNUSED;
926 if (GET_CODE (operand) == SUBREG)
927 operand = XEXP (operand, 0);
929 return GET_CODE (operand) == REG
930 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
931 || REGNO (operand) == HARD_D_REGNUM);
935 hard_addr_reg_operand (operand, mode)
937 enum machine_mode mode ATTRIBUTE_UNUSED;
939 if (GET_CODE (operand) == SUBREG)
940 operand = XEXP (operand, 0);
942 return GET_CODE (operand) == REG
943 && (REGNO (operand) == HARD_X_REGNUM
944 || REGNO (operand) == HARD_Y_REGNUM
945 || REGNO (operand) == HARD_Z_REGNUM);
949 hard_reg_operand (operand, mode)
951 enum machine_mode mode ATTRIBUTE_UNUSED;
953 if (GET_CODE (operand) == SUBREG)
954 operand = XEXP (operand, 0);
956 return GET_CODE (operand) == REG
957 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
958 || H_REGNO_P (REGNO (operand)));
962 memory_indexed_operand (operand, mode)
964 enum machine_mode mode ATTRIBUTE_UNUSED;
966 if (GET_CODE (operand) != MEM)
969 operand = XEXP (operand, 0);
970 if (GET_CODE (operand) == PLUS)
972 if (GET_CODE (XEXP (operand, 0)) == REG)
973 operand = XEXP (operand, 0);
974 else if (GET_CODE (XEXP (operand, 1)) == REG)
975 operand = XEXP (operand, 1);
977 return GET_CODE (operand) == REG
978 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
979 || A_REGNO_P (REGNO (operand)));
983 push_pop_operand_p (operand)
986 if (GET_CODE (operand) != MEM)
990 operand = XEXP (operand, 0);
991 return PUSH_POP_ADDRESS_P (operand);
994 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
995 reference and a constant. */
998 symbolic_memory_operand (op, mode)
1000 enum machine_mode mode;
1002 switch (GET_CODE (op))
1009 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1010 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1011 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1013 /* ??? This clause seems to be irrelevant. */
1015 return GET_MODE (op) == mode;
1018 return symbolic_memory_operand (XEXP (op, 0), mode)
1019 && symbolic_memory_operand (XEXP (op, 1), mode);
1027 m68hc11_logical_operator (op, mode)
1029 enum machine_mode mode ATTRIBUTE_UNUSED;
1031 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1035 m68hc11_arith_operator (op, mode)
1037 enum machine_mode mode ATTRIBUTE_UNUSED;
1039 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1040 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1041 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1042 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1043 || GET_CODE (op) == ROTATERT;
1047 m68hc11_non_shift_operator (op, mode)
1049 enum machine_mode mode ATTRIBUTE_UNUSED;
1051 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1052 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1057 m68hc11_unary_operator (op, mode)
1059 enum machine_mode mode ATTRIBUTE_UNUSED;
1061 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1062 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1069 m68hc11_block_profiler (out, blockno)
1070 FILE *out ATTRIBUTE_UNUSED;
1071 int blockno ATTRIBUTE_UNUSED;
1077 m68hc11_function_block_profiler (out, block_or_label)
1078 FILE *out ATTRIBUTE_UNUSED;
1079 int block_or_label ATTRIBUTE_UNUSED;
1084 /* Emit the code to build the trampoline used to call a nested function.
1088 ldy #&CXT movw #&CXT,*_.d1
1089 sty *_.d1 jmp FNADDR
1094 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
1099 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1102 if (*static_chain_reg == '*')
1106 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1107 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1108 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1110 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1111 gen_rtx_CONST (QImode,
1112 gen_rtx_SYMBOL_REF (Pmode,
1113 static_chain_reg)));
1114 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1116 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1120 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1121 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1122 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1123 gen_rtx_CONST (HImode,
1124 gen_rtx_SYMBOL_REF (Pmode,
1125 static_chain_reg)));
1126 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1128 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1132 /* Declaration of types. */
1134 const struct attribute_spec m68hc11_attribute_table[] =
1136 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1137 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1138 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1139 { NULL, 0, 0, false, false, false, NULL }
1142 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1143 arguments as in struct attribute_spec.handler. */
1145 m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
1148 tree args ATTRIBUTE_UNUSED;
1149 int flags ATTRIBUTE_UNUSED;
1152 if (TREE_CODE (*node) != FUNCTION_TYPE
1153 && TREE_CODE (*node) != FIELD_DECL
1154 && TREE_CODE (*node) != TYPE_DECL)
1156 warning ("`%s' attribute only applies to functions",
1157 IDENTIFIER_POINTER (name));
1158 *no_add_attrs = true;
1164 /* Define this macro if references to a symbol must be treated
1165 differently depending on something about the variable or function
1166 named by the symbol (such as what section it is in).
1168 For the 68HC11, we want to recognize trap handlers so that we
1169 handle calls to traps in a special manner (by issuing the trap).
1170 This information is stored in SYMBOL_REF_FLAG. */
1172 m68hc11_encode_section_info (decl)
1179 if (TREE_CODE (decl) != FUNCTION_DECL)
1182 rtl = DECL_RTL (decl);
1184 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1185 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1186 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
1190 /* Argument support functions. */
1192 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1193 Arrays are passed by references and other types by value.
1195 SCz: I tried to pass DImode by reference but it seems that this
1196 does not work very well. */
1198 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1199 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1200 enum machine_mode mode ATTRIBUTE_UNUSED;
1202 int named ATTRIBUTE_UNUSED;
1204 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1205 /* Consider complex values as aggregates, so care for TCmode. */
1206 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1207 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1211 /* Define the offset between two registers, one to be eliminated, and the
1212 other its replacement, at the start of a routine. */
1214 m68hc11_initial_elimination_offset (from, to)
1223 /* For a trap handler, we must take into account the registers which
1224 are pushed on the stack during the trap (except the PC). */
1225 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1226 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1227 if (trap_handler && from == ARG_POINTER_REGNUM)
1232 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1234 /* 2 is for the saved frame.
1235 1 is for the 'sts' correction when creating the frame. */
1236 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1239 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1241 return m68hc11_sp_correction;
1244 /* Push any 2 byte pseudo hard registers that we need to save. */
1245 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1247 if (regs_ever_live[regno] && !call_used_regs[regno])
1253 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1255 return get_frame_size () + size;
1258 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1265 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1266 for a call to a function whose data type is FNTYPE.
1267 For a library call, FNTYPE is 0. */
1270 m68hc11_init_cumulative_args (cum, fntype, libname)
1271 CUMULATIVE_ARGS *cum;
1277 z_replacement_completed = 0;
1281 /* For a library call, we must find out the type of the return value.
1282 When the return value is bigger than 4 bytes, it is returned in
1283 memory. In that case, the first argument of the library call is a
1284 pointer to the memory location. Because the first argument is passed in
1285 register D, we have to identify this, so that the first function
1286 parameter is not passed in D either. */
1292 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1295 /* If the library ends in 'di' or in 'df', we assume it's
1296 returning some DImode or some DFmode which are 64-bit wide. */
1297 name = XSTR (libname, 0);
1298 len = strlen (name);
1300 && ((name[len - 2] == 'd'
1301 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1302 || (name[len - 3] == 'd'
1303 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1305 /* We are in. Mark the first parameter register as already used. */
1312 ret_type = TREE_TYPE (fntype);
1314 if (ret_type && aggregate_value_p (ret_type))
1321 /* Update the data in CUM to advance over an argument
1322 of mode MODE and data type TYPE.
1323 (TYPE is null for libcalls where that information may not be available.) */
1326 m68hc11_function_arg_advance (cum, mode, type, named)
1327 CUMULATIVE_ARGS *cum;
1328 enum machine_mode mode;
1330 int named ATTRIBUTE_UNUSED;
1332 if (mode != BLKmode)
1334 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1337 cum->words = GET_MODE_SIZE (mode);
1341 cum->words += GET_MODE_SIZE (mode);
1342 if (cum->words <= HARD_REG_SIZE)
1348 cum->words += int_size_in_bytes (type);
1353 /* Define where to put the arguments to a function.
1354 Value is zero to push the argument on the stack,
1355 or a hard register in which to store the argument.
1357 MODE is the argument's machine mode.
1358 TYPE is the data type of the argument (as a tree).
1359 This is null for libcalls where that information may
1361 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1362 the preceding args and about the function being called.
1363 NAMED is nonzero if this argument is a named parameter
1364 (otherwise it is an extra parameter matching an ellipsis). */
1367 m68hc11_function_arg (cum, mode, type, named)
1368 const CUMULATIVE_ARGS *cum;
1369 enum machine_mode mode;
1370 tree type ATTRIBUTE_UNUSED;
1371 int named ATTRIBUTE_UNUSED;
1373 if (cum->words != 0)
1378 if (mode != BLKmode)
1380 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1381 return gen_rtx (REG, mode, HARD_X_REGNUM);
1383 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1387 return gen_rtx (REG, mode, HARD_D_REGNUM);
1392 /* The "standard" implementation of va_start: just assign `nextarg' to
1395 m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
1396 int stdarg_p ATTRIBUTE_UNUSED;
1402 /* SCz: the default implementation in builtins.c adjust the
1403 nextarg using UNITS_PER_WORD. This works only with -mshort
1404 and fails when integers are 32-bit. Here is the correct way. */
1406 nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
1408 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1409 make_tree (ptr_type_node, nextarg));
1410 TREE_SIDE_EFFECTS (t) = 1;
1412 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1416 m68hc11_va_arg (valist, type)
1421 HOST_WIDE_INT align;
1422 HOST_WIDE_INT rounded_size;
1426 /* Compute the rounded size of the type. */
1427 align = PARM_BOUNDARY / BITS_PER_UNIT;
1428 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1432 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
1434 if (pad_direction == downward)
1436 /* Small args are padded downward. */
1439 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1440 if (rounded_size > align)
1443 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1444 build_int_2 (rounded_size - adj, 0));
1447 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1448 addr = copy_to_reg (addr);
1450 /* Compute new value for AP. */
1451 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1452 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1453 build_int_2 (rounded_size, 0)));
1454 TREE_SIDE_EFFECTS (t) = 1;
1455 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1460 /* If defined, a C expression which determines whether, and in which direction,
1461 to pad out an argument with extra space. The value should be of type
1462 `enum direction': either `upward' to pad above the argument,
1463 `downward' to pad below, or `none' to inhibit padding.
1465 Structures are stored left shifted in their argument slot. */
1467 m68hc11_function_arg_padding (mode, type)
1468 enum machine_mode mode;
1471 if (type != 0 && AGGREGATE_TYPE_P (type))
1474 /* This is the default definition. */
1475 return (!BYTES_BIG_ENDIAN
1478 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1479 && int_size_in_bytes (type) <
1480 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1481 PARM_BOUNDARY) ? downward : upward));
1485 /* Function prologue and epilogue. */
1487 /* Emit a move after the reload pass has completed. This is used to
1488 emit the prologue and epilogue. */
1490 emit_move_after_reload (to, from, scratch)
1491 rtx to, from, scratch;
1495 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1497 insn = emit_move_insn (to, from);
1501 emit_move_insn (scratch, from);
1502 insn = emit_move_insn (to, scratch);
1505 /* Put a REG_INC note to tell the flow analysis that the instruction
1507 if (IS_STACK_PUSH (to))
1509 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1510 XEXP (XEXP (to, 0), 0),
1513 else if (IS_STACK_POP (from))
1515 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1516 XEXP (XEXP (from, 0), 0),
1522 m68hc11_total_frame_size ()
1527 size = get_frame_size ();
1528 if (current_function_interrupt)
1530 size += 3 * HARD_REG_SIZE;
1532 if (frame_pointer_needed)
1533 size += HARD_REG_SIZE;
1535 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1536 if (regs_ever_live[regno] && !call_used_regs[regno])
1537 size += HARD_REG_SIZE;
1543 m68hc11_output_function_epilogue (out, size)
1544 FILE *out ATTRIBUTE_UNUSED;
1545 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1547 /* We catch the function epilogue generation to have a chance
1548 to clear the z_replacement_completed flag. */
1549 z_replacement_completed = 0;
1560 if (reload_completed != 1)
1563 size = get_frame_size ();
1567 /* Generate specific prologue for interrupt handlers. */
1568 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1569 current_function_interrupt = lookup_attribute ("interrupt",
1570 func_attr) != NULL_TREE;
1571 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1573 /* Get the scratch register to build the frame and push registers.
1574 If the first argument is a 32-bit quantity, the D+X registers
1575 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1576 For 68HC12, this scratch register is not used. */
1577 if (current_function_args_info.nregs == 2)
1582 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1583 Other soft registers in page0 need not to be saved because they
1584 will be restored by C functions. For a trap handler, we don't
1585 need to preserve these registers because this is a synchronous call. */
1586 if (current_function_interrupt)
1588 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1589 emit_move_after_reload (stack_push_word,
1590 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1591 emit_move_after_reload (stack_push_word,
1592 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1596 /* Save current stack frame. */
1597 if (frame_pointer_needed)
1598 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1600 /* Allocate local variables. */
1601 if (TARGET_M6812 && size >= 2)
1603 emit_insn (gen_addhi3 (stack_pointer_rtx,
1604 stack_pointer_rtx, GEN_INT (-size)));
1610 insn = gen_rtx_PARALLEL
1613 gen_rtx_SET (VOIDmode,
1615 gen_rtx_PLUS (HImode,
1618 gen_rtx_CLOBBER (VOIDmode, scratch)));
1625 /* Allocate by pushing scratch values. */
1626 for (i = 2; i <= size; i += 2)
1627 emit_move_after_reload (stack_push_word, ix_reg, 0);
1630 emit_insn (gen_addhi3 (stack_pointer_rtx,
1631 stack_pointer_rtx, GEN_INT (-1)));
1634 /* Create the frame pointer. */
1635 if (frame_pointer_needed)
1636 emit_move_after_reload (hard_frame_pointer_rtx,
1637 stack_pointer_rtx, scratch);
1639 /* Push any 2 byte pseudo hard registers that we need to save. */
1640 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1642 if (regs_ever_live[regno] && !call_used_regs[regno])
1644 emit_move_after_reload (stack_push_word,
1645 gen_rtx (REG, HImode, regno), scratch);
1658 if (reload_completed != 1)
1661 size = get_frame_size ();
1663 /* If we are returning a value in two registers, we have to preserve the
1664 X register and use the Y register to restore the stack and the saved
1665 registers. Otherwise, use X because it's faster (and smaller). */
1666 if (current_function_return_rtx == 0)
1668 else if (GET_CODE (current_function_return_rtx) == MEM)
1669 return_size = HARD_REG_SIZE;
1671 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1673 if (return_size > HARD_REG_SIZE)
1678 /* Pop any 2 byte pseudo hard registers that we saved. */
1679 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1681 if (regs_ever_live[regno] && !call_used_regs[regno])
1683 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1684 stack_pop_word, scratch);
1688 /* de-allocate auto variables */
1689 if (TARGET_M6812 && size >= 2)
1691 emit_insn (gen_addhi3 (stack_pointer_rtx,
1692 stack_pointer_rtx, GEN_INT (size)));
1698 insn = gen_rtx_PARALLEL
1701 gen_rtx_SET (VOIDmode,
1703 gen_rtx_PLUS (HImode,
1706 gen_rtx_CLOBBER (VOIDmode, scratch)));
1713 for (i = 2; i <= size; i += 2)
1714 emit_move_after_reload (scratch, stack_pop_word, scratch);
1716 emit_insn (gen_addhi3 (stack_pointer_rtx,
1717 stack_pointer_rtx, GEN_INT (1)));
1720 /* Restore previous frame pointer. */
1721 if (frame_pointer_needed)
1722 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1724 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1725 if (current_function_interrupt)
1727 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1728 stack_pop_word, scratch);
1729 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1730 stack_pop_word, scratch);
1731 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1734 /* If the trap handler returns some value, copy the value
1735 in D, X onto the stack so that the rti will pop the return value
1737 else if (current_function_trap && return_size != 0)
1739 rtx addr_reg = stack_pointer_rtx;
1743 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1746 emit_move_after_reload (gen_rtx (MEM, HImode,
1747 gen_rtx (PLUS, HImode, addr_reg,
1748 GEN_INT (1))), d_reg, 0);
1749 if (return_size > HARD_REG_SIZE)
1750 emit_move_after_reload (gen_rtx (MEM, HImode,
1751 gen_rtx (PLUS, HImode, addr_reg,
1752 GEN_INT (3))), ix_reg, 0);
1755 emit_jump_insn (gen_return ());
1759 /* Low and High part extraction for 68HC11. These routines are
1760 similar to gen_lowpart and gen_highpart but they have been
1761 fixed to work for constants and 68HC11 specific registers. */
1764 m68hc11_gen_lowpart (mode, x)
1765 enum machine_mode mode;
1768 /* We assume that the low part of an auto-inc mode is the same with
1769 the mode changed and that the caller split the larger mode in the
1771 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1773 return gen_rtx (MEM, mode, XEXP (x, 0));
1776 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1777 floating-point constant. A CONST_DOUBLE is used whenever the
1778 constant requires more than one word in order to be adequately
1780 if (GET_CODE (x) == CONST_DOUBLE)
1784 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1788 if (GET_MODE (x) == SFmode)
1790 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1791 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1797 split_double (x, &first, &second);
1801 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1803 return gen_rtx (CONST_INT, VOIDmode,
1804 trunc_int_for_mode (l[0], HImode));
1808 l[0] = CONST_DOUBLE_LOW (x);
1811 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1812 else if (mode == HImode && GET_MODE (x) == SFmode)
1813 return gen_rtx (CONST_INT, VOIDmode,
1814 trunc_int_for_mode (l[0], HImode));
1819 if (mode == QImode && D_REG_P (x))
1820 return gen_rtx (REG, mode, HARD_B_REGNUM);
1822 /* gen_lowpart crashes when it is called with a SUBREG. */
1823 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1826 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1827 else if (mode == HImode)
1828 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1832 x = gen_lowpart (mode, x);
1834 /* Return a different rtx to avoid to share it in several insns
1835 (when used by a split pattern). Sharing addresses within
1836 a MEM breaks the Z register replacement (and reloading). */
1837 if (GET_CODE (x) == MEM)
1843 m68hc11_gen_highpart (mode, x)
1844 enum machine_mode mode;
1847 /* We assume that the high part of an auto-inc mode is the same with
1848 the mode changed and that the caller split the larger mode in the
1850 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1852 return gen_rtx (MEM, mode, XEXP (x, 0));
1855 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1856 floating-point constant. A CONST_DOUBLE is used whenever the
1857 constant requires more than one word in order to be adequately
1859 if (GET_CODE (x) == CONST_DOUBLE)
1863 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1867 if (GET_MODE (x) == SFmode)
1869 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1870 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1876 split_double (x, &first, &second);
1880 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1882 return gen_rtx (CONST_INT, VOIDmode,
1883 trunc_int_for_mode ((l[1] >> 16), HImode));
1887 l[1] = CONST_DOUBLE_HIGH (x);
1891 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1892 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1893 return gen_rtx (CONST_INT, VOIDmode,
1894 trunc_int_for_mode ((l[0] >> 16), HImode));
1898 if (GET_CODE (x) == CONST_INT)
1900 HOST_WIDE_INT val = INTVAL (x);
1904 return gen_rtx (CONST_INT, VOIDmode,
1905 trunc_int_for_mode (val >> 8, QImode));
1907 else if (mode == HImode)
1909 return gen_rtx (CONST_INT, VOIDmode,
1910 trunc_int_for_mode (val >> 16, HImode));
1913 if (mode == QImode && D_REG_P (x))
1914 return gen_rtx (REG, mode, HARD_A_REGNUM);
1916 /* There is no way in GCC to represent the upper part of a word register.
1917 To obtain the 8-bit upper part of a soft register, we change the
1918 reg into a mem rtx. This is possible because they are physically
1919 located in memory. There is no offset because we are big-endian. */
1920 if (mode == QImode && S_REG_P (x))
1924 /* For 68HC12, avoid the '*' for direct addressing mode. */
1925 pos = TARGET_M6812 ? 1 : 0;
1926 return gen_rtx (MEM, QImode,
1927 gen_rtx (SYMBOL_REF, Pmode,
1928 ®_names[REGNO (x)][pos]));
1931 /* gen_highpart crashes when it is called with a SUBREG. */
1932 if (GET_CODE (x) == SUBREG)
1934 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1936 if (GET_CODE (x) == REG)
1938 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1939 return gen_rtx (REG, mode, REGNO (x));
1941 return gen_rtx_SUBREG (mode, x, 0);
1944 if (GET_CODE (x) == MEM)
1946 x = change_address (x, mode, 0);
1948 /* Return a different rtx to avoid to share it in several insns
1949 (when used by a split pattern). Sharing addresses within
1950 a MEM breaks the Z register replacement (and reloading). */
1951 if (GET_CODE (x) == MEM)
1959 /* Obscure register manipulation. */
1961 /* Finds backward in the instructions to see if register 'reg' is
1962 dead. This is used when generating code to see if we can use 'reg'
1963 as a scratch register. This allows us to choose a better generation
1964 of code when we know that some register dies or can be clobbered. */
1967 dead_register_here (x, reg)
1975 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
1979 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1980 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
1986 if (GET_CODE (body) == CALL_INSN)
1988 if (GET_CODE (body) == JUMP_INSN)
1991 if (GET_CODE (body) == SET)
1993 rtx dst = XEXP (body, 0);
1995 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
1997 if (x_reg && rtx_equal_p (dst, x_reg))
2000 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2003 else if (reg_mentioned_p (reg, p)
2004 || (x_reg && reg_mentioned_p (x_reg, p)))
2008 /* Scan forward to see if the register is set in some insns and never
2010 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2014 if (GET_CODE (p) == CODE_LABEL
2015 || GET_CODE (p) == JUMP_INSN
2016 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2019 if (GET_CODE (p) != INSN)
2023 if (GET_CODE (body) == SET)
2025 rtx src = XEXP (body, 1);
2026 rtx dst = XEXP (body, 0);
2028 if (GET_CODE (dst) == REG
2029 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2033 /* Register is used (may be in source or in dest). */
2034 if (reg_mentioned_p (reg, p)
2035 || (x_reg != 0 && GET_MODE (p) == SImode
2036 && reg_mentioned_p (x_reg, p)))
2039 return p == 0 ? 1 : 0;
2043 /* Code generation operations called from machine description file. */
2045 /* Print the name of register 'regno' in the assembly file. */
2047 asm_print_register (file, regno)
2051 const char *name = reg_names[regno];
2053 if (TARGET_M6812 && name[0] == '*')
2056 asm_fprintf (file, "%s", name);
2059 /* A C compound statement to output to stdio stream STREAM the
2060 assembler syntax for an instruction operand X. X is an RTL
2063 CODE is a value that can be used to specify one of several ways
2064 of printing the operand. It is used when identical operands
2065 must be printed differently depending on the context. CODE
2066 comes from the `%' specification that was used to request
2067 printing of the operand. If the specification was just `%DIGIT'
2068 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2069 is the ASCII code for LTR.
2071 If X is a register, this macro should print the register's name.
2072 The names can be found in an array `reg_names' whose type is
2073 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2075 When the machine description has a specification `%PUNCT' (a `%'
2076 followed by a punctuation character), this macro is called with
2077 a null pointer for X and the punctuation character for CODE.
2079 The M68HC11 specific codes are:
2081 'b' for the low part of the operand.
2082 'h' for the high part of the operand
2083 The 'b' or 'h' modifiers have no effect if the operand has
2084 the QImode and is not a S_REG_P (soft register). If the
2085 operand is a hard register, these two modifiers have no effect.
2086 't' generate the temporary scratch register. The operand is
2088 'T' generate the low-part temporary scratch register. The operand is
2092 print_operand (file, op, letter)
2099 asm_print_register (file, SOFT_TMP_REGNUM);
2102 else if (letter == 'T')
2104 asm_print_register (file, SOFT_TMP_REGNUM);
2105 asm_fprintf (file, "+1");
2108 else if (letter == '#')
2110 asm_fprintf (file, "%0I");
2113 if (GET_CODE (op) == REG)
2115 if (letter == 'b' && S_REG_P (op))
2117 asm_print_register (file, REGNO (op));
2118 asm_fprintf (file, "+1");
2122 asm_print_register (file, REGNO (op));
2127 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2130 asm_fprintf (file, "%0I%%lo(");
2132 asm_fprintf (file, "%0I%%hi(");
2134 output_addr_const (file, op);
2135 asm_fprintf (file, ")");
2139 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2140 are specified. If we already have a QImode, there is nothing to do. */
2141 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2145 op = m68hc11_gen_lowpart (QImode, op);
2147 else if (letter == 'h')
2149 op = m68hc11_gen_highpart (QImode, op);
2153 if (GET_CODE (op) == MEM)
2155 rtx base = XEXP (op, 0);
2156 switch (GET_CODE (base))
2161 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2162 asm_print_register (file, REGNO (XEXP (base, 0)));
2171 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2172 asm_print_register (file, REGNO (XEXP (base, 0)));
2173 asm_fprintf (file, "-");
2182 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2183 asm_print_register (file, REGNO (XEXP (base, 0)));
2184 asm_fprintf (file, "+");
2193 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2194 asm_print_register (file, REGNO (XEXP (base, 0)));
2201 output_address (base);
2205 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2208 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2209 ASM_OUTPUT_FLOAT_OPERAND (letter, file, r);
2211 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode)
2214 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2215 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r);
2217 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2220 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2221 ASM_OUTPUT_DOUBLE_OPERAND (file, r);
2225 int need_parenthesize = 0;
2228 asm_fprintf (file, "%0I");
2230 need_parenthesize = must_parenthesize (op);
2232 if (need_parenthesize)
2233 asm_fprintf (file, "(");
2235 output_addr_const (file, op);
2236 if (need_parenthesize)
2237 asm_fprintf (file, ")");
2241 /* Returns true if the operand 'op' must be printed with parenthesis
2242 arround it. This must be done only if there is a symbol whose name
2243 is a processor register. */
2245 must_parenthesize (op)
2250 switch (GET_CODE (op))
2253 name = XSTR (op, 0);
2254 /* Avoid a conflict between symbol name and a possible
2256 return (strcasecmp (name, "a") == 0
2257 || strcasecmp (name, "b") == 0
2258 || strcasecmp (name, "d") == 0
2259 || strcasecmp (name, "x") == 0
2260 || strcasecmp (name, "y") == 0
2261 || strcasecmp (name, "pc") == 0
2262 || strcasecmp (name, "sp") == 0
2263 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2267 return must_parenthesize (XEXP (op, 0))
2268 || must_parenthesize (XEXP (op, 1));
2274 return must_parenthesize (XEXP (op, 0));
2285 /* A C compound statement to output to stdio stream STREAM the
2286 assembler syntax for an instruction operand that is a memory
2287 reference whose address is ADDR. ADDR is an RTL expression. */
2290 print_operand_address (file, addr)
2296 int need_parenthesis = 0;
2298 switch (GET_CODE (addr))
2301 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2304 asm_fprintf (file, "0,");
2305 asm_print_register (file, REGNO (addr));
2309 base = XEXP (addr, 0);
2310 switch (GET_CODE (base))
2315 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2316 asm_print_register (file, REGNO (XEXP (base, 0)));
2325 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2326 asm_print_register (file, REGNO (XEXP (base, 0)));
2327 asm_fprintf (file, "-");
2336 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2337 asm_print_register (file, REGNO (XEXP (base, 0)));
2338 asm_fprintf (file, "+");
2347 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2348 asm_print_register (file, REGNO (XEXP (base, 0)));
2355 need_parenthesis = must_parenthesize (base);
2356 if (need_parenthesis)
2357 asm_fprintf (file, "(");
2359 output_addr_const (file, base);
2360 if (need_parenthesis)
2361 asm_fprintf (file, ")");
2367 base = XEXP (addr, 0);
2368 offset = XEXP (addr, 1);
2369 if (!G_REG_P (base) && G_REG_P (offset))
2371 base = XEXP (addr, 1);
2372 offset = XEXP (addr, 0);
2374 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2376 need_parenthesis = must_parenthesize (addr);
2378 if (need_parenthesis)
2379 asm_fprintf (file, "(");
2381 output_addr_const (file, base);
2382 asm_fprintf (file, "+");
2383 output_addr_const (file, offset);
2384 if (need_parenthesis)
2385 asm_fprintf (file, ")");
2387 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2393 asm_print_register (file, REGNO (offset));
2394 asm_fprintf (file, ",");
2395 asm_print_register (file, REGNO (base));
2402 output_addr_const (file, offset);
2403 asm_fprintf (file, ",");
2404 asm_print_register (file, REGNO (base));
2414 if (GET_CODE (addr) == CONST_INT
2415 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2417 asm_fprintf (file, "%d", INTVAL (addr));
2421 need_parenthesis = must_parenthesize (addr);
2422 if (need_parenthesis)
2423 asm_fprintf (file, "(");
2425 output_addr_const (file, addr);
2426 if (need_parenthesis)
2427 asm_fprintf (file, ")");
2434 /* Splitting of some instructions. */
2437 m68hc11_expand_compare (code, op0, op1)
2443 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2447 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2448 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2449 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2456 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2458 rtx op0, op1, label;
2462 switch (GET_MODE (op0))
2466 tmp = m68hc11_expand_compare (code, op0, op1);
2467 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2468 gen_rtx_LABEL_REF (VOIDmode, label),
2470 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2474 /* SCz: from i386.c */
2477 /* Don't expand the comparison early, so that we get better code
2478 when jump or whoever decides to reverse the comparison. */
2483 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2484 &m68hc11_compare_op1);
2486 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2487 m68hc11_compare_op0, m68hc11_compare_op1);
2488 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2489 gen_rtx_LABEL_REF (VOIDmode, label),
2491 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2493 use_fcomi = ix86_use_fcomi_compare (code);
2494 vec = rtvec_alloc (3 + !use_fcomi);
2495 RTVEC_ELT (vec, 0) = tmp;
2497 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2499 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2502 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2504 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2510 /* Expand SImode branch into multiple compare+branch. */
2512 rtx lo[2], hi[2], label2;
2513 enum rtx_code code1, code2, code3;
2515 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2520 code = swap_condition (code);
2522 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2523 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2524 hi[0] = m68hc11_gen_highpart (HImode, op0);
2525 hi[1] = m68hc11_gen_highpart (HImode, op1);
2527 /* Otherwise, if we are doing less-than, op1 is a constant and the
2528 low word is zero, then we can just examine the high word. */
2530 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2531 && (code == LT || code == LTU))
2533 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2537 /* Otherwise, we need two or three jumps. */
2539 label2 = gen_label_rtx ();
2542 code2 = swap_condition (code);
2543 code3 = unsigned_condition (code);
2584 * if (hi(a) < hi(b)) goto true;
2585 * if (hi(a) > hi(b)) goto false;
2586 * if (lo(a) < lo(b)) goto true;
2590 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2592 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2594 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2597 emit_label (label2);
2608 /* Split a DI, SI or HI move into several smaller move operations.
2609 The scratch register 'scratch' is used as a temporary to load
2610 store intermediate values. It must be a hard register. */
2612 m68hc11_split_move (to, from, scratch)
2613 rtx to, from, scratch;
2615 rtx low_to, low_from;
2616 rtx high_to, high_from;
2617 enum machine_mode mode;
2620 mode = GET_MODE (to);
2621 if (GET_MODE_SIZE (mode) == 8)
2623 else if (GET_MODE_SIZE (mode) == 4)
2629 && IS_STACK_PUSH (to)
2630 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2636 else if (mode == HImode)
2644 low_to = m68hc11_gen_lowpart (mode, to);
2645 high_to = m68hc11_gen_highpart (mode, to);
2647 low_from = m68hc11_gen_lowpart (mode, from);
2648 if (mode == SImode && GET_CODE (from) == CONST_INT)
2650 if (INTVAL (from) >= 0)
2651 high_from = const0_rtx;
2653 high_from = constm1_rtx;
2656 high_from = m68hc11_gen_highpart (mode, from);
2660 high_from = adjust_address (high_from, mode, offset);
2661 low_from = high_from;
2665 m68hc11_split_move (low_to, low_from, scratch);
2666 m68hc11_split_move (high_to, high_from, scratch);
2668 else if (H_REG_P (to) || H_REG_P (from)
2670 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2671 || m68hc11_small_indexed_indirect_p (from,
2673 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2674 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2676 emit_move_insn (low_to, low_from);
2677 emit_move_insn (high_to, high_from);
2683 emit_move_insn (scratch, low_from);
2684 insn = emit_move_insn (low_to, scratch);
2686 emit_move_insn (scratch, high_from);
2687 insn = emit_move_insn (high_to, scratch);
2692 simplify_logical (mode, code, operand, result)
2693 enum machine_mode mode;
2702 if (GET_CODE (operand) != CONST_INT)
2710 val = INTVAL (operand);
2714 if ((val & mask) == 0)
2716 if ((val & mask) == mask)
2717 *result = constm1_rtx;
2721 if ((val & mask) == 0)
2722 *result = const0_rtx;
2723 if ((val & mask) == mask)
2728 if ((val & mask) == 0)
2736 m68hc11_emit_logical (mode, code, operands)
2737 enum machine_mode mode;
2744 need_copy = (rtx_equal_p (operands[0], operands[1])
2745 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2747 operands[1] = simplify_logical (mode, code, operands[1], &result);
2748 operands[2] = simplify_logical (mode, code, operands[2], &result);
2750 if (result && GET_CODE (result) == CONST_INT)
2752 if (!H_REG_P (operands[0]) && operands[3]
2753 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2755 emit_move_insn (operands[3], result);
2756 emit_move_insn (operands[0], operands[3]);
2760 emit_move_insn (operands[0], result);
2763 else if (operands[1] != 0 && operands[2] != 0)
2767 if (!H_REG_P (operands[0]) && operands[3])
2769 emit_move_insn (operands[3], operands[1]);
2770 emit_insn (gen_rtx (SET, mode,
2772 gen_rtx (code, mode,
2773 operands[3], operands[2])));
2774 insn = emit_move_insn (operands[0], operands[3]);
2778 insn = emit_insn (gen_rtx (SET, mode,
2780 gen_rtx (code, mode,
2781 operands[0], operands[2])));
2785 /* The logical operation is similar to a copy. */
2790 if (GET_CODE (operands[1]) == CONST_INT)
2795 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2797 emit_move_insn (operands[3], src);
2798 emit_move_insn (operands[0], operands[3]);
2802 emit_move_insn (operands[0], src);
2808 m68hc11_split_logical (mode, code, operands)
2809 enum machine_mode mode;
2816 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2817 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2818 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2820 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2822 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
2824 if (INTVAL (operands[1]) >= 0)
2825 high[1] = const0_rtx;
2827 high[1] = constm1_rtx;
2830 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2832 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
2834 if (INTVAL (operands[2]) >= 0)
2835 high[2] = const0_rtx;
2837 high[2] = constm1_rtx;
2840 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2842 low[3] = operands[3];
2843 high[3] = operands[3];
2846 m68hc11_split_logical (HImode, code, low);
2847 m68hc11_split_logical (HImode, code, high);
2851 m68hc11_emit_logical (mode, code, low);
2852 m68hc11_emit_logical (mode, code, high);
2856 /* Code generation. */
2859 m68hc11_output_swap (insn, operands)
2860 rtx insn ATTRIBUTE_UNUSED;
2863 /* We have to be careful with the cc_status. An address register swap
2864 is generated for some comparison. The comparison is made with D
2865 but the branch really uses the address register. See the split
2866 pattern for compare. The xgdx/xgdy preserve the flags but after
2867 the exchange, the flags will reflect to the value of X and not D.
2868 Tell this by setting the cc_status according to the cc_prev_status. */
2869 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2871 if (cc_prev_status.value1 != 0
2872 && (D_REG_P (cc_prev_status.value1)
2873 || X_REG_P (cc_prev_status.value1)))
2875 cc_status = cc_prev_status;
2876 if (D_REG_P (cc_status.value1))
2877 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2880 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2886 output_asm_insn ("xgdx", operands);
2890 if (cc_prev_status.value1 != 0
2891 && (D_REG_P (cc_prev_status.value1)
2892 || Y_REG_P (cc_prev_status.value1)))
2894 cc_status = cc_prev_status;
2895 if (D_REG_P (cc_status.value1))
2896 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2899 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2905 output_asm_insn ("xgdy", operands);
2909 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2910 This is used to decide whether a move that set flags should be used
2913 next_insn_test_reg (insn, reg)
2919 insn = next_nonnote_insn (insn);
2920 if (GET_CODE (insn) != INSN)
2923 body = PATTERN (insn);
2924 if (sets_cc0_p (body) != 1)
2927 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
2933 /* Generate the code to move a 16-bit operand into another one. */
2936 m68hc11_gen_movhi (insn, operands)
2942 /* Move a register or memory to the same location.
2943 This is possible because such insn can appear
2944 in a non-optimizing mode. */
2945 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
2947 cc_status = cc_prev_status;
2953 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
2955 cc_status = cc_prev_status;
2956 switch (REGNO (operands[1]))
2961 output_asm_insn ("psh%1", operands);
2968 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2970 cc_status = cc_prev_status;
2971 switch (REGNO (operands[0]))
2976 output_asm_insn ("pul%0", operands);
2983 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
2985 m68hc11_notice_keep_cc (operands[0]);
2986 output_asm_insn ("tfr\t%1,%0", operands);
2988 else if (H_REG_P (operands[0]))
2990 if (SP_REG_P (operands[0]))
2991 output_asm_insn ("lds\t%1", operands);
2993 output_asm_insn ("ld%0\t%1", operands);
2995 else if (H_REG_P (operands[1]))
2997 if (SP_REG_P (operands[1]))
2998 output_asm_insn ("sts\t%0", operands);
3000 output_asm_insn ("st%1\t%0", operands);
3004 rtx from = operands[1];
3005 rtx to = operands[0];
3007 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3008 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3009 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3010 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3016 ops[0] = operands[2];
3019 m68hc11_gen_movhi (insn, ops);
3021 ops[1] = operands[2];
3022 m68hc11_gen_movhi (insn, ops);
3026 /* !!!! SCz wrong here. */
3027 fatal_insn ("Move insn not handled", insn);
3032 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3034 output_asm_insn ("clr\t%h0", operands);
3035 output_asm_insn ("clr\t%b0", operands);
3039 m68hc11_notice_keep_cc (operands[0]);
3040 output_asm_insn ("movw\t%1,%0", operands);
3047 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3049 cc_status = cc_prev_status;
3050 switch (REGNO (operands[0]))
3054 output_asm_insn ("pul%0", operands);
3057 output_asm_insn ("pula", operands);
3058 output_asm_insn ("pulb", operands);
3065 /* Some moves to a hard register are special. Not all of them
3066 are really supported and we have to use a temporary
3067 location to provide them (either the stack of a temp var). */
3068 if (H_REG_P (operands[0]))
3070 switch (REGNO (operands[0]))
3073 if (X_REG_P (operands[1]))
3075 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3077 m68hc11_output_swap (insn, operands);
3079 else if (next_insn_test_reg (insn, operands[0]))
3081 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3085 m68hc11_notice_keep_cc (operands[0]);
3086 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3089 else if (Y_REG_P (operands[1]))
3091 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3093 m68hc11_output_swap (insn, operands);
3097 /* %t means *ZTMP scratch register. */
3098 output_asm_insn ("sty\t%t1", operands);
3099 output_asm_insn ("ldd\t%t1", operands);
3102 else if (SP_REG_P (operands[1]))
3107 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3108 output_asm_insn ("xgdx", operands);
3109 output_asm_insn ("tsx", operands);
3110 output_asm_insn ("xgdx", operands);
3112 else if (IS_STACK_POP (operands[1]))
3114 output_asm_insn ("pula\n\tpulb", operands);
3116 else if (GET_CODE (operands[1]) == CONST_INT
3117 && INTVAL (operands[1]) == 0)
3119 output_asm_insn ("clra\n\tclrb", operands);
3123 output_asm_insn ("ldd\t%1", operands);
3128 if (D_REG_P (operands[1]))
3130 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3132 m68hc11_output_swap (insn, operands);
3134 else if (next_insn_test_reg (insn, operands[0]))
3136 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3140 m68hc11_notice_keep_cc (operands[0]);
3141 output_asm_insn ("pshb", operands);
3142 output_asm_insn ("psha", operands);
3143 output_asm_insn ("pulx", operands);
3146 else if (Y_REG_P (operands[1]))
3148 /* When both D and Y are dead, use the sequence xgdy, xgdx
3149 to move Y into X. The D and Y registers are modified. */
3150 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3151 && dead_register_here (insn, d_reg))
3153 output_asm_insn ("xgdy", operands);
3154 output_asm_insn ("xgdx", operands);
3159 output_asm_insn ("sty\t%t1", operands);
3160 output_asm_insn ("ldx\t%t1", operands);
3163 else if (SP_REG_P (operands[1]))
3165 /* tsx, tsy preserve the flags */
3166 cc_status = cc_prev_status;
3167 output_asm_insn ("tsx", operands);
3171 output_asm_insn ("ldx\t%1", operands);
3176 if (D_REG_P (operands[1]))
3178 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3180 m68hc11_output_swap (insn, operands);
3184 output_asm_insn ("std\t%t1", operands);
3185 output_asm_insn ("ldy\t%t1", operands);
3188 else if (X_REG_P (operands[1]))
3190 /* When both D and X are dead, use the sequence xgdx, xgdy
3191 to move X into Y. The D and X registers are modified. */
3192 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3193 && dead_register_here (insn, d_reg))
3195 output_asm_insn ("xgdx", operands);
3196 output_asm_insn ("xgdy", operands);
3201 output_asm_insn ("stx\t%t1", operands);
3202 output_asm_insn ("ldy\t%t1", operands);
3205 else if (SP_REG_P (operands[1]))
3207 /* tsx, tsy preserve the flags */
3208 cc_status = cc_prev_status;
3209 output_asm_insn ("tsy", operands);
3213 output_asm_insn ("ldy\t%1", operands);
3217 case HARD_SP_REGNUM:
3218 if (D_REG_P (operands[1]))
3220 m68hc11_notice_keep_cc (operands[0]);
3221 output_asm_insn ("xgdx", operands);
3222 output_asm_insn ("txs", operands);
3223 output_asm_insn ("xgdx", operands);
3225 else if (X_REG_P (operands[1]))
3227 /* tys, txs preserve the flags */
3228 cc_status = cc_prev_status;
3229 output_asm_insn ("txs", operands);
3231 else if (Y_REG_P (operands[1]))
3233 /* tys, txs preserve the flags */
3234 cc_status = cc_prev_status;
3235 output_asm_insn ("tys", operands);
3239 /* lds sets the flags but the des does not. */
3241 output_asm_insn ("lds\t%1", operands);
3242 output_asm_insn ("des", operands);
3247 fatal_insn ("Invalid register in the move instruction", insn);
3252 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3253 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3255 output_asm_insn ("sts\t%0", operands);
3259 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3261 cc_status = cc_prev_status;
3262 switch (REGNO (operands[1]))
3266 output_asm_insn ("psh%1", operands);
3269 output_asm_insn ("pshb", operands);
3270 output_asm_insn ("psha", operands);
3278 /* Operand 1 must be a hard register. */
3279 if (!H_REG_P (operands[1]))
3281 fatal_insn ("Invalid operand in the instruction", insn);
3284 reg = REGNO (operands[1]);
3288 output_asm_insn ("std\t%0", operands);
3292 output_asm_insn ("stx\t%0", operands);
3296 output_asm_insn ("sty\t%0", operands);
3299 case HARD_SP_REGNUM:
3303 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3305 output_asm_insn ("pshx", operands);
3306 output_asm_insn ("tsx", operands);
3307 output_asm_insn ("inx", operands);
3308 output_asm_insn ("inx", operands);
3309 output_asm_insn ("stx\t%0", operands);
3310 output_asm_insn ("pulx", operands);
3313 else if (reg_mentioned_p (ix_reg, operands[0]))
3315 output_asm_insn ("sty\t%t0", operands);
3316 output_asm_insn ("tsy", operands);
3317 output_asm_insn ("sty\t%0", operands);
3318 output_asm_insn ("ldy\t%t0", operands);
3322 output_asm_insn ("stx\t%t0", operands);
3323 output_asm_insn ("tsx", operands);
3324 output_asm_insn ("stx\t%0", operands);
3325 output_asm_insn ("ldx\t%t0", operands);
3331 fatal_insn ("Invalid register in the move instruction", insn);
3337 m68hc11_gen_movqi (insn, operands)
3341 /* Move a register or memory to the same location.
3342 This is possible because such insn can appear
3343 in a non-optimizing mode. */
3344 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3346 cc_status = cc_prev_status;
3353 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3355 m68hc11_notice_keep_cc (operands[0]);
3356 output_asm_insn ("tfr\t%1,%0", operands);
3358 else if (H_REG_P (operands[0]))
3360 if (Q_REG_P (operands[0]))
3361 output_asm_insn ("lda%0\t%b1", operands);
3362 else if (D_REG_P (operands[0]))
3363 output_asm_insn ("ldab\t%b1", operands);
3367 else if (H_REG_P (operands[1]))
3369 if (Q_REG_P (operands[1]))
3370 output_asm_insn ("sta%1\t%b0", operands);
3371 else if (D_REG_P (operands[1]))
3372 output_asm_insn ("stab\t%b0", operands);
3378 rtx from = operands[1];
3379 rtx to = operands[0];
3381 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3382 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3383 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3384 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3390 ops[0] = operands[2];
3393 m68hc11_gen_movqi (insn, ops);
3395 ops[1] = operands[2];
3396 m68hc11_gen_movqi (insn, ops);
3400 /* !!!! SCz wrong here. */
3401 fatal_insn ("Move insn not handled", insn);
3406 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3408 output_asm_insn ("clr\t%b0", operands);
3412 m68hc11_notice_keep_cc (operands[0]);
3413 output_asm_insn ("movb\t%b1,%b0", operands);
3421 if (H_REG_P (operands[0]))
3423 switch (REGNO (operands[0]))
3427 if (X_REG_P (operands[1]))
3429 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3431 m68hc11_output_swap (insn, operands);
3435 output_asm_insn ("stx\t%t1", operands);
3436 output_asm_insn ("ldab\t%T0", operands);
3439 else if (Y_REG_P (operands[1]))
3441 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3443 m68hc11_output_swap (insn, operands);
3447 output_asm_insn ("sty\t%t1", operands);
3448 output_asm_insn ("ldab\t%T0", operands);
3451 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3452 && !DA_REG_P (operands[1]))
3454 output_asm_insn ("ldab\t%b1", operands);
3456 else if (DA_REG_P (operands[1]))
3458 output_asm_insn ("tab", operands);
3462 cc_status = cc_prev_status;
3468 if (X_REG_P (operands[1]))
3470 output_asm_insn ("stx\t%t1", operands);
3471 output_asm_insn ("ldaa\t%T0", operands);
3473 else if (Y_REG_P (operands[1]))
3475 output_asm_insn ("sty\t%t1", operands);
3476 output_asm_insn ("ldaa\t%T0", operands);
3478 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3479 && !DA_REG_P (operands[1]))
3481 output_asm_insn ("ldaa\t%b1", operands);
3483 else if (!DA_REG_P (operands[1]))
3485 output_asm_insn ("tba", operands);
3489 cc_status = cc_prev_status;
3494 if (D_REG_P (operands[1]))
3496 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3498 m68hc11_output_swap (insn, operands);
3502 output_asm_insn ("stab\t%T1", operands);
3503 output_asm_insn ("ldx\t%t1", operands);
3507 else if (Y_REG_P (operands[1]))
3509 output_asm_insn ("sty\t%t0", operands);
3510 output_asm_insn ("ldx\t%t0", operands);
3512 else if (GET_CODE (operands[1]) == CONST_INT)
3514 output_asm_insn ("ldx\t%1", operands);
3516 else if (dead_register_here (insn, d_reg))
3518 output_asm_insn ("ldab\t%b1", operands);
3519 output_asm_insn ("xgdx", operands);
3521 else if (!reg_mentioned_p (operands[0], operands[1]))
3523 output_asm_insn ("xgdx", operands);
3524 output_asm_insn ("ldab\t%b1", operands);
3525 output_asm_insn ("xgdx", operands);
3529 output_asm_insn ("pshb", operands);
3530 output_asm_insn ("ldab\t%b1", operands);
3531 output_asm_insn ("stab\t%T1", operands);
3532 output_asm_insn ("ldx\t%t1", operands);
3533 output_asm_insn ("pulb", operands);
3539 if (D_REG_P (operands[1]))
3541 output_asm_insn ("stab\t%T1", operands);
3542 output_asm_insn ("ldy\t%t1", operands);
3545 else if (X_REG_P (operands[1]))
3547 output_asm_insn ("stx\t%t1", operands);
3548 output_asm_insn ("ldy\t%t1", operands);
3551 else if (GET_CODE (operands[1]) == CONST_INT)
3553 output_asm_insn ("ldy\t%1", operands);
3555 else if (dead_register_here (insn, d_reg))
3557 output_asm_insn ("ldab\t%b1", operands);
3558 output_asm_insn ("xgdy", operands);
3560 else if (!reg_mentioned_p (operands[0], operands[1]))
3562 output_asm_insn ("xgdy", operands);
3563 output_asm_insn ("ldab\t%b1", operands);
3564 output_asm_insn ("xgdy", operands);
3568 output_asm_insn ("pshb", operands);
3569 output_asm_insn ("ldab\t%b1", operands);
3570 output_asm_insn ("stab\t%T1", operands);
3571 output_asm_insn ("ldy\t%t1", operands);
3572 output_asm_insn ("pulb", operands);
3578 fatal_insn ("Invalid register in the instruction", insn);
3582 else if (H_REG_P (operands[1]))
3584 switch (REGNO (operands[1]))
3588 output_asm_insn ("stab\t%b0", operands);
3592 output_asm_insn ("staa\t%b0", operands);
3596 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3600 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3604 fatal_insn ("Invalid register in the move instruction", insn);
3611 fatal_insn ("Operand 1 must be a hard register", insn);
3615 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3616 The source and destination must be D or A and the shift must
3619 m68hc11_gen_rotate (code, insn, operands)
3626 if (GET_CODE (operands[2]) != CONST_INT
3627 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3628 fatal_insn ("Invalid rotate insn", insn);
3630 val = INTVAL (operands[2]);
3631 if (code == ROTATERT)
3632 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3634 if (GET_MODE (operands[0]) != QImode)
3637 /* Rotate by 8-bits if the shift is within [5..11]. */
3638 if (val >= 5 && val <= 11)
3640 output_asm_insn ("psha", operands);
3641 output_asm_insn ("tba", operands);
3642 output_asm_insn ("pulb", operands);
3646 /* If the shift is big, invert the rotation. */
3654 /* Set the carry to bit-15, but don't change D yet. */
3655 if (GET_MODE (operands[0]) != QImode)
3657 output_asm_insn ("asra", operands);
3658 output_asm_insn ("rola", operands);
3663 /* Rotate B first to move the carry to bit-0. */
3664 if (D_REG_P (operands[0]))
3665 output_asm_insn ("rolb", operands);
3667 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3668 output_asm_insn ("rola", operands);
3673 /* Set the carry to bit-8 of D. */
3674 if (val != 0 && GET_MODE (operands[0]) != QImode)
3676 output_asm_insn ("tap", operands);
3681 /* Rotate B first to move the carry to bit-7. */
3682 if (D_REG_P (operands[0]))
3683 output_asm_insn ("rorb", operands);
3685 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3686 output_asm_insn ("rora", operands);
3693 /* Store in cc_status the expressions that the condition codes will
3694 describe after execution of an instruction whose pattern is EXP.
3695 Do not alter them if the instruction would not alter the cc's. */
3698 m68hc11_notice_update_cc (exp, insn)
3700 rtx insn ATTRIBUTE_UNUSED;
3702 /* recognize SET insn's. */
3703 if (GET_CODE (exp) == SET)
3705 /* Jumps do not alter the cc's. */
3706 if (SET_DEST (exp) == pc_rtx)
3709 /* NOTE: most instructions don't affect the carry bit, but the
3710 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3711 the conditions.h header. */
3713 /* Function calls clobber the cc's. */
3714 else if (GET_CODE (SET_SRC (exp)) == CALL)
3719 /* Tests and compares set the cc's in predictable ways. */
3720 else if (SET_DEST (exp) == cc0_rtx)
3722 cc_status.flags = 0;
3723 cc_status.value1 = XEXP (exp, 0);
3724 cc_status.value2 = XEXP (exp, 1);
3728 /* All other instructions affect the condition codes. */
3729 cc_status.flags = 0;
3730 cc_status.value1 = XEXP (exp, 0);
3731 cc_status.value2 = XEXP (exp, 1);
3736 /* Default action if we haven't recognized something
3737 and returned earlier. */
3741 if (cc_status.value2 != 0)
3742 switch (GET_CODE (cc_status.value2))
3744 /* These logical operations can generate several insns.
3745 The flags are setup according to what is generated. */
3751 /* The (not ...) generates several 'com' instructions for
3752 non QImode. We have to invalidate the flags. */
3754 if (GET_MODE (cc_status.value2) != QImode)
3766 if (GET_MODE (cc_status.value2) != VOIDmode)
3767 cc_status.flags |= CC_NO_OVERFLOW;
3770 /* The asl sets the overflow bit in such a way that this
3771 makes the flags unusable for a next compare insn. */
3775 if (GET_MODE (cc_status.value2) != VOIDmode)
3776 cc_status.flags |= CC_NO_OVERFLOW;
3779 /* A load/store instruction does not affect the carry. */
3784 cc_status.flags |= CC_NO_OVERFLOW;
3790 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3792 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3793 cc_status.value2 = 0;
3796 /* The current instruction does not affect the flags but changes
3797 the register 'reg'. See if the previous flags can be kept for the
3798 next instruction to avoid a comparison. */
3800 m68hc11_notice_keep_cc (reg)
3804 || cc_prev_status.value1 == 0
3805 || rtx_equal_p (reg, cc_prev_status.value1)
3806 || (cc_prev_status.value2
3807 && reg_mentioned_p (reg, cc_prev_status.value2)))
3810 cc_status = cc_prev_status;
3815 /* Machine Specific Reorg. */
3817 /* Z register replacement:
3819 GCC treats the Z register as an index base address register like
3820 X or Y. In general, it uses it during reload to compute the address
3821 of some operand. This helps the reload pass to avoid to fall into the
3822 register spill failure.
3824 The Z register is in the A_REGS class. In the machine description,
3825 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3827 It can appear everywhere an X or Y register can appear, except for
3828 some templates in the clobber section (when a clobber of X or Y is asked).
3829 For a given instruction, the template must ensure that no more than
3830 2 'A' registers are used. Otherwise, the register replacement is not
3833 To replace the Z register, the algorithm is not terrific:
3834 1. Insns that do not use the Z register are not changed
3835 2. When a Z register is used, we scan forward the insns to see
3836 a potential register to use: either X or Y and sometimes D.
3837 We stop when a call, a label or a branch is seen, or when we
3838 detect that both X and Y are used (probably at different times, but it does
3840 3. The register that will be used for the replacement of Z is saved
3841 in a .page0 register or on the stack. If the first instruction that
3842 used Z, uses Z as an input, the value is loaded from another .page0
3843 register. The replacement register is pushed on the stack in the
3844 rare cases where a compare insn uses Z and we couldn't find if X/Y
3846 4. The Z register is replaced in all instructions until we reach
3847 the end of the Z-block, as detected by step 2.
3848 5. If we detect that Z is still alive, its value is saved.
3849 If the replacement register is alive, its old value is loaded.
3851 The Z register can be disabled with -ffixed-z.
3861 int must_restore_reg;
3872 int save_before_last;
3873 int z_loaded_with_sp;
3876 static rtx z_reg_qi;
3878 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
3879 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
3880 static void m68hc11_z_replacement PARAMS ((rtx));
3881 static void m68hc11_reassign_regs PARAMS ((rtx));
3883 int z_replacement_completed = 0;
3885 /* Analyze the insn to find out which replacement register to use and
3886 the boundaries of the replacement.
3887 Returns 0 if we reached the last insn to be replaced, 1 if we can
3888 continue replacement in next insns. */
3891 m68hc11_check_z_replacement (insn, info)
3893 struct replace_info *info;
3895 int this_insn_uses_ix;
3896 int this_insn_uses_iy;
3897 int this_insn_uses_z;
3898 int this_insn_uses_z_in_dst;
3899 int this_insn_uses_d;
3903 /* A call is said to clobber the Z register, we don't need
3904 to save the value of Z. We also don't need to restore
3905 the replacement register (unless it is used by the call). */
3906 if (GET_CODE (insn) == CALL_INSN)
3908 body = PATTERN (insn);
3910 info->can_use_d = 0;
3912 /* If the call is an indirect call with Z, we have to use the
3913 Y register because X can be used as an input (D+X).
3914 We also must not save Z nor restore Y. */
3915 if (reg_mentioned_p (z_reg, body))
3917 insn = NEXT_INSN (insn);
3920 info->found_call = 1;
3921 info->must_restore_reg = 0;
3922 info->last = NEXT_INSN (insn);
3924 info->need_save_z = 0;
3927 if (GET_CODE (insn) == CODE_LABEL
3928 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
3931 if (GET_CODE (insn) == JUMP_INSN)
3933 if (reg_mentioned_p (z_reg, insn) == 0)
3936 info->can_use_d = 0;
3937 info->must_save_reg = 0;
3938 info->must_restore_reg = 0;
3939 info->need_save_z = 0;
3940 info->last = NEXT_INSN (insn);
3943 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
3948 /* Z register dies here. */
3949 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
3951 body = PATTERN (insn);
3952 if (GET_CODE (body) == SET)
3954 rtx src = XEXP (body, 1);
3955 rtx dst = XEXP (body, 0);
3957 /* Condition code is set here. We have to restore the X/Y and
3958 save into Z before any test/compare insn because once we save/restore
3959 we can change the condition codes. When the compare insn uses Z and
3960 we can't use X/Y, the comparison is made with the *ZREG soft register
3961 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3964 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
3965 || (GET_CODE (src) == COMPARE &&
3966 (rtx_equal_p (XEXP (src, 0), z_reg)
3967 || rtx_equal_p (XEXP (src, 1), z_reg))))
3969 if (insn == info->first)
3971 info->must_load_z = 0;
3972 info->must_save_reg = 0;
3973 info->must_restore_reg = 0;
3974 info->need_save_z = 0;
3975 info->found_call = 1;
3976 info->regno = SOFT_Z_REGNUM;
3981 if (reg_mentioned_p (z_reg, src) == 0)
3983 info->can_use_d = 0;
3987 if (insn != info->first)
3990 /* Compare insn which uses Z. We have to save/restore the X/Y
3991 register without modifying the condition codes. For this
3992 we have to use a push/pop insn. */
3993 info->must_push_reg = 1;
3997 /* Z reg is set to something new. We don't need to load it. */
4000 if (!reg_mentioned_p (z_reg, src))
4002 /* Z reg is used before being set. Treat this as
4003 a new sequence of Z register replacement. */
4004 if (insn != info->first)
4008 info->must_load_z = 0;
4010 info->z_set_count++;
4011 info->z_value = src;
4013 info->z_loaded_with_sp = 1;
4015 else if (reg_mentioned_p (z_reg, dst))
4016 info->can_use_d = 0;
4018 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4019 | reg_mentioned_p (d_reg, dst);
4020 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4021 | reg_mentioned_p (ix_reg, dst);
4022 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4023 | reg_mentioned_p (iy_reg, dst);
4024 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4026 /* If z is used as an address operand (like (MEM (reg z))),
4027 we can't replace it with d. */
4028 if (this_insn_uses_z && !Z_REG_P (src)
4029 && !(m68hc11_arith_operator (src, GET_MODE (src))
4030 && Z_REG_P (XEXP (src, 0))
4031 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4032 && insn == info->first
4033 && dead_register_here (insn, d_reg)))
4034 info->can_use_d = 0;
4036 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4037 if (TARGET_M6812 && !z_dies_here
4038 && ((this_insn_uses_z && side_effects_p (src))
4039 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4041 info->need_save_z = 1;
4042 info->z_set_count++;
4044 this_insn_uses_z |= this_insn_uses_z_in_dst;
4046 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4048 fatal_insn ("Registers IX, IY and Z used in the same INSN", insn);
4051 if (this_insn_uses_d)
4052 info->can_use_d = 0;
4054 /* IX and IY are used at the same time, we have to restore
4055 the value of the scratch register before this insn. */
4056 if (this_insn_uses_ix && this_insn_uses_iy)
4061 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4062 info->can_use_d = 0;
4064 if (info->x_used == 0 && this_insn_uses_ix)
4068 /* We have a (set (REG:HI X) (REG:HI Z)).
4069 Since we use Z as the replacement register, this insn
4070 is no longer necessary. We turn it into a note. We must
4071 not reload the old value of X. */
4072 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4076 info->need_save_z = 0;
4079 info->must_save_reg = 0;
4080 info->must_restore_reg = 0;
4081 info->found_call = 1;
4082 info->can_use_d = 0;
4083 PUT_CODE (insn, NOTE);
4084 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4085 NOTE_SOURCE_FILE (insn) = 0;
4086 info->last = NEXT_INSN (insn);
4091 && (rtx_equal_p (src, z_reg)
4092 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4096 info->need_save_z = 0;
4099 info->last = NEXT_INSN (insn);
4100 info->must_save_reg = 0;
4101 info->must_restore_reg = 0;
4103 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4104 && !reg_mentioned_p (ix_reg, src))
4109 info->need_save_z = 0;
4113 info->save_before_last = 1;
4115 info->must_restore_reg = 0;
4116 info->last = NEXT_INSN (insn);
4118 else if (info->can_use_d)
4120 info->last = NEXT_INSN (insn);
4126 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4127 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4129 info->need_save_z = 0;
4131 info->last = NEXT_INSN (insn);
4132 info->regno = HARD_X_REGNUM;
4133 info->must_save_reg = 0;
4134 info->must_restore_reg = 0;
4137 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4139 info->regno = HARD_X_REGNUM;
4140 info->must_restore_reg = 0;
4141 info->must_save_reg = 0;
4145 if (info->y_used == 0 && this_insn_uses_iy)
4149 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4153 info->need_save_z = 0;
4156 info->must_save_reg = 0;
4157 info->must_restore_reg = 0;
4158 info->found_call = 1;
4159 info->can_use_d = 0;
4160 PUT_CODE (insn, NOTE);
4161 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4162 NOTE_SOURCE_FILE (insn) = 0;
4163 info->last = NEXT_INSN (insn);
4168 && (rtx_equal_p (src, z_reg)
4169 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4174 info->need_save_z = 0;
4176 info->last = NEXT_INSN (insn);
4177 info->must_save_reg = 0;
4178 info->must_restore_reg = 0;
4180 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4181 && !reg_mentioned_p (iy_reg, src))
4186 info->need_save_z = 0;
4190 info->save_before_last = 1;
4192 info->must_restore_reg = 0;
4193 info->last = NEXT_INSN (insn);
4195 else if (info->can_use_d)
4197 info->last = NEXT_INSN (insn);
4204 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4205 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4207 info->need_save_z = 0;
4209 info->last = NEXT_INSN (insn);
4210 info->regno = HARD_Y_REGNUM;
4211 info->must_save_reg = 0;
4212 info->must_restore_reg = 0;
4215 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4217 info->regno = HARD_Y_REGNUM;
4218 info->must_restore_reg = 0;
4219 info->must_save_reg = 0;
4225 info->need_save_z = 0;
4227 if (info->last == 0)
4228 info->last = NEXT_INSN (insn);
4231 return info->last != NULL_RTX ? 0 : 1;
4233 if (GET_CODE (body) == PARALLEL)
4236 char ix_clobber = 0;
4237 char iy_clobber = 0;
4239 this_insn_uses_iy = 0;
4240 this_insn_uses_ix = 0;
4241 this_insn_uses_z = 0;
4243 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4246 int uses_ix, uses_iy, uses_z;
4248 x = XVECEXP (body, 0, i);
4250 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4251 info->can_use_d = 0;
4253 uses_ix = reg_mentioned_p (ix_reg, x);
4254 uses_iy = reg_mentioned_p (iy_reg, x);
4255 uses_z = reg_mentioned_p (z_reg, x);
4256 if (GET_CODE (x) == CLOBBER)
4258 ix_clobber |= uses_ix;
4259 iy_clobber |= uses_iy;
4260 z_clobber |= uses_z;
4264 this_insn_uses_ix |= uses_ix;
4265 this_insn_uses_iy |= uses_iy;
4266 this_insn_uses_z |= uses_z;
4268 if (uses_z && GET_CODE (x) == SET)
4270 rtx dst = XEXP (x, 0);
4273 info->z_set_count++;
4275 if (TARGET_M6812 && uses_z && side_effects_p (x))
4276 info->need_save_z = 1;
4279 info->need_save_z = 0;
4283 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4284 this_insn_uses_ix, this_insn_uses_iy,
4285 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4288 if (this_insn_uses_z)
4289 info->can_use_d = 0;
4291 if (z_clobber && info->first != insn)
4293 info->need_save_z = 0;
4297 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4299 if (this_insn_uses_z == 0 && insn == info->first)
4301 info->must_load_z = 0;
4303 if (dead_register_here (insn, d_reg))
4305 info->regno = HARD_D_REGNUM;
4306 info->must_save_reg = 0;
4307 info->must_restore_reg = 0;
4309 else if (dead_register_here (insn, ix_reg))
4311 info->regno = HARD_X_REGNUM;
4312 info->must_save_reg = 0;
4313 info->must_restore_reg = 0;
4315 else if (dead_register_here (insn, iy_reg))
4317 info->regno = HARD_Y_REGNUM;
4318 info->must_save_reg = 0;
4319 info->must_restore_reg = 0;
4321 if (info->regno >= 0)
4323 info->last = NEXT_INSN (insn);
4326 if (this_insn_uses_ix == 0)
4328 info->regno = HARD_X_REGNUM;
4329 info->must_save_reg = 1;
4330 info->must_restore_reg = 1;
4332 else if (this_insn_uses_iy == 0)
4334 info->regno = HARD_Y_REGNUM;
4335 info->must_save_reg = 1;
4336 info->must_restore_reg = 1;
4340 info->regno = HARD_D_REGNUM;
4341 info->must_save_reg = 1;
4342 info->must_restore_reg = 1;
4344 info->last = NEXT_INSN (insn);
4348 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4349 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4351 if (this_insn_uses_z)
4353 if (info->y_used == 0 && iy_clobber)
4355 info->regno = HARD_Y_REGNUM;
4356 info->must_save_reg = 0;
4357 info->must_restore_reg = 0;
4359 info->last = NEXT_INSN (insn);
4360 info->save_before_last = 1;
4364 if (this_insn_uses_ix && this_insn_uses_iy)
4366 if (this_insn_uses_z)
4368 fatal_insn ("Cannot do z-register replacement", insn);
4372 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4379 if (iy_clobber || z_clobber)
4381 info->last = NEXT_INSN (insn);
4382 info->save_before_last = 1;
4387 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4394 if (ix_clobber || z_clobber)
4396 info->last = NEXT_INSN (insn);
4397 info->save_before_last = 1;
4404 info->need_save_z = 0;
4408 if (GET_CODE (body) == CLOBBER)
4411 /* IX and IY are used at the same time, we have to restore
4412 the value of the scratch register before this insn. */
4413 if (this_insn_uses_ix && this_insn_uses_iy)
4417 if (info->x_used == 0 && this_insn_uses_ix)
4425 if (info->y_used == 0 && this_insn_uses_iy)
4439 m68hc11_find_z_replacement (insn, info)
4441 struct replace_info *info;
4445 info->replace_reg = NULL_RTX;
4446 info->must_load_z = 1;
4447 info->need_save_z = 1;
4448 info->must_save_reg = 1;
4449 info->must_restore_reg = 1;
4453 info->can_use_d = TARGET_M6811 ? 1 : 0;
4454 info->found_call = 0;
4458 info->z_set_count = 0;
4459 info->z_value = NULL_RTX;
4460 info->must_push_reg = 0;
4461 info->save_before_last = 0;
4462 info->z_loaded_with_sp = 0;
4464 /* Scan the insn forward to find an address register that is not used.
4466 - the flow of the program changes,
4467 - when we detect that both X and Y are necessary,
4468 - when the Z register dies,
4469 - when the condition codes are set. */
4471 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4473 if (m68hc11_check_z_replacement (insn, info) == 0)
4477 /* May be we can use Y or X if they contain the same value as Z.
4478 This happens very often after the reload. */
4479 if (info->z_set_count == 1)
4481 rtx p = info->first;
4486 v = find_last_value (iy_reg, &p, insn, 1);
4488 else if (info->y_used)
4490 v = find_last_value (ix_reg, &p, insn, 1);
4492 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4495 info->regno = HARD_Y_REGNUM;
4497 info->regno = HARD_X_REGNUM;
4498 info->must_load_z = 0;
4499 info->must_save_reg = 0;
4500 info->must_restore_reg = 0;
4501 info->found_call = 1;
4504 if (info->z_set_count == 0)
4505 info->need_save_z = 0;
4508 info->need_save_z = 0;
4510 if (info->last == 0)
4513 if (info->regno >= 0)
4516 info->replace_reg = gen_rtx (REG, HImode, reg);
4518 else if (info->can_use_d)
4520 reg = HARD_D_REGNUM;
4521 info->replace_reg = d_reg;
4523 else if (info->x_used)
4525 reg = HARD_Y_REGNUM;
4526 info->replace_reg = iy_reg;
4530 reg = HARD_X_REGNUM;
4531 info->replace_reg = ix_reg;
4535 if (info->must_save_reg && info->must_restore_reg)
4537 if (insn && dead_register_here (insn, info->replace_reg))
4539 info->must_save_reg = 0;
4540 info->must_restore_reg = 0;
4545 /* The insn uses the Z register. Find a replacement register for it
4546 (either X or Y) and replace it in the insn and the next ones until
4547 the flow changes or the replacement register is used. Instructions
4548 are emited before and after the Z-block to preserve the value of
4549 Z and of the replacement register. */
4552 m68hc11_z_replacement (insn)
4557 struct replace_info info;
4559 /* Find trivial case where we only need to replace z with the
4560 equivalent soft register. */
4561 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4563 rtx body = PATTERN (insn);
4564 rtx src = XEXP (body, 1);
4565 rtx dst = XEXP (body, 0);
4567 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4569 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4572 else if (Z_REG_P (src)
4573 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4575 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4578 else if (D_REG_P (dst)
4579 && m68hc11_arith_operator (src, GET_MODE (src))
4580 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4582 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4585 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4586 && INTVAL (src) == 0)
4588 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4589 /* Force it to be re-recognized. */
4590 INSN_CODE (insn) = -1;
4595 m68hc11_find_z_replacement (insn, &info);
4597 replace_reg = info.replace_reg;
4598 replace_reg_qi = NULL_RTX;
4600 /* Save the X register in a .page0 location. */
4601 if (info.must_save_reg && !info.must_push_reg)
4605 if (info.must_push_reg && 0)
4606 dst = gen_rtx (MEM, HImode,
4607 gen_rtx (PRE_DEC, HImode,
4608 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4610 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4612 emit_insn_before (gen_movhi (dst,
4613 gen_rtx (REG, HImode, info.regno)), insn);
4615 if (info.must_load_z && !info.must_push_reg)
4617 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4618 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4623 /* Replace all occurence of Z by replace_reg.
4624 Stop when the last instruction to replace is reached.
4625 Also stop when we detect a change in the flow (but it's not
4626 necessary; just safeguard). */
4628 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4632 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4635 if (GET_CODE (insn) != INSN
4636 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4639 body = PATTERN (insn);
4640 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4641 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4643 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4645 printf ("Reg mentioned here...:\n");
4650 /* Stack pointer was decremented by 2 due to the push.
4651 Correct that by adding 2 to the destination. */
4652 if (info.must_push_reg
4653 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4657 src = SET_SRC (body);
4658 dst = SET_DEST (body);
4659 if (SP_REG_P (src) && Z_REG_P (dst))
4661 emit_insn_after (gen_addhi3 (dst,
4664 VOIDmode, 2)), insn);
4668 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4669 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4671 INSN_CODE (insn) = -1;
4672 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4673 fatal_insn ("Cannot do z-register replacement", insn);
4676 /* Likewise for (REG:QI Z). */
4677 if (reg_mentioned_p (z_reg, insn))
4679 if (replace_reg_qi == NULL_RTX)
4680 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4681 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4684 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4688 /* Save Z before restoring the old value. */
4689 if (insn && info.need_save_z && !info.must_push_reg)
4691 rtx save_pos_insn = insn;
4693 /* If Z is clobber by the last insn, we have to save its value
4694 before the last instruction. */
4695 if (info.save_before_last)
4696 save_pos_insn = PREV_INSN (save_pos_insn);
4698 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4699 gen_rtx (REG, HImode, info.regno)),
4703 if (info.must_push_reg && info.last)
4707 body = PATTERN (info.last);
4708 new_body = gen_rtx (PARALLEL, VOIDmode,
4710 gen_rtx (USE, VOIDmode,
4712 gen_rtx (USE, VOIDmode,
4713 gen_rtx (REG, HImode,
4715 PATTERN (info.last) = new_body;
4717 /* Force recognition on insn since we changed it. */
4718 INSN_CODE (insn) = -1;
4720 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4722 fatal_insn ("Invalid Z register replacement for insn", insn);
4724 insn = NEXT_INSN (info.last);
4727 /* Restore replacement register unless it was died. */
4728 if (insn && info.must_restore_reg && !info.must_push_reg)
4732 if (info.must_push_reg && 0)
4733 dst = gen_rtx (MEM, HImode,
4734 gen_rtx (POST_INC, HImode,
4735 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4737 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4739 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4746 /* Scan all the insn and re-affects some registers
4747 - The Z register (if it was used), is affected to X or Y depending
4748 on the instruction. */
4751 m68hc11_reassign_regs (first)
4756 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
4757 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
4758 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4759 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
4761 /* Scan all insns to replace Z by X or Y preserving the old value
4762 of X/Y and restoring it afterward. */
4764 for (insn = first; insn; insn = NEXT_INSN (insn))
4768 if (GET_CODE (insn) == CODE_LABEL
4769 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4772 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4775 body = PATTERN (insn);
4776 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4779 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4780 || GET_CODE (body) == ASM_OPERANDS
4781 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4784 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4785 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4788 /* If Z appears in this insn, replace it in the current insn
4789 and the next ones until the flow changes or we have to
4790 restore back the replacement register. */
4792 if (reg_mentioned_p (z_reg, body))
4794 m68hc11_z_replacement (insn);
4799 printf ("Insn not handled by Z replacement:\n");
4808 m68hc11_reorg (first)
4814 z_replacement_completed = 0;
4815 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4817 /* Some RTX are shared at this point. This breaks the Z register
4818 replacement, unshare everything. */
4819 unshare_all_rtl_again (first);
4821 /* Force a split of all splitable insn. This is necessary for the
4822 Z register replacement mechanism because we end up with basic insns. */
4823 split_all_insns_noflow ();
4826 z_replacement_completed = 1;
4827 m68hc11_reassign_regs (first);
4829 /* After some splitting, there are some oportunities for CSE pass.
4830 This happens quite often when 32-bit or above patterns are split. */
4831 if (optimize > 0 && split_done)
4832 reload_cse_regs (first);
4834 /* Re-create the REG_DEAD notes. These notes are used in the machine
4835 description to use the best assembly directives. */
4838 /* Before recomputing the REG_DEAD notes, remove all of them.
4839 This is necessary because the reload_cse_regs() pass can
4840 have replaced some (MEM) with a register. In that case,
4841 the REG_DEAD that could exist for that register may become
4843 for (insn = first; insn; insn = NEXT_INSN (insn))
4849 pnote = ®_NOTES (insn);
4852 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
4853 *pnote = XEXP (*pnote, 1);
4855 pnote = &XEXP (*pnote, 1);
4860 find_basic_blocks (first, max_reg_num (), 0);
4861 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
4864 z_replacement_completed = 2;
4866 /* If optimizing, then go ahead and split insns that must be
4867 split after Z register replacement. This gives more opportunities
4868 for peephole (in particular for consecutives xgdx/xgdy). */
4870 split_all_insns_noflow ();
4872 /* Once insns are split after the z_replacement_completed == 2,
4873 we must not re-run the life_analysis. The xgdx/xgdy patterns
4874 are not recognized and the life_analysis pass removes some
4875 insns because it thinks some (SETs) are noops or made to dead
4876 stores (which is false due to the swap).
4878 Do a simple pass to eliminate the noop set that the final
4879 split could generate (because it was easier for split definition). */
4883 for (insn = first; insn; insn = NEXT_INSN (insn))
4887 if (INSN_DELETED_P (insn))
4889 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4892 /* Remove the (set (R) (R)) insns generated by some splits. */
4893 body = PATTERN (insn);
4894 if (GET_CODE (body) == SET
4895 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
4897 PUT_CODE (insn, NOTE);
4898 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4899 NOTE_SOURCE_FILE (insn) = 0;
4907 /* Cost functions. */
4909 /* Cost of moving memory. */
4911 m68hc11_memory_move_cost (mode, class, in)
4912 enum machine_mode mode;
4913 enum reg_class class;
4914 int in ATTRIBUTE_UNUSED;
4916 if (class <= H_REGS)
4918 if (GET_MODE_SIZE (mode) <= 2)
4919 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4921 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
4925 if (GET_MODE_SIZE (mode) <= 2)
4926 return COSTS_N_INSNS (2);
4928 return COSTS_N_INSNS (4);
4933 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4934 Reload does not check the constraint of set insns when the two registers
4935 have a move cost of 2. Setting a higher cost will force reload to check
4938 m68hc11_register_move_cost (from, to)
4939 enum reg_class from;
4942 if (from >= S_REGS && to >= S_REGS)
4944 return COSTS_N_INSNS (3);
4946 if (from <= S_REGS && to <= S_REGS)
4948 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4950 return COSTS_N_INSNS (2);
4954 /* Provide the costs of an addressing mode that contains ADDR.
4955 If ADDR is not a valid address, its cost is irrelevant. */
4958 m68hc11_address_cost (addr)
4963 switch (GET_CODE (addr))
4966 /* Make the cost of hard registers and specially SP, FP small. */
4967 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
4984 register rtx plus0 = XEXP (addr, 0);
4985 register rtx plus1 = XEXP (addr, 1);
4987 if (GET_CODE (plus0) != REG)
4990 switch (GET_CODE (plus1))
4993 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
4994 || INTVAL (plus1) < m68hc11_min_offset)
4996 else if (INTVAL (plus1) >= m68hc11_max_offset)
5000 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5022 if (SP_REG_P (XEXP (addr, 0)))
5031 printf ("Address cost: %d for :", cost);
5040 m68hc11_shift_cost (mode, x, shift)
5041 enum machine_mode mode;
5047 total = rtx_cost (x, SET);
5049 total += m68hc11_cost->shiftQI_const[shift % 8];
5050 else if (mode == HImode)
5051 total += m68hc11_cost->shiftHI_const[shift % 16];
5052 else if (shift == 8 || shift == 16 || shift == 32)
5053 total += m68hc11_cost->shiftHI_const[8];
5054 else if (shift != 0 && shift != 16 && shift != 32)
5056 total += m68hc11_cost->shiftHI_const[1] * shift;
5059 /* For SI and others, the cost is higher. */
5060 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5061 total *= GET_MODE_SIZE (mode) / 2;
5063 /* When optimizing for size, make shift more costly so that
5064 multiplications are preferred. */
5065 if (optimize_size && (shift % 8) != 0)
5072 m68hc11_rtx_costs (x, code, outer_code)
5075 enum rtx_code outer_code ATTRIBUTE_UNUSED;
5077 enum machine_mode mode = GET_MODE (x);
5088 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5090 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5093 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5094 total += m68hc11_cost->shift_var;
5100 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5101 total += m68hc11_cost->logical;
5103 /* Logical instructions are byte instructions only. */
5104 total *= GET_MODE_SIZE (mode);
5109 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5110 total += m68hc11_cost->add;
5111 if (GET_MODE_SIZE (mode) > 2)
5113 total *= GET_MODE_SIZE (mode) / 2;
5120 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5124 total += m68hc11_cost->divQI;
5128 total += m68hc11_cost->divHI;
5133 total += m68hc11_cost->divSI;
5139 /* mul instruction produces 16-bit result. */
5140 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5141 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5142 return m68hc11_cost->multQI
5143 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5144 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5146 /* emul instruction produces 32-bit result for 68HC12. */
5147 if (TARGET_M6812 && mode == SImode
5148 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5149 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5150 return m68hc11_cost->multHI
5151 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5152 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5154 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5158 total += m68hc11_cost->multQI;
5162 total += m68hc11_cost->multHI;
5167 total += m68hc11_cost->multSI;
5174 extra_cost = COSTS_N_INSNS (2);
5181 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5184 return total + COSTS_N_INSNS (1);
5188 return total + COSTS_N_INSNS (2);
5192 return total + COSTS_N_INSNS (4);
5194 return total + COSTS_N_INSNS (8);
5197 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5198 return COSTS_N_INSNS (1);
5200 return COSTS_N_INSNS (1);
5203 return COSTS_N_INSNS (4);
5208 /* print_options - called at the start of the code generation for a
5211 extern char *asm_file_name;
5214 #include <sys/types.h>
5223 extern int save_argc;
5224 extern char **save_argv;
5226 fprintf (out, ";;; Command:\t");
5227 for (i = 0; i < save_argc; i++)
5229 fprintf (out, "%s", save_argv[i]);
5230 if (i + 1 < save_argc)
5233 fprintf (out, "\n");
5235 a_time = ctime (&c_time);
5236 fprintf (out, ";;; Compiled:\t%s", a_time);
5239 #define __VERSION__ "[unknown]"
5241 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
5243 fprintf (out, ";;; (META)compiled by CC.\n");
5248 m68hc11_asm_file_start (out, main_file)
5250 const char *main_file;
5252 fprintf (out, ";;;-----------------------------------------\n");
5253 fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
5254 fprintf (out, ";;; gcc compiler %s\n", version_string);
5255 print_options (out);
5256 fprintf (out, ";;;-----------------------------------------\n");
5257 output_file_directive (out, main_file);
5262 m68hc11_add_gc_roots ()
5264 ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
5265 ggc_add_rtx_root (&ix_reg, 1);
5266 ggc_add_rtx_root (&iy_reg, 1);
5267 ggc_add_rtx_root (&d_reg, 1);
5268 ggc_add_rtx_root (&da_reg, 1);
5269 ggc_add_rtx_root (&z_reg, 1);
5270 ggc_add_rtx_root (&z_reg_qi, 1);
5271 ggc_add_rtx_root (&stack_push_word, 1);
5272 ggc_add_rtx_root (&stack_pop_word, 1);
5276 m68hc11_asm_out_constructor (symbol, priority)
5280 default_ctor_section_asm_out_constructor (symbol, priority);
5281 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5285 m68hc11_asm_out_destructor (symbol, priority)
5289 default_dtor_section_asm_out_destructor (symbol, priority);
5290 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");