1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@nerim.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
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
38 #include "coretypes.h"
44 #include "hard-reg-set.h"
46 #include "insn-config.h"
47 #include "conditions.h"
49 #include "insn-attr.h"
54 #include "basic-block.h"
59 #include "target-def.h"
61 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
62 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
63 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
64 static void m68hc11_reorg PARAMS ((void));
65 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
67 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
68 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
69 static int must_parenthesize PARAMS ((rtx));
70 static int m68hc11_address_cost PARAMS ((rtx));
71 static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
72 static int m68hc11_rtx_costs_1 PARAMS ((rtx, enum rtx_code, enum rtx_code));
73 static bool m68hc11_rtx_costs PARAMS ((rtx, int, int, int *));
74 static int m68hc11_auto_inc_p PARAMS ((rtx));
75 static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
76 const struct attribute_spec m68hc11_attribute_table[];
78 void create_regs_rtx PARAMS ((void));
80 static void asm_print_register PARAMS ((FILE *, int));
81 static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
82 static void m68hc11_asm_out_constructor PARAMS ((rtx, int));
83 static void m68hc11_asm_out_destructor PARAMS ((rtx, int));
84 static void m68hc11_file_start PARAMS ((void));
85 static void m68hc11_encode_section_info PARAMS((tree, rtx, int));
86 static int autoinc_mode PARAMS((rtx));
87 static int m68hc11_make_autoinc_notes PARAMS((rtx *, void *));
89 /* Must be set to 1 to produce debug messages. */
92 extern FILE *asm_out_file;
97 rtx m68hc11_soft_tmp_reg;
98 static GTY(()) rtx stack_push_word;
99 static GTY(()) rtx stack_pop_word;
100 static GTY(()) rtx z_reg;
101 static GTY(()) rtx z_reg_qi;
102 static int regs_inited = 0;
104 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
105 int current_function_interrupt;
107 /* Set to 1 by expand_prologue() when the function is a trap handler. */
108 int current_function_trap;
110 /* Set to 1 when the current function is placed in 68HC12 banked
111 memory and must return with rtc. */
112 int current_function_far;
114 /* Min offset that is valid for the indirect addressing mode. */
115 HOST_WIDE_INT m68hc11_min_offset = 0;
117 /* Max offset that is valid for the indirect addressing mode. */
118 HOST_WIDE_INT m68hc11_max_offset = 256;
120 /* The class value for base registers. */
121 enum reg_class m68hc11_base_reg_class = A_REGS;
123 /* The class value for index registers. This is NO_REGS for 68HC11. */
124 enum reg_class m68hc11_index_reg_class = NO_REGS;
126 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
128 /* Tables that tell whether a given hard register is valid for
129 a base or an index register. It is filled at init time depending
130 on the target processor. */
131 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
132 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
134 /* A correction offset which is applied to the stack pointer.
135 This is 1 for 68HC11 and 0 for 68HC12. */
136 int m68hc11_sp_correction;
138 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
139 rtx m68hc11_compare_op0;
140 rtx m68hc11_compare_op1;
143 const struct processor_costs *m68hc11_cost;
145 /* Costs for a 68HC11. */
146 static const struct processor_costs m6811_cost = {
151 /* non-constant shift */
154 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
155 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
156 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
159 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
160 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
161 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
162 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
163 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
164 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
169 COSTS_N_INSNS (20 * 4),
171 COSTS_N_INSNS (20 * 16),
180 /* Costs for a 68HC12. */
181 static const struct processor_costs m6812_cost = {
186 /* non-constant shift */
189 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
190 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
191 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
194 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
195 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
196 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
197 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
198 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
199 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
206 COSTS_N_INSNS (3 * 4),
215 /* Machine specific options */
217 const char *m68hc11_regparm_string;
218 const char *m68hc11_reg_alloc_order;
219 const char *m68hc11_soft_reg_count;
221 static int nb_soft_regs;
223 /* Initialize the GCC target structure. */
224 #undef TARGET_ATTRIBUTE_TABLE
225 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
227 #undef TARGET_ASM_ALIGNED_HI_OP
228 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
230 #undef TARGET_ASM_FUNCTION_EPILOGUE
231 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
233 #undef TARGET_ASM_FILE_START
234 #define TARGET_ASM_FILE_START m68hc11_file_start
235 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
236 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
238 #undef TARGET_ENCODE_SECTION_INFO
239 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
241 #undef TARGET_RTX_COSTS
242 #define TARGET_RTX_COSTS m68hc11_rtx_costs
243 #undef TARGET_ADDRESS_COST
244 #define TARGET_ADDRESS_COST m68hc11_address_cost
246 #undef TARGET_MACHINE_DEPENDENT_REORG
247 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
249 struct gcc_target targetm = TARGET_INITIALIZER;
252 m68hc11_override_options ()
254 memset (m68hc11_reg_valid_for_index, 0,
255 sizeof (m68hc11_reg_valid_for_index));
256 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
258 /* Compilation with -fpic generates a wrong code. */
261 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
262 (flag_pic > 1) ? "PIC" : "pic");
266 /* Configure for a 68hc11 processor. */
269 /* If gcc was built for a 68hc12, invalidate that because
270 a -m68hc11 option was specified on the command line. */
271 if (TARGET_DEFAULT != MASK_M6811)
272 target_flags &= ~TARGET_DEFAULT;
275 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
276 m68hc11_cost = &m6811_cost;
277 m68hc11_min_offset = 0;
278 m68hc11_max_offset = 256;
279 m68hc11_index_reg_class = NO_REGS;
280 m68hc11_base_reg_class = A_REGS;
281 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
282 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
283 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
284 m68hc11_sp_correction = 1;
285 m68hc11_tmp_regs_class = D_REGS;
286 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
287 m68hc11_soft_reg_count = "4";
290 /* Configure for a 68hc12 processor. */
293 m68hc11_cost = &m6812_cost;
294 m68hc11_min_offset = -65536;
295 m68hc11_max_offset = 65536;
296 m68hc11_index_reg_class = D_REGS;
297 m68hc11_base_reg_class = A_OR_SP_REGS;
298 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
299 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
300 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
301 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
302 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
303 m68hc11_sp_correction = 0;
304 m68hc11_tmp_regs_class = TMP_REGS;
305 target_flags &= ~MASK_M6811;
306 target_flags |= MASK_NO_DIRECT_MODE;
307 if (m68hc11_soft_reg_count == 0)
308 m68hc11_soft_reg_count = "0";
310 if (TARGET_LONG_CALLS)
311 current_function_far = 1;
318 m68hc11_conditional_register_usage ()
321 int cnt = atoi (m68hc11_soft_reg_count);
325 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
326 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
329 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
332 call_used_regs[i] = 1;
335 /* For 68HC12, the Z register emulation is not necessary when the
336 frame pointer is not used. The frame pointer is eliminated and
337 replaced by the stack register (which is a BASE_REG_CLASS). */
338 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
340 fixed_regs[HARD_Z_REGNUM] = 1;
345 /* Reload and register operations. */
347 static const char *const reg_class_names[] = REG_CLASS_NAMES;
353 /* regs_inited = 1; */
354 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
355 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
356 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
357 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
359 stack_push_word = gen_rtx (MEM, HImode,
360 gen_rtx (PRE_DEC, HImode,
361 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
362 stack_pop_word = gen_rtx (MEM, HImode,
363 gen_rtx (POST_INC, HImode,
364 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
368 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
369 - 8 bit values are stored anywhere (except the SP register).
370 - 16 bit values can be stored in any register whose mode is 16
371 - 32 bit values can be stored in D, X registers or in a soft register
372 (except the last one because we need 2 soft registers)
373 - Values whose size is > 32 bit are not stored in real hard
374 registers. They may be stored in soft registers if there are
377 hard_regno_mode_ok (regno, mode)
379 enum machine_mode mode;
381 switch (GET_MODE_SIZE (mode))
384 return S_REGNO_P (regno) && nb_soft_regs >= 4;
387 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
390 return G_REGNO_P (regno);
393 /* We have to accept a QImode in X or Y registers. Otherwise, the
394 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
395 in the insns. Reload fails if the insn rejects the register class 'a'
396 as well as if it accepts it. Patterns that failed were
397 zero_extend_qihi2 and iorqi3. */
399 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
407 m68hc11_hard_regno_rename_ok (reg1, reg2)
410 /* Don't accept renaming to Z register. We will replace it to
411 X,Y or D during machine reorg pass. */
412 if (reg2 == HARD_Z_REGNUM)
415 /* Don't accept renaming D,X to Y register as the code will be bigger. */
416 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
417 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
424 preferred_reload_class (operand, class)
426 enum reg_class class;
428 enum machine_mode mode;
430 mode = GET_MODE (operand);
434 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
437 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
438 return m68hc11_base_reg_class;
440 if (class >= S_REGS && (GET_CODE (operand) == MEM
441 || GET_CODE (operand) == CONST_INT))
443 /* S_REGS class must not be used. The movhi template does not
444 work to move a memory to a soft register.
445 Restrict to a hard reg. */
450 case D_OR_A_OR_S_REGS:
456 case D_OR_SP_OR_S_REGS:
457 class = D_OR_SP_REGS;
459 case D_OR_Y_OR_S_REGS:
462 case D_OR_X_OR_S_REGS:
478 else if (class == Y_REGS && GET_CODE (operand) == MEM)
482 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
486 else if (class >= S_REGS && S_REG_P (operand))
492 case D_OR_A_OR_S_REGS:
498 case D_OR_SP_OR_S_REGS:
499 class = D_OR_SP_REGS;
501 case D_OR_Y_OR_S_REGS:
504 case D_OR_X_OR_S_REGS:
520 else if (class >= S_REGS)
524 printf ("Class = %s for: ", reg_class_names[class]);
532 printf (" => class=%s\n", reg_class_names[class]);
540 /* Return 1 if the operand is a valid indexed addressing mode.
541 For 68hc11: n,r with n in [0..255] and r in A_REGS class
542 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
544 register_indirect_p (operand, mode, strict)
546 enum machine_mode mode;
551 switch (GET_CODE (operand))
557 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
558 return register_indirect_p (XEXP (operand, 0), mode, strict);
562 base = XEXP (operand, 0);
563 if (GET_CODE (base) == MEM)
566 offset = XEXP (operand, 1);
567 if (GET_CODE (offset) == MEM)
570 if (GET_CODE (base) == REG)
572 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
578 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
580 if (GET_CODE (offset) == REG)
582 if (!VALID_CONSTANT_OFFSET_P (base, mode))
588 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
593 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
599 return VALID_CONSTANT_OFFSET_P (operand, mode);
606 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
607 a 68HC12 1-byte index addressing mode. */
609 m68hc11_small_indexed_indirect_p (operand, mode)
611 enum machine_mode mode;
615 if (GET_CODE (operand) == REG && reload_in_progress
616 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
617 && reg_equiv_memory_loc[REGNO (operand)])
619 operand = reg_equiv_memory_loc[REGNO (operand)];
620 operand = eliminate_regs (operand, 0, NULL_RTX);
623 if (GET_CODE (operand) != MEM)
626 operand = XEXP (operand, 0);
627 if (CONSTANT_ADDRESS_P (operand))
630 if (PUSH_POP_ADDRESS_P (operand))
633 if (!register_indirect_p (operand, mode, reload_completed))
636 if (TARGET_M6812 && GET_CODE (operand) == PLUS
637 && (reload_completed | reload_in_progress))
639 base = XEXP (operand, 0);
640 offset = XEXP (operand, 1);
642 /* The offset can be a symbol address and this is too big
643 for the operand constraint. */
644 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
647 if (GET_CODE (base) == CONST_INT)
650 switch (GET_MODE_SIZE (mode))
653 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
658 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
663 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
672 m68hc11_register_indirect_p (operand, mode)
674 enum machine_mode mode;
676 if (GET_CODE (operand) != MEM)
679 operand = XEXP (operand, 0);
680 return register_indirect_p (operand, mode,
681 (reload_completed | reload_in_progress));
685 go_if_legitimate_address_internal (operand, mode, strict)
687 enum machine_mode mode;
690 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
692 /* Reject the global variables if they are too wide. This forces
693 a load of their address in a register and generates smaller code. */
694 if (GET_MODE_SIZE (mode) == 8)
699 if (register_indirect_p (operand, mode, strict))
703 if (PUSH_POP_ADDRESS_P (operand))
707 if (symbolic_memory_operand (operand, mode))
715 m68hc11_go_if_legitimate_address (operand, mode, strict)
717 enum machine_mode mode;
724 printf ("Checking: ");
729 result = go_if_legitimate_address_internal (operand, mode, strict);
733 printf (" -> %s\n", result == 0 ? "NO" : "YES");
740 printf ("go_if_legitimate%s, ret 0: %d:",
741 (strict ? "_strict" : ""), mode);
750 m68hc11_legitimize_address (operand, old_operand, mode)
751 rtx *operand ATTRIBUTE_UNUSED;
752 rtx old_operand ATTRIBUTE_UNUSED;
753 enum machine_mode mode ATTRIBUTE_UNUSED;
760 m68hc11_reload_operands (operands)
763 enum machine_mode mode;
765 if (regs_inited == 0)
768 mode = GET_MODE (operands[1]);
770 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
771 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
773 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
774 rtx base = XEXP (XEXP (operands[1], 0), 0);
776 if (GET_CODE (base) != REG)
783 /* If the offset is out of range, we have to compute the address
784 with a separate add instruction. We try to do with with an 8-bit
785 add on the A register. This is possible only if the lowest part
786 of the offset (ie, big_offset % 256) is a valid constant offset
787 with respect to the mode. If it's not, we have to generate a
788 16-bit add on the D register. From:
790 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
794 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
795 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
796 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
797 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
799 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
800 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
803 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
806 rtx reg = operands[0];
808 int val = INTVAL (big_offset);
811 /* We use the 'operands[0]' as a scratch register to compute the
812 address. Make sure 'base' is in that register. */
813 if (!rtx_equal_p (base, operands[0]))
815 emit_move_insn (reg, base);
825 vh = (val >> 8) & 0x0FF;
829 /* Create the lowest part offset that still remains to be added.
830 If it's not a valid offset, do a 16-bit add. */
831 offset = GEN_INT (vl);
832 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
834 emit_insn (gen_rtx (SET, VOIDmode, reg,
835 gen_rtx (PLUS, HImode, reg, big_offset)));
840 emit_insn (gen_rtx (SET, VOIDmode, reg,
841 gen_rtx (PLUS, HImode, reg,
842 GEN_INT (vh << 8))));
844 emit_move_insn (operands[0],
845 gen_rtx (MEM, GET_MODE (operands[1]),
846 gen_rtx (PLUS, Pmode, reg, offset)));
851 /* Use the normal gen_movhi pattern. */
856 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
859 enum machine_mode dmode;
860 enum machine_mode smode;
870 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
874 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
875 dmode, 1, operands[1], smode);
876 equiv = gen_rtx (code, dmode, operands[1]);
880 ret = emit_library_call_value (libcall, NULL_RTX,
882 operands[1], smode, operands[2],
884 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
891 insns = get_insns ();
893 emit_libcall_block (insns, operands[0], ret, equiv);
896 /* Returns true if X is a PRE/POST increment decrement
897 (same as auto_inc_p() in rtlanal.c but do not take into
898 account the stack). */
900 m68hc11_auto_inc_p (x)
903 return GET_CODE (x) == PRE_DEC
904 || GET_CODE (x) == POST_INC
905 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
909 /* Predicates for machine description. */
912 memory_reload_operand (operand, mode)
914 enum machine_mode mode ATTRIBUTE_UNUSED;
916 return GET_CODE (operand) == MEM
917 && GET_CODE (XEXP (operand, 0)) == PLUS
918 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
919 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
920 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
921 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
925 tst_operand (operand, mode)
927 enum machine_mode mode;
929 if (GET_CODE (operand) == MEM && reload_completed == 0)
931 rtx addr = XEXP (operand, 0);
932 if (m68hc11_auto_inc_p (addr))
935 return nonimmediate_operand (operand, mode);
939 cmp_operand (operand, mode)
941 enum machine_mode mode;
943 if (GET_CODE (operand) == MEM)
945 rtx addr = XEXP (operand, 0);
946 if (m68hc11_auto_inc_p (addr))
949 return general_operand (operand, mode);
953 non_push_operand (operand, mode)
955 enum machine_mode mode;
957 if (general_operand (operand, mode) == 0)
960 if (push_operand (operand, mode) == 1)
966 reg_or_some_mem_operand (operand, mode)
968 enum machine_mode mode;
970 if (GET_CODE (operand) == MEM)
972 rtx op = XEXP (operand, 0);
974 if (symbolic_memory_operand (op, mode))
977 if (IS_STACK_PUSH (operand))
980 if (m68hc11_register_indirect_p (operand, mode))
986 return register_operand (operand, mode);
990 m68hc11_symbolic_p (operand, mode)
992 enum machine_mode mode;
994 if (GET_CODE (operand) == MEM)
996 rtx op = XEXP (operand, 0);
998 if (symbolic_memory_operand (op, mode))
1005 m68hc11_indirect_p (operand, mode)
1007 enum machine_mode mode;
1009 if (GET_CODE (operand) == MEM)
1011 rtx op = XEXP (operand, 0);
1013 if (symbolic_memory_operand (op, mode))
1016 if (reload_in_progress)
1019 operand = XEXP (operand, 0);
1020 return register_indirect_p (operand, mode, reload_completed);
1026 stack_register_operand (operand, mode)
1028 enum machine_mode mode ATTRIBUTE_UNUSED;
1030 return SP_REG_P (operand);
1034 d_register_operand (operand, mode)
1036 enum machine_mode mode ATTRIBUTE_UNUSED;
1038 if (GET_MODE (operand) != mode && mode != VOIDmode)
1041 if (GET_CODE (operand) == SUBREG)
1042 operand = XEXP (operand, 0);
1044 return GET_CODE (operand) == REG
1045 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1046 || REGNO (operand) == HARD_D_REGNUM
1047 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
1051 hard_addr_reg_operand (operand, mode)
1053 enum machine_mode mode ATTRIBUTE_UNUSED;
1055 if (GET_MODE (operand) != mode && mode != VOIDmode)
1058 if (GET_CODE (operand) == SUBREG)
1059 operand = XEXP (operand, 0);
1061 return GET_CODE (operand) == REG
1062 && (REGNO (operand) == HARD_X_REGNUM
1063 || REGNO (operand) == HARD_Y_REGNUM
1064 || REGNO (operand) == HARD_Z_REGNUM);
1068 hard_reg_operand (operand, mode)
1070 enum machine_mode mode;
1072 if (GET_MODE (operand) != mode && mode != VOIDmode)
1075 if (GET_CODE (operand) == SUBREG)
1076 operand = XEXP (operand, 0);
1078 return GET_CODE (operand) == REG
1079 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1080 || H_REGNO_P (REGNO (operand)));
1084 memory_indexed_operand (operand, mode)
1086 enum machine_mode mode ATTRIBUTE_UNUSED;
1088 if (GET_CODE (operand) != MEM)
1091 operand = XEXP (operand, 0);
1092 if (GET_CODE (operand) == PLUS)
1094 if (GET_CODE (XEXP (operand, 0)) == REG)
1095 operand = XEXP (operand, 0);
1096 else if (GET_CODE (XEXP (operand, 1)) == REG)
1097 operand = XEXP (operand, 1);
1099 return GET_CODE (operand) == REG
1100 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1101 || A_REGNO_P (REGNO (operand)));
1105 push_pop_operand_p (operand)
1108 if (GET_CODE (operand) != MEM)
1112 operand = XEXP (operand, 0);
1113 return PUSH_POP_ADDRESS_P (operand);
1116 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1117 reference and a constant. */
1120 symbolic_memory_operand (op, mode)
1122 enum machine_mode mode;
1124 switch (GET_CODE (op))
1132 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1133 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1134 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1136 /* ??? This clause seems to be irrelevant. */
1138 return GET_MODE (op) == mode;
1141 return symbolic_memory_operand (XEXP (op, 0), mode)
1142 && symbolic_memory_operand (XEXP (op, 1), mode);
1150 m68hc11_eq_compare_operator (op, mode)
1152 enum machine_mode mode ATTRIBUTE_UNUSED;
1154 return GET_CODE (op) == EQ || GET_CODE (op) == NE;
1158 m68hc11_logical_operator (op, mode)
1160 enum machine_mode mode ATTRIBUTE_UNUSED;
1162 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1166 m68hc11_arith_operator (op, mode)
1168 enum machine_mode mode ATTRIBUTE_UNUSED;
1170 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1171 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1172 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1173 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1174 || GET_CODE (op) == ROTATERT;
1178 m68hc11_non_shift_operator (op, mode)
1180 enum machine_mode mode ATTRIBUTE_UNUSED;
1182 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1183 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1186 /* Return true if op is a shift operator. */
1188 m68hc11_shift_operator (op, mode)
1190 enum machine_mode mode ATTRIBUTE_UNUSED;
1192 return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
1193 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
1194 || GET_CODE (op) == ASHIFTRT;
1198 m68hc11_unary_operator (op, mode)
1200 enum machine_mode mode ATTRIBUTE_UNUSED;
1202 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1203 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1206 /* Emit the code to build the trampoline used to call a nested function.
1210 ldy #&CXT movw #&CXT,*_.d1
1211 sty *_.d1 jmp FNADDR
1216 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
1221 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1224 if (*static_chain_reg == '*')
1228 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1229 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1230 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1232 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1233 gen_rtx_CONST (QImode,
1234 gen_rtx_SYMBOL_REF (Pmode,
1235 static_chain_reg)));
1236 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1238 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1242 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1243 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1244 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1245 gen_rtx_CONST (HImode,
1246 gen_rtx_SYMBOL_REF (Pmode,
1247 static_chain_reg)));
1248 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1250 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1254 /* Declaration of types. */
1256 const struct attribute_spec m68hc11_attribute_table[] =
1258 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1259 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1260 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1261 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1262 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1263 { NULL, 0, 0, false, false, false, NULL }
1266 /* Keep track of the symbol which has a `trap' attribute and which uses
1267 the `swi' calling convention. Since there is only one trap, we only
1268 record one such symbol. If there are several, a warning is reported. */
1269 static rtx trap_handler_symbol = 0;
1271 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1272 arguments as in struct attribute_spec.handler. */
1274 m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
1277 tree args ATTRIBUTE_UNUSED;
1278 int flags ATTRIBUTE_UNUSED;
1281 if (TREE_CODE (*node) != FUNCTION_TYPE
1282 && TREE_CODE (*node) != METHOD_TYPE
1283 && TREE_CODE (*node) != FIELD_DECL
1284 && TREE_CODE (*node) != TYPE_DECL)
1286 warning ("`%s' attribute only applies to functions",
1287 IDENTIFIER_POINTER (name));
1288 *no_add_attrs = true;
1294 /* We want to recognize trap handlers so that we handle calls to traps
1295 in a special manner (by issuing the trap). This information is stored
1296 in SYMBOL_REF_FLAG. */
1299 m68hc11_encode_section_info (decl, rtl, first)
1302 int first ATTRIBUTE_UNUSED;
1308 if (TREE_CODE (decl) != FUNCTION_DECL)
1311 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1314 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1316 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1317 is_far = TARGET_LONG_CALLS != 0;
1319 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1320 if (trap_handler && is_far)
1322 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1327 if (trap_handler_symbol != 0)
1328 warning ("`trap' attribute is already used");
1330 trap_handler_symbol = XEXP (rtl, 0);
1332 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1336 m68hc11_is_far_symbol (sym)
1339 if (GET_CODE (sym) == MEM)
1340 sym = XEXP (sym, 0);
1342 return SYMBOL_REF_FLAG (sym);
1346 m68hc11_is_trap_symbol (sym)
1349 if (GET_CODE (sym) == MEM)
1350 sym = XEXP (sym, 0);
1352 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1356 /* Argument support functions. */
1358 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1359 Arrays are passed by references and other types by value.
1361 SCz: I tried to pass DImode by reference but it seems that this
1362 does not work very well. */
1364 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1365 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1366 enum machine_mode mode ATTRIBUTE_UNUSED;
1368 int named ATTRIBUTE_UNUSED;
1370 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1371 /* Consider complex values as aggregates, so care for TCmode. */
1372 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1373 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1377 /* Define the offset between two registers, one to be eliminated, and the
1378 other its replacement, at the start of a routine. */
1380 m68hc11_initial_elimination_offset (from, to)
1389 /* For a trap handler, we must take into account the registers which
1390 are pushed on the stack during the trap (except the PC). */
1391 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1393 if (lookup_attribute ("far", func_attr) != 0)
1394 current_function_far = 1;
1395 else if (lookup_attribute ("near", func_attr) != 0)
1396 current_function_far = 0;
1398 current_function_far = TARGET_LONG_CALLS != 0;
1400 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1401 if (trap_handler && from == ARG_POINTER_REGNUM)
1404 /* For a function using 'call/rtc' we must take into account the
1405 page register which is pushed in the call. */
1406 else if (current_function_far && from == ARG_POINTER_REGNUM)
1411 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1413 /* 2 is for the saved frame.
1414 1 is for the 'sts' correction when creating the frame. */
1415 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1418 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1420 return m68hc11_sp_correction;
1423 /* Push any 2 byte pseudo hard registers that we need to save. */
1424 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1426 if (regs_ever_live[regno] && !call_used_regs[regno])
1432 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1434 return get_frame_size () + size;
1437 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1444 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1445 for a call to a function whose data type is FNTYPE.
1446 For a library call, FNTYPE is 0. */
1449 m68hc11_init_cumulative_args (cum, fntype, libname)
1450 CUMULATIVE_ARGS *cum;
1456 z_replacement_completed = 0;
1460 /* For a library call, we must find out the type of the return value.
1461 When the return value is bigger than 4 bytes, it is returned in
1462 memory. In that case, the first argument of the library call is a
1463 pointer to the memory location. Because the first argument is passed in
1464 register D, we have to identify this, so that the first function
1465 parameter is not passed in D either. */
1471 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1474 /* If the library ends in 'di' or in 'df', we assume it's
1475 returning some DImode or some DFmode which are 64-bit wide. */
1476 name = XSTR (libname, 0);
1477 len = strlen (name);
1479 && ((name[len - 2] == 'd'
1480 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1481 || (name[len - 3] == 'd'
1482 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1484 /* We are in. Mark the first parameter register as already used. */
1491 ret_type = TREE_TYPE (fntype);
1493 if (ret_type && aggregate_value_p (ret_type, fntype))
1500 /* Update the data in CUM to advance over an argument
1501 of mode MODE and data type TYPE.
1502 (TYPE is null for libcalls where that information may not be available.) */
1505 m68hc11_function_arg_advance (cum, mode, type, named)
1506 CUMULATIVE_ARGS *cum;
1507 enum machine_mode mode;
1509 int named ATTRIBUTE_UNUSED;
1511 if (mode != BLKmode)
1513 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1516 cum->words = GET_MODE_SIZE (mode);
1520 cum->words += GET_MODE_SIZE (mode);
1521 if (cum->words <= HARD_REG_SIZE)
1527 cum->words += int_size_in_bytes (type);
1532 /* Define where to put the arguments to a function.
1533 Value is zero to push the argument on the stack,
1534 or a hard register in which to store the argument.
1536 MODE is the argument's machine mode.
1537 TYPE is the data type of the argument (as a tree).
1538 This is null for libcalls where that information may
1540 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1541 the preceding args and about the function being called.
1542 NAMED is nonzero if this argument is a named parameter
1543 (otherwise it is an extra parameter matching an ellipsis). */
1546 m68hc11_function_arg (cum, mode, type, named)
1547 const CUMULATIVE_ARGS *cum;
1548 enum machine_mode mode;
1549 tree type ATTRIBUTE_UNUSED;
1550 int named ATTRIBUTE_UNUSED;
1552 if (cum->words != 0)
1557 if (mode != BLKmode)
1559 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1560 return gen_rtx (REG, mode, HARD_X_REGNUM);
1562 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1566 return gen_rtx (REG, mode, HARD_D_REGNUM);
1571 /* If defined, a C expression which determines whether, and in which direction,
1572 to pad out an argument with extra space. The value should be of type
1573 `enum direction': either `upward' to pad above the argument,
1574 `downward' to pad below, or `none' to inhibit padding.
1576 Structures are stored left shifted in their argument slot. */
1578 m68hc11_function_arg_padding (mode, type)
1579 enum machine_mode mode;
1582 if (type != 0 && AGGREGATE_TYPE_P (type))
1585 /* Fall back to the default. */
1586 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1590 /* Function prologue and epilogue. */
1592 /* Emit a move after the reload pass has completed. This is used to
1593 emit the prologue and epilogue. */
1595 emit_move_after_reload (to, from, scratch)
1596 rtx to, from, scratch;
1600 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1602 insn = emit_move_insn (to, from);
1606 emit_move_insn (scratch, from);
1607 insn = emit_move_insn (to, scratch);
1610 /* Put a REG_INC note to tell the flow analysis that the instruction
1612 if (IS_STACK_PUSH (to))
1614 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1615 XEXP (XEXP (to, 0), 0),
1618 else if (IS_STACK_POP (from))
1620 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1621 XEXP (XEXP (from, 0), 0),
1625 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1626 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1627 The problem is that we are lying to gcc and use `txs' for x = sp
1628 (which is not really true because txs is really x = sp + 1). */
1629 else if (TARGET_M6811 && SP_REG_P (from))
1631 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1638 m68hc11_total_frame_size ()
1643 size = get_frame_size ();
1644 if (current_function_interrupt)
1646 size += 3 * HARD_REG_SIZE;
1648 if (frame_pointer_needed)
1649 size += HARD_REG_SIZE;
1651 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1652 if (regs_ever_live[regno] && !call_used_regs[regno])
1653 size += HARD_REG_SIZE;
1659 m68hc11_output_function_epilogue (out, size)
1660 FILE *out ATTRIBUTE_UNUSED;
1661 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1663 /* We catch the function epilogue generation to have a chance
1664 to clear the z_replacement_completed flag. */
1665 z_replacement_completed = 0;
1676 if (reload_completed != 1)
1679 size = get_frame_size ();
1683 /* Generate specific prologue for interrupt handlers. */
1684 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1685 current_function_interrupt = lookup_attribute ("interrupt",
1686 func_attr) != NULL_TREE;
1687 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1688 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1689 current_function_far = 1;
1690 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1691 current_function_far = 0;
1693 current_function_far = TARGET_LONG_CALLS != 0;
1695 /* Get the scratch register to build the frame and push registers.
1696 If the first argument is a 32-bit quantity, the D+X registers
1697 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1698 For 68HC12, this scratch register is not used. */
1699 if (current_function_args_info.nregs == 2)
1704 /* Save current stack frame. */
1705 if (frame_pointer_needed)
1706 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1708 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1709 Other soft registers in page0 need not to be saved because they
1710 will be restored by C functions. For a trap handler, we don't
1711 need to preserve these registers because this is a synchronous call. */
1712 if (current_function_interrupt)
1714 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1715 emit_move_after_reload (stack_push_word,
1716 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1717 emit_move_after_reload (stack_push_word,
1718 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1722 /* Allocate local variables. */
1723 if (TARGET_M6812 && (size > 4 || size == 3))
1725 emit_insn (gen_addhi3 (stack_pointer_rtx,
1726 stack_pointer_rtx, GEN_INT (-size)));
1728 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1732 insn = gen_rtx_PARALLEL
1735 gen_rtx_SET (VOIDmode,
1737 gen_rtx_PLUS (HImode,
1740 gen_rtx_CLOBBER (VOIDmode, scratch)));
1747 /* Allocate by pushing scratch values. */
1748 for (i = 2; i <= size; i += 2)
1749 emit_move_after_reload (stack_push_word, ix_reg, 0);
1752 emit_insn (gen_addhi3 (stack_pointer_rtx,
1753 stack_pointer_rtx, GEN_INT (-1)));
1756 /* Create the frame pointer. */
1757 if (frame_pointer_needed)
1758 emit_move_after_reload (hard_frame_pointer_rtx,
1759 stack_pointer_rtx, scratch);
1761 /* Push any 2 byte pseudo hard registers that we need to save. */
1762 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1764 if (regs_ever_live[regno] && !call_used_regs[regno])
1766 emit_move_after_reload (stack_push_word,
1767 gen_rtx (REG, HImode, regno), scratch);
1780 if (reload_completed != 1)
1783 size = get_frame_size ();
1785 /* If we are returning a value in two registers, we have to preserve the
1786 X register and use the Y register to restore the stack and the saved
1787 registers. Otherwise, use X because it's faster (and smaller). */
1788 if (current_function_return_rtx == 0)
1790 else if (GET_CODE (current_function_return_rtx) == MEM)
1791 return_size = HARD_REG_SIZE;
1793 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1795 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1800 /* Pop any 2 byte pseudo hard registers that we saved. */
1801 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1803 if (regs_ever_live[regno] && !call_used_regs[regno])
1805 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1806 stack_pop_word, scratch);
1810 /* de-allocate auto variables */
1811 if (TARGET_M6812 && (size > 4 || size == 3))
1813 emit_insn (gen_addhi3 (stack_pointer_rtx,
1814 stack_pointer_rtx, GEN_INT (size)));
1816 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1820 insn = gen_rtx_PARALLEL
1823 gen_rtx_SET (VOIDmode,
1825 gen_rtx_PLUS (HImode,
1828 gen_rtx_CLOBBER (VOIDmode, scratch)));
1835 for (i = 2; i <= size; i += 2)
1836 emit_move_after_reload (scratch, stack_pop_word, scratch);
1838 emit_insn (gen_addhi3 (stack_pointer_rtx,
1839 stack_pointer_rtx, GEN_INT (1)));
1842 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1843 if (current_function_interrupt)
1845 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1846 stack_pop_word, scratch);
1847 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1848 stack_pop_word, scratch);
1849 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1852 /* Restore previous frame pointer. */
1853 if (frame_pointer_needed)
1854 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1856 /* If the trap handler returns some value, copy the value
1857 in D, X onto the stack so that the rti will pop the return value
1859 else if (current_function_trap && return_size != 0)
1861 rtx addr_reg = stack_pointer_rtx;
1865 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1868 emit_move_after_reload (gen_rtx (MEM, HImode,
1869 gen_rtx (PLUS, HImode, addr_reg,
1870 GEN_INT (1))), d_reg, 0);
1871 if (return_size > HARD_REG_SIZE)
1872 emit_move_after_reload (gen_rtx (MEM, HImode,
1873 gen_rtx (PLUS, HImode, addr_reg,
1874 GEN_INT (3))), ix_reg, 0);
1877 emit_jump_insn (gen_return ());
1881 /* Low and High part extraction for 68HC11. These routines are
1882 similar to gen_lowpart and gen_highpart but they have been
1883 fixed to work for constants and 68HC11 specific registers. */
1886 m68hc11_gen_lowpart (mode, x)
1887 enum machine_mode mode;
1890 /* We assume that the low part of an auto-inc mode is the same with
1891 the mode changed and that the caller split the larger mode in the
1893 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1895 return gen_rtx (MEM, mode, XEXP (x, 0));
1898 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1899 floating-point constant. A CONST_DOUBLE is used whenever the
1900 constant requires more than one word in order to be adequately
1902 if (GET_CODE (x) == CONST_DOUBLE)
1906 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1910 if (GET_MODE (x) == SFmode)
1912 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1913 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1919 split_double (x, &first, &second);
1923 return GEN_INT (l[0]);
1925 return gen_int_mode (l[0], HImode);
1929 l[0] = CONST_DOUBLE_LOW (x);
1932 return GEN_INT (l[0]);
1933 else if (mode == HImode && GET_MODE (x) == SFmode)
1934 return gen_int_mode (l[0], HImode);
1939 if (mode == QImode && D_REG_P (x))
1940 return gen_rtx (REG, mode, HARD_B_REGNUM);
1942 /* gen_lowpart crashes when it is called with a SUBREG. */
1943 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1946 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1947 else if (mode == HImode)
1948 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1952 x = gen_lowpart (mode, x);
1954 /* Return a different rtx to avoid to share it in several insns
1955 (when used by a split pattern). Sharing addresses within
1956 a MEM breaks the Z register replacement (and reloading). */
1957 if (GET_CODE (x) == MEM)
1963 m68hc11_gen_highpart (mode, x)
1964 enum machine_mode mode;
1967 /* We assume that the high part of an auto-inc mode is the same with
1968 the mode changed and that the caller split the larger mode in the
1970 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1972 return gen_rtx (MEM, mode, XEXP (x, 0));
1975 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1976 floating-point constant. A CONST_DOUBLE is used whenever the
1977 constant requires more than one word in order to be adequately
1979 if (GET_CODE (x) == CONST_DOUBLE)
1983 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1987 if (GET_MODE (x) == SFmode)
1989 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1990 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1996 split_double (x, &first, &second);
2000 return GEN_INT (l[1]);
2002 return gen_int_mode ((l[1] >> 16), HImode);
2006 l[1] = CONST_DOUBLE_HIGH (x);
2010 return GEN_INT (l[1]);
2011 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2012 return gen_int_mode ((l[0] >> 16), HImode);
2016 if (GET_CODE (x) == CONST_INT)
2018 HOST_WIDE_INT val = INTVAL (x);
2022 return gen_int_mode (val >> 8, QImode);
2024 else if (mode == HImode)
2026 return gen_int_mode (val >> 16, HImode);
2029 if (mode == QImode && D_REG_P (x))
2030 return gen_rtx (REG, mode, HARD_A_REGNUM);
2032 /* There is no way in GCC to represent the upper part of a word register.
2033 To obtain the 8-bit upper part of a soft register, we change the
2034 reg into a mem rtx. This is possible because they are physically
2035 located in memory. There is no offset because we are big-endian. */
2036 if (mode == QImode && S_REG_P (x))
2040 /* Avoid the '*' for direct addressing mode when this
2041 addressing mode is disabled. */
2042 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
2043 return gen_rtx (MEM, QImode,
2044 gen_rtx (SYMBOL_REF, Pmode,
2045 ®_names[REGNO (x)][pos]));
2048 /* gen_highpart crashes when it is called with a SUBREG. */
2049 if (GET_CODE (x) == SUBREG)
2051 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
2053 if (GET_CODE (x) == REG)
2055 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
2056 return gen_rtx (REG, mode, REGNO (x));
2058 return gen_rtx_SUBREG (mode, x, 0);
2061 if (GET_CODE (x) == MEM)
2063 x = change_address (x, mode, 0);
2065 /* Return a different rtx to avoid to share it in several insns
2066 (when used by a split pattern). Sharing addresses within
2067 a MEM breaks the Z register replacement (and reloading). */
2068 if (GET_CODE (x) == MEM)
2076 /* Obscure register manipulation. */
2078 /* Finds backward in the instructions to see if register 'reg' is
2079 dead. This is used when generating code to see if we can use 'reg'
2080 as a scratch register. This allows us to choose a better generation
2081 of code when we know that some register dies or can be clobbered. */
2084 dead_register_here (x, reg)
2092 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
2096 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2103 if (GET_CODE (body) == CALL_INSN)
2105 if (GET_CODE (body) == JUMP_INSN)
2108 if (GET_CODE (body) == SET)
2110 rtx dst = XEXP (body, 0);
2112 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2114 if (x_reg && rtx_equal_p (dst, x_reg))
2117 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2120 else if (reg_mentioned_p (reg, p)
2121 || (x_reg && reg_mentioned_p (x_reg, p)))
2125 /* Scan forward to see if the register is set in some insns and never
2127 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2131 if (GET_CODE (p) == CODE_LABEL
2132 || GET_CODE (p) == JUMP_INSN
2133 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2136 if (GET_CODE (p) != INSN)
2140 if (GET_CODE (body) == SET)
2142 rtx src = XEXP (body, 1);
2143 rtx dst = XEXP (body, 0);
2145 if (GET_CODE (dst) == REG
2146 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2150 /* Register is used (may be in source or in dest). */
2151 if (reg_mentioned_p (reg, p)
2152 || (x_reg != 0 && GET_MODE (p) == SImode
2153 && reg_mentioned_p (x_reg, p)))
2156 return p == 0 ? 1 : 0;
2160 /* Code generation operations called from machine description file. */
2162 /* Print the name of register 'regno' in the assembly file. */
2164 asm_print_register (file, regno)
2168 const char *name = reg_names[regno];
2170 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2173 fprintf (file, "%s", name);
2176 /* A C compound statement to output to stdio stream STREAM the
2177 assembler syntax for an instruction operand X. X is an RTL
2180 CODE is a value that can be used to specify one of several ways
2181 of printing the operand. It is used when identical operands
2182 must be printed differently depending on the context. CODE
2183 comes from the `%' specification that was used to request
2184 printing of the operand. If the specification was just `%DIGIT'
2185 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2186 is the ASCII code for LTR.
2188 If X is a register, this macro should print the register's name.
2189 The names can be found in an array `reg_names' whose type is
2190 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2192 When the machine description has a specification `%PUNCT' (a `%'
2193 followed by a punctuation character), this macro is called with
2194 a null pointer for X and the punctuation character for CODE.
2196 The M68HC11 specific codes are:
2198 'b' for the low part of the operand.
2199 'h' for the high part of the operand
2200 The 'b' or 'h' modifiers have no effect if the operand has
2201 the QImode and is not a S_REG_P (soft register). If the
2202 operand is a hard register, these two modifiers have no effect.
2203 't' generate the temporary scratch register. The operand is
2205 'T' generate the low-part temporary scratch register. The operand is
2209 print_operand (file, op, letter)
2216 asm_print_register (file, SOFT_TMP_REGNUM);
2219 else if (letter == 'T')
2221 asm_print_register (file, SOFT_TMP_REGNUM);
2222 fprintf (file, "+1");
2225 else if (letter == '#')
2227 asm_fprintf (file, "%I");
2230 if (GET_CODE (op) == REG)
2232 if (letter == 'b' && S_REG_P (op))
2234 asm_print_register (file, REGNO (op));
2235 fprintf (file, "+1");
2237 else if (letter == 'b' && D_REG_P (op))
2239 asm_print_register (file, HARD_B_REGNUM);
2243 asm_print_register (file, REGNO (op));
2248 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2251 asm_fprintf (file, "%I%%lo(");
2253 asm_fprintf (file, "%I%%hi(");
2255 output_addr_const (file, op);
2256 fprintf (file, ")");
2260 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2261 are specified. If we already have a QImode, there is nothing to do. */
2262 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2266 op = m68hc11_gen_lowpart (QImode, op);
2268 else if (letter == 'h')
2270 op = m68hc11_gen_highpart (QImode, op);
2274 if (GET_CODE (op) == MEM)
2276 rtx base = XEXP (op, 0);
2277 switch (GET_CODE (base))
2282 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2283 asm_print_register (file, REGNO (XEXP (base, 0)));
2292 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2293 asm_print_register (file, REGNO (XEXP (base, 0)));
2294 fprintf (file, "-");
2303 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2304 asm_print_register (file, REGNO (XEXP (base, 0)));
2305 fprintf (file, "+");
2314 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2315 asm_print_register (file, REGNO (XEXP (base, 0)));
2322 output_address (base);
2326 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2331 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2332 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2333 asm_fprintf (file, "%I0x%lx", l);
2335 else if (GET_CODE (op) == CONST_DOUBLE
2336 && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode))
2340 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2341 sizeof (dstr), 0, 1);
2342 asm_fprintf (file, "%I0r%s", dstr);
2346 int need_parenthesize = 0;
2349 asm_fprintf (file, "%I");
2351 need_parenthesize = must_parenthesize (op);
2353 if (need_parenthesize)
2354 fprintf (file, "(");
2356 output_addr_const (file, op);
2357 if (need_parenthesize)
2358 fprintf (file, ")");
2362 /* Returns true if the operand 'op' must be printed with parenthesis
2363 around it. This must be done only if there is a symbol whose name
2364 is a processor register. */
2366 must_parenthesize (op)
2371 switch (GET_CODE (op))
2374 name = XSTR (op, 0);
2375 /* Avoid a conflict between symbol name and a possible
2377 return (strcasecmp (name, "a") == 0
2378 || strcasecmp (name, "b") == 0
2379 || strcasecmp (name, "d") == 0
2380 || strcasecmp (name, "x") == 0
2381 || strcasecmp (name, "y") == 0
2382 || strcasecmp (name, "ix") == 0
2383 || strcasecmp (name, "iy") == 0
2384 || strcasecmp (name, "pc") == 0
2385 || strcasecmp (name, "sp") == 0
2386 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2390 return must_parenthesize (XEXP (op, 0))
2391 || must_parenthesize (XEXP (op, 1));
2397 return must_parenthesize (XEXP (op, 0));
2408 /* A C compound statement to output to stdio stream STREAM the
2409 assembler syntax for an instruction operand that is a memory
2410 reference whose address is ADDR. ADDR is an RTL expression. */
2413 print_operand_address (file, addr)
2419 int need_parenthesis = 0;
2421 switch (GET_CODE (addr))
2424 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2427 fprintf (file, "0,");
2428 asm_print_register (file, REGNO (addr));
2432 base = XEXP (addr, 0);
2433 switch (GET_CODE (base))
2438 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2439 asm_print_register (file, REGNO (XEXP (base, 0)));
2448 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2449 asm_print_register (file, REGNO (XEXP (base, 0)));
2450 fprintf (file, "-");
2459 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2460 asm_print_register (file, REGNO (XEXP (base, 0)));
2461 fprintf (file, "+");
2470 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2471 asm_print_register (file, REGNO (XEXP (base, 0)));
2478 need_parenthesis = must_parenthesize (base);
2479 if (need_parenthesis)
2480 fprintf (file, "(");
2482 output_addr_const (file, base);
2483 if (need_parenthesis)
2484 fprintf (file, ")");
2490 base = XEXP (addr, 0);
2491 offset = XEXP (addr, 1);
2492 if (!G_REG_P (base) && G_REG_P (offset))
2494 base = XEXP (addr, 1);
2495 offset = XEXP (addr, 0);
2497 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2499 need_parenthesis = must_parenthesize (addr);
2501 if (need_parenthesis)
2502 fprintf (file, "(");
2504 output_addr_const (file, base);
2505 fprintf (file, "+");
2506 output_addr_const (file, offset);
2507 if (need_parenthesis)
2508 fprintf (file, ")");
2510 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2516 asm_print_register (file, REGNO (offset));
2517 fprintf (file, ",");
2518 asm_print_register (file, REGNO (base));
2525 need_parenthesis = must_parenthesize (offset);
2526 if (need_parenthesis)
2527 fprintf (file, "(");
2529 output_addr_const (file, offset);
2530 if (need_parenthesis)
2531 fprintf (file, ")");
2532 fprintf (file, ",");
2533 asm_print_register (file, REGNO (base));
2543 if (GET_CODE (addr) == CONST_INT
2544 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2546 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2550 need_parenthesis = must_parenthesize (addr);
2551 if (need_parenthesis)
2552 fprintf (file, "(");
2554 output_addr_const (file, addr);
2555 if (need_parenthesis)
2556 fprintf (file, ")");
2563 /* Splitting of some instructions. */
2566 m68hc11_expand_compare (code, op0, op1)
2572 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2576 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2577 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2578 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2585 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2587 rtx op0, op1, label;
2591 switch (GET_MODE (op0))
2595 tmp = m68hc11_expand_compare (code, op0, op1);
2596 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2597 gen_rtx_LABEL_REF (VOIDmode, label),
2599 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2603 /* SCz: from i386.c */
2606 /* Don't expand the comparison early, so that we get better code
2607 when jump or whoever decides to reverse the comparison. */
2612 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2613 &m68hc11_compare_op1);
2615 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2616 m68hc11_compare_op0, m68hc11_compare_op1);
2617 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2618 gen_rtx_LABEL_REF (VOIDmode, label),
2620 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2622 use_fcomi = ix86_use_fcomi_compare (code);
2623 vec = rtvec_alloc (3 + !use_fcomi);
2624 RTVEC_ELT (vec, 0) = tmp;
2626 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2628 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2631 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2633 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2639 /* Expand SImode branch into multiple compare+branch. */
2641 rtx lo[2], hi[2], label2;
2642 enum rtx_code code1, code2, code3;
2644 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2649 code = swap_condition (code);
2651 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2652 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2653 hi[0] = m68hc11_gen_highpart (HImode, op0);
2654 hi[1] = m68hc11_gen_highpart (HImode, op1);
2656 /* Otherwise, if we are doing less-than, op1 is a constant and the
2657 low word is zero, then we can just examine the high word. */
2659 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2660 && (code == LT || code == LTU))
2662 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2666 /* Otherwise, we need two or three jumps. */
2668 label2 = gen_label_rtx ();
2671 code2 = swap_condition (code);
2672 code3 = unsigned_condition (code);
2713 * if (hi(a) < hi(b)) goto true;
2714 * if (hi(a) > hi(b)) goto false;
2715 * if (lo(a) < lo(b)) goto true;
2719 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2721 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2723 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2726 emit_label (label2);
2736 /* Return the increment/decrement mode of a MEM if it is such.
2737 Return CONST if it is anything else. */
2742 if (GET_CODE (x) != MEM)
2746 if (GET_CODE (x) == PRE_INC
2747 || GET_CODE (x) == PRE_DEC
2748 || GET_CODE (x) == POST_INC
2749 || GET_CODE (x) == POST_DEC)
2750 return GET_CODE (x);
2756 m68hc11_make_autoinc_notes (x, data)
2762 switch (GET_CODE (*x))
2769 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2778 /* Split a DI, SI or HI move into several smaller move operations.
2779 The scratch register 'scratch' is used as a temporary to load
2780 store intermediate values. It must be a hard register. */
2782 m68hc11_split_move (to, from, scratch)
2783 rtx to, from, scratch;
2785 rtx low_to, low_from;
2786 rtx high_to, high_from;
2788 enum machine_mode mode;
2790 int autoinc_from = autoinc_mode (from);
2791 int autoinc_to = autoinc_mode (to);
2793 mode = GET_MODE (to);
2795 /* If the TO and FROM contain autoinc modes that are not compatible
2796 together (one pop and the other a push), we must change one to
2797 an offsetable operand and generate an appropriate add at the end. */
2798 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2803 /* The source uses an autoinc mode which is not compatible with
2804 a split (this would result in a word swap). */
2805 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2807 code = GET_CODE (XEXP (from, 0));
2808 reg = XEXP (XEXP (from, 0), 0);
2809 offset = GET_MODE_SIZE (GET_MODE (from));
2810 if (code == POST_DEC)
2813 if (code == PRE_INC)
2814 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2816 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2817 if (code == POST_DEC)
2818 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2822 /* Likewise for destination. */
2823 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2825 code = GET_CODE (XEXP (to, 0));
2826 reg = XEXP (XEXP (to, 0), 0);
2827 offset = GET_MODE_SIZE (GET_MODE (to));
2828 if (code == POST_DEC)
2831 if (code == PRE_INC)
2832 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2834 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2835 if (code == POST_DEC)
2836 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2840 /* The source and destination auto increment modes must be compatible
2841 with each other: same direction. */
2842 if ((autoinc_to != autoinc_from
2843 && autoinc_to != CONST && autoinc_from != CONST)
2844 /* The destination address register must not be used within
2845 the source operand because the source address would change
2846 while doing the copy. */
2847 || (autoinc_to != CONST
2848 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2849 && !IS_STACK_PUSH (to)))
2851 /* Must change the destination. */
2852 code = GET_CODE (XEXP (to, 0));
2853 reg = XEXP (XEXP (to, 0), 0);
2854 offset = GET_MODE_SIZE (GET_MODE (to));
2855 if (code == PRE_DEC || code == POST_DEC)
2858 if (code == PRE_DEC || code == PRE_INC)
2859 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2860 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2861 if (code == POST_DEC || code == POST_INC)
2862 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2867 /* Likewise, the source address register must not be used within
2868 the destination operand. */
2869 if (autoinc_from != CONST
2870 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2871 && !IS_STACK_PUSH (to))
2873 /* Must change the source. */
2874 code = GET_CODE (XEXP (from, 0));
2875 reg = XEXP (XEXP (from, 0), 0);
2876 offset = GET_MODE_SIZE (GET_MODE (from));
2877 if (code == PRE_DEC || code == POST_DEC)
2880 if (code == PRE_DEC || code == PRE_INC)
2881 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2882 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2883 if (code == POST_DEC || code == POST_INC)
2884 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2890 if (GET_MODE_SIZE (mode) == 8)
2892 else if (GET_MODE_SIZE (mode) == 4)
2898 && IS_STACK_PUSH (to)
2899 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2905 else if (mode == HImode)
2913 low_to = m68hc11_gen_lowpart (mode, to);
2914 high_to = m68hc11_gen_highpart (mode, to);
2916 low_from = m68hc11_gen_lowpart (mode, from);
2917 if (mode == SImode && GET_CODE (from) == CONST_INT)
2919 if (INTVAL (from) >= 0)
2920 high_from = const0_rtx;
2922 high_from = constm1_rtx;
2925 high_from = m68hc11_gen_highpart (mode, from);
2929 high_from = adjust_address (high_from, mode, offset);
2930 low_from = high_from;
2933 /* When copying with a POST_INC mode, we must copy the
2934 high part and then the low part to guarantee a correct
2937 && GET_MODE_SIZE (mode) >= 2
2938 && autoinc_from != autoinc_to
2939 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2948 low_from = high_from;
2953 m68hc11_split_move (low_to, low_from, scratch);
2954 m68hc11_split_move (high_to, high_from, scratch);
2956 else if (H_REG_P (to) || H_REG_P (from)
2957 || (low_from == const0_rtx
2958 && high_from == const0_rtx
2959 && ! push_operand (to, GET_MODE (to))
2960 && ! H_REG_P (scratch))
2962 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2963 || m68hc11_small_indexed_indirect_p (from,
2965 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2966 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2968 insn = emit_move_insn (low_to, low_from);
2969 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2971 insn = emit_move_insn (high_to, high_from);
2972 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2976 insn = emit_move_insn (scratch, low_from);
2977 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2978 insn = emit_move_insn (low_to, scratch);
2979 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2981 insn = emit_move_insn (scratch, high_from);
2982 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2983 insn = emit_move_insn (high_to, scratch);
2984 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2989 simplify_logical (mode, code, operand, result)
2990 enum machine_mode mode;
2999 if (GET_CODE (operand) != CONST_INT)
3007 val = INTVAL (operand);
3011 if ((val & mask) == 0)
3013 if ((val & mask) == mask)
3014 *result = constm1_rtx;
3018 if ((val & mask) == 0)
3019 *result = const0_rtx;
3020 if ((val & mask) == mask)
3025 if ((val & mask) == 0)
3033 m68hc11_emit_logical (mode, code, operands)
3034 enum machine_mode mode;
3041 need_copy = (rtx_equal_p (operands[0], operands[1])
3042 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
3044 operands[1] = simplify_logical (mode, code, operands[1], &result);
3045 operands[2] = simplify_logical (mode, code, operands[2], &result);
3047 if (result && GET_CODE (result) == CONST_INT)
3049 if (!H_REG_P (operands[0]) && operands[3]
3050 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
3052 emit_move_insn (operands[3], result);
3053 emit_move_insn (operands[0], operands[3]);
3057 emit_move_insn (operands[0], result);
3060 else if (operands[1] != 0 && operands[2] != 0)
3064 if (!H_REG_P (operands[0]) && operands[3])
3066 emit_move_insn (operands[3], operands[1]);
3067 emit_insn (gen_rtx (SET, mode,
3069 gen_rtx (code, mode,
3070 operands[3], operands[2])));
3071 insn = emit_move_insn (operands[0], operands[3]);
3075 insn = emit_insn (gen_rtx (SET, mode,
3077 gen_rtx (code, mode,
3078 operands[0], operands[2])));
3082 /* The logical operation is similar to a copy. */
3087 if (GET_CODE (operands[1]) == CONST_INT)
3092 if (!H_REG_P (operands[0]) && !H_REG_P (src))
3094 emit_move_insn (operands[3], src);
3095 emit_move_insn (operands[0], operands[3]);
3099 emit_move_insn (operands[0], src);
3105 m68hc11_split_logical (mode, code, operands)
3106 enum machine_mode mode;
3113 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3114 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3115 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3117 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3119 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3121 if (INTVAL (operands[1]) >= 0)
3122 high[1] = const0_rtx;
3124 high[1] = constm1_rtx;
3127 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3129 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3131 if (INTVAL (operands[2]) >= 0)
3132 high[2] = const0_rtx;
3134 high[2] = constm1_rtx;
3137 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3139 low[3] = operands[3];
3140 high[3] = operands[3];
3143 m68hc11_split_logical (HImode, code, low);
3144 m68hc11_split_logical (HImode, code, high);
3148 m68hc11_emit_logical (mode, code, low);
3149 m68hc11_emit_logical (mode, code, high);
3153 /* Code generation. */
3156 m68hc11_output_swap (insn, operands)
3157 rtx insn ATTRIBUTE_UNUSED;
3160 /* We have to be careful with the cc_status. An address register swap
3161 is generated for some comparison. The comparison is made with D
3162 but the branch really uses the address register. See the split
3163 pattern for compare. The xgdx/xgdy preserve the flags but after
3164 the exchange, the flags will reflect to the value of X and not D.
3165 Tell this by setting the cc_status according to the cc_prev_status. */
3166 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3168 if (cc_prev_status.value1 != 0
3169 && (D_REG_P (cc_prev_status.value1)
3170 || X_REG_P (cc_prev_status.value1)))
3172 cc_status = cc_prev_status;
3173 if (D_REG_P (cc_status.value1))
3174 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3177 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3183 output_asm_insn ("xgdx", operands);
3187 if (cc_prev_status.value1 != 0
3188 && (D_REG_P (cc_prev_status.value1)
3189 || Y_REG_P (cc_prev_status.value1)))
3191 cc_status = cc_prev_status;
3192 if (D_REG_P (cc_status.value1))
3193 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3196 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3202 output_asm_insn ("xgdy", operands);
3206 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3207 This is used to decide whether a move that set flags should be used
3210 next_insn_test_reg (insn, reg)
3216 insn = next_nonnote_insn (insn);
3217 if (GET_CODE (insn) != INSN)
3220 body = PATTERN (insn);
3221 if (sets_cc0_p (body) != 1)
3224 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3230 /* Generate the code to move a 16-bit operand into another one. */
3233 m68hc11_gen_movhi (insn, operands)
3239 /* Move a register or memory to the same location.
3240 This is possible because such insn can appear
3241 in a non-optimizing mode. */
3242 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3244 cc_status = cc_prev_status;
3250 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3252 cc_status = cc_prev_status;
3253 switch (REGNO (operands[1]))
3258 output_asm_insn ("psh%1", operands);
3260 case HARD_SP_REGNUM:
3261 output_asm_insn ("sts\t-2,sp", operands);
3268 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3270 cc_status = cc_prev_status;
3271 switch (REGNO (operands[0]))
3276 output_asm_insn ("pul%0", operands);
3283 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3285 m68hc11_notice_keep_cc (operands[0]);
3286 output_asm_insn ("tfr\t%1,%0", operands);
3288 else if (H_REG_P (operands[0]))
3290 if (SP_REG_P (operands[0]))
3291 output_asm_insn ("lds\t%1", operands);
3293 output_asm_insn ("ld%0\t%1", operands);
3295 else if (H_REG_P (operands[1]))
3297 if (SP_REG_P (operands[1]))
3298 output_asm_insn ("sts\t%0", operands);
3300 output_asm_insn ("st%1\t%0", operands);
3304 rtx from = operands[1];
3305 rtx to = operands[0];
3307 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3308 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3309 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3310 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3316 ops[0] = operands[2];
3319 m68hc11_gen_movhi (insn, ops);
3321 ops[1] = operands[2];
3322 m68hc11_gen_movhi (insn, ops);
3326 /* !!!! SCz wrong here. */
3327 fatal_insn ("move insn not handled", insn);
3332 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3334 output_asm_insn ("clr\t%h0", operands);
3335 output_asm_insn ("clr\t%b0", operands);
3339 m68hc11_notice_keep_cc (operands[0]);
3340 output_asm_insn ("movw\t%1,%0", operands);
3347 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3349 cc_status = cc_prev_status;
3350 switch (REGNO (operands[0]))
3354 output_asm_insn ("pul%0", operands);
3357 output_asm_insn ("pula", operands);
3358 output_asm_insn ("pulb", operands);
3365 /* Some moves to a hard register are special. Not all of them
3366 are really supported and we have to use a temporary
3367 location to provide them (either the stack of a temp var). */
3368 if (H_REG_P (operands[0]))
3370 switch (REGNO (operands[0]))
3373 if (X_REG_P (operands[1]))
3375 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3377 m68hc11_output_swap (insn, operands);
3379 else if (next_insn_test_reg (insn, operands[0]))
3381 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3385 m68hc11_notice_keep_cc (operands[0]);
3386 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3389 else if (Y_REG_P (operands[1]))
3391 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3393 m68hc11_output_swap (insn, operands);
3397 /* %t means *ZTMP scratch register. */
3398 output_asm_insn ("sty\t%t1", operands);
3399 output_asm_insn ("ldd\t%t1", operands);
3402 else if (SP_REG_P (operands[1]))
3407 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3408 output_asm_insn ("xgdx", operands);
3409 output_asm_insn ("tsx", operands);
3410 output_asm_insn ("xgdx", operands);
3412 else if (IS_STACK_POP (operands[1]))
3414 output_asm_insn ("pula\n\tpulb", operands);
3416 else if (GET_CODE (operands[1]) == CONST_INT
3417 && INTVAL (operands[1]) == 0)
3419 output_asm_insn ("clra\n\tclrb", operands);
3423 output_asm_insn ("ldd\t%1", operands);
3428 if (D_REG_P (operands[1]))
3430 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3432 m68hc11_output_swap (insn, operands);
3434 else if (next_insn_test_reg (insn, operands[0]))
3436 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3440 m68hc11_notice_keep_cc (operands[0]);
3441 output_asm_insn ("pshb", operands);
3442 output_asm_insn ("psha", operands);
3443 output_asm_insn ("pulx", operands);
3446 else if (Y_REG_P (operands[1]))
3448 /* When both D and Y are dead, use the sequence xgdy, xgdx
3449 to move Y into X. The D and Y registers are modified. */
3450 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3451 && dead_register_here (insn, d_reg))
3453 output_asm_insn ("xgdy", operands);
3454 output_asm_insn ("xgdx", operands);
3457 else if (!optimize_size)
3459 output_asm_insn ("sty\t%t1", operands);
3460 output_asm_insn ("ldx\t%t1", operands);
3465 output_asm_insn ("pshy", operands);
3466 output_asm_insn ("pulx", operands);
3469 else if (SP_REG_P (operands[1]))
3471 /* tsx, tsy preserve the flags */
3472 cc_status = cc_prev_status;
3473 output_asm_insn ("tsx", operands);
3477 output_asm_insn ("ldx\t%1", operands);
3482 if (D_REG_P (operands[1]))
3484 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3486 m68hc11_output_swap (insn, operands);
3490 output_asm_insn ("std\t%t1", operands);
3491 output_asm_insn ("ldy\t%t1", operands);
3494 else if (X_REG_P (operands[1]))
3496 /* When both D and X are dead, use the sequence xgdx, xgdy
3497 to move X into Y. The D and X registers are modified. */
3498 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3499 && dead_register_here (insn, d_reg))
3501 output_asm_insn ("xgdx", operands);
3502 output_asm_insn ("xgdy", operands);
3505 else if (!optimize_size)
3507 output_asm_insn ("stx\t%t1", operands);
3508 output_asm_insn ("ldy\t%t1", operands);
3513 output_asm_insn ("pshx", operands);
3514 output_asm_insn ("puly", operands);
3517 else if (SP_REG_P (operands[1]))
3519 /* tsx, tsy preserve the flags */
3520 cc_status = cc_prev_status;
3521 output_asm_insn ("tsy", operands);
3525 output_asm_insn ("ldy\t%1", operands);
3529 case HARD_SP_REGNUM:
3530 if (D_REG_P (operands[1]))
3532 m68hc11_notice_keep_cc (operands[0]);
3533 output_asm_insn ("xgdx", operands);
3534 output_asm_insn ("txs", operands);
3535 output_asm_insn ("xgdx", operands);
3537 else if (X_REG_P (operands[1]))
3539 /* tys, txs preserve the flags */
3540 cc_status = cc_prev_status;
3541 output_asm_insn ("txs", operands);
3543 else if (Y_REG_P (operands[1]))
3545 /* tys, txs preserve the flags */
3546 cc_status = cc_prev_status;
3547 output_asm_insn ("tys", operands);
3551 /* lds sets the flags but the des does not. */
3553 output_asm_insn ("lds\t%1", operands);
3554 output_asm_insn ("des", operands);
3559 fatal_insn ("invalid register in the move instruction", insn);
3564 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3565 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3567 output_asm_insn ("sts\t%0", operands);
3571 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3573 cc_status = cc_prev_status;
3574 switch (REGNO (operands[1]))
3578 output_asm_insn ("psh%1", operands);
3581 output_asm_insn ("pshb", operands);
3582 output_asm_insn ("psha", operands);
3590 /* Operand 1 must be a hard register. */
3591 if (!H_REG_P (operands[1]))
3593 fatal_insn ("invalid operand in the instruction", insn);
3596 reg = REGNO (operands[1]);
3600 output_asm_insn ("std\t%0", operands);
3604 output_asm_insn ("stx\t%0", operands);
3608 output_asm_insn ("sty\t%0", operands);
3611 case HARD_SP_REGNUM:
3615 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3617 output_asm_insn ("pshx", operands);
3618 output_asm_insn ("tsx", operands);
3619 output_asm_insn ("inx", operands);
3620 output_asm_insn ("inx", operands);
3621 output_asm_insn ("stx\t%0", operands);
3622 output_asm_insn ("pulx", operands);
3625 else if (reg_mentioned_p (ix_reg, operands[0]))
3627 output_asm_insn ("sty\t%t0", operands);
3628 output_asm_insn ("tsy", operands);
3629 output_asm_insn ("sty\t%0", operands);
3630 output_asm_insn ("ldy\t%t0", operands);
3634 output_asm_insn ("stx\t%t0", operands);
3635 output_asm_insn ("tsx", operands);
3636 output_asm_insn ("stx\t%0", operands);
3637 output_asm_insn ("ldx\t%t0", operands);
3643 fatal_insn ("invalid register in the move instruction", insn);
3649 m68hc11_gen_movqi (insn, operands)
3653 /* Move a register or memory to the same location.
3654 This is possible because such insn can appear
3655 in a non-optimizing mode. */
3656 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3658 cc_status = cc_prev_status;
3665 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3667 m68hc11_notice_keep_cc (operands[0]);
3668 output_asm_insn ("tfr\t%1,%0", operands);
3670 else if (H_REG_P (operands[0]))
3672 if (Q_REG_P (operands[0]))
3673 output_asm_insn ("lda%0\t%b1", operands);
3674 else if (D_REG_P (operands[0]))
3675 output_asm_insn ("ldab\t%b1", operands);
3679 else if (H_REG_P (operands[1]))
3681 if (Q_REG_P (operands[1]))
3682 output_asm_insn ("sta%1\t%b0", operands);
3683 else if (D_REG_P (operands[1]))
3684 output_asm_insn ("stab\t%b0", operands);
3690 rtx from = operands[1];
3691 rtx to = operands[0];
3693 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3694 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3695 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3696 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3702 ops[0] = operands[2];
3705 m68hc11_gen_movqi (insn, ops);
3707 ops[1] = operands[2];
3708 m68hc11_gen_movqi (insn, ops);
3712 /* !!!! SCz wrong here. */
3713 fatal_insn ("move insn not handled", insn);
3718 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3720 output_asm_insn ("clr\t%b0", operands);
3724 m68hc11_notice_keep_cc (operands[0]);
3725 output_asm_insn ("movb\t%b1,%b0", operands);
3733 if (H_REG_P (operands[0]))
3735 switch (REGNO (operands[0]))
3739 if (X_REG_P (operands[1]))
3741 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3743 m68hc11_output_swap (insn, operands);
3747 output_asm_insn ("stx\t%t1", operands);
3748 output_asm_insn ("ldab\t%T0", operands);
3751 else if (Y_REG_P (operands[1]))
3753 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3755 m68hc11_output_swap (insn, operands);
3759 output_asm_insn ("sty\t%t1", operands);
3760 output_asm_insn ("ldab\t%T0", operands);
3763 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3764 && !DA_REG_P (operands[1]))
3766 output_asm_insn ("ldab\t%b1", operands);
3768 else if (DA_REG_P (operands[1]))
3770 output_asm_insn ("tab", operands);
3774 cc_status = cc_prev_status;
3780 if (X_REG_P (operands[1]))
3782 output_asm_insn ("stx\t%t1", operands);
3783 output_asm_insn ("ldaa\t%T0", operands);
3785 else if (Y_REG_P (operands[1]))
3787 output_asm_insn ("sty\t%t1", operands);
3788 output_asm_insn ("ldaa\t%T0", operands);
3790 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3791 && !DA_REG_P (operands[1]))
3793 output_asm_insn ("ldaa\t%b1", operands);
3795 else if (!DA_REG_P (operands[1]))
3797 output_asm_insn ("tba", operands);
3801 cc_status = cc_prev_status;
3806 if (D_REG_P (operands[1]))
3808 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3810 m68hc11_output_swap (insn, operands);
3814 output_asm_insn ("stab\t%T1", operands);
3815 output_asm_insn ("ldx\t%t1", operands);
3819 else if (Y_REG_P (operands[1]))
3821 output_asm_insn ("sty\t%t0", operands);
3822 output_asm_insn ("ldx\t%t0", operands);
3824 else if (GET_CODE (operands[1]) == CONST_INT)
3826 output_asm_insn ("ldx\t%1", operands);
3828 else if (dead_register_here (insn, d_reg))
3830 output_asm_insn ("ldab\t%b1", operands);
3831 output_asm_insn ("xgdx", operands);
3833 else if (!reg_mentioned_p (operands[0], operands[1]))
3835 output_asm_insn ("xgdx", operands);
3836 output_asm_insn ("ldab\t%b1", operands);
3837 output_asm_insn ("xgdx", operands);
3841 output_asm_insn ("pshb", operands);
3842 output_asm_insn ("ldab\t%b1", operands);
3843 output_asm_insn ("stab\t%T1", operands);
3844 output_asm_insn ("ldx\t%t1", operands);
3845 output_asm_insn ("pulb", operands);
3851 if (D_REG_P (operands[1]))
3853 output_asm_insn ("stab\t%T1", operands);
3854 output_asm_insn ("ldy\t%t1", operands);
3857 else if (X_REG_P (operands[1]))
3859 output_asm_insn ("stx\t%t1", operands);
3860 output_asm_insn ("ldy\t%t1", operands);
3863 else if (GET_CODE (operands[1]) == CONST_INT)
3865 output_asm_insn ("ldy\t%1", operands);
3867 else if (dead_register_here (insn, d_reg))
3869 output_asm_insn ("ldab\t%b1", operands);
3870 output_asm_insn ("xgdy", operands);
3872 else if (!reg_mentioned_p (operands[0], operands[1]))
3874 output_asm_insn ("xgdy", operands);
3875 output_asm_insn ("ldab\t%b1", operands);
3876 output_asm_insn ("xgdy", operands);
3880 output_asm_insn ("pshb", operands);
3881 output_asm_insn ("ldab\t%b1", operands);
3882 output_asm_insn ("stab\t%T1", operands);
3883 output_asm_insn ("ldy\t%t1", operands);
3884 output_asm_insn ("pulb", operands);
3890 fatal_insn ("invalid register in the instruction", insn);
3894 else if (H_REG_P (operands[1]))
3896 switch (REGNO (operands[1]))
3900 output_asm_insn ("stab\t%b0", operands);
3904 output_asm_insn ("staa\t%b0", operands);
3908 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3912 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3916 fatal_insn ("invalid register in the move instruction", insn);
3923 fatal_insn ("operand 1 must be a hard register", insn);
3927 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3928 The source and destination must be D or A and the shift must
3931 m68hc11_gen_rotate (code, insn, operands)
3938 if (GET_CODE (operands[2]) != CONST_INT
3939 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3940 fatal_insn ("invalid rotate insn", insn);
3942 val = INTVAL (operands[2]);
3943 if (code == ROTATERT)
3944 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3946 if (GET_MODE (operands[0]) != QImode)
3949 /* Rotate by 8-bits if the shift is within [5..11]. */
3950 if (val >= 5 && val <= 11)
3953 output_asm_insn ("exg\ta,b", operands);
3956 output_asm_insn ("psha", operands);
3957 output_asm_insn ("tba", operands);
3958 output_asm_insn ("pulb", operands);
3963 /* If the shift is big, invert the rotation. */
3973 /* Set the carry to bit-15, but don't change D yet. */
3974 if (GET_MODE (operands[0]) != QImode)
3976 output_asm_insn ("asra", operands);
3977 output_asm_insn ("rola", operands);
3980 /* Rotate B first to move the carry to bit-0. */
3981 if (D_REG_P (operands[0]))
3982 output_asm_insn ("rolb", operands);
3984 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3985 output_asm_insn ("rola", operands);
3992 /* Set the carry to bit-8 of D. */
3993 if (GET_MODE (operands[0]) != QImode)
3994 output_asm_insn ("tap", operands);
3996 /* Rotate B first to move the carry to bit-7. */
3997 if (D_REG_P (operands[0]))
3998 output_asm_insn ("rorb", operands);
4000 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
4001 output_asm_insn ("rora", operands);
4008 /* Store in cc_status the expressions that the condition codes will
4009 describe after execution of an instruction whose pattern is EXP.
4010 Do not alter them if the instruction would not alter the cc's. */
4013 m68hc11_notice_update_cc (exp, insn)
4015 rtx insn ATTRIBUTE_UNUSED;
4017 /* recognize SET insn's. */
4018 if (GET_CODE (exp) == SET)
4020 /* Jumps do not alter the cc's. */
4021 if (SET_DEST (exp) == pc_rtx)
4024 /* NOTE: most instructions don't affect the carry bit, but the
4025 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
4026 the conditions.h header. */
4028 /* Function calls clobber the cc's. */
4029 else if (GET_CODE (SET_SRC (exp)) == CALL)
4034 /* Tests and compares set the cc's in predictable ways. */
4035 else if (SET_DEST (exp) == cc0_rtx)
4037 cc_status.flags = 0;
4038 cc_status.value1 = XEXP (exp, 0);
4039 cc_status.value2 = XEXP (exp, 1);
4043 /* All other instructions affect the condition codes. */
4044 cc_status.flags = 0;
4045 cc_status.value1 = XEXP (exp, 0);
4046 cc_status.value2 = XEXP (exp, 1);
4051 /* Default action if we haven't recognized something
4052 and returned earlier. */
4056 if (cc_status.value2 != 0)
4057 switch (GET_CODE (cc_status.value2))
4059 /* These logical operations can generate several insns.
4060 The flags are setup according to what is generated. */
4066 /* The (not ...) generates several 'com' instructions for
4067 non QImode. We have to invalidate the flags. */
4069 if (GET_MODE (cc_status.value2) != QImode)
4081 if (GET_MODE (cc_status.value2) != VOIDmode)
4082 cc_status.flags |= CC_NO_OVERFLOW;
4085 /* The asl sets the overflow bit in such a way that this
4086 makes the flags unusable for a next compare insn. */
4090 if (GET_MODE (cc_status.value2) != VOIDmode)
4091 cc_status.flags |= CC_NO_OVERFLOW;
4094 /* A load/store instruction does not affect the carry. */
4099 cc_status.flags |= CC_NO_OVERFLOW;
4105 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
4107 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
4108 cc_status.value2 = 0;
4111 /* The current instruction does not affect the flags but changes
4112 the register 'reg'. See if the previous flags can be kept for the
4113 next instruction to avoid a comparison. */
4115 m68hc11_notice_keep_cc (reg)
4119 || cc_prev_status.value1 == 0
4120 || rtx_equal_p (reg, cc_prev_status.value1)
4121 || (cc_prev_status.value2
4122 && reg_mentioned_p (reg, cc_prev_status.value2)))
4125 cc_status = cc_prev_status;
4130 /* Machine Specific Reorg. */
4132 /* Z register replacement:
4134 GCC treats the Z register as an index base address register like
4135 X or Y. In general, it uses it during reload to compute the address
4136 of some operand. This helps the reload pass to avoid to fall into the
4137 register spill failure.
4139 The Z register is in the A_REGS class. In the machine description,
4140 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4142 It can appear everywhere an X or Y register can appear, except for
4143 some templates in the clobber section (when a clobber of X or Y is asked).
4144 For a given instruction, the template must ensure that no more than
4145 2 'A' registers are used. Otherwise, the register replacement is not
4148 To replace the Z register, the algorithm is not terrific:
4149 1. Insns that do not use the Z register are not changed
4150 2. When a Z register is used, we scan forward the insns to see
4151 a potential register to use: either X or Y and sometimes D.
4152 We stop when a call, a label or a branch is seen, or when we
4153 detect that both X and Y are used (probably at different times, but it does
4155 3. The register that will be used for the replacement of Z is saved
4156 in a .page0 register or on the stack. If the first instruction that
4157 used Z, uses Z as an input, the value is loaded from another .page0
4158 register. The replacement register is pushed on the stack in the
4159 rare cases where a compare insn uses Z and we couldn't find if X/Y
4161 4. The Z register is replaced in all instructions until we reach
4162 the end of the Z-block, as detected by step 2.
4163 5. If we detect that Z is still alive, its value is saved.
4164 If the replacement register is alive, its old value is loaded.
4166 The Z register can be disabled with -ffixed-z.
4176 int must_restore_reg;
4187 int save_before_last;
4188 int z_loaded_with_sp;
4191 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
4192 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
4193 static void m68hc11_z_replacement PARAMS ((rtx));
4194 static void m68hc11_reassign_regs PARAMS ((rtx));
4196 int z_replacement_completed = 0;
4198 /* Analyze the insn to find out which replacement register to use and
4199 the boundaries of the replacement.
4200 Returns 0 if we reached the last insn to be replaced, 1 if we can
4201 continue replacement in next insns. */
4204 m68hc11_check_z_replacement (insn, info)
4206 struct replace_info *info;
4208 int this_insn_uses_ix;
4209 int this_insn_uses_iy;
4210 int this_insn_uses_z;
4211 int this_insn_uses_z_in_dst;
4212 int this_insn_uses_d;
4216 /* A call is said to clobber the Z register, we don't need
4217 to save the value of Z. We also don't need to restore
4218 the replacement register (unless it is used by the call). */
4219 if (GET_CODE (insn) == CALL_INSN)
4221 body = PATTERN (insn);
4223 info->can_use_d = 0;
4225 /* If the call is an indirect call with Z, we have to use the
4226 Y register because X can be used as an input (D+X).
4227 We also must not save Z nor restore Y. */
4228 if (reg_mentioned_p (z_reg, body))
4230 insn = NEXT_INSN (insn);
4233 info->found_call = 1;
4234 info->must_restore_reg = 0;
4235 info->last = NEXT_INSN (insn);
4237 info->need_save_z = 0;
4240 if (GET_CODE (insn) == CODE_LABEL
4241 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4244 if (GET_CODE (insn) == JUMP_INSN)
4246 if (reg_mentioned_p (z_reg, insn) == 0)
4249 info->can_use_d = 0;
4250 info->must_save_reg = 0;
4251 info->must_restore_reg = 0;
4252 info->need_save_z = 0;
4253 info->last = NEXT_INSN (insn);
4256 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4261 /* Z register dies here. */
4262 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4264 body = PATTERN (insn);
4265 if (GET_CODE (body) == SET)
4267 rtx src = XEXP (body, 1);
4268 rtx dst = XEXP (body, 0);
4270 /* Condition code is set here. We have to restore the X/Y and
4271 save into Z before any test/compare insn because once we save/restore
4272 we can change the condition codes. When the compare insn uses Z and
4273 we can't use X/Y, the comparison is made with the *ZREG soft register
4274 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4277 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4278 || (GET_CODE (src) == COMPARE &&
4279 (rtx_equal_p (XEXP (src, 0), z_reg)
4280 || rtx_equal_p (XEXP (src, 1), z_reg))))
4282 if (insn == info->first)
4284 info->must_load_z = 0;
4285 info->must_save_reg = 0;
4286 info->must_restore_reg = 0;
4287 info->need_save_z = 0;
4288 info->found_call = 1;
4289 info->regno = SOFT_Z_REGNUM;
4290 info->last = NEXT_INSN (insn);
4294 if (reg_mentioned_p (z_reg, src) == 0)
4296 info->can_use_d = 0;
4300 if (insn != info->first)
4303 /* Compare insn which uses Z. We have to save/restore the X/Y
4304 register without modifying the condition codes. For this
4305 we have to use a push/pop insn. */
4306 info->must_push_reg = 1;
4310 /* Z reg is set to something new. We don't need to load it. */
4313 if (!reg_mentioned_p (z_reg, src))
4315 /* Z reg is used before being set. Treat this as
4316 a new sequence of Z register replacement. */
4317 if (insn != info->first)
4321 info->must_load_z = 0;
4323 info->z_set_count++;
4324 info->z_value = src;
4326 info->z_loaded_with_sp = 1;
4328 else if (reg_mentioned_p (z_reg, dst))
4329 info->can_use_d = 0;
4331 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4332 | reg_mentioned_p (d_reg, dst);
4333 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4334 | reg_mentioned_p (ix_reg, dst);
4335 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4336 | reg_mentioned_p (iy_reg, dst);
4337 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4339 /* If z is used as an address operand (like (MEM (reg z))),
4340 we can't replace it with d. */
4341 if (this_insn_uses_z && !Z_REG_P (src)
4342 && !(m68hc11_arith_operator (src, GET_MODE (src))
4343 && Z_REG_P (XEXP (src, 0))
4344 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4345 && insn == info->first
4346 && dead_register_here (insn, d_reg)))
4347 info->can_use_d = 0;
4349 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4350 if (TARGET_M6812 && !z_dies_here
4351 && ((this_insn_uses_z && side_effects_p (src))
4352 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4354 info->need_save_z = 1;
4355 info->z_set_count++;
4357 this_insn_uses_z |= this_insn_uses_z_in_dst;
4359 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4361 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4364 if (this_insn_uses_d)
4365 info->can_use_d = 0;
4367 /* IX and IY are used at the same time, we have to restore
4368 the value of the scratch register before this insn. */
4369 if (this_insn_uses_ix && this_insn_uses_iy)
4374 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4375 info->can_use_d = 0;
4377 if (info->x_used == 0 && this_insn_uses_ix)
4381 /* We have a (set (REG:HI X) (REG:HI Z)).
4382 Since we use Z as the replacement register, this insn
4383 is no longer necessary. We turn it into a note. We must
4384 not reload the old value of X. */
4385 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4389 info->need_save_z = 0;
4392 info->must_save_reg = 0;
4393 info->must_restore_reg = 0;
4394 info->found_call = 1;
4395 info->can_use_d = 0;
4396 PUT_CODE (insn, NOTE);
4397 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4398 NOTE_SOURCE_FILE (insn) = 0;
4399 info->last = NEXT_INSN (insn);
4404 && (rtx_equal_p (src, z_reg)
4405 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4409 info->need_save_z = 0;
4412 info->last = NEXT_INSN (insn);
4413 info->must_save_reg = 0;
4414 info->must_restore_reg = 0;
4416 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4417 && !reg_mentioned_p (ix_reg, src))
4422 info->need_save_z = 0;
4424 else if (TARGET_M6812 && side_effects_p (src))
4427 info->must_restore_reg = 0;
4432 info->save_before_last = 1;
4434 info->must_restore_reg = 0;
4435 info->last = NEXT_INSN (insn);
4437 else if (info->can_use_d)
4439 info->last = NEXT_INSN (insn);
4445 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4446 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4448 info->need_save_z = 0;
4450 info->last = NEXT_INSN (insn);
4451 info->regno = HARD_X_REGNUM;
4452 info->must_save_reg = 0;
4453 info->must_restore_reg = 0;
4456 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4458 info->regno = HARD_X_REGNUM;
4459 info->must_restore_reg = 0;
4460 info->must_save_reg = 0;
4464 if (info->y_used == 0 && this_insn_uses_iy)
4468 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4472 info->need_save_z = 0;
4475 info->must_save_reg = 0;
4476 info->must_restore_reg = 0;
4477 info->found_call = 1;
4478 info->can_use_d = 0;
4479 PUT_CODE (insn, NOTE);
4480 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4481 NOTE_SOURCE_FILE (insn) = 0;
4482 info->last = NEXT_INSN (insn);
4487 && (rtx_equal_p (src, z_reg)
4488 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4493 info->need_save_z = 0;
4495 info->last = NEXT_INSN (insn);
4496 info->must_save_reg = 0;
4497 info->must_restore_reg = 0;
4499 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4500 && !reg_mentioned_p (iy_reg, src))
4505 info->need_save_z = 0;
4507 else if (TARGET_M6812 && side_effects_p (src))
4510 info->must_restore_reg = 0;
4515 info->save_before_last = 1;
4517 info->must_restore_reg = 0;
4518 info->last = NEXT_INSN (insn);
4520 else if (info->can_use_d)
4522 info->last = NEXT_INSN (insn);
4529 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4530 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4532 info->need_save_z = 0;
4534 info->last = NEXT_INSN (insn);
4535 info->regno = HARD_Y_REGNUM;
4536 info->must_save_reg = 0;
4537 info->must_restore_reg = 0;
4540 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4542 info->regno = HARD_Y_REGNUM;
4543 info->must_restore_reg = 0;
4544 info->must_save_reg = 0;
4550 info->need_save_z = 0;
4552 if (info->last == 0)
4553 info->last = NEXT_INSN (insn);
4556 return info->last != NULL_RTX ? 0 : 1;
4558 if (GET_CODE (body) == PARALLEL)
4561 char ix_clobber = 0;
4562 char iy_clobber = 0;
4564 this_insn_uses_iy = 0;
4565 this_insn_uses_ix = 0;
4566 this_insn_uses_z = 0;
4568 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4571 int uses_ix, uses_iy, uses_z;
4573 x = XVECEXP (body, 0, i);
4575 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4576 info->can_use_d = 0;
4578 uses_ix = reg_mentioned_p (ix_reg, x);
4579 uses_iy = reg_mentioned_p (iy_reg, x);
4580 uses_z = reg_mentioned_p (z_reg, x);
4581 if (GET_CODE (x) == CLOBBER)
4583 ix_clobber |= uses_ix;
4584 iy_clobber |= uses_iy;
4585 z_clobber |= uses_z;
4589 this_insn_uses_ix |= uses_ix;
4590 this_insn_uses_iy |= uses_iy;
4591 this_insn_uses_z |= uses_z;
4593 if (uses_z && GET_CODE (x) == SET)
4595 rtx dst = XEXP (x, 0);
4598 info->z_set_count++;
4600 if (TARGET_M6812 && uses_z && side_effects_p (x))
4601 info->need_save_z = 1;
4604 info->need_save_z = 0;
4608 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4609 this_insn_uses_ix, this_insn_uses_iy,
4610 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4613 if (this_insn_uses_z)
4614 info->can_use_d = 0;
4616 if (z_clobber && info->first != insn)
4618 info->need_save_z = 0;
4622 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4624 if (this_insn_uses_z == 0 && insn == info->first)
4626 info->must_load_z = 0;
4628 if (dead_register_here (insn, d_reg))
4630 info->regno = HARD_D_REGNUM;
4631 info->must_save_reg = 0;
4632 info->must_restore_reg = 0;
4634 else if (dead_register_here (insn, ix_reg))
4636 info->regno = HARD_X_REGNUM;
4637 info->must_save_reg = 0;
4638 info->must_restore_reg = 0;
4640 else if (dead_register_here (insn, iy_reg))
4642 info->regno = HARD_Y_REGNUM;
4643 info->must_save_reg = 0;
4644 info->must_restore_reg = 0;
4646 if (info->regno >= 0)
4648 info->last = NEXT_INSN (insn);
4651 if (this_insn_uses_ix == 0)
4653 info->regno = HARD_X_REGNUM;
4654 info->must_save_reg = 1;
4655 info->must_restore_reg = 1;
4657 else if (this_insn_uses_iy == 0)
4659 info->regno = HARD_Y_REGNUM;
4660 info->must_save_reg = 1;
4661 info->must_restore_reg = 1;
4665 info->regno = HARD_D_REGNUM;
4666 info->must_save_reg = 1;
4667 info->must_restore_reg = 1;
4669 info->last = NEXT_INSN (insn);
4673 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4674 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4676 if (this_insn_uses_z)
4678 if (info->y_used == 0 && iy_clobber)
4680 info->regno = HARD_Y_REGNUM;
4681 info->must_save_reg = 0;
4682 info->must_restore_reg = 0;
4684 if (info->first != insn
4685 && ((info->y_used && ix_clobber)
4686 || (info->x_used && iy_clobber)))
4689 info->last = NEXT_INSN (insn);
4690 info->save_before_last = 1;
4694 if (this_insn_uses_ix && this_insn_uses_iy)
4696 if (this_insn_uses_z)
4698 fatal_insn ("cannot do z-register replacement", insn);
4702 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4709 if (iy_clobber || z_clobber)
4711 info->last = NEXT_INSN (insn);
4712 info->save_before_last = 1;
4717 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4724 if (ix_clobber || z_clobber)
4726 info->last = NEXT_INSN (insn);
4727 info->save_before_last = 1;
4734 info->need_save_z = 0;
4738 if (GET_CODE (body) == CLOBBER)
4741 /* IX and IY are used at the same time, we have to restore
4742 the value of the scratch register before this insn. */
4743 if (this_insn_uses_ix && this_insn_uses_iy)
4747 if (info->x_used == 0 && this_insn_uses_ix)
4755 if (info->y_used == 0 && this_insn_uses_iy)
4769 m68hc11_find_z_replacement (insn, info)
4771 struct replace_info *info;
4775 info->replace_reg = NULL_RTX;
4776 info->must_load_z = 1;
4777 info->need_save_z = 1;
4778 info->must_save_reg = 1;
4779 info->must_restore_reg = 1;
4783 info->can_use_d = TARGET_M6811 ? 1 : 0;
4784 info->found_call = 0;
4788 info->z_set_count = 0;
4789 info->z_value = NULL_RTX;
4790 info->must_push_reg = 0;
4791 info->save_before_last = 0;
4792 info->z_loaded_with_sp = 0;
4794 /* Scan the insn forward to find an address register that is not used.
4796 - the flow of the program changes,
4797 - when we detect that both X and Y are necessary,
4798 - when the Z register dies,
4799 - when the condition codes are set. */
4801 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4803 if (m68hc11_check_z_replacement (insn, info) == 0)
4807 /* May be we can use Y or X if they contain the same value as Z.
4808 This happens very often after the reload. */
4809 if (info->z_set_count == 1)
4811 rtx p = info->first;
4816 v = find_last_value (iy_reg, &p, insn, 1);
4818 else if (info->y_used)
4820 v = find_last_value (ix_reg, &p, insn, 1);
4822 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4825 info->regno = HARD_Y_REGNUM;
4827 info->regno = HARD_X_REGNUM;
4828 info->must_load_z = 0;
4829 info->must_save_reg = 0;
4830 info->must_restore_reg = 0;
4831 info->found_call = 1;
4834 if (info->z_set_count == 0)
4835 info->need_save_z = 0;
4838 info->need_save_z = 0;
4840 if (info->last == 0)
4843 if (info->regno >= 0)
4846 info->replace_reg = gen_rtx (REG, HImode, reg);
4848 else if (info->can_use_d)
4850 reg = HARD_D_REGNUM;
4851 info->replace_reg = d_reg;
4853 else if (info->x_used)
4855 reg = HARD_Y_REGNUM;
4856 info->replace_reg = iy_reg;
4860 reg = HARD_X_REGNUM;
4861 info->replace_reg = ix_reg;
4865 if (info->must_save_reg && info->must_restore_reg)
4867 if (insn && dead_register_here (insn, info->replace_reg))
4869 info->must_save_reg = 0;
4870 info->must_restore_reg = 0;
4875 /* The insn uses the Z register. Find a replacement register for it
4876 (either X or Y) and replace it in the insn and the next ones until
4877 the flow changes or the replacement register is used. Instructions
4878 are emitted before and after the Z-block to preserve the value of
4879 Z and of the replacement register. */
4882 m68hc11_z_replacement (insn)
4887 struct replace_info info;
4889 /* Find trivial case where we only need to replace z with the
4890 equivalent soft register. */
4891 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4893 rtx body = PATTERN (insn);
4894 rtx src = XEXP (body, 1);
4895 rtx dst = XEXP (body, 0);
4897 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4899 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4902 else if (Z_REG_P (src)
4903 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4905 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4908 else if (D_REG_P (dst)
4909 && m68hc11_arith_operator (src, GET_MODE (src))
4910 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4912 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4915 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4916 && INTVAL (src) == 0)
4918 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4919 /* Force it to be re-recognized. */
4920 INSN_CODE (insn) = -1;
4925 m68hc11_find_z_replacement (insn, &info);
4927 replace_reg = info.replace_reg;
4928 replace_reg_qi = NULL_RTX;
4930 /* Save the X register in a .page0 location. */
4931 if (info.must_save_reg && !info.must_push_reg)
4935 if (info.must_push_reg && 0)
4936 dst = gen_rtx (MEM, HImode,
4937 gen_rtx (PRE_DEC, HImode,
4938 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4940 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4942 emit_insn_before (gen_movhi (dst,
4943 gen_rtx (REG, HImode, info.regno)), insn);
4945 if (info.must_load_z && !info.must_push_reg)
4947 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4948 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4953 /* Replace all occurrence of Z by replace_reg.
4954 Stop when the last instruction to replace is reached.
4955 Also stop when we detect a change in the flow (but it's not
4956 necessary; just safeguard). */
4958 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4962 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4965 if (GET_CODE (insn) != INSN
4966 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4969 body = PATTERN (insn);
4970 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4971 || GET_CODE (body) == ASM_OPERANDS
4972 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4976 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4978 printf ("Reg mentioned here...:\n");
4983 /* Stack pointer was decremented by 2 due to the push.
4984 Correct that by adding 2 to the destination. */
4985 if (info.must_push_reg
4986 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4990 src = SET_SRC (body);
4991 dst = SET_DEST (body);
4992 if (SP_REG_P (src) && Z_REG_P (dst))
4993 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4996 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4997 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4999 INSN_CODE (insn) = -1;
5000 if (!validate_replace_rtx (z_reg, replace_reg, insn))
5001 fatal_insn ("cannot do z-register replacement", insn);
5004 /* Likewise for (REG:QI Z). */
5005 if (reg_mentioned_p (z_reg, insn))
5007 if (replace_reg_qi == NULL_RTX)
5008 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
5009 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
5012 /* If there is a REG_INC note on Z, replace it with a
5013 REG_INC note on the replacement register. This is necessary
5014 to make sure that the flow pass will identify the change
5015 and it will not remove a possible insn that saves Z. */
5016 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
5018 if (REG_NOTE_KIND (note) == REG_INC
5019 && GET_CODE (XEXP (note, 0)) == REG
5020 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
5022 XEXP (note, 0) = replace_reg;
5026 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5030 /* Save Z before restoring the old value. */
5031 if (insn && info.need_save_z && !info.must_push_reg)
5033 rtx save_pos_insn = insn;
5035 /* If Z is clobber by the last insn, we have to save its value
5036 before the last instruction. */
5037 if (info.save_before_last)
5038 save_pos_insn = PREV_INSN (save_pos_insn);
5040 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
5041 gen_rtx (REG, HImode, info.regno)),
5045 if (info.must_push_reg && info.last)
5049 body = PATTERN (info.last);
5050 new_body = gen_rtx (PARALLEL, VOIDmode,
5052 gen_rtx (USE, VOIDmode,
5054 gen_rtx (USE, VOIDmode,
5055 gen_rtx (REG, HImode,
5057 PATTERN (info.last) = new_body;
5059 /* Force recognition on insn since we changed it. */
5060 INSN_CODE (insn) = -1;
5062 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
5064 fatal_insn ("invalid Z register replacement for insn", insn);
5066 insn = NEXT_INSN (info.last);
5069 /* Restore replacement register unless it was died. */
5070 if (insn && info.must_restore_reg && !info.must_push_reg)
5074 if (info.must_push_reg && 0)
5075 dst = gen_rtx (MEM, HImode,
5076 gen_rtx (POST_INC, HImode,
5077 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
5079 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
5081 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
5088 /* Scan all the insn and re-affects some registers
5089 - The Z register (if it was used), is affected to X or Y depending
5090 on the instruction. */
5093 m68hc11_reassign_regs (first)
5098 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
5099 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
5100 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5101 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
5103 /* Scan all insns to replace Z by X or Y preserving the old value
5104 of X/Y and restoring it afterward. */
5106 for (insn = first; insn; insn = NEXT_INSN (insn))
5110 if (GET_CODE (insn) == CODE_LABEL
5111 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
5117 body = PATTERN (insn);
5118 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5121 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5122 || GET_CODE (body) == ASM_OPERANDS
5123 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5126 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5127 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5130 /* If Z appears in this insn, replace it in the current insn
5131 and the next ones until the flow changes or we have to
5132 restore back the replacement register. */
5134 if (reg_mentioned_p (z_reg, body))
5136 m68hc11_z_replacement (insn);
5141 printf ("insn not handled by Z replacement:\n");
5149 /* Machine-dependent reorg pass.
5150 Specific optimizations are defined here:
5151 - this pass changes the Z register into either X or Y
5152 (it preserves X/Y previous values in a memory slot in page0).
5154 When this pass is finished, the global variable
5155 'z_replacement_completed' is set to 2. */
5163 z_replacement_completed = 0;
5164 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5165 first = get_insns ();
5167 /* Some RTX are shared at this point. This breaks the Z register
5168 replacement, unshare everything. */
5169 unshare_all_rtl_again (first);
5171 /* Force a split of all splitable insn. This is necessary for the
5172 Z register replacement mechanism because we end up with basic insns. */
5173 split_all_insns_noflow ();
5176 z_replacement_completed = 1;
5177 m68hc11_reassign_regs (first);
5180 compute_bb_for_insn ();
5182 /* After some splitting, there are some opportunities for CSE pass.
5183 This happens quite often when 32-bit or above patterns are split. */
5184 if (optimize > 0 && split_done)
5186 reload_cse_regs (first);
5189 /* Re-create the REG_DEAD notes. These notes are used in the machine
5190 description to use the best assembly directives. */
5193 /* Before recomputing the REG_DEAD notes, remove all of them.
5194 This is necessary because the reload_cse_regs() pass can
5195 have replaced some (MEM) with a register. In that case,
5196 the REG_DEAD that could exist for that register may become
5198 for (insn = first; insn; insn = NEXT_INSN (insn))
5204 pnote = ®_NOTES (insn);
5207 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5208 *pnote = XEXP (*pnote, 1);
5210 pnote = &XEXP (*pnote, 1);
5215 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
5218 z_replacement_completed = 2;
5220 /* If optimizing, then go ahead and split insns that must be
5221 split after Z register replacement. This gives more opportunities
5222 for peephole (in particular for consecutives xgdx/xgdy). */
5224 split_all_insns_noflow ();
5226 /* Once insns are split after the z_replacement_completed == 2,
5227 we must not re-run the life_analysis. The xgdx/xgdy patterns
5228 are not recognized and the life_analysis pass removes some
5229 insns because it thinks some (SETs) are noops or made to dead
5230 stores (which is false due to the swap).
5232 Do a simple pass to eliminate the noop set that the final
5233 split could generate (because it was easier for split definition). */
5237 for (insn = first; insn; insn = NEXT_INSN (insn))
5241 if (INSN_DELETED_P (insn))
5246 /* Remove the (set (R) (R)) insns generated by some splits. */
5247 body = PATTERN (insn);
5248 if (GET_CODE (body) == SET
5249 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5251 PUT_CODE (insn, NOTE);
5252 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5253 NOTE_SOURCE_FILE (insn) = 0;
5261 /* Cost functions. */
5263 /* Cost of moving memory. */
5265 m68hc11_memory_move_cost (mode, class, in)
5266 enum machine_mode mode;
5267 enum reg_class class;
5268 int in ATTRIBUTE_UNUSED;
5270 if (class <= H_REGS && class > NO_REGS)
5272 if (GET_MODE_SIZE (mode) <= 2)
5273 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5275 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5279 if (GET_MODE_SIZE (mode) <= 2)
5280 return COSTS_N_INSNS (3);
5282 return COSTS_N_INSNS (4);
5287 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5288 Reload does not check the constraint of set insns when the two registers
5289 have a move cost of 2. Setting a higher cost will force reload to check
5292 m68hc11_register_move_cost (mode, from, to)
5293 enum machine_mode mode;
5294 enum reg_class from;
5297 /* All costs are symmetric, so reduce cases by putting the
5298 lower number class as the destination. */
5301 enum reg_class tmp = to;
5302 to = from, from = tmp;
5305 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5306 else if (from <= S_REGS)
5307 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5309 return COSTS_N_INSNS (2);
5313 /* Provide the costs of an addressing mode that contains ADDR.
5314 If ADDR is not a valid address, its cost is irrelevant. */
5317 m68hc11_address_cost (addr)
5322 switch (GET_CODE (addr))
5325 /* Make the cost of hard registers and specially SP, FP small. */
5326 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5343 register rtx plus0 = XEXP (addr, 0);
5344 register rtx plus1 = XEXP (addr, 1);
5346 if (GET_CODE (plus0) != REG)
5349 switch (GET_CODE (plus1))
5352 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5353 || INTVAL (plus1) < m68hc11_min_offset)
5355 else if (INTVAL (plus1) >= m68hc11_max_offset)
5359 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5381 if (SP_REG_P (XEXP (addr, 0)))
5390 printf ("Address cost: %d for :", cost);
5399 m68hc11_shift_cost (mode, x, shift)
5400 enum machine_mode mode;
5406 total = rtx_cost (x, SET);
5408 total += m68hc11_cost->shiftQI_const[shift % 8];
5409 else if (mode == HImode)
5410 total += m68hc11_cost->shiftHI_const[shift % 16];
5411 else if (shift == 8 || shift == 16 || shift == 32)
5412 total += m68hc11_cost->shiftHI_const[8];
5413 else if (shift != 0 && shift != 16 && shift != 32)
5415 total += m68hc11_cost->shiftHI_const[1] * shift;
5418 /* For SI and others, the cost is higher. */
5419 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5420 total *= GET_MODE_SIZE (mode) / 2;
5422 /* When optimizing for size, make shift more costly so that
5423 multiplications are preferred. */
5424 if (optimize_size && (shift % 8) != 0)
5431 m68hc11_rtx_costs_1 (x, code, outer_code)
5434 enum rtx_code outer_code ATTRIBUTE_UNUSED;
5436 enum machine_mode mode = GET_MODE (x);
5447 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5449 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5452 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5453 total += m68hc11_cost->shift_var;
5459 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5460 total += m68hc11_cost->logical;
5462 /* Logical instructions are byte instructions only. */
5463 total *= GET_MODE_SIZE (mode);
5468 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5469 total += m68hc11_cost->add;
5470 if (GET_MODE_SIZE (mode) > 2)
5472 total *= GET_MODE_SIZE (mode) / 2;
5479 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5483 total += m68hc11_cost->divQI;
5487 total += m68hc11_cost->divHI;
5492 total += m68hc11_cost->divSI;
5498 /* mul instruction produces 16-bit result. */
5499 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5500 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5501 return m68hc11_cost->multQI
5502 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5503 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5505 /* emul instruction produces 32-bit result for 68HC12. */
5506 if (TARGET_M6812 && mode == SImode
5507 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5508 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5509 return m68hc11_cost->multHI
5510 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5511 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5513 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5517 total += m68hc11_cost->multQI;
5521 total += m68hc11_cost->multHI;
5526 total += m68hc11_cost->multSI;
5533 extra_cost = COSTS_N_INSNS (2);
5540 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5543 return total + COSTS_N_INSNS (1);
5547 return total + COSTS_N_INSNS (2);
5551 return total + COSTS_N_INSNS (4);
5553 return total + COSTS_N_INSNS (8);
5556 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5557 return COSTS_N_INSNS (1);
5559 return COSTS_N_INSNS (1);
5562 return COSTS_N_INSNS (4);
5567 m68hc11_rtx_costs (x, code, outer_code, total)
5569 int code, outer_code;
5574 /* Constants are cheap. Moving them in registers must be avoided
5575 because most instructions do not handle two register operands. */
5581 /* Logical and arithmetic operations with a constant operand are
5582 better because they are not supported with two registers. */
5584 if (outer_code == SET && x == const0_rtx)
5585 /* After reload, the reload_cse pass checks the cost to change
5586 a SET into a PLUS. Make const0 cheap then. */
5587 *total = 1 - reload_completed;
5612 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5622 m68hc11_file_start ()
5624 default_file_start ();
5626 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5631 m68hc11_asm_out_constructor (symbol, priority)
5635 default_ctor_section_asm_out_constructor (symbol, priority);
5636 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5640 m68hc11_asm_out_destructor (symbol, priority)
5644 default_dtor_section_asm_out_destructor (symbol, priority);
5645 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5648 #include "gt-m68hc11.h"