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"
56 #include "target-def.h"
58 static void print_options PARAMS ((FILE *));
59 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
60 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
61 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
62 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
64 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
65 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
66 static int must_parenthesize PARAMS ((rtx));
67 static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
68 static int m68hc11_auto_inc_p PARAMS ((rtx));
69 static int m68hc11_valid_type_attribute_p PARAMS((tree, tree,
72 void create_regs_rtx PARAMS ((void));
73 static void m68hc11_add_gc_roots PARAMS ((void));
75 static void asm_print_register PARAMS ((FILE *, int));
76 static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
78 rtx m68hc11_soft_tmp_reg;
80 /* Must be set to 1 to produce debug messages. */
83 extern FILE *asm_out_file;
91 static int regs_inited = 0;
94 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
95 int current_function_interrupt;
97 /* Set to 1 by expand_prologue() when the function is a trap handler. */
98 int current_function_trap;
100 /* Min offset that is valid for the indirect addressing mode. */
101 HOST_WIDE_INT m68hc11_min_offset = 0;
103 /* Max offset that is valid for the indirect addressing mode. */
104 HOST_WIDE_INT m68hc11_max_offset = 256;
106 /* The class value for base registers. */
107 enum reg_class m68hc11_base_reg_class = A_REGS;
109 /* The class value for index registers. This is NO_REGS for 68HC11. */
110 enum reg_class m68hc11_index_reg_class = NO_REGS;
112 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
114 /* Tables that tell whether a given hard register is valid for
115 a base or an index register. It is filled at init time depending
116 on the target processor. */
117 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
118 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
120 /* A correction offset which is applied to the stack pointer.
121 This is 1 for 68HC11 and 0 for 68HC12. */
122 int m68hc11_sp_correction;
124 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
125 rtx m68hc11_compare_op0;
126 rtx m68hc11_compare_op1;
129 struct processor_costs *m68hc11_cost;
131 /* Costs for a 68HC11. */
132 struct processor_costs m6811_cost = {
137 /* non-constant shift */
140 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
141 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
142 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
145 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
146 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
147 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
148 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
149 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
150 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
155 COSTS_N_INSNS (20 * 4),
157 COSTS_N_INSNS (20 * 16),
166 /* Costs for a 68HC12. */
167 struct processor_costs m6812_cost = {
172 /* non-constant shift */
175 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
176 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
177 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
180 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
181 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
182 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
183 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
184 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
185 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
192 COSTS_N_INSNS (3 * 4),
201 /* Machine specific options */
203 const char *m68hc11_regparm_string;
204 const char *m68hc11_reg_alloc_order;
205 const char *m68hc11_soft_reg_count;
207 static int nb_soft_regs;
209 /* Initialize the GCC target structure. */
210 #undef TARGET_VALID_TYPE_ATTRIBUTE
211 #define TARGET_VALID_TYPE_ATTRIBUTE m68hc11_valid_type_attribute_p
213 #undef TARGET_ASM_FUNCTION_EPILOGUE
214 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
216 struct gcc_target targetm = TARGET_INITIALIZER;
219 m68hc11_override_options ()
221 m68hc11_add_gc_roots ();
223 memset (m68hc11_reg_valid_for_index, 0,
224 sizeof (m68hc11_reg_valid_for_index));
225 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
227 /* Compilation with -fpic generates a wrong code. */
230 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
231 (flag_pic > 1) ? "PIC" : "pic");
235 /* Configure for a 68hc11 processor. */
238 /* If gcc was built for a 68hc12, invalidate that because
239 a -m68hc11 option was specified on the command line. */
240 if (TARGET_DEFAULT != MASK_M6811)
241 target_flags &= ~TARGET_DEFAULT;
243 m68hc11_cost = &m6811_cost;
244 m68hc11_min_offset = 0;
245 m68hc11_max_offset = 256;
246 m68hc11_index_reg_class = NO_REGS;
247 m68hc11_base_reg_class = A_REGS;
248 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
249 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
250 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
251 m68hc11_sp_correction = 1;
252 m68hc11_tmp_regs_class = D_REGS;
253 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
254 m68hc11_soft_reg_count = "4";
257 /* Configure for a 68hc12 processor. */
260 m68hc11_cost = &m6812_cost;
261 m68hc11_min_offset = -65536;
262 m68hc11_max_offset = 65536;
263 m68hc11_index_reg_class = D_REGS;
264 m68hc11_base_reg_class = A_OR_SP_REGS;
265 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
266 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
267 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
268 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
269 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
270 m68hc11_sp_correction = 0;
271 m68hc11_tmp_regs_class = TMP_REGS;
272 target_flags &= ~MASK_M6811;
273 if (m68hc11_soft_reg_count == 0)
274 m68hc11_soft_reg_count = "2";
281 m68hc11_conditional_register_usage ()
284 int cnt = atoi (m68hc11_soft_reg_count);
288 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
289 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
292 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
295 call_used_regs[i] = 1;
300 /* Reload and register operations. */
302 static const char *reg_class_names[] = REG_CLASS_NAMES;
308 /* regs_inited = 1; */
309 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
310 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
311 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
312 da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
313 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
315 stack_push_word = gen_rtx (MEM, HImode,
316 gen_rtx (PRE_DEC, HImode,
317 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
318 stack_pop_word = gen_rtx (MEM, HImode,
319 gen_rtx (POST_INC, HImode,
320 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
324 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
325 - 8 bit values are stored anywhere (except the SP register).
326 - 16 bit values can be stored in any register whose mode is 16
327 - 32 bit values can be stored in D, X registers or in a soft register
328 (except the last one because we need 2 soft registers)
329 - Values whose size is > 32 bit are not stored in real hard
330 registers. They may be stored in soft registers if there are
333 hard_regno_mode_ok (regno, mode)
335 enum machine_mode mode;
337 switch (GET_MODE_SIZE (mode))
340 return S_REGNO_P (regno) && nb_soft_regs >= 4;
343 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
346 return G_REGNO_P (regno);
349 /* We have to accept a QImode in X or Y registers. Otherwise, the
350 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
351 in the insns. Reload fails if the insn rejects the register class 'a'
352 as well as if it accepts it. Patterns that failed were
353 zero_extend_qihi2 and iorqi3. */
355 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
363 preferred_reload_class (operand, class)
365 enum reg_class class;
367 enum machine_mode mode;
369 mode = GET_MODE (operand);
373 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
376 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
377 return m68hc11_base_reg_class;
379 if (class >= S_REGS && (GET_CODE (operand) == MEM
380 || GET_CODE (operand) == CONST_INT))
382 /* S_REGS class must not be used. The movhi template does not
383 work to move a memory to a soft register.
384 Restrict to a hard reg. */
389 case D_OR_A_OR_S_REGS:
395 case D_OR_SP_OR_S_REGS:
396 class = D_OR_SP_REGS;
398 case D_OR_Y_OR_S_REGS:
401 case D_OR_X_OR_S_REGS:
417 else if (class == Y_REGS && GET_CODE (operand) == MEM)
421 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
425 else if (class >= S_REGS && S_REG_P (operand))
431 case D_OR_A_OR_S_REGS:
437 case D_OR_SP_OR_S_REGS:
438 class = D_OR_SP_REGS;
440 case D_OR_Y_OR_S_REGS:
443 case D_OR_X_OR_S_REGS:
459 else if (class >= S_REGS)
463 printf ("Class = %s for: ", reg_class_names[class]);
471 printf (" => class=%s\n", reg_class_names[class]);
479 /* Return 1 if the operand is a valid indexed addressing mode.
480 For 68hc11: n,r with n in [0..255] and r in A_REGS class
481 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
483 register_indirect_p (operand, mode, strict)
485 enum machine_mode mode;
490 switch (GET_CODE (operand))
496 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
497 return register_indirect_p (XEXP (operand, 0), mode, strict);
501 base = XEXP (operand, 0);
502 if (GET_CODE (base) == MEM)
505 offset = XEXP (operand, 1);
506 if (GET_CODE (offset) == MEM)
509 if (GET_CODE (base) == REG)
511 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
517 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
519 if (GET_CODE (offset) == REG)
521 if (!VALID_CONSTANT_OFFSET_P (base, mode))
527 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
532 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
539 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
540 a 68HC12 1-byte index addressing mode. */
542 m68hc11_small_indexed_indirect_p (operand, mode)
544 enum machine_mode mode;
548 if (GET_CODE (operand) != MEM)
551 operand = XEXP (operand, 0);
552 if (CONSTANT_ADDRESS_P (operand))
555 if (PUSH_POP_ADDRESS_P (operand))
558 if (!register_indirect_p (operand, mode,
559 (reload_completed | reload_in_progress)))
562 if (TARGET_M6812 && GET_CODE (operand) == PLUS
563 && (reload_completed | reload_in_progress))
565 base = XEXP (operand, 0);
566 offset = XEXP (operand, 1);
567 if (GET_CODE (base) == CONST_INT)
570 switch (GET_MODE_SIZE (mode))
573 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
578 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
583 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
592 m68hc11_register_indirect_p (operand, mode)
594 enum machine_mode mode;
596 if (GET_CODE (operand) != MEM)
599 operand = XEXP (operand, 0);
600 return register_indirect_p (operand, mode,
601 (reload_completed | reload_in_progress));
605 go_if_legitimate_address_internal (operand, mode, strict)
607 enum machine_mode mode;
610 if (CONSTANT_ADDRESS_P (operand))
612 /* Reject the global variables if they are too wide. This forces
613 a load of their address in a register and generates smaller code. */
614 if (GET_MODE_SIZE (mode) == 8)
619 if (register_indirect_p (operand, mode, strict))
623 if (PUSH_POP_ADDRESS_P (operand))
627 if (symbolic_memory_operand (operand, mode))
635 m68hc11_go_if_legitimate_address (operand, mode, strict)
637 enum machine_mode mode;
644 printf ("Checking: ");
649 result = go_if_legitimate_address_internal (operand, mode, strict);
653 printf (" -> %s\n", result == 0 ? "NO" : "YES");
660 printf ("go_if_legitimate%s, ret 0: %d:",
661 (strict ? "_strict" : ""), mode);
670 m68hc11_legitimize_address (operand, old_operand, mode)
671 rtx *operand ATTRIBUTE_UNUSED;
672 rtx old_operand ATTRIBUTE_UNUSED;
673 enum machine_mode mode ATTRIBUTE_UNUSED;
680 m68hc11_reload_operands (operands)
683 enum machine_mode mode;
685 if (regs_inited == 0)
688 mode = GET_MODE (operands[1]);
690 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
691 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
693 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
694 rtx base = XEXP (XEXP (operands[1], 0), 0);
696 if (GET_CODE (base) != REG)
703 /* If the offset is out of range, we have to compute the address
704 with a separate add instruction. We try to do with with an 8-bit
705 add on the A register. This is possible only if the lowest part
706 of the offset (ie, big_offset % 256) is a valid constant offset
707 with respect to the mode. If it's not, we have to generate a
708 16-bit add on the D register. From:
710 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
714 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
715 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
716 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
717 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
719 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
720 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
723 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
726 rtx reg = operands[0];
728 int val = INTVAL (big_offset);
731 /* We use the 'operands[0]' as a scratch register to compute the
732 address. Make sure 'base' is in that register. */
733 if (!rtx_equal_p (base, operands[0]))
735 emit_move_insn (reg, base);
745 vh = (val >> 8) & 0x0FF;
749 /* Create the lowest part offset that still remains to be added.
750 If it's not a valid offset, do a 16-bit add. */
751 offset = gen_rtx (CONST_INT, VOIDmode, vl);
752 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
754 emit_insn (gen_rtx (SET, VOIDmode, reg,
755 gen_rtx (PLUS, HImode, reg, big_offset)));
760 emit_insn (gen_rtx (SET, VOIDmode, reg,
761 gen_rtx (PLUS, HImode, reg,
763 VOIDmode, vh << 8))));
765 emit_move_insn (operands[0],
766 gen_rtx (MEM, GET_MODE (operands[1]),
767 gen_rtx (PLUS, Pmode, reg, offset)));
772 /* Use the normal gen_movhi pattern. */
777 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
780 enum machine_mode dmode;
781 enum machine_mode smode;
791 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
795 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
796 dmode, 1, operands[1], smode);
797 equiv = gen_rtx (code, dmode, operands[1]);
801 ret = emit_library_call_value (libcall, NULL_RTX,
803 operands[1], smode, operands[2],
805 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
812 insns = get_insns ();
814 emit_libcall_block (insns, operands[0], ret, equiv);
817 /* Returns true if X is a PRE/POST increment decrement
818 (same as auto_inc_p() in rtlanal.c but do not take into
819 account the stack). */
821 m68hc11_auto_inc_p (x)
824 return GET_CODE (x) == PRE_DEC
825 || GET_CODE (x) == POST_INC
826 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
830 /* Predicates for machine description. */
833 memory_reload_operand (operand, mode)
835 enum machine_mode mode ATTRIBUTE_UNUSED;
837 return GET_CODE (operand) == MEM
838 && GET_CODE (XEXP (operand, 0)) == PLUS
839 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
840 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
841 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
842 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
846 tst_operand (operand, mode)
848 enum machine_mode mode;
850 if (GET_CODE (operand) == MEM)
852 rtx addr = XEXP (operand, 0);
853 if (m68hc11_auto_inc_p (addr))
856 return nonimmediate_operand (operand, mode);
860 cmp_operand (operand, mode)
862 enum machine_mode mode;
864 if (GET_CODE (operand) == MEM)
866 rtx addr = XEXP (operand, 0);
867 if (m68hc11_auto_inc_p (addr))
870 return general_operand (operand, mode);
874 non_push_operand (operand, mode)
876 enum machine_mode mode;
878 if (general_operand (operand, mode) == 0)
881 if (push_operand (operand, mode) == 1)
887 reg_or_some_mem_operand (operand, mode)
889 enum machine_mode mode;
891 if (GET_CODE (operand) == MEM)
893 rtx op = XEXP (operand, 0);
895 if (symbolic_memory_operand (op, mode))
898 if (IS_STACK_PUSH (operand))
901 if (m68hc11_register_indirect_p (operand, mode))
907 return register_operand (operand, mode);
911 stack_register_operand (operand, mode)
913 enum machine_mode mode ATTRIBUTE_UNUSED;
915 return SP_REG_P (operand);
919 d_register_operand (operand, mode)
921 enum machine_mode mode ATTRIBUTE_UNUSED;
923 if (GET_CODE (operand) == SUBREG)
924 operand = XEXP (operand, 0);
926 return GET_CODE (operand) == REG
927 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
928 || REGNO (operand) == HARD_D_REGNUM);
932 hard_addr_reg_operand (operand, mode)
934 enum machine_mode mode ATTRIBUTE_UNUSED;
936 if (GET_CODE (operand) == SUBREG)
937 operand = XEXP (operand, 0);
939 return GET_CODE (operand) == REG
940 && (REGNO (operand) == HARD_X_REGNUM
941 || REGNO (operand) == HARD_Y_REGNUM
942 || REGNO (operand) == HARD_Z_REGNUM);
946 hard_reg_operand (operand, mode)
948 enum machine_mode mode ATTRIBUTE_UNUSED;
950 if (GET_CODE (operand) == SUBREG)
951 operand = XEXP (operand, 0);
953 return GET_CODE (operand) == REG
954 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
955 || H_REGNO_P (REGNO (operand)));
959 memory_indexed_operand (operand, mode)
961 enum machine_mode mode ATTRIBUTE_UNUSED;
963 if (GET_CODE (operand) != MEM)
966 operand = XEXP (operand, 0);
967 if (GET_CODE (operand) == PLUS)
969 if (GET_CODE (XEXP (operand, 0)) == REG)
970 operand = XEXP (operand, 0);
971 else if (GET_CODE (XEXP (operand, 1)) == REG)
972 operand = XEXP (operand, 1);
974 return GET_CODE (operand) == REG
975 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
976 || A_REGNO_P (REGNO (operand)));
980 push_pop_operand_p (operand)
983 if (GET_CODE (operand) != MEM)
987 operand = XEXP (operand, 0);
988 return PUSH_POP_ADDRESS_P (operand);
991 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
992 reference and a constant. */
995 symbolic_memory_operand (op, mode)
997 enum machine_mode mode;
999 switch (GET_CODE (op))
1006 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1007 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1008 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1010 /* ??? This clause seems to be irrelevant. */
1012 return GET_MODE (op) == mode;
1015 return symbolic_memory_operand (XEXP (op, 0), mode)
1016 && symbolic_memory_operand (XEXP (op, 1), mode);
1024 m68hc11_logical_operator (op, mode)
1026 enum machine_mode mode ATTRIBUTE_UNUSED;
1028 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1032 m68hc11_arith_operator (op, mode)
1034 enum machine_mode mode ATTRIBUTE_UNUSED;
1036 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1037 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1038 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1039 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1040 || GET_CODE (op) == ROTATERT;
1044 m68hc11_non_shift_operator (op, mode)
1046 enum machine_mode mode ATTRIBUTE_UNUSED;
1048 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1049 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1054 m68hc11_unary_operator (op, mode)
1056 enum machine_mode mode ATTRIBUTE_UNUSED;
1058 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1059 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1066 m68hc11_block_profiler (out, blockno)
1067 FILE *out ATTRIBUTE_UNUSED;
1068 int blockno ATTRIBUTE_UNUSED;
1074 m68hc11_function_block_profiler (out, block_or_label)
1075 FILE *out ATTRIBUTE_UNUSED;
1076 int block_or_label ATTRIBUTE_UNUSED;
1081 /* Emit the code to build the trampoline used to call a nested function.
1085 ldy #&CXT movw #&CXT,*_.d1
1086 sty *_.d1 jmp FNADDR
1091 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
1096 char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1099 if (*static_chain_reg == '*')
1103 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1104 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1105 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1107 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1108 gen_rtx_CONST (QImode,
1109 gen_rtx_SYMBOL_REF (Pmode,
1110 static_chain_reg)));
1111 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1113 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1117 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1118 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1119 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1120 gen_rtx_CONST (HImode,
1121 gen_rtx_SYMBOL_REF (Pmode,
1122 static_chain_reg)));
1123 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1125 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1129 /* Declaration of types. */
1131 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1132 with arguments ARGS is a valid machine specific attribute for TYPE.
1133 The attributes in ATTRIBUTES have previously been assigned to TYPE. */
1136 m68hc11_valid_type_attribute_p (type, attributes, identifier, args)
1138 tree attributes ATTRIBUTE_UNUSED;
1142 if (TREE_CODE (type) != FUNCTION_TYPE
1143 && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL)
1146 if (TREE_CODE (type) == FUNCTION_TYPE)
1148 if (is_attribute_p ("interrupt", identifier))
1149 return (args == NULL_TREE);
1150 if (is_attribute_p ("trap", identifier))
1151 return (args == NULL_TREE);
1157 /* Define this macro if references to a symbol must be treated
1158 differently depending on something about the variable or function
1159 named by the symbol (such as what section it is in).
1161 For the 68HC11, we want to recognize trap handlers so that we
1162 handle calls to traps in a special manner (by issuing the trap).
1163 This information is stored in SYMBOL_REF_FLAG. */
1165 m68hc11_encode_section_info (decl)
1172 if (TREE_CODE (decl) != FUNCTION_DECL)
1175 rtl = DECL_RTL (decl);
1177 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1178 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1179 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
1183 /* Argument support functions. */
1185 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1186 Arrays are passed by references and other types by value.
1188 SCz: I tried to pass DImode by reference but it seems that this
1189 does not work very well. */
1191 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1192 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1193 enum machine_mode mode ATTRIBUTE_UNUSED;
1195 int named ATTRIBUTE_UNUSED;
1197 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1198 /* Consider complex values as aggregates, so care for TCmode. */
1199 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1200 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1204 /* Define the offset between two registers, one to be eliminated, and the
1205 other its replacement, at the start of a routine. */
1207 m68hc11_initial_elimination_offset (from, to)
1216 /* For a trap handler, we must take into account the registers which
1217 are pushed on the stack during the trap (except the PC). */
1218 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1219 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1220 if (trap_handler && from == ARG_POINTER_REGNUM)
1225 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1227 /* 2 is for the saved frame.
1228 1 is for the 'sts' correction when creating the frame. */
1229 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1232 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1234 return m68hc11_sp_correction;
1237 /* Push any 2 byte pseudo hard registers that we need to save. */
1238 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1240 if (regs_ever_live[regno] && !call_used_regs[regno])
1246 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1248 return get_frame_size () + size;
1251 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1258 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1259 for a call to a function whose data type is FNTYPE.
1260 For a library call, FNTYPE is 0. */
1263 m68hc11_init_cumulative_args (cum, fntype, libname)
1264 CUMULATIVE_ARGS *cum;
1270 z_replacement_completed = 0;
1274 /* For a library call, we must find out the type of the return value.
1275 When the return value is bigger than 4 bytes, it is returned in
1276 memory. In that case, the first argument of the library call is a
1277 pointer to the memory location. Because the first argument is passed in
1278 register D, we have to identify this, so that the first function
1279 parameter is not passed in D either. */
1285 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1288 /* If the library ends in 'di' or in 'df', we assume it's
1289 returning some DImode or some DFmode which are 64-bit wide. */
1290 name = XSTR (libname, 0);
1291 len = strlen (name);
1293 && ((name[len - 2] == 'd'
1294 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1295 || (name[len - 3] == 'd'
1296 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1298 /* We are in. Mark the first parameter register as already used. */
1305 ret_type = TREE_TYPE (fntype);
1307 if (ret_type && aggregate_value_p (ret_type))
1314 /* Update the data in CUM to advance over an argument
1315 of mode MODE and data type TYPE.
1316 (TYPE is null for libcalls where that information may not be available.) */
1319 m68hc11_function_arg_advance (cum, mode, type, named)
1320 CUMULATIVE_ARGS *cum;
1321 enum machine_mode mode;
1323 int named ATTRIBUTE_UNUSED;
1325 if (mode != BLKmode)
1327 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1330 cum->words = GET_MODE_SIZE (mode);
1334 cum->words += GET_MODE_SIZE (mode);
1335 if (cum->words <= HARD_REG_SIZE)
1341 cum->words += int_size_in_bytes (type);
1346 /* Define where to put the arguments to a function.
1347 Value is zero to push the argument on the stack,
1348 or a hard register in which to store the argument.
1350 MODE is the argument's machine mode.
1351 TYPE is the data type of the argument (as a tree).
1352 This is null for libcalls where that information may
1354 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1355 the preceding args and about the function being called.
1356 NAMED is nonzero if this argument is a named parameter
1357 (otherwise it is an extra parameter matching an ellipsis). */
1360 m68hc11_function_arg (cum, mode, type, named)
1361 const CUMULATIVE_ARGS *cum;
1362 enum machine_mode mode;
1363 tree type ATTRIBUTE_UNUSED;
1364 int named ATTRIBUTE_UNUSED;
1366 if (cum->words != 0)
1371 if (mode != BLKmode)
1373 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1374 return gen_rtx (REG, mode, HARD_X_REGNUM);
1376 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1380 return gen_rtx (REG, mode, HARD_D_REGNUM);
1385 /* The "standard" implementation of va_start: just assign `nextarg' to
1388 m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
1389 int stdarg_p ATTRIBUTE_UNUSED;
1395 /* SCz: the default implementation in builtins.c adjust the
1396 nextarg using UNITS_PER_WORD. This works only with -mshort
1397 and fails when integers are 32-bit. Here is the correct way. */
1399 nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
1401 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1402 make_tree (ptr_type_node, nextarg));
1403 TREE_SIDE_EFFECTS (t) = 1;
1405 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1409 m68hc11_va_arg (valist, type)
1414 HOST_WIDE_INT align;
1415 HOST_WIDE_INT rounded_size;
1419 /* Compute the rounded size of the type. */
1420 align = PARM_BOUNDARY / BITS_PER_UNIT;
1421 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1425 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
1427 if (pad_direction == downward)
1429 /* Small args are padded downward. */
1432 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1433 if (rounded_size > align)
1436 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1437 build_int_2 (rounded_size - adj, 0));
1440 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1441 addr = copy_to_reg (addr);
1443 /* Compute new value for AP. */
1444 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1445 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1446 build_int_2 (rounded_size, 0)));
1447 TREE_SIDE_EFFECTS (t) = 1;
1448 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1453 /* If defined, a C expression which determines whether, and in which direction,
1454 to pad out an argument with extra space. The value should be of type
1455 `enum direction': either `upward' to pad above the argument,
1456 `downward' to pad below, or `none' to inhibit padding.
1458 Structures are stored left shifted in their argument slot. */
1460 m68hc11_function_arg_padding (mode, type)
1461 enum machine_mode mode;
1464 if (type != 0 && AGGREGATE_TYPE_P (type))
1467 /* This is the default definition. */
1468 return (!BYTES_BIG_ENDIAN
1471 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1472 && int_size_in_bytes (type) <
1473 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1474 PARM_BOUNDARY) ? downward : upward));
1478 /* Function prologue and epilogue. */
1480 /* Emit a move after the reload pass has completed. This is used to
1481 emit the prologue and epilogue. */
1483 emit_move_after_reload (to, from, scratch)
1484 rtx to, from, scratch;
1488 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1490 insn = emit_move_insn (to, from);
1494 emit_move_insn (scratch, from);
1495 insn = emit_move_insn (to, scratch);
1498 /* Put a REG_INC note to tell the flow analysis that the instruction
1500 if (IS_STACK_PUSH (to))
1502 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1503 XEXP (XEXP (to, 0), 0),
1506 else if (IS_STACK_POP (from))
1508 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1509 XEXP (XEXP (from, 0), 0),
1515 m68hc11_total_frame_size ()
1520 size = get_frame_size ();
1521 if (current_function_interrupt)
1523 size += 3 * HARD_REG_SIZE;
1525 if (frame_pointer_needed)
1526 size += HARD_REG_SIZE;
1528 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1529 if (regs_ever_live[regno] && !call_used_regs[regno])
1530 size += HARD_REG_SIZE;
1536 m68hc11_output_function_epilogue (out, size)
1537 FILE *out ATTRIBUTE_UNUSED;
1538 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1540 /* We catch the function epilogue generation to have a chance
1541 to clear the z_replacement_completed flag. */
1542 z_replacement_completed = 0;
1553 if (reload_completed != 1)
1556 size = get_frame_size ();
1560 /* Generate specific prologue for interrupt handlers. */
1561 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1562 current_function_interrupt = lookup_attribute ("interrupt",
1563 func_attr) != NULL_TREE;
1564 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1566 /* Get the scratch register to build the frame and push registers.
1567 If the first argument is a 32-bit quantity, the D+X registers
1568 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1569 For 68HC12, this scratch register is not used. */
1570 if (current_function_args_info.nregs == 2)
1575 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1576 Other soft registers in page0 need not to be saved because they
1577 will be restored by C functions. For a trap handler, we don't
1578 need to preserve these registers because this is a synchronous call. */
1579 if (current_function_interrupt)
1581 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1582 emit_move_after_reload (stack_push_word,
1583 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1584 emit_move_after_reload (stack_push_word,
1585 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1589 /* Save current stack frame. */
1590 if (frame_pointer_needed)
1591 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1593 /* Allocate local variables. */
1594 if (TARGET_M6812 && size >= 2)
1596 emit_insn (gen_addhi3 (stack_pointer_rtx,
1597 stack_pointer_rtx, GEN_INT (-size)));
1603 insn = gen_rtx_PARALLEL
1606 gen_rtx_SET (VOIDmode,
1608 gen_rtx_PLUS (HImode,
1611 gen_rtx_CLOBBER (VOIDmode, scratch)));
1618 /* Allocate by pushing scratch values. */
1619 for (i = 2; i <= size; i += 2)
1620 emit_move_after_reload (stack_push_word, ix_reg, 0);
1623 emit_insn (gen_addhi3 (stack_pointer_rtx,
1624 stack_pointer_rtx, GEN_INT (-1)));
1627 /* Create the frame pointer. */
1628 if (frame_pointer_needed)
1629 emit_move_after_reload (hard_frame_pointer_rtx,
1630 stack_pointer_rtx, scratch);
1632 /* Push any 2 byte pseudo hard registers that we need to save. */
1633 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1635 if (regs_ever_live[regno] && !call_used_regs[regno])
1637 emit_move_after_reload (stack_push_word,
1638 gen_rtx (REG, HImode, regno), scratch);
1651 if (reload_completed != 1)
1654 size = get_frame_size ();
1656 /* If we are returning a value in two registers, we have to preserve the
1657 X register and use the Y register to restore the stack and the saved
1658 registers. Otherwise, use X because it's faster (and smaller). */
1659 if (current_function_return_rtx == 0)
1661 else if (GET_CODE (current_function_return_rtx) == MEM)
1662 return_size = HARD_REG_SIZE;
1664 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1666 if (return_size > HARD_REG_SIZE)
1671 /* Pop any 2 byte pseudo hard registers that we saved. */
1672 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1674 if (regs_ever_live[regno] && !call_used_regs[regno])
1676 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1677 stack_pop_word, scratch);
1681 /* de-allocate auto variables */
1682 if (TARGET_M6812 && size >= 2)
1684 emit_insn (gen_addhi3 (stack_pointer_rtx,
1685 stack_pointer_rtx, GEN_INT (size)));
1691 insn = gen_rtx_PARALLEL
1694 gen_rtx_SET (VOIDmode,
1696 gen_rtx_PLUS (HImode,
1699 gen_rtx_CLOBBER (VOIDmode, scratch)));
1706 for (i = 2; i <= size; i += 2)
1707 emit_move_after_reload (scratch, stack_pop_word, scratch);
1709 emit_insn (gen_addhi3 (stack_pointer_rtx,
1710 stack_pointer_rtx, GEN_INT (1)));
1713 /* Restore previous frame pointer. */
1714 if (frame_pointer_needed)
1715 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1717 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1718 if (current_function_interrupt)
1720 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1721 stack_pop_word, scratch);
1722 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1723 stack_pop_word, scratch);
1724 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1727 /* If the trap handler returns some value, copy the value
1728 in D, X onto the stack so that the rti will pop the return value
1730 else if (current_function_trap && return_size != 0)
1732 rtx addr_reg = stack_pointer_rtx;
1736 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1739 emit_move_after_reload (gen_rtx (MEM, HImode,
1740 gen_rtx (PLUS, HImode, addr_reg,
1741 GEN_INT (1))), d_reg, 0);
1742 if (return_size > HARD_REG_SIZE)
1743 emit_move_after_reload (gen_rtx (MEM, HImode,
1744 gen_rtx (PLUS, HImode, addr_reg,
1745 GEN_INT (3))), ix_reg, 0);
1748 emit_jump_insn (gen_return ());
1752 /* Low and High part extraction for 68HC11. These routines are
1753 similar to gen_lowpart and gen_highpart but they have been
1754 fixed to work for constants and 68HC11 specific registers. */
1757 m68hc11_gen_lowpart (mode, x)
1758 enum machine_mode mode;
1761 /* We assume that the low part of an auto-inc mode is the same with
1762 the mode changed and that the caller split the larger mode in the
1764 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1766 return gen_rtx (MEM, mode, XEXP (x, 0));
1769 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1770 floating-point constant. A CONST_DOUBLE is used whenever the
1771 constant requires more than one word in order to be adequately
1773 if (GET_CODE (x) == CONST_DOUBLE)
1777 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1781 if (GET_MODE (x) == SFmode)
1783 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1784 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1790 split_double (x, &first, &second);
1794 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1796 return gen_rtx (CONST_INT, VOIDmode,
1797 trunc_int_for_mode (l[0], HImode));
1801 l[0] = CONST_DOUBLE_LOW (x);
1804 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1805 else if (mode == HImode && GET_MODE (x) == SFmode)
1806 return gen_rtx (CONST_INT, VOIDmode,
1807 trunc_int_for_mode (l[0], HImode));
1812 if (mode == QImode && D_REG_P (x))
1813 return gen_rtx (REG, mode, HARD_B_REGNUM);
1815 /* gen_lowpart crashes when it is called with a SUBREG. */
1816 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1819 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1820 else if (mode == HImode)
1821 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1825 x = gen_lowpart (mode, x);
1827 /* Return a different rtx to avoid to share it in several insns
1828 (when used by a split pattern). Sharing addresses within
1829 a MEM breaks the Z register replacement (and reloading). */
1830 if (GET_CODE (x) == MEM)
1836 m68hc11_gen_highpart (mode, x)
1837 enum machine_mode mode;
1840 /* We assume that the high part of an auto-inc mode is the same with
1841 the mode changed and that the caller split the larger mode in the
1843 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1845 return gen_rtx (MEM, mode, XEXP (x, 0));
1848 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1849 floating-point constant. A CONST_DOUBLE is used whenever the
1850 constant requires more than one word in order to be adequately
1852 if (GET_CODE (x) == CONST_DOUBLE)
1856 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1860 if (GET_MODE (x) == SFmode)
1862 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1863 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1869 split_double (x, &first, &second);
1873 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1875 return gen_rtx (CONST_INT, VOIDmode,
1876 trunc_int_for_mode ((l[1] >> 16), HImode));
1880 l[1] = CONST_DOUBLE_HIGH (x);
1884 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1885 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1886 return gen_rtx (CONST_INT, VOIDmode,
1887 trunc_int_for_mode ((l[0] >> 16), HImode));
1891 if (GET_CODE (x) == CONST_INT)
1893 HOST_WIDE_INT val = INTVAL (x);
1897 return gen_rtx (CONST_INT, VOIDmode,
1898 trunc_int_for_mode (val >> 8, QImode));
1900 else if (mode == HImode)
1902 return gen_rtx (CONST_INT, VOIDmode,
1903 trunc_int_for_mode (val >> 16, HImode));
1906 if (mode == QImode && D_REG_P (x))
1907 return gen_rtx (REG, mode, HARD_A_REGNUM);
1909 /* There is no way in GCC to represent the upper part of a word register.
1910 To obtain the 8-bit upper part of a soft register, we change the
1911 reg into a mem rtx. This is possible because they are physically
1912 located in memory. There is no offset because we are big-endian. */
1913 if (mode == QImode && S_REG_P (x))
1917 /* For 68HC12, avoid the '*' for direct addressing mode. */
1918 pos = TARGET_M6812 ? 1 : 0;
1919 return gen_rtx (MEM, QImode,
1920 gen_rtx (SYMBOL_REF, Pmode,
1921 ®_names[REGNO (x)][pos]));
1924 /* gen_highpart crashes when it is called with a SUBREG. */
1925 if (GET_CODE (x) == SUBREG)
1927 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1929 if (GET_CODE (x) == REG)
1931 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1932 return gen_rtx (REG, mode, REGNO (x));
1934 return gen_rtx_SUBREG (mode, x, 0);
1937 if (GET_CODE (x) == MEM)
1939 x = change_address (x, mode, 0);
1941 /* Return a different rtx to avoid to share it in several insns
1942 (when used by a split pattern). Sharing addresses within
1943 a MEM breaks the Z register replacement (and reloading). */
1944 if (GET_CODE (x) == MEM)
1952 /* Obscure register manipulation. */
1954 /* Finds backward in the instructions to see if register 'reg' is
1955 dead. This is used when generating code to see if we can use 'reg'
1956 as a scratch register. This allows us to choose a better generation
1957 of code when we know that some register dies or can be clobbered. */
1960 dead_register_here (x, reg)
1968 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
1972 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1973 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
1979 if (GET_CODE (body) == CALL_INSN)
1981 if (GET_CODE (body) == JUMP_INSN)
1984 if (GET_CODE (body) == SET)
1986 rtx dst = XEXP (body, 0);
1988 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
1990 if (x_reg && rtx_equal_p (dst, x_reg))
1993 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
1996 else if (reg_mentioned_p (reg, p)
1997 || (x_reg && reg_mentioned_p (x_reg, p)))
2001 /* Scan forward to see if the register is set in some insns and never
2003 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2007 if (GET_CODE (p) == CODE_LABEL
2008 || GET_CODE (p) == JUMP_INSN
2009 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2012 if (GET_CODE (p) != INSN)
2016 if (GET_CODE (body) == SET)
2018 rtx src = XEXP (body, 1);
2019 rtx dst = XEXP (body, 0);
2021 if (GET_CODE (dst) == REG
2022 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2026 /* Register is used (may be in source or in dest). */
2027 if (reg_mentioned_p (reg, p)
2028 || (x_reg != 0 && GET_MODE (p) == SImode
2029 && reg_mentioned_p (x_reg, p)))
2032 return p == 0 ? 1 : 0;
2036 /* Code generation operations called from machine description file. */
2038 /* Print the name of register 'regno' in the assembly file. */
2040 asm_print_register (file, regno)
2044 const char *name = reg_names[regno];
2046 if (TARGET_M6812 && name[0] == '*')
2049 asm_fprintf (file, "%s", name);
2052 /* A C compound statement to output to stdio stream STREAM the
2053 assembler syntax for an instruction operand X. X is an RTL
2056 CODE is a value that can be used to specify one of several ways
2057 of printing the operand. It is used when identical operands
2058 must be printed differently depending on the context. CODE
2059 comes from the `%' specification that was used to request
2060 printing of the operand. If the specification was just `%DIGIT'
2061 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2062 is the ASCII code for LTR.
2064 If X is a register, this macro should print the register's name.
2065 The names can be found in an array `reg_names' whose type is
2066 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2068 When the machine description has a specification `%PUNCT' (a `%'
2069 followed by a punctuation character), this macro is called with
2070 a null pointer for X and the punctuation character for CODE.
2072 The M68HC11 specific codes are:
2074 'b' for the low part of the operand.
2075 'h' for the high part of the operand
2076 The 'b' or 'h' modifiers have no effect if the operand has
2077 the QImode and is not a S_REG_P (soft register). If the
2078 operand is a hard register, these two modifiers have no effect.
2079 't' generate the temporary scratch register. The operand is
2081 'T' generate the low-part temporary scratch register. The operand is
2085 print_operand (file, op, letter)
2092 asm_print_register (file, SOFT_TMP_REGNUM);
2095 else if (letter == 'T')
2097 asm_print_register (file, SOFT_TMP_REGNUM);
2098 asm_fprintf (file, "+1");
2101 else if (letter == '#')
2103 asm_fprintf (file, "%0I");
2106 if (GET_CODE (op) == REG)
2108 if (letter == 'b' && S_REG_P (op))
2110 asm_print_register (file, REGNO (op));
2111 asm_fprintf (file, "+1");
2115 asm_print_register (file, REGNO (op));
2120 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2123 asm_fprintf (file, "%0I%%lo(");
2125 asm_fprintf (file, "%0I%%hi(");
2127 output_addr_const (file, op);
2128 asm_fprintf (file, ")");
2132 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2133 are specified. If we already have a QImode, there is nothing to do. */
2134 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2138 op = m68hc11_gen_lowpart (QImode, op);
2140 else if (letter == 'h')
2142 op = m68hc11_gen_highpart (QImode, op);
2146 if (GET_CODE (op) == MEM)
2148 rtx base = XEXP (op, 0);
2149 switch (GET_CODE (base))
2154 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2155 asm_print_register (file, REGNO (XEXP (base, 0)));
2164 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2165 asm_print_register (file, REGNO (XEXP (base, 0)));
2166 asm_fprintf (file, "-");
2175 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2176 asm_print_register (file, REGNO (XEXP (base, 0)));
2177 asm_fprintf (file, "+");
2186 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2187 asm_print_register (file, REGNO (XEXP (base, 0)));
2194 output_address (base);
2198 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2201 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2202 ASM_OUTPUT_FLOAT_OPERAND (letter, file, r);
2204 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode)
2207 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2208 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r);
2210 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2213 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2214 ASM_OUTPUT_DOUBLE_OPERAND (file, r);
2218 int need_parenthesize = 0;
2221 asm_fprintf (file, "%0I");
2223 need_parenthesize = must_parenthesize (op);
2225 if (need_parenthesize)
2226 asm_fprintf (file, "(");
2228 output_addr_const (file, op);
2229 if (need_parenthesize)
2230 asm_fprintf (file, ")");
2234 /* Returns true if the operand 'op' must be printed with parenthesis
2235 arround it. This must be done only if there is a symbol whose name
2236 is a processor register. */
2238 must_parenthesize (op)
2243 switch (GET_CODE (op))
2246 name = XSTR (op, 0);
2247 /* Avoid a conflict between symbol name and a possible
2249 return (strcasecmp (name, "a") == 0
2250 || strcasecmp (name, "b") == 0
2251 || strcasecmp (name, "d") == 0
2252 || strcasecmp (name, "x") == 0
2253 || strcasecmp (name, "y") == 0
2254 || strcasecmp (name, "pc") == 0
2255 || strcasecmp (name, "sp") == 0
2256 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2260 return must_parenthesize (XEXP (op, 0))
2261 || must_parenthesize (XEXP (op, 1));
2267 return must_parenthesize (XEXP (op, 0));
2278 /* A C compound statement to output to stdio stream STREAM the
2279 assembler syntax for an instruction operand that is a memory
2280 reference whose address is ADDR. ADDR is an RTL expression. */
2283 print_operand_address (file, addr)
2289 int need_parenthesis = 0;
2291 switch (GET_CODE (addr))
2294 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2297 asm_fprintf (file, "0,");
2298 asm_print_register (file, REGNO (addr));
2302 base = XEXP (addr, 0);
2303 switch (GET_CODE (base))
2308 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2309 asm_print_register (file, REGNO (XEXP (base, 0)));
2318 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2319 asm_print_register (file, REGNO (XEXP (base, 0)));
2320 asm_fprintf (file, "-");
2329 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2330 asm_print_register (file, REGNO (XEXP (base, 0)));
2331 asm_fprintf (file, "+");
2340 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2341 asm_print_register (file, REGNO (XEXP (base, 0)));
2348 need_parenthesis = must_parenthesize (base);
2349 if (need_parenthesis)
2350 asm_fprintf (file, "(");
2352 output_addr_const (file, base);
2353 if (need_parenthesis)
2354 asm_fprintf (file, ")");
2360 base = XEXP (addr, 0);
2361 offset = XEXP (addr, 1);
2362 if (!G_REG_P (base) && G_REG_P (offset))
2364 base = XEXP (addr, 1);
2365 offset = XEXP (addr, 0);
2367 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2369 need_parenthesis = must_parenthesize (addr);
2371 if (need_parenthesis)
2372 asm_fprintf (file, "(");
2374 output_addr_const (file, base);
2375 asm_fprintf (file, "+");
2376 output_addr_const (file, offset);
2377 if (need_parenthesis)
2378 asm_fprintf (file, ")");
2380 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2386 asm_print_register (file, REGNO (offset));
2387 asm_fprintf (file, ",");
2388 asm_print_register (file, REGNO (base));
2395 output_addr_const (file, offset);
2396 asm_fprintf (file, ",");
2397 asm_print_register (file, REGNO (base));
2407 if (GET_CODE (addr) == CONST_INT
2408 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2410 asm_fprintf (file, "%d", INTVAL (addr));
2414 need_parenthesis = must_parenthesize (addr);
2415 if (need_parenthesis)
2416 asm_fprintf (file, "(");
2418 output_addr_const (file, addr);
2419 if (need_parenthesis)
2420 asm_fprintf (file, ")");
2427 /* Splitting of some instructions. */
2430 m68hc11_expand_compare (code, op0, op1)
2436 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2440 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2441 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2442 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2449 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2451 rtx op0, op1, label;
2455 switch (GET_MODE (op0))
2459 tmp = m68hc11_expand_compare (code, op0, op1);
2460 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2461 gen_rtx_LABEL_REF (VOIDmode, label),
2463 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2467 /* SCz: from i386.c */
2470 /* Don't expand the comparison early, so that we get better code
2471 when jump or whoever decides to reverse the comparison. */
2476 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2477 &m68hc11_compare_op1);
2479 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2480 m68hc11_compare_op0, m68hc11_compare_op1);
2481 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2482 gen_rtx_LABEL_REF (VOIDmode, label),
2484 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2486 use_fcomi = ix86_use_fcomi_compare (code);
2487 vec = rtvec_alloc (3 + !use_fcomi);
2488 RTVEC_ELT (vec, 0) = tmp;
2490 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2492 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2495 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2497 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2503 /* Expand SImode branch into multiple compare+branch. */
2505 rtx lo[2], hi[2], label2;
2506 enum rtx_code code1, code2, code3;
2508 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2513 code = swap_condition (code);
2515 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2516 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2517 hi[0] = m68hc11_gen_highpart (HImode, op0);
2518 hi[1] = m68hc11_gen_highpart (HImode, op1);
2520 /* Otherwise, if we are doing less-than, op1 is a constant and the
2521 low word is zero, then we can just examine the high word. */
2523 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2524 && (code == LT || code == LTU))
2526 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2530 /* Otherwise, we need two or three jumps. */
2532 label2 = gen_label_rtx ();
2535 code2 = swap_condition (code);
2536 code3 = unsigned_condition (code);
2577 * if (hi(a) < hi(b)) goto true;
2578 * if (hi(a) > hi(b)) goto false;
2579 * if (lo(a) < lo(b)) goto true;
2583 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2585 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2587 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2590 emit_label (label2);
2601 /* Split a DI, SI or HI move into several smaller move operations.
2602 The scratch register 'scratch' is used as a temporary to load
2603 store intermediate values. It must be a hard register. */
2605 m68hc11_split_move (to, from, scratch)
2606 rtx to, from, scratch;
2608 rtx low_to, low_from;
2609 rtx high_to, high_from;
2610 enum machine_mode mode;
2613 mode = GET_MODE (to);
2614 if (GET_MODE_SIZE (mode) == 8)
2616 else if (GET_MODE_SIZE (mode) == 4)
2622 && IS_STACK_PUSH (to)
2623 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2629 else if (mode == HImode)
2637 low_to = m68hc11_gen_lowpart (mode, to);
2638 high_to = m68hc11_gen_highpart (mode, to);
2640 low_from = m68hc11_gen_lowpart (mode, from);
2641 if (mode == SImode && GET_CODE (from) == CONST_INT)
2643 if (INTVAL (from) >= 0)
2644 high_from = const0_rtx;
2646 high_from = constm1_rtx;
2649 high_from = m68hc11_gen_highpart (mode, from);
2653 high_from = adjust_address (high_from, mode, offset);
2654 low_from = high_from;
2658 m68hc11_split_move (low_to, low_from, scratch);
2659 m68hc11_split_move (high_to, high_from, scratch);
2661 else if (H_REG_P (to) || H_REG_P (from)
2663 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2664 || m68hc11_small_indexed_indirect_p (from,
2666 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2667 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2669 emit_move_insn (low_to, low_from);
2670 emit_move_insn (high_to, high_from);
2676 emit_move_insn (scratch, low_from);
2677 insn = emit_move_insn (low_to, scratch);
2679 emit_move_insn (scratch, high_from);
2680 insn = emit_move_insn (high_to, scratch);
2685 simplify_logical (mode, code, operand, result)
2686 enum machine_mode mode;
2695 if (GET_CODE (operand) != CONST_INT)
2703 val = INTVAL (operand);
2707 if ((val & mask) == 0)
2709 if ((val & mask) == mask)
2710 *result = constm1_rtx;
2714 if ((val & mask) == 0)
2715 *result = const0_rtx;
2716 if ((val & mask) == mask)
2721 if ((val & mask) == 0)
2729 m68hc11_emit_logical (mode, code, operands)
2730 enum machine_mode mode;
2737 need_copy = (rtx_equal_p (operands[0], operands[1])
2738 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2740 operands[1] = simplify_logical (mode, code, operands[1], &result);
2741 operands[2] = simplify_logical (mode, code, operands[2], &result);
2743 if (result && GET_CODE (result) == CONST_INT)
2745 if (!H_REG_P (operands[0]) && operands[3]
2746 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2748 emit_move_insn (operands[3], result);
2749 emit_move_insn (operands[0], operands[3]);
2753 emit_move_insn (operands[0], result);
2756 else if (operands[1] != 0 && operands[2] != 0)
2760 if (!H_REG_P (operands[0]) && operands[3])
2762 emit_move_insn (operands[3], operands[1]);
2763 emit_insn (gen_rtx (SET, mode,
2765 gen_rtx (code, mode,
2766 operands[3], operands[2])));
2767 insn = emit_move_insn (operands[0], operands[3]);
2771 insn = emit_insn (gen_rtx (SET, mode,
2773 gen_rtx (code, mode,
2774 operands[0], operands[2])));
2778 /* The logical operation is similar to a copy. */
2783 if (GET_CODE (operands[1]) == CONST_INT)
2788 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2790 emit_move_insn (operands[3], src);
2791 emit_move_insn (operands[0], operands[3]);
2795 emit_move_insn (operands[0], src);
2801 m68hc11_split_logical (mode, code, operands)
2802 enum machine_mode mode;
2809 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2810 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2811 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2813 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2815 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
2817 if (INTVAL (operands[1]) >= 0)
2818 high[1] = const0_rtx;
2820 high[1] = constm1_rtx;
2823 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2825 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
2827 if (INTVAL (operands[2]) >= 0)
2828 high[2] = const0_rtx;
2830 high[2] = constm1_rtx;
2833 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2835 low[3] = operands[3];
2836 high[3] = operands[3];
2839 m68hc11_split_logical (HImode, code, low);
2840 m68hc11_split_logical (HImode, code, high);
2844 m68hc11_emit_logical (mode, code, low);
2845 m68hc11_emit_logical (mode, code, high);
2849 /* Code generation. */
2852 m68hc11_output_swap (insn, operands)
2853 rtx insn ATTRIBUTE_UNUSED;
2856 /* We have to be careful with the cc_status. An address register swap
2857 is generated for some comparison. The comparison is made with D
2858 but the branch really uses the address register. See the split
2859 pattern for compare. The xgdx/xgdy preserve the flags but after
2860 the exchange, the flags will reflect to the value of X and not D.
2861 Tell this by setting the cc_status according to the cc_prev_status. */
2862 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2864 if (cc_prev_status.value1 != 0
2865 && (D_REG_P (cc_prev_status.value1)
2866 || X_REG_P (cc_prev_status.value1)))
2868 cc_status = cc_prev_status;
2869 if (D_REG_P (cc_status.value1))
2870 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2873 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2879 output_asm_insn ("xgdx", operands);
2883 if (cc_prev_status.value1 != 0
2884 && (D_REG_P (cc_prev_status.value1)
2885 || Y_REG_P (cc_prev_status.value1)))
2887 cc_status = cc_prev_status;
2888 if (D_REG_P (cc_status.value1))
2889 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2892 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2898 output_asm_insn ("xgdy", operands);
2902 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2903 This is used to decide whether a move that set flags should be used
2906 next_insn_test_reg (insn, reg)
2912 insn = next_nonnote_insn (insn);
2913 if (GET_CODE (insn) != INSN)
2916 body = PATTERN (insn);
2917 if (sets_cc0_p (body) != 1)
2920 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
2926 /* Generate the code to move a 16-bit operand into another one. */
2929 m68hc11_gen_movhi (insn, operands)
2935 /* Move a register or memory to the same location.
2936 This is possible because such insn can appear
2937 in a non-optimizing mode. */
2938 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
2940 cc_status = cc_prev_status;
2946 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
2948 cc_status = cc_prev_status;
2949 switch (REGNO (operands[1]))
2954 output_asm_insn ("psh%1", operands);
2961 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2963 cc_status = cc_prev_status;
2964 switch (REGNO (operands[0]))
2969 output_asm_insn ("pul%0", operands);
2976 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
2978 m68hc11_notice_keep_cc (operands[0]);
2979 output_asm_insn ("tfr\t%1,%0", operands);
2981 else if (H_REG_P (operands[0]))
2983 if (SP_REG_P (operands[0]))
2984 output_asm_insn ("lds\t%1", operands);
2986 output_asm_insn ("ld%0\t%1", operands);
2988 else if (H_REG_P (operands[1]))
2990 if (SP_REG_P (operands[1]))
2991 output_asm_insn ("sts\t%0", operands);
2993 output_asm_insn ("st%1\t%0", operands);
2997 rtx from = operands[1];
2998 rtx to = operands[0];
3000 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3001 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3002 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3003 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3009 ops[0] = operands[2];
3012 m68hc11_gen_movhi (insn, ops);
3014 ops[1] = operands[2];
3015 m68hc11_gen_movhi (insn, ops);
3019 /* !!!! SCz wrong here. */
3020 fatal_insn ("Move insn not handled", insn);
3025 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3027 output_asm_insn ("clr\t%h0", operands);
3028 output_asm_insn ("clr\t%b0", operands);
3032 m68hc11_notice_keep_cc (operands[0]);
3033 output_asm_insn ("movw\t%1,%0", operands);
3040 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3042 cc_status = cc_prev_status;
3043 switch (REGNO (operands[0]))
3047 output_asm_insn ("pul%0", operands);
3050 output_asm_insn ("pula", operands);
3051 output_asm_insn ("pulb", operands);
3058 /* Some moves to a hard register are special. Not all of them
3059 are really supported and we have to use a temporary
3060 location to provide them (either the stack of a temp var). */
3061 if (H_REG_P (operands[0]))
3063 switch (REGNO (operands[0]))
3066 if (X_REG_P (operands[1]))
3068 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3070 m68hc11_output_swap (insn, operands);
3072 else if (next_insn_test_reg (insn, operands[0]))
3074 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3078 m68hc11_notice_keep_cc (operands[0]);
3079 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3082 else if (Y_REG_P (operands[1]))
3084 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3086 m68hc11_output_swap (insn, operands);
3090 /* %t means *ZTMP scratch register. */
3091 output_asm_insn ("sty\t%t1", operands);
3092 output_asm_insn ("ldd\t%t1", operands);
3095 else if (SP_REG_P (operands[1]))
3100 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3101 output_asm_insn ("xgdx", operands);
3102 output_asm_insn ("tsx", operands);
3103 output_asm_insn ("xgdx", operands);
3105 else if (IS_STACK_POP (operands[1]))
3107 output_asm_insn ("pula\n\tpulb", operands);
3109 else if (GET_CODE (operands[1]) == CONST_INT
3110 && INTVAL (operands[1]) == 0)
3112 output_asm_insn ("clra\n\tclrb", operands);
3116 output_asm_insn ("ldd\t%1", operands);
3121 if (D_REG_P (operands[1]))
3123 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3125 m68hc11_output_swap (insn, operands);
3127 else if (next_insn_test_reg (insn, operands[0]))
3129 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3133 m68hc11_notice_keep_cc (operands[0]);
3134 output_asm_insn ("pshb", operands);
3135 output_asm_insn ("psha", operands);
3136 output_asm_insn ("pulx", operands);
3139 else if (Y_REG_P (operands[1]))
3141 /* When both D and Y are dead, use the sequence xgdy, xgdx
3142 to move Y into X. The D and Y registers are modified. */
3143 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3144 && dead_register_here (insn, d_reg))
3146 output_asm_insn ("xgdy", operands);
3147 output_asm_insn ("xgdx", operands);
3152 output_asm_insn ("sty\t%t1", operands);
3153 output_asm_insn ("ldx\t%t1", operands);
3156 else if (SP_REG_P (operands[1]))
3158 /* tsx, tsy preserve the flags */
3159 cc_status = cc_prev_status;
3160 output_asm_insn ("tsx", operands);
3164 output_asm_insn ("ldx\t%1", operands);
3169 if (D_REG_P (operands[1]))
3171 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3173 m68hc11_output_swap (insn, operands);
3177 output_asm_insn ("std\t%t1", operands);
3178 output_asm_insn ("ldy\t%t1", operands);
3181 else if (X_REG_P (operands[1]))
3183 /* When both D and X are dead, use the sequence xgdx, xgdy
3184 to move X into Y. The D and X registers are modified. */
3185 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3186 && dead_register_here (insn, d_reg))
3188 output_asm_insn ("xgdx", operands);
3189 output_asm_insn ("xgdy", operands);
3194 output_asm_insn ("stx\t%t1", operands);
3195 output_asm_insn ("ldy\t%t1", operands);
3198 else if (SP_REG_P (operands[1]))
3200 /* tsx, tsy preserve the flags */
3201 cc_status = cc_prev_status;
3202 output_asm_insn ("tsy", operands);
3206 output_asm_insn ("ldy\t%1", operands);
3210 case HARD_SP_REGNUM:
3211 if (D_REG_P (operands[1]))
3213 m68hc11_notice_keep_cc (operands[0]);
3214 output_asm_insn ("xgdx", operands);
3215 output_asm_insn ("txs", operands);
3216 output_asm_insn ("xgdx", operands);
3218 else if (X_REG_P (operands[1]))
3220 /* tys, txs preserve the flags */
3221 cc_status = cc_prev_status;
3222 output_asm_insn ("txs", operands);
3224 else if (Y_REG_P (operands[1]))
3226 /* tys, txs preserve the flags */
3227 cc_status = cc_prev_status;
3228 output_asm_insn ("tys", operands);
3232 /* lds sets the flags but the des does not. */
3234 output_asm_insn ("lds\t%1", operands);
3235 output_asm_insn ("des", operands);
3240 fatal_insn ("Invalid register in the move instruction", insn);
3245 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3246 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3248 output_asm_insn ("sts\t%0", operands);
3252 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3254 cc_status = cc_prev_status;
3255 switch (REGNO (operands[1]))
3259 output_asm_insn ("psh%1", operands);
3262 output_asm_insn ("pshb", operands);
3263 output_asm_insn ("psha", operands);
3271 /* Operand 1 must be a hard register. */
3272 if (!H_REG_P (operands[1]))
3274 fatal_insn ("Invalid operand in the instruction", insn);
3277 reg = REGNO (operands[1]);
3281 output_asm_insn ("std\t%0", operands);
3285 output_asm_insn ("stx\t%0", operands);
3289 output_asm_insn ("sty\t%0", operands);
3292 case HARD_SP_REGNUM:
3296 if (reg_mentioned_p (ix_reg, operands[0]))
3298 output_asm_insn ("sty\t%t0", operands);
3299 output_asm_insn ("tsy", operands);
3300 output_asm_insn ("sty\t%0", operands);
3301 output_asm_insn ("ldy\t%t0", operands);
3305 output_asm_insn ("stx\t%t0", operands);
3306 output_asm_insn ("tsx", operands);
3307 output_asm_insn ("stx\t%0", operands);
3308 output_asm_insn ("ldx\t%t0", operands);
3314 fatal_insn ("Invalid register in the move instruction", insn);
3320 m68hc11_gen_movqi (insn, operands)
3324 /* Move a register or memory to the same location.
3325 This is possible because such insn can appear
3326 in a non-optimizing mode. */
3327 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3329 cc_status = cc_prev_status;
3336 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3338 m68hc11_notice_keep_cc (operands[0]);
3339 output_asm_insn ("tfr\t%1,%0", operands);
3341 else if (H_REG_P (operands[0]))
3343 if (Q_REG_P (operands[0]))
3344 output_asm_insn ("lda%0\t%b1", operands);
3345 else if (D_REG_P (operands[0]))
3346 output_asm_insn ("ldab\t%b1", operands);
3350 else if (H_REG_P (operands[1]))
3352 if (Q_REG_P (operands[1]))
3353 output_asm_insn ("sta%1\t%b0", operands);
3354 else if (D_REG_P (operands[1]))
3355 output_asm_insn ("stab\t%b0", operands);
3361 rtx from = operands[1];
3362 rtx to = operands[0];
3364 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3365 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3366 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3367 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3373 ops[0] = operands[2];
3376 m68hc11_gen_movqi (insn, ops);
3378 ops[1] = operands[2];
3379 m68hc11_gen_movqi (insn, ops);
3383 /* !!!! SCz wrong here. */
3384 fatal_insn ("Move insn not handled", insn);
3389 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3391 output_asm_insn ("clr\t%b0", operands);
3395 m68hc11_notice_keep_cc (operands[0]);
3396 output_asm_insn ("movb\t%b1,%b0", operands);
3404 if (H_REG_P (operands[0]))
3406 switch (REGNO (operands[0]))
3410 if (X_REG_P (operands[1]))
3412 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3414 m68hc11_output_swap (insn, operands);
3418 output_asm_insn ("stx\t%t1", operands);
3419 output_asm_insn ("ldab\t%T0", operands);
3422 else if (Y_REG_P (operands[1]))
3424 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3426 m68hc11_output_swap (insn, operands);
3430 output_asm_insn ("sty\t%t1", operands);
3431 output_asm_insn ("ldab\t%T0", operands);
3434 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3435 && !DA_REG_P (operands[1]))
3437 output_asm_insn ("ldab\t%b1", operands);
3439 else if (DA_REG_P (operands[1]))
3441 output_asm_insn ("tab", operands);
3445 cc_status = cc_prev_status;
3451 if (X_REG_P (operands[1]))
3453 output_asm_insn ("stx\t%t1", operands);
3454 output_asm_insn ("ldaa\t%T0", operands);
3456 else if (Y_REG_P (operands[1]))
3458 output_asm_insn ("sty\t%t1", operands);
3459 output_asm_insn ("ldaa\t%T0", operands);
3461 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3462 && !DA_REG_P (operands[1]))
3464 output_asm_insn ("ldaa\t%b1", operands);
3466 else if (!DA_REG_P (operands[1]))
3468 output_asm_insn ("tba", operands);
3472 cc_status = cc_prev_status;
3477 if (D_REG_P (operands[1]))
3479 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3481 m68hc11_output_swap (insn, operands);
3485 output_asm_insn ("stab\t%T1", operands);
3486 output_asm_insn ("ldx\t%t1", operands);
3490 else if (Y_REG_P (operands[1]))
3492 output_asm_insn ("sty\t%t0", operands);
3493 output_asm_insn ("ldx\t%t0", operands);
3495 else if (GET_CODE (operands[1]) == CONST_INT)
3497 output_asm_insn ("ldx\t%1", operands);
3499 else if (dead_register_here (insn, d_reg))
3501 output_asm_insn ("ldab\t%b1", operands);
3502 output_asm_insn ("xgdx", operands);
3504 else if (!reg_mentioned_p (operands[0], operands[1]))
3506 output_asm_insn ("xgdx", operands);
3507 output_asm_insn ("ldab\t%b1", operands);
3508 output_asm_insn ("xgdx", operands);
3512 output_asm_insn ("pshb", operands);
3513 output_asm_insn ("ldab\t%b1", operands);
3514 output_asm_insn ("stab\t%T1", operands);
3515 output_asm_insn ("ldx\t%t1", operands);
3516 output_asm_insn ("pulb", operands);
3522 if (D_REG_P (operands[1]))
3524 output_asm_insn ("stab\t%T1", operands);
3525 output_asm_insn ("ldy\t%t1", operands);
3528 else if (X_REG_P (operands[1]))
3530 output_asm_insn ("stx\t%t1", operands);
3531 output_asm_insn ("ldy\t%t1", operands);
3534 else if (GET_CODE (operands[1]) == CONST_INT)
3536 output_asm_insn ("ldy\t%1", operands);
3538 else if (dead_register_here (insn, d_reg))
3540 output_asm_insn ("ldab\t%b1", operands);
3541 output_asm_insn ("xgdy", operands);
3543 else if (!reg_mentioned_p (operands[0], operands[1]))
3545 output_asm_insn ("xgdy", operands);
3546 output_asm_insn ("ldab\t%b1", operands);
3547 output_asm_insn ("xgdy", operands);
3551 output_asm_insn ("pshb", operands);
3552 output_asm_insn ("ldab\t%b1", operands);
3553 output_asm_insn ("stab\t%T1", operands);
3554 output_asm_insn ("ldy\t%t1", operands);
3555 output_asm_insn ("pulb", operands);
3561 fatal_insn ("Invalid register in the instruction", insn);
3565 else if (H_REG_P (operands[1]))
3567 switch (REGNO (operands[1]))
3571 output_asm_insn ("stab\t%b0", operands);
3575 output_asm_insn ("staa\t%b0", operands);
3579 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3583 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3587 fatal_insn ("Invalid register in the move instruction", insn);
3594 fatal_insn ("Operand 1 must be a hard register", insn);
3598 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3599 The source and destination must be D or A and the shift must
3602 m68hc11_gen_rotate (code, insn, operands)
3609 if (GET_CODE (operands[2]) != CONST_INT
3610 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3611 fatal_insn ("Invalid rotate insn", insn);
3613 val = INTVAL (operands[2]);
3614 if (code == ROTATERT)
3615 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3617 if (GET_MODE (operands[0]) != QImode)
3620 /* Rotate by 8-bits if the shift is within [5..11]. */
3621 if (val >= 5 && val <= 11)
3623 output_asm_insn ("psha", operands);
3624 output_asm_insn ("tba", operands);
3625 output_asm_insn ("pulb", operands);
3629 /* If the shift is big, invert the rotation. */
3637 /* Set the carry to bit-15, but don't change D yet. */
3638 if (GET_MODE (operands[0]) != QImode)
3640 output_asm_insn ("asra", operands);
3641 output_asm_insn ("rola", operands);
3646 /* Rotate B first to move the carry to bit-0. */
3647 if (D_REG_P (operands[0]))
3648 output_asm_insn ("rolb", operands);
3650 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3651 output_asm_insn ("rola", operands);
3656 /* Set the carry to bit-8 of D. */
3657 if (val != 0 && GET_MODE (operands[0]) != QImode)
3659 output_asm_insn ("tap", operands);
3664 /* Rotate B first to move the carry to bit-7. */
3665 if (D_REG_P (operands[0]))
3666 output_asm_insn ("rorb", operands);
3668 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3669 output_asm_insn ("rora", operands);
3676 /* Store in cc_status the expressions that the condition codes will
3677 describe after execution of an instruction whose pattern is EXP.
3678 Do not alter them if the instruction would not alter the cc's. */
3681 m68hc11_notice_update_cc (exp, insn)
3683 rtx insn ATTRIBUTE_UNUSED;
3685 /* recognize SET insn's. */
3686 if (GET_CODE (exp) == SET)
3688 /* Jumps do not alter the cc's. */
3689 if (SET_DEST (exp) == pc_rtx)
3692 /* NOTE: most instructions don't affect the carry bit, but the
3693 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3694 the conditions.h header. */
3696 /* Function calls clobber the cc's. */
3697 else if (GET_CODE (SET_SRC (exp)) == CALL)
3702 /* Tests and compares set the cc's in predictable ways. */
3703 else if (SET_DEST (exp) == cc0_rtx)
3705 cc_status.flags = 0;
3706 cc_status.value1 = XEXP (exp, 0);
3707 cc_status.value2 = XEXP (exp, 1);
3711 /* All other instructions affect the condition codes. */
3712 cc_status.flags = 0;
3713 cc_status.value1 = XEXP (exp, 0);
3714 cc_status.value2 = XEXP (exp, 1);
3719 /* Default action if we haven't recognized something
3720 and returned earlier. */
3724 if (cc_status.value2 != 0)
3725 switch (GET_CODE (cc_status.value2))
3727 /* These logical operations can generate several insns.
3728 The flags are setup according to what is generated. */
3734 /* The (not ...) generates several 'com' instructions for
3735 non QImode. We have to invalidate the flags. */
3737 if (GET_MODE (cc_status.value2) != QImode)
3749 if (GET_MODE (cc_status.value2) != VOIDmode)
3750 cc_status.flags |= CC_NO_OVERFLOW;
3753 /* The asl sets the overflow bit in such a way that this
3754 makes the flags unusable for a next compare insn. */
3758 if (GET_MODE (cc_status.value2) != VOIDmode)
3759 cc_status.flags |= CC_NO_OVERFLOW;
3762 /* A load/store instruction does not affect the carry. */
3767 cc_status.flags |= CC_NO_OVERFLOW;
3773 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3775 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3776 cc_status.value2 = 0;
3779 /* The current instruction does not affect the flags but changes
3780 the register 'reg'. See if the previous flags can be kept for the
3781 next instruction to avoid a comparison. */
3783 m68hc11_notice_keep_cc (reg)
3787 || cc_prev_status.value1 == 0
3788 || rtx_equal_p (reg, cc_prev_status.value1)
3789 || (cc_prev_status.value2
3790 && reg_mentioned_p (reg, cc_prev_status.value2)))
3793 cc_status = cc_prev_status;
3798 /* Machine Specific Reorg. */
3800 /* Z register replacement:
3802 GCC treats the Z register as an index base address register like
3803 X or Y. In general, it uses it during reload to compute the address
3804 of some operand. This helps the reload pass to avoid to fall into the
3805 register spill failure.
3807 The Z register is in the A_REGS class. In the machine description,
3808 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3810 It can appear everywhere an X or Y register can appear, except for
3811 some templates in the clobber section (when a clobber of X or Y is asked).
3812 For a given instruction, the template must ensure that no more than
3813 2 'A' registers are used. Otherwise, the register replacement is not
3816 To replace the Z register, the algorithm is not terrific:
3817 1. Insns that do not use the Z register are not changed
3818 2. When a Z register is used, we scan forward the insns to see
3819 a potential register to use: either X or Y and sometimes D.
3820 We stop when a call, a label or a branch is seen, or when we
3821 detect that both X and Y are used (probably at different times, but it does
3823 3. The register that will be used for the replacement of Z is saved
3824 in a .page0 register or on the stack. If the first instruction that
3825 used Z, uses Z as an input, the value is loaded from another .page0
3826 register. The replacement register is pushed on the stack in the
3827 rare cases where a compare insn uses Z and we couldn't find if X/Y
3829 4. The Z register is replaced in all instructions until we reach
3830 the end of the Z-block, as detected by step 2.
3831 5. If we detect that Z is still alive, its value is saved.
3832 If the replacement register is alive, its old value is loaded.
3834 The Z register can be disabled with -ffixed-z.
3844 int must_restore_reg;
3855 int save_before_last;
3856 int z_loaded_with_sp;
3859 static rtx z_reg_qi;
3861 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
3862 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
3863 static void m68hc11_z_replacement PARAMS ((rtx));
3864 static void m68hc11_reassign_regs PARAMS ((rtx));
3866 int z_replacement_completed = 0;
3868 /* Analyze the insn to find out which replacement register to use and
3869 the boundaries of the replacement.
3870 Returns 0 if we reached the last insn to be replaced, 1 if we can
3871 continue replacement in next insns. */
3874 m68hc11_check_z_replacement (insn, info)
3876 struct replace_info *info;
3878 int this_insn_uses_ix;
3879 int this_insn_uses_iy;
3880 int this_insn_uses_z;
3881 int this_insn_uses_z_in_dst;
3882 int this_insn_uses_d;
3886 /* A call is said to clobber the Z register, we don't need
3887 to save the value of Z. We also don't need to restore
3888 the replacement register (unless it is used by the call). */
3889 if (GET_CODE (insn) == CALL_INSN)
3891 body = PATTERN (insn);
3893 info->can_use_d = 0;
3895 /* If the call is an indirect call with Z, we have to use the
3896 Y register because X can be used as an input (D+X).
3897 We also must not save Z nor restore Y. */
3898 if (reg_mentioned_p (z_reg, body))
3900 insn = NEXT_INSN (insn);
3903 info->found_call = 1;
3904 info->must_restore_reg = 0;
3905 info->last = NEXT_INSN (insn);
3907 info->need_save_z = 0;
3910 if (GET_CODE (insn) == CODE_LABEL
3911 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
3914 if (GET_CODE (insn) == JUMP_INSN)
3916 if (reg_mentioned_p (z_reg, insn) == 0)
3919 info->can_use_d = 0;
3920 info->must_save_reg = 0;
3921 info->must_restore_reg = 0;
3922 info->need_save_z = 0;
3923 info->last = NEXT_INSN (insn);
3926 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
3931 /* Z register dies here. */
3932 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
3934 body = PATTERN (insn);
3935 if (GET_CODE (body) == SET)
3937 rtx src = XEXP (body, 1);
3938 rtx dst = XEXP (body, 0);
3940 /* Condition code is set here. We have to restore the X/Y and
3941 save into Z before any test/compare insn because once we save/restore
3942 we can change the condition codes. When the compare insn uses Z and
3943 we can't use X/Y, the comparison is made with the *ZREG soft register
3944 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3947 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
3948 || (GET_CODE (src) == COMPARE &&
3949 (rtx_equal_p (XEXP (src, 0), z_reg)
3950 || rtx_equal_p (XEXP (src, 1), z_reg))))
3952 if (insn == info->first)
3954 info->must_load_z = 0;
3955 info->must_save_reg = 0;
3956 info->must_restore_reg = 0;
3957 info->need_save_z = 0;
3958 info->found_call = 1;
3959 info->regno = SOFT_Z_REGNUM;
3964 if (reg_mentioned_p (z_reg, src) == 0)
3966 info->can_use_d = 0;
3970 if (insn != info->first)
3973 /* Compare insn which uses Z. We have to save/restore the X/Y
3974 register without modifying the condition codes. For this
3975 we have to use a push/pop insn. */
3976 info->must_push_reg = 1;
3980 /* Z reg is set to something new. We don't need to load it. */
3983 if (!reg_mentioned_p (z_reg, src))
3985 /* Z reg is used before being set. Treat this as
3986 a new sequence of Z register replacement. */
3987 if (insn != info->first)
3991 info->must_load_z = 0;
3993 info->z_set_count++;
3994 info->z_value = src;
3996 info->z_loaded_with_sp = 1;
3998 else if (reg_mentioned_p (z_reg, dst))
3999 info->can_use_d = 0;
4001 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4002 | reg_mentioned_p (d_reg, dst);
4003 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4004 | reg_mentioned_p (ix_reg, dst);
4005 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4006 | reg_mentioned_p (iy_reg, dst);
4007 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4009 /* If z is used as an address operand (like (MEM (reg z))),
4010 we can't replace it with d. */
4011 if (this_insn_uses_z && !Z_REG_P (src)
4012 && !(m68hc11_arith_operator (src, GET_MODE (src))
4013 && Z_REG_P (XEXP (src, 0))
4014 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4015 && insn == info->first
4016 && dead_register_here (insn, d_reg)))
4017 info->can_use_d = 0;
4019 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4020 if (TARGET_M6812 && !z_dies_here
4021 && ((this_insn_uses_z && side_effects_p (src))
4022 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4024 info->need_save_z = 1;
4025 info->z_set_count++;
4027 this_insn_uses_z |= this_insn_uses_z_in_dst;
4029 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4031 fatal_insn ("Registers IX, IY and Z used in the same INSN", insn);
4034 if (this_insn_uses_d)
4035 info->can_use_d = 0;
4037 /* IX and IY are used at the same time, we have to restore
4038 the value of the scratch register before this insn. */
4039 if (this_insn_uses_ix && this_insn_uses_iy)
4044 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4045 info->can_use_d = 0;
4047 if (info->x_used == 0 && this_insn_uses_ix)
4051 /* We have a (set (REG:HI X) (REG:HI Z)).
4052 Since we use Z as the replacement register, this insn
4053 is no longer necessary. We turn it into a note. We must
4054 not reload the old value of X. */
4055 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4059 info->need_save_z = 0;
4062 info->must_save_reg = 0;
4063 info->must_restore_reg = 0;
4064 info->found_call = 1;
4065 info->can_use_d = 0;
4066 PUT_CODE (insn, NOTE);
4067 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4068 NOTE_SOURCE_FILE (insn) = 0;
4069 info->last = NEXT_INSN (insn);
4074 && (rtx_equal_p (src, z_reg)
4075 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4079 info->need_save_z = 0;
4082 info->last = NEXT_INSN (insn);
4083 info->must_save_reg = 0;
4084 info->must_restore_reg = 0;
4086 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4087 && !reg_mentioned_p (ix_reg, src))
4092 info->need_save_z = 0;
4096 info->save_before_last = 1;
4098 info->must_restore_reg = 0;
4099 info->last = NEXT_INSN (insn);
4101 else if (info->can_use_d)
4103 info->last = NEXT_INSN (insn);
4109 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4110 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4112 info->need_save_z = 0;
4114 info->last = NEXT_INSN (insn);
4115 info->regno = HARD_X_REGNUM;
4116 info->must_save_reg = 0;
4117 info->must_restore_reg = 0;
4120 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4122 info->regno = HARD_X_REGNUM;
4123 info->must_restore_reg = 0;
4124 info->must_save_reg = 0;
4128 if (info->y_used == 0 && this_insn_uses_iy)
4132 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4136 info->need_save_z = 0;
4139 info->must_save_reg = 0;
4140 info->must_restore_reg = 0;
4141 info->found_call = 1;
4142 info->can_use_d = 0;
4143 PUT_CODE (insn, NOTE);
4144 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4145 NOTE_SOURCE_FILE (insn) = 0;
4146 info->last = NEXT_INSN (insn);
4151 && (rtx_equal_p (src, z_reg)
4152 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4157 info->need_save_z = 0;
4159 info->last = NEXT_INSN (insn);
4160 info->must_save_reg = 0;
4161 info->must_restore_reg = 0;
4163 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4164 && !reg_mentioned_p (iy_reg, src))
4169 info->need_save_z = 0;
4173 info->save_before_last = 1;
4175 info->must_restore_reg = 0;
4176 info->last = NEXT_INSN (insn);
4178 else if (info->can_use_d)
4180 info->last = NEXT_INSN (insn);
4187 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4188 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4190 info->need_save_z = 0;
4192 info->last = NEXT_INSN (insn);
4193 info->regno = HARD_Y_REGNUM;
4194 info->must_save_reg = 0;
4195 info->must_restore_reg = 0;
4198 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4200 info->regno = HARD_Y_REGNUM;
4201 info->must_restore_reg = 0;
4202 info->must_save_reg = 0;
4208 info->need_save_z = 0;
4210 if (info->last == 0)
4211 info->last = NEXT_INSN (insn);
4214 return info->last != NULL_RTX ? 0 : 1;
4216 if (GET_CODE (body) == PARALLEL)
4219 char ix_clobber = 0;
4220 char iy_clobber = 0;
4222 this_insn_uses_iy = 0;
4223 this_insn_uses_ix = 0;
4224 this_insn_uses_z = 0;
4226 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4229 int uses_ix, uses_iy, uses_z;
4231 x = XVECEXP (body, 0, i);
4233 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4234 info->can_use_d = 0;
4236 uses_ix = reg_mentioned_p (ix_reg, x);
4237 uses_iy = reg_mentioned_p (iy_reg, x);
4238 uses_z = reg_mentioned_p (z_reg, x);
4239 if (GET_CODE (x) == CLOBBER)
4241 ix_clobber |= uses_ix;
4242 iy_clobber |= uses_iy;
4243 z_clobber |= uses_z;
4247 this_insn_uses_ix |= uses_ix;
4248 this_insn_uses_iy |= uses_iy;
4249 this_insn_uses_z |= uses_z;
4251 if (uses_z && GET_CODE (x) == SET)
4253 rtx dst = XEXP (x, 0);
4256 info->z_set_count++;
4258 if (TARGET_M6812 && uses_z && side_effects_p (x))
4259 info->need_save_z = 1;
4262 info->need_save_z = 0;
4266 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4267 this_insn_uses_ix, this_insn_uses_iy,
4268 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4271 if (this_insn_uses_z)
4272 info->can_use_d = 0;
4274 if (z_clobber && info->first != insn)
4276 info->need_save_z = 0;
4280 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4282 if (this_insn_uses_z == 0 && insn == info->first)
4284 info->must_load_z = 0;
4286 if (dead_register_here (insn, d_reg))
4288 info->regno = HARD_D_REGNUM;
4289 info->must_save_reg = 0;
4290 info->must_restore_reg = 0;
4292 else if (dead_register_here (insn, ix_reg))
4294 info->regno = HARD_X_REGNUM;
4295 info->must_save_reg = 0;
4296 info->must_restore_reg = 0;
4298 else if (dead_register_here (insn, iy_reg))
4300 info->regno = HARD_Y_REGNUM;
4301 info->must_save_reg = 0;
4302 info->must_restore_reg = 0;
4304 if (info->regno >= 0)
4306 info->last = NEXT_INSN (insn);
4309 if (this_insn_uses_ix == 0)
4311 info->regno = HARD_X_REGNUM;
4312 info->must_save_reg = 1;
4313 info->must_restore_reg = 1;
4315 else if (this_insn_uses_iy == 0)
4317 info->regno = HARD_Y_REGNUM;
4318 info->must_save_reg = 1;
4319 info->must_restore_reg = 1;
4323 info->regno = HARD_D_REGNUM;
4324 info->must_save_reg = 1;
4325 info->must_restore_reg = 1;
4327 info->last = NEXT_INSN (insn);
4331 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4332 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4334 if (this_insn_uses_z)
4336 if (info->y_used == 0 && iy_clobber)
4338 info->regno = HARD_Y_REGNUM;
4339 info->must_save_reg = 0;
4340 info->must_restore_reg = 0;
4342 info->last = NEXT_INSN (insn);
4343 info->save_before_last = 1;
4347 if (this_insn_uses_ix && this_insn_uses_iy)
4349 if (this_insn_uses_z)
4351 fatal_insn ("Cannot do z-register replacement", insn);
4355 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4362 if (iy_clobber || z_clobber)
4364 info->last = NEXT_INSN (insn);
4365 info->save_before_last = 1;
4370 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4377 if (ix_clobber || z_clobber)
4379 info->last = NEXT_INSN (insn);
4380 info->save_before_last = 1;
4387 info->need_save_z = 0;
4391 if (GET_CODE (body) == CLOBBER)
4394 /* IX and IY are used at the same time, we have to restore
4395 the value of the scratch register before this insn. */
4396 if (this_insn_uses_ix && this_insn_uses_iy)
4400 if (info->x_used == 0 && this_insn_uses_ix)
4408 if (info->y_used == 0 && this_insn_uses_iy)
4422 m68hc11_find_z_replacement (insn, info)
4424 struct replace_info *info;
4428 info->replace_reg = NULL_RTX;
4429 info->must_load_z = 1;
4430 info->need_save_z = 1;
4431 info->must_save_reg = 1;
4432 info->must_restore_reg = 1;
4436 info->can_use_d = TARGET_M6811 ? 1 : 0;
4437 info->found_call = 0;
4441 info->z_set_count = 0;
4442 info->z_value = NULL_RTX;
4443 info->must_push_reg = 0;
4444 info->save_before_last = 0;
4445 info->z_loaded_with_sp = 0;
4447 /* Scan the insn forward to find an address register that is not used.
4449 - the flow of the program changes,
4450 - when we detect that both X and Y are necessary,
4451 - when the Z register dies,
4452 - when the condition codes are set. */
4454 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4456 if (m68hc11_check_z_replacement (insn, info) == 0)
4460 /* May be we can use Y or X if they contain the same value as Z.
4461 This happens very often after the reload. */
4462 if (info->z_set_count == 1)
4464 rtx p = info->first;
4469 v = find_last_value (iy_reg, &p, insn, 1);
4471 else if (info->y_used)
4473 v = find_last_value (ix_reg, &p, insn, 1);
4475 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4478 info->regno = HARD_Y_REGNUM;
4480 info->regno = HARD_X_REGNUM;
4481 info->must_load_z = 0;
4482 info->must_save_reg = 0;
4483 info->must_restore_reg = 0;
4484 info->found_call = 1;
4487 if (info->z_set_count == 0)
4488 info->need_save_z = 0;
4491 info->need_save_z = 0;
4493 if (info->last == 0)
4496 if (info->regno >= 0)
4499 info->replace_reg = gen_rtx (REG, HImode, reg);
4501 else if (info->can_use_d)
4503 reg = HARD_D_REGNUM;
4504 info->replace_reg = d_reg;
4506 else if (info->x_used)
4508 reg = HARD_Y_REGNUM;
4509 info->replace_reg = iy_reg;
4513 reg = HARD_X_REGNUM;
4514 info->replace_reg = ix_reg;
4518 if (info->must_save_reg && info->must_restore_reg)
4520 if (insn && dead_register_here (insn, info->replace_reg))
4522 info->must_save_reg = 0;
4523 info->must_restore_reg = 0;
4528 /* The insn uses the Z register. Find a replacement register for it
4529 (either X or Y) and replace it in the insn and the next ones until
4530 the flow changes or the replacement register is used. Instructions
4531 are emited before and after the Z-block to preserve the value of
4532 Z and of the replacement register. */
4535 m68hc11_z_replacement (insn)
4540 struct replace_info info;
4542 /* Find trivial case where we only need to replace z with the
4543 equivalent soft register. */
4544 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4546 rtx body = PATTERN (insn);
4547 rtx src = XEXP (body, 1);
4548 rtx dst = XEXP (body, 0);
4550 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4552 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4555 else if (Z_REG_P (src)
4556 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4558 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4561 else if (D_REG_P (dst)
4562 && m68hc11_arith_operator (src, GET_MODE (src))
4563 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4565 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4568 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4569 && INTVAL (src) == 0)
4571 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4572 /* Force it to be re-recognized. */
4573 INSN_CODE (insn) = -1;
4578 m68hc11_find_z_replacement (insn, &info);
4580 replace_reg = info.replace_reg;
4581 replace_reg_qi = NULL_RTX;
4583 /* Save the X register in a .page0 location. */
4584 if (info.must_save_reg && !info.must_push_reg)
4588 if (info.must_push_reg && 0)
4589 dst = gen_rtx (MEM, HImode,
4590 gen_rtx (PRE_DEC, HImode,
4591 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4593 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4595 emit_insn_before (gen_movhi (dst,
4596 gen_rtx (REG, HImode, info.regno)), insn);
4598 if (info.must_load_z && !info.must_push_reg)
4600 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4601 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4606 /* Replace all occurence of Z by replace_reg.
4607 Stop when the last instruction to replace is reached.
4608 Also stop when we detect a change in the flow (but it's not
4609 necessary; just safeguard). */
4611 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4615 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4618 if (GET_CODE (insn) != INSN
4619 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4622 body = PATTERN (insn);
4623 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4624 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4626 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4628 printf ("Reg mentioned here...:\n");
4633 /* Stack pointer was decremented by 2 due to the push.
4634 Correct that by adding 2 to the destination. */
4635 if (info.must_push_reg
4636 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4640 src = SET_SRC (body);
4641 dst = SET_DEST (body);
4642 if (SP_REG_P (src) && Z_REG_P (dst))
4644 emit_insn_after (gen_addhi3 (dst,
4647 VOIDmode, 2)), insn);
4651 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4652 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4654 INSN_CODE (insn) = -1;
4655 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4656 fatal_insn ("Cannot do z-register replacement", insn);
4659 /* Likewise for (REG:QI Z). */
4660 if (reg_mentioned_p (z_reg, insn))
4662 if (replace_reg_qi == NULL_RTX)
4663 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4664 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4667 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4671 /* Save Z before restoring the old value. */
4672 if (insn && info.need_save_z && !info.must_push_reg)
4674 rtx save_pos_insn = insn;
4676 /* If Z is clobber by the last insn, we have to save its value
4677 before the last instruction. */
4678 if (info.save_before_last)
4679 save_pos_insn = PREV_INSN (save_pos_insn);
4681 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4682 gen_rtx (REG, HImode, info.regno)),
4686 if (info.must_push_reg && info.last)
4690 body = PATTERN (info.last);
4691 new_body = gen_rtx (PARALLEL, VOIDmode,
4693 gen_rtx (USE, VOIDmode,
4695 gen_rtx (USE, VOIDmode,
4696 gen_rtx (REG, HImode,
4698 PATTERN (info.last) = new_body;
4700 /* Force recognition on insn since we changed it. */
4701 INSN_CODE (insn) = -1;
4703 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4705 fatal_insn ("Invalid Z register replacement for insn", insn);
4707 insn = NEXT_INSN (info.last);
4710 /* Restore replacement register unless it was died. */
4711 if (insn && info.must_restore_reg && !info.must_push_reg)
4715 if (info.must_push_reg && 0)
4716 dst = gen_rtx (MEM, HImode,
4717 gen_rtx (POST_INC, HImode,
4718 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4720 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4722 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4729 /* Scan all the insn and re-affects some registers
4730 - The Z register (if it was used), is affected to X or Y depending
4731 on the instruction. */
4734 m68hc11_reassign_regs (first)
4739 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
4740 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
4741 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4742 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
4744 /* Scan all insns to replace Z by X or Y preserving the old value
4745 of X/Y and restoring it afterward. */
4747 for (insn = first; insn; insn = NEXT_INSN (insn))
4751 if (GET_CODE (insn) == CODE_LABEL
4752 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4755 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4758 body = PATTERN (insn);
4759 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4762 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4763 || GET_CODE (body) == ASM_OPERANDS
4764 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4767 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4768 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4771 /* If Z appears in this insn, replace it in the current insn
4772 and the next ones until the flow changes or we have to
4773 restore back the replacement register. */
4775 if (reg_mentioned_p (z_reg, body))
4777 m68hc11_z_replacement (insn);
4782 printf ("Insn not handled by Z replacement:\n");
4791 m68hc11_reorg (first)
4797 z_replacement_completed = 0;
4798 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4800 /* Some RTX are shared at this point. This breaks the Z register
4801 replacement, unshare everything. */
4802 unshare_all_rtl_again (first);
4804 /* Force a split of all splitable insn. This is necessary for the
4805 Z register replacement mechanism because we end up with basic insns. */
4806 split_all_insns_noflow ();
4809 z_replacement_completed = 1;
4810 m68hc11_reassign_regs (first);
4812 /* After some splitting, there are some oportunities for CSE pass.
4813 This happens quite often when 32-bit or above patterns are split. */
4814 if (optimize > 0 && split_done)
4815 reload_cse_regs (first);
4817 /* Re-create the REG_DEAD notes. These notes are used in the machine
4818 description to use the best assembly directives. */
4821 /* Before recomputing the REG_DEAD notes, remove all of them.
4822 This is necessary because the reload_cse_regs() pass can
4823 have replaced some (MEM) with a register. In that case,
4824 the REG_DEAD that could exist for that register may become
4826 for (insn = first; insn; insn = NEXT_INSN (insn))
4832 pnote = ®_NOTES (insn);
4835 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
4836 *pnote = XEXP (*pnote, 1);
4838 pnote = &XEXP (*pnote, 1);
4843 find_basic_blocks (first, max_reg_num (), 0);
4844 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
4847 z_replacement_completed = 2;
4849 /* If optimizing, then go ahead and split insns that must be
4850 split after Z register replacement. This gives more opportunities
4851 for peephole (in particular for consecutives xgdx/xgdy). */
4853 split_all_insns_noflow ();
4855 /* Once insns are split after the z_replacement_completed == 2,
4856 we must not re-run the life_analysis. The xgdx/xgdy patterns
4857 are not recognized and the life_analysis pass removes some
4858 insns because it thinks some (SETs) are noops or made to dead
4859 stores (which is false due to the swap).
4861 Do a simple pass to eliminate the noop set that the final
4862 split could generate (because it was easier for split definition). */
4866 for (insn = first; insn; insn = NEXT_INSN (insn))
4870 if (INSN_DELETED_P (insn))
4872 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4875 /* Remove the (set (R) (R)) insns generated by some splits. */
4876 body = PATTERN (insn);
4877 if (GET_CODE (body) == SET
4878 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
4880 PUT_CODE (insn, NOTE);
4881 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4882 NOTE_SOURCE_FILE (insn) = 0;
4890 /* Cost functions. */
4892 /* Cost of moving memory. */
4894 m68hc11_memory_move_cost (mode, class, in)
4895 enum machine_mode mode;
4896 enum reg_class class;
4897 int in ATTRIBUTE_UNUSED;
4899 if (class <= H_REGS)
4901 if (GET_MODE_SIZE (mode) <= 2)
4902 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4904 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
4908 if (GET_MODE_SIZE (mode) <= 2)
4909 return COSTS_N_INSNS (2);
4911 return COSTS_N_INSNS (4);
4916 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4917 Reload does not check the constraint of set insns when the two registers
4918 have a move cost of 2. Setting a higher cost will force reload to check
4921 m68hc11_register_move_cost (from, to)
4922 enum reg_class from;
4925 if (from >= S_REGS && to >= S_REGS)
4927 return COSTS_N_INSNS (3);
4929 if (from <= S_REGS && to <= S_REGS)
4931 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4933 return COSTS_N_INSNS (2);
4937 /* Provide the costs of an addressing mode that contains ADDR.
4938 If ADDR is not a valid address, its cost is irrelevant. */
4941 m68hc11_address_cost (addr)
4946 switch (GET_CODE (addr))
4949 /* Make the cost of hard registers and specially SP, FP small. */
4950 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
4967 register rtx plus0 = XEXP (addr, 0);
4968 register rtx plus1 = XEXP (addr, 1);
4970 if (GET_CODE (plus0) != REG)
4973 switch (GET_CODE (plus1))
4976 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
4977 || INTVAL (plus1) < m68hc11_min_offset)
4979 else if (INTVAL (plus1) >= m68hc11_max_offset)
4983 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5005 if (SP_REG_P (XEXP (addr, 0)))
5014 printf ("Address cost: %d for :", cost);
5023 m68hc11_shift_cost (mode, x, shift)
5024 enum machine_mode mode;
5030 total = rtx_cost (x, SET);
5032 total += m68hc11_cost->shiftQI_const[shift % 8];
5033 else if (mode == HImode)
5034 total += m68hc11_cost->shiftHI_const[shift % 16];
5035 else if (shift == 8 || shift == 16 || shift == 32)
5036 total += m68hc11_cost->shiftHI_const[8];
5037 else if (shift != 0 && shift != 16 && shift != 32)
5039 total += m68hc11_cost->shiftHI_const[1] * shift;
5042 /* For SI and others, the cost is higher. */
5043 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5044 total *= GET_MODE_SIZE (mode) / 2;
5046 /* When optimizing for size, make shift more costly so that
5047 multiplications are prefered. */
5048 if (optimize_size && (shift % 8) != 0)
5055 m68hc11_rtx_costs (x, code, outer_code)
5058 enum rtx_code outer_code ATTRIBUTE_UNUSED;
5060 enum machine_mode mode = GET_MODE (x);
5071 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5073 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5076 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5077 total += m68hc11_cost->shift_var;
5083 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5084 total += m68hc11_cost->logical;
5086 /* Logical instructions are byte instructions only. */
5087 total *= GET_MODE_SIZE (mode);
5092 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5093 total += m68hc11_cost->add;
5094 if (GET_MODE_SIZE (mode) > 2)
5096 total *= GET_MODE_SIZE (mode) / 2;
5103 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5107 total += m68hc11_cost->divQI;
5111 total += m68hc11_cost->divHI;
5116 total += m68hc11_cost->divSI;
5122 /* mul instruction produces 16-bit result. */
5123 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5124 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5125 return m68hc11_cost->multQI
5126 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5127 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5129 /* emul instruction produces 32-bit result for 68HC12. */
5130 if (TARGET_M6812 && mode == SImode
5131 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5132 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5133 return m68hc11_cost->multHI
5134 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5135 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5137 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5141 total += m68hc11_cost->multQI;
5145 total += m68hc11_cost->multHI;
5150 total += m68hc11_cost->multSI;
5157 extra_cost = COSTS_N_INSNS (2);
5164 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5167 return total + COSTS_N_INSNS (1);
5171 return total + COSTS_N_INSNS (2);
5175 return total + COSTS_N_INSNS (4);
5177 return total + COSTS_N_INSNS (8);
5180 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5181 return COSTS_N_INSNS (1);
5183 return COSTS_N_INSNS (1);
5186 return COSTS_N_INSNS (4);
5191 /* print_options - called at the start of the code generation for a
5194 extern char *asm_file_name;
5197 #include <sys/types.h>
5206 extern int save_argc;
5207 extern char **save_argv;
5209 fprintf (out, ";;; Command:\t");
5210 for (i = 0; i < save_argc; i++)
5212 fprintf (out, "%s", save_argv[i]);
5213 if (i + 1 < save_argc)
5216 fprintf (out, "\n");
5218 a_time = ctime (&c_time);
5219 fprintf (out, ";;; Compiled:\t%s", a_time);
5222 #define __VERSION__ "[unknown]"
5224 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
5226 fprintf (out, ";;; (META)compiled by CC.\n");
5231 m68hc11_asm_file_start (out, main_file)
5235 fprintf (out, ";;;-----------------------------------------\n");
5236 fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
5237 fprintf (out, ";;; gcc compiler %s\n", version_string);
5238 print_options (out);
5239 fprintf (out, ";;;-----------------------------------------\n");
5240 output_file_directive (out, main_file);
5245 m68hc11_add_gc_roots ()
5247 ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
5248 ggc_add_rtx_root (&ix_reg, 1);
5249 ggc_add_rtx_root (&iy_reg, 1);
5250 ggc_add_rtx_root (&d_reg, 1);
5251 ggc_add_rtx_root (&da_reg, 1);
5252 ggc_add_rtx_root (&z_reg, 1);
5253 ggc_add_rtx_root (&z_reg_qi, 1);
5254 ggc_add_rtx_root (&stack_push_word, 1);
5255 ggc_add_rtx_root (&stack_pop_word, 1);