1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 2009 Free Software Foundation, Inc.
4 Contributed by Stephane Carrez (stcarrez@nerim.fr)
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>.
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"
45 #include "hard-reg-set.h"
47 #include "insn-config.h"
48 #include "conditions.h"
50 #include "insn-attr.h"
56 #include "basic-block.h"
61 #include "target-def.h"
64 static void emit_move_after_reload (rtx, rtx, rtx);
65 static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
66 static void m68hc11_emit_logical (enum machine_mode, enum rtx_code, rtx *);
67 static void m68hc11_reorg (void);
68 static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool);
69 static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool);
70 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
71 static int must_parenthesize (rtx);
72 static int m68hc11_address_cost (rtx, bool);
73 static int m68hc11_shift_cost (enum machine_mode, rtx, int);
74 static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
75 static bool m68hc11_rtx_costs (rtx, int, int, int *, bool);
76 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
77 static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *);
79 void create_regs_rtx (void);
81 static void asm_print_register (FILE *, int);
82 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
83 static void m68hc11_asm_out_constructor (rtx, int);
84 static void m68hc11_asm_out_destructor (rtx, int);
85 static void m68hc11_file_start (void);
86 static void m68hc11_encode_section_info (tree, rtx, int);
87 static const char *m68hc11_strip_name_encoding (const char* str);
88 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
89 static int autoinc_mode (rtx);
90 static int m68hc11_make_autoinc_notes (rtx *, void *);
91 static void m68hc11_init_libfuncs (void);
92 static rtx m68hc11_struct_value_rtx (tree, int);
93 static bool m68hc11_return_in_memory (const_tree, const_tree);
94 static bool m68hc11_can_eliminate (const int, const int);
95 static void m68hc11_trampoline_init (rtx, tree, rtx);
97 /* Must be set to 1 to produce debug messages. */
100 extern FILE *asm_out_file;
105 rtx m68hc11_soft_tmp_reg;
106 static GTY(()) rtx stack_push_word;
107 static GTY(()) rtx stack_pop_word;
108 static GTY(()) rtx z_reg;
109 static GTY(()) rtx z_reg_qi;
110 static int regs_inited = 0;
112 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
113 int current_function_interrupt;
115 /* Set to 1 by expand_prologue() when the function is a trap handler. */
116 int current_function_trap;
118 /* Set to 1 when the current function is placed in 68HC12 banked
119 memory and must return with rtc. */
120 int current_function_far;
122 /* Min offset that is valid for the indirect addressing mode. */
123 HOST_WIDE_INT m68hc11_min_offset = 0;
125 /* Max offset that is valid for the indirect addressing mode. */
126 HOST_WIDE_INT m68hc11_max_offset = 256;
128 /* The class value for base registers. */
129 enum reg_class m68hc11_base_reg_class = A_REGS;
131 /* The class value for index registers. This is NO_REGS for 68HC11. */
132 enum reg_class m68hc11_index_reg_class = NO_REGS;
134 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
136 /* Tables that tell whether a given hard register is valid for
137 a base or an index register. It is filled at init time depending
138 on the target processor. */
139 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
140 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
142 /* A correction offset which is applied to the stack pointer.
143 This is 1 for 68HC11 and 0 for 68HC12. */
144 int m68hc11_sp_correction;
146 int m68hc11_addr_mode;
147 int m68hc11_mov_addr_mode;
150 const struct processor_costs *m68hc11_cost;
152 /* Costs for a 68HC11. */
153 static const struct processor_costs m6811_cost = {
158 /* non-constant shift */
161 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
162 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
163 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
166 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
167 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
168 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
169 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
170 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
171 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
176 COSTS_N_INSNS (20 * 4),
178 COSTS_N_INSNS (20 * 16),
187 /* Costs for a 68HC12. */
188 static const struct processor_costs m6812_cost = {
193 /* non-constant shift */
196 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
197 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
198 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
201 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
202 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
203 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
204 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
205 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
206 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
213 COSTS_N_INSNS (3 * 4),
222 /* M68HC11 specific attributes. */
224 static const struct attribute_spec m68hc11_attribute_table[] =
226 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
227 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
228 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
229 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
230 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
231 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
232 { NULL, 0, 0, false, false, false, NULL }
235 /* Initialize the GCC target structure. */
236 #undef TARGET_ATTRIBUTE_TABLE
237 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
239 #undef TARGET_ASM_ALIGNED_HI_OP
240 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
242 #undef TARGET_ASM_FUNCTION_EPILOGUE
243 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
245 #undef TARGET_ASM_FILE_START
246 #define TARGET_ASM_FILE_START m68hc11_file_start
247 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
248 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
250 #undef TARGET_DEFAULT_TARGET_FLAGS
251 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
253 #undef TARGET_ENCODE_SECTION_INFO
254 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
256 #undef TARGET_SECTION_TYPE_FLAGS
257 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
259 #undef TARGET_RTX_COSTS
260 #define TARGET_RTX_COSTS m68hc11_rtx_costs
261 #undef TARGET_ADDRESS_COST
262 #define TARGET_ADDRESS_COST m68hc11_address_cost
264 #undef TARGET_MACHINE_DEPENDENT_REORG
265 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
267 #undef TARGET_INIT_LIBFUNCS
268 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
270 #undef TARGET_STRUCT_VALUE_RTX
271 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
272 #undef TARGET_RETURN_IN_MEMORY
273 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
274 #undef TARGET_CALLEE_COPIES
275 #define TARGET_CALLEE_COPIES hook_callee_copies_named
277 #undef TARGET_STRIP_NAME_ENCODING
278 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
280 #undef TARGET_LEGITIMATE_ADDRESS_P
281 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
283 #undef TARGET_CAN_ELIMINATE
284 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
286 #undef TARGET_TRAMPOLINE_INIT
287 #define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
289 struct gcc_target targetm = TARGET_INITIALIZER;
292 m68hc11_override_options (void)
294 memset (m68hc11_reg_valid_for_index, 0,
295 sizeof (m68hc11_reg_valid_for_index));
296 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
298 /* Compilation with -fpic generates a wrong code. */
301 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
302 (flag_pic > 1) ? "PIC" : "pic");
306 /* Do not enable -fweb because it breaks the 32-bit shift patterns
307 by breaking the match_dup of those patterns. The shift patterns
308 will no longer be recognized after that. */
311 /* Configure for a 68hc11 processor. */
314 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
315 m68hc11_cost = &m6811_cost;
316 m68hc11_min_offset = 0;
317 m68hc11_max_offset = 256;
318 m68hc11_index_reg_class = NO_REGS;
319 m68hc11_base_reg_class = A_REGS;
320 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
321 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
322 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
323 m68hc11_sp_correction = 1;
324 m68hc11_tmp_regs_class = D_REGS;
325 m68hc11_addr_mode = ADDR_OFFSET;
326 m68hc11_mov_addr_mode = 0;
327 if (m68hc11_soft_reg_count < 0)
328 m68hc11_soft_reg_count = 4;
331 /* Configure for a 68hc12 processor. */
334 m68hc11_cost = &m6812_cost;
335 m68hc11_min_offset = -65536;
336 m68hc11_max_offset = 65536;
337 m68hc11_index_reg_class = D_REGS;
338 m68hc11_base_reg_class = A_OR_SP_REGS;
339 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
340 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
341 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
342 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
343 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
344 m68hc11_sp_correction = 0;
345 m68hc11_tmp_regs_class = TMP_REGS;
346 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
347 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
348 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
349 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
350 target_flags |= MASK_NO_DIRECT_MODE;
351 if (m68hc11_soft_reg_count < 0)
352 m68hc11_soft_reg_count = 0;
354 if (TARGET_LONG_CALLS)
355 current_function_far = 1;
362 m68hc11_conditional_register_usage (void)
366 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
367 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
369 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
372 call_used_regs[i] = 1;
375 /* For 68HC12, the Z register emulation is not necessary when the
376 frame pointer is not used. The frame pointer is eliminated and
377 replaced by the stack register (which is a BASE_REG_CLASS). */
378 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
380 fixed_regs[HARD_Z_REGNUM] = 1;
385 /* Reload and register operations. */
389 create_regs_rtx (void)
391 /* regs_inited = 1; */
392 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
393 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
394 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
395 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
397 stack_push_word = gen_rtx_MEM (HImode,
398 gen_rtx_PRE_DEC (HImode,
399 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
400 stack_pop_word = gen_rtx_MEM (HImode,
401 gen_rtx_POST_INC (HImode,
402 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
406 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
407 - 8-bit values are stored anywhere (except the SP register).
408 - 16-bit values can be stored in any register whose mode is 16
409 - 32-bit values can be stored in D, X registers or in a soft register
410 (except the last one because we need 2 soft registers)
411 - Values whose size is > 32 bit are not stored in real hard
412 registers. They may be stored in soft registers if there are
415 hard_regno_mode_ok (int regno, enum machine_mode mode)
417 switch (GET_MODE_SIZE (mode))
420 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
423 return (X_REGNO_P (regno)
424 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
427 return G_REGNO_P (regno);
430 /* We have to accept a QImode in X or Y registers. Otherwise, the
431 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
432 in the insns. Reload fails if the insn rejects the register class 'a'
433 as well as if it accepts it. Patterns that failed were
434 zero_extend_qihi2 and iorqi3. */
436 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
444 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
446 /* Don't accept renaming to Z register. We will replace it to
447 X,Y or D during machine reorg pass. */
448 if (reg2 == HARD_Z_REGNUM)
451 /* Don't accept renaming D,X to Y register as the code will be bigger. */
452 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
453 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
460 preferred_reload_class (rtx operand, enum reg_class rclass)
462 enum machine_mode mode;
464 mode = GET_MODE (operand);
468 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
471 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
472 return m68hc11_base_reg_class;
474 if (rclass >= S_REGS && (GET_CODE (operand) == MEM
475 || GET_CODE (operand) == CONST_INT))
477 /* S_REGS class must not be used. The movhi template does not
478 work to move a memory to a soft register.
479 Restrict to a hard reg. */
484 case D_OR_A_OR_S_REGS:
485 rclass = A_OR_D_REGS;
490 case D_OR_SP_OR_S_REGS:
491 rclass = D_OR_SP_REGS;
493 case D_OR_Y_OR_S_REGS:
494 rclass = D_OR_Y_REGS;
496 case D_OR_X_OR_S_REGS:
497 rclass = D_OR_X_REGS;
512 else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
516 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
518 rclass = D_OR_X_REGS;
520 else if (rclass >= S_REGS && S_REG_P (operand))
526 case D_OR_A_OR_S_REGS:
527 rclass = A_OR_D_REGS;
532 case D_OR_SP_OR_S_REGS:
533 rclass = D_OR_SP_REGS;
535 case D_OR_Y_OR_S_REGS:
536 rclass = D_OR_Y_REGS;
538 case D_OR_X_OR_S_REGS:
539 rclass = D_OR_X_REGS;
554 else if (rclass >= S_REGS)
558 printf ("Class = %s for: ", reg_class_names[rclass]);
566 printf (" => class=%s\n", reg_class_names[rclass]);
574 /* Return 1 if the operand is a valid indexed addressing mode.
575 For 68hc11: n,r with n in [0..255] and r in A_REGS class
576 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
578 m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
582 switch (GET_CODE (operand))
585 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
586 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
587 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
594 if (addr_mode & ADDR_INCDEC)
595 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
596 addr_mode & ADDR_STRICT);
600 base = XEXP (operand, 0);
601 if (GET_CODE (base) == MEM)
604 offset = XEXP (operand, 1);
605 if (GET_CODE (offset) == MEM)
608 /* Indexed addressing mode with 2 registers. */
609 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
611 if (!(addr_mode & ADDR_INDEXED))
614 addr_mode &= ADDR_STRICT;
615 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
616 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
619 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
620 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
626 if (!(addr_mode & ADDR_OFFSET))
629 if (GET_CODE (base) == REG)
631 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
634 if (!(addr_mode & ADDR_STRICT))
637 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
640 if (GET_CODE (offset) == REG)
642 if (!VALID_CONSTANT_OFFSET_P (base, mode))
645 if (!(addr_mode & ADDR_STRICT))
648 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
653 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
656 if (addr_mode & ADDR_CONST)
657 return VALID_CONSTANT_OFFSET_P (operand, mode);
665 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
666 a 68HC12 1-byte index addressing mode. */
668 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
673 if (GET_CODE (operand) == REG && reload_in_progress
674 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
675 && reg_equiv_memory_loc[REGNO (operand)])
677 operand = reg_equiv_memory_loc[REGNO (operand)];
678 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
681 if (GET_CODE (operand) != MEM)
684 operand = XEXP (operand, 0);
685 if (CONSTANT_ADDRESS_P (operand))
688 if (PUSH_POP_ADDRESS_P (operand))
691 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
692 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
695 if (TARGET_M6812 && GET_CODE (operand) == PLUS
696 && (reload_completed | reload_in_progress))
698 base = XEXP (operand, 0);
699 offset = XEXP (operand, 1);
701 /* The offset can be a symbol address and this is too big
702 for the operand constraint. */
703 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
706 if (GET_CODE (base) == CONST_INT)
709 switch (GET_MODE_SIZE (mode))
712 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
717 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
722 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
731 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
735 if (GET_CODE (operand) == REG && reload_in_progress
736 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
737 && reg_equiv_memory_loc[REGNO (operand)])
739 operand = reg_equiv_memory_loc[REGNO (operand)];
740 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
742 if (GET_CODE (operand) != MEM)
745 operand = XEXP (operand, 0);
746 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
747 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
751 m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
756 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
758 /* Reject the global variables if they are too wide. This forces
759 a load of their address in a register and generates smaller code. */
760 if (GET_MODE_SIZE (mode) == 8)
765 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
766 if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
770 if (PUSH_POP_ADDRESS_P (operand))
774 if (symbolic_memory_operand (operand, mode))
782 m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
789 printf ("Checking: ");
794 result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
798 printf (" -> %s\n", result == 0 ? "NO" : "YES");
805 printf ("go_if_legitimate%s, ret 0: %d:",
806 (strict ? "_strict" : ""), mode);
816 m68hc11_reload_operands (rtx operands[])
818 enum machine_mode mode;
820 if (regs_inited == 0)
823 mode = GET_MODE (operands[1]);
825 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
826 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
828 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
829 rtx base = XEXP (XEXP (operands[1], 0), 0);
831 if (GET_CODE (base) != REG)
838 /* If the offset is out of range, we have to compute the address
839 with a separate add instruction. We try to do this with an 8-bit
840 add on the A register. This is possible only if the lowest part
841 of the offset (i.e., big_offset % 256) is a valid constant offset
842 with respect to the mode. If it's not, we have to generate a
843 16-bit add on the D register. From:
845 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
849 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
850 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
851 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
852 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
854 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
855 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
858 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
861 rtx reg = operands[0];
863 int val = INTVAL (big_offset);
866 /* We use the 'operands[0]' as a scratch register to compute the
867 address. Make sure 'base' is in that register. */
868 if (!rtx_equal_p (base, operands[0]))
870 emit_move_insn (reg, base);
880 vh = (val >> 8) & 0x0FF;
884 /* Create the lowest part offset that still remains to be added.
885 If it's not a valid offset, do a 16-bit add. */
886 offset = GEN_INT (vl);
887 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
889 emit_insn (gen_rtx_SET (VOIDmode, reg,
890 gen_rtx_PLUS (HImode, reg, big_offset)));
895 emit_insn (gen_rtx_SET (VOIDmode, reg,
896 gen_rtx_PLUS (HImode, reg,
897 GEN_INT (vh << 8))));
899 emit_move_insn (operands[0],
900 gen_rtx_MEM (GET_MODE (operands[1]),
901 gen_rtx_PLUS (Pmode, reg, offset)));
906 /* Use the normal gen_movhi pattern. */
911 m68hc11_emit_libcall (const char *name, enum rtx_code code,
912 enum machine_mode dmode, enum machine_mode smode,
913 int noperands, rtx *operands)
921 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
925 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
926 dmode, 1, operands[1], smode);
927 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
931 ret = emit_library_call_value (libcall, NULL_RTX,
933 operands[1], smode, operands[2],
935 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
942 insns = get_insns ();
944 emit_libcall_block (insns, operands[0], ret, equiv);
947 /* Returns true if X is a PRE/POST increment decrement
948 (same as auto_inc_p() in rtlanal.c but do not take into
949 account the stack). */
951 m68hc11_auto_inc_p (rtx x)
953 return GET_CODE (x) == PRE_DEC
954 || GET_CODE (x) == POST_INC
955 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
959 /* Predicates for machine description. */
962 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
964 return GET_CODE (operand) == MEM
965 && GET_CODE (XEXP (operand, 0)) == PLUS
966 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
967 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
968 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
969 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
973 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
975 if (GET_CODE (operand) == MEM)
977 rtx op = XEXP (operand, 0);
979 if (symbolic_memory_operand (op, mode))
986 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
988 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
990 rtx op = XEXP (operand, 0);
993 if (m68hc11_page0_symbol_p (op))
996 if (symbolic_memory_operand (op, mode))
999 if (reload_in_progress)
1002 operand = XEXP (operand, 0);
1003 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1004 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
1010 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1012 if (GET_CODE (operand) != MEM)
1015 operand = XEXP (operand, 0);
1016 if (GET_CODE (operand) == PLUS)
1018 if (GET_CODE (XEXP (operand, 0)) == REG)
1019 operand = XEXP (operand, 0);
1020 else if (GET_CODE (XEXP (operand, 1)) == REG)
1021 operand = XEXP (operand, 1);
1023 return GET_CODE (operand) == REG
1024 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1025 || A_REGNO_P (REGNO (operand)));
1029 push_pop_operand_p (rtx operand)
1031 if (GET_CODE (operand) != MEM)
1035 operand = XEXP (operand, 0);
1036 return PUSH_POP_ADDRESS_P (operand);
1039 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1040 reference and a constant. */
1043 symbolic_memory_operand (rtx op, enum machine_mode mode)
1045 switch (GET_CODE (op))
1053 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1054 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1055 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1057 /* ??? This clause seems to be irrelevant. */
1059 return GET_MODE (op) == mode;
1062 return symbolic_memory_operand (XEXP (op, 0), mode)
1063 && symbolic_memory_operand (XEXP (op, 1), mode);
1070 /* Emit the code to build the trampoline used to call a nested function.
1074 ldy #&CXT movw #&CXT,*_.d1
1075 sty *_.d1 jmp FNADDR
1080 m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
1082 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1083 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
1087 if (*static_chain_reg == '*')
1091 mem = adjust_address (m_tramp, HImode, 0);
1092 emit_move_insn (mem, GEN_INT (0x18ce));
1093 mem = adjust_address (m_tramp, HImode, 2);
1094 emit_move_insn (mem, cxt);
1095 mem = adjust_address (m_tramp, HImode, 4);
1096 emit_move_insn (mem, GEN_INT (0x18df));
1097 mem = adjust_address (m_tramp, QImode, 6);
1098 emit_move_insn (mem,
1099 gen_rtx_CONST (QImode,
1100 gen_rtx_SYMBOL_REF (Pmode,
1101 static_chain_reg)));
1102 mem = adjust_address (m_tramp, QImode, 7);
1103 emit_move_insn (mem, GEN_INT (0x7e));
1104 mem = adjust_address (m_tramp, HImode, 8);
1105 emit_move_insn (mem, fnaddr);
1109 mem = adjust_address (m_tramp, HImode, 0);
1110 emit_move_insn (mem, GEN_INT (0x1803));
1111 mem = adjust_address (m_tramp, HImode, 2);
1112 emit_move_insn (mem, cxt);
1113 mem = adjust_address (m_tramp, HImode, 4);
1114 emit_move_insn (mem,
1115 gen_rtx_CONST (HImode,
1116 gen_rtx_SYMBOL_REF (Pmode,
1117 static_chain_reg)));
1118 mem = adjust_address (m_tramp, QImode, 6);
1119 emit_move_insn (mem, GEN_INT (0x06));
1120 mem = adjust_address (m_tramp, HImode, 7);
1121 emit_move_insn (mem, fnaddr);
1125 /* Declaration of types. */
1127 /* Handle an "tiny_data" attribute; arguments as in
1128 struct attribute_spec.handler. */
1130 m68hc11_handle_page0_attribute (tree *node, tree name,
1131 tree args ATTRIBUTE_UNUSED,
1132 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1136 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1138 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1142 warning (OPT_Wattributes, "%qE attribute ignored",
1144 *no_add_attrs = true;
1150 /* Keep track of the symbol which has a `trap' attribute and which uses
1151 the `swi' calling convention. Since there is only one trap, we only
1152 record one such symbol. If there are several, a warning is reported. */
1153 static rtx trap_handler_symbol = 0;
1155 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1156 arguments as in struct attribute_spec.handler. */
1158 m68hc11_handle_fntype_attribute (tree *node, tree name,
1159 tree args ATTRIBUTE_UNUSED,
1160 int flags ATTRIBUTE_UNUSED,
1163 if (TREE_CODE (*node) != FUNCTION_TYPE
1164 && TREE_CODE (*node) != METHOD_TYPE
1165 && TREE_CODE (*node) != FIELD_DECL
1166 && TREE_CODE (*node) != TYPE_DECL)
1168 warning (OPT_Wattributes, "%qE attribute only applies to functions",
1170 *no_add_attrs = true;
1175 /* Undo the effects of the above. */
1178 m68hc11_strip_name_encoding (const char *str)
1180 return str + (*str == '*' || *str == '@' || *str == '&');
1184 m68hc11_encode_label (tree decl)
1186 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1187 int len = strlen (str);
1188 char *newstr = XALLOCAVEC (char, len + 2);
1191 strcpy (&newstr[1], str);
1193 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1196 /* Return 1 if this is a symbol in page0 */
1198 m68hc11_page0_symbol_p (rtx x)
1200 switch (GET_CODE (x))
1203 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1206 return m68hc11_page0_symbol_p (XEXP (x, 0));
1209 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1212 return GET_CODE (XEXP (x, 1)) == CONST_INT
1213 && INTVAL (XEXP (x, 1)) < 256
1214 && INTVAL (XEXP (x, 1)) >= 0;
1221 /* We want to recognize trap handlers so that we handle calls to traps
1222 in a special manner (by issuing the trap). This information is stored
1223 in SYMBOL_REF_FLAG. */
1226 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1232 if (TREE_CODE (decl) == VAR_DECL)
1234 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1235 m68hc11_encode_label (decl);
1239 if (TREE_CODE (decl) != FUNCTION_DECL)
1242 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1245 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1247 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1248 is_far = TARGET_LONG_CALLS != 0;
1250 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1251 if (trap_handler && is_far)
1253 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1254 "not compatible, ignoring %<far%>");
1259 if (trap_handler_symbol != 0)
1260 warning (OPT_Wattributes, "%<trap%> attribute is already used");
1262 trap_handler_symbol = XEXP (rtl, 0);
1264 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1268 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1270 unsigned int flags = default_section_type_flags (decl, name, reloc);
1272 if (strncmp (name, ".eeprom", 7) == 0)
1274 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1281 m68hc11_is_far_symbol (rtx sym)
1283 if (GET_CODE (sym) == MEM)
1284 sym = XEXP (sym, 0);
1286 return SYMBOL_REF_FLAG (sym);
1290 m68hc11_is_trap_symbol (rtx sym)
1292 if (GET_CODE (sym) == MEM)
1293 sym = XEXP (sym, 0);
1295 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1299 /* Argument support functions. */
1301 /* Given FROM and TO register numbers, say whether this elimination is
1302 allowed. Frame pointer elimination is automatically handled.
1304 All other eliminations are valid. */
1307 m68hc11_can_eliminate (const int from, const int to)
1309 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
1310 ? ! frame_pointer_needed
1314 /* Define the offset between two registers, one to be eliminated, and the
1315 other its replacement, at the start of a routine. */
1317 m68hc11_initial_elimination_offset (int from, int to)
1324 /* For a trap handler, we must take into account the registers which
1325 are pushed on the stack during the trap (except the PC). */
1326 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1327 current_function_interrupt = lookup_attribute ("interrupt",
1328 func_attr) != NULL_TREE;
1329 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1331 if (lookup_attribute ("far", func_attr) != 0)
1332 current_function_far = 1;
1333 else if (lookup_attribute ("near", func_attr) != 0)
1334 current_function_far = 0;
1336 current_function_far = (TARGET_LONG_CALLS != 0
1337 && !current_function_interrupt
1340 if (trap_handler && from == ARG_POINTER_REGNUM)
1343 /* For a function using 'call/rtc' we must take into account the
1344 page register which is pushed in the call. */
1345 else if (current_function_far && from == ARG_POINTER_REGNUM)
1350 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1352 /* 2 is for the saved frame.
1353 1 is for the 'sts' correction when creating the frame. */
1354 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1357 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1359 return m68hc11_sp_correction;
1362 /* Push any 2 byte pseudo hard registers that we need to save. */
1363 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1365 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1371 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1373 return get_frame_size () + size;
1376 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1383 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1384 for a call to a function whose data type is FNTYPE.
1385 For a library call, FNTYPE is 0. */
1388 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1392 z_replacement_completed = 0;
1396 /* For a library call, we must find out the type of the return value.
1397 When the return value is bigger than 4 bytes, it is returned in
1398 memory. In that case, the first argument of the library call is a
1399 pointer to the memory location. Because the first argument is passed in
1400 register D, we have to identify this, so that the first function
1401 parameter is not passed in D either. */
1407 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1410 /* If the library ends in 'di' or in 'df', we assume it's
1411 returning some DImode or some DFmode which are 64-bit wide. */
1412 name = XSTR (libname, 0);
1413 len = strlen (name);
1415 && ((name[len - 2] == 'd'
1416 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1417 || (name[len - 3] == 'd'
1418 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1420 /* We are in. Mark the first parameter register as already used. */
1427 ret_type = TREE_TYPE (fntype);
1429 if (ret_type && aggregate_value_p (ret_type, fntype))
1436 /* Update the data in CUM to advance over an argument
1437 of mode MODE and data type TYPE.
1438 (TYPE is null for libcalls where that information may not be available.) */
1441 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1442 tree type, int named ATTRIBUTE_UNUSED)
1444 if (mode != BLKmode)
1446 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1449 cum->words = GET_MODE_SIZE (mode);
1453 cum->words += GET_MODE_SIZE (mode);
1454 if (cum->words <= HARD_REG_SIZE)
1460 cum->words += int_size_in_bytes (type);
1465 /* Define where to put the arguments to a function.
1466 Value is zero to push the argument on the stack,
1467 or a hard register in which to store the argument.
1469 MODE is the argument's machine mode.
1470 TYPE is the data type of the argument (as a tree).
1471 This is null for libcalls where that information may
1473 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1474 the preceding args and about the function being called.
1475 NAMED is nonzero if this argument is a named parameter
1476 (otherwise it is an extra parameter matching an ellipsis). */
1479 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1480 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1482 if (cum->words != 0)
1487 if (mode != BLKmode)
1489 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1490 return gen_rtx_REG (mode, HARD_X_REGNUM);
1492 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1496 return gen_rtx_REG (mode, HARD_D_REGNUM);
1501 /* If defined, a C expression which determines whether, and in which direction,
1502 to pad out an argument with extra space. The value should be of type
1503 `enum direction': either `upward' to pad above the argument,
1504 `downward' to pad below, or `none' to inhibit padding.
1506 Structures are stored left shifted in their argument slot. */
1508 m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
1510 if (type != 0 && AGGREGATE_TYPE_P (type))
1513 /* Fall back to the default. */
1514 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1518 /* Function prologue and epilogue. */
1520 /* Emit a move after the reload pass has completed. This is used to
1521 emit the prologue and epilogue. */
1523 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1527 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1529 insn = emit_move_insn (to, from);
1533 emit_move_insn (scratch, from);
1534 insn = emit_move_insn (to, scratch);
1537 /* Put a REG_INC note to tell the flow analysis that the instruction
1539 if (IS_STACK_PUSH (to))
1540 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
1541 else if (IS_STACK_POP (from))
1542 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
1544 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1545 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1546 The problem is that we are lying to gcc and use `txs' for x = sp
1547 (which is not really true because txs is really x = sp + 1). */
1548 else if (TARGET_M6811 && SP_REG_P (from))
1549 add_reg_note (insn, REG_INC, from);
1553 m68hc11_total_frame_size (void)
1558 size = get_frame_size ();
1559 if (current_function_interrupt)
1561 size += 3 * HARD_REG_SIZE;
1563 if (frame_pointer_needed)
1564 size += HARD_REG_SIZE;
1566 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1567 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1568 size += HARD_REG_SIZE;
1574 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1575 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1577 /* We catch the function epilogue generation to have a chance
1578 to clear the z_replacement_completed flag. */
1579 z_replacement_completed = 0;
1583 expand_prologue (void)
1590 gcc_assert (reload_completed == 1);
1592 size = get_frame_size ();
1596 /* Generate specific prologue for interrupt handlers. */
1597 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1598 current_function_interrupt = lookup_attribute ("interrupt",
1599 func_attr) != NULL_TREE;
1600 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1601 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1602 current_function_far = 1;
1603 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1604 current_function_far = 0;
1606 current_function_far = (TARGET_LONG_CALLS != 0
1607 && !current_function_interrupt
1608 && !current_function_trap);
1610 /* Get the scratch register to build the frame and push registers.
1611 If the first argument is a 32-bit quantity, the D+X registers
1612 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1613 For 68HC12, this scratch register is not used. */
1614 if (crtl->args.info.nregs == 2)
1619 /* Save current stack frame. */
1620 if (frame_pointer_needed)
1621 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1623 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1624 Other soft registers in page0 need not to be saved because they
1625 will be restored by C functions. For a trap handler, we don't
1626 need to preserve these registers because this is a synchronous call. */
1627 if (current_function_interrupt)
1629 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1630 emit_move_after_reload (stack_push_word,
1631 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1632 emit_move_after_reload (stack_push_word,
1633 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1637 /* Allocate local variables. */
1638 if (TARGET_M6812 && (size > 4 || size == 3))
1640 emit_insn (gen_addhi3 (stack_pointer_rtx,
1641 stack_pointer_rtx, GEN_INT (-size)));
1643 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1647 insn = gen_rtx_PARALLEL
1650 gen_rtx_SET (VOIDmode,
1652 gen_rtx_PLUS (HImode,
1655 gen_rtx_CLOBBER (VOIDmode, scratch)));
1662 /* Allocate by pushing scratch values. */
1663 for (i = 2; i <= size; i += 2)
1664 emit_move_after_reload (stack_push_word, ix_reg, 0);
1667 emit_insn (gen_addhi3 (stack_pointer_rtx,
1668 stack_pointer_rtx, constm1_rtx));
1671 /* Create the frame pointer. */
1672 if (frame_pointer_needed)
1673 emit_move_after_reload (hard_frame_pointer_rtx,
1674 stack_pointer_rtx, scratch);
1676 /* Push any 2 byte pseudo hard registers that we need to save. */
1677 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1679 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1681 emit_move_after_reload (stack_push_word,
1682 gen_rtx_REG (HImode, regno), scratch);
1688 expand_epilogue (void)
1695 gcc_assert (reload_completed == 1);
1697 size = get_frame_size ();
1699 /* If we are returning a value in two registers, we have to preserve the
1700 X register and use the Y register to restore the stack and the saved
1701 registers. Otherwise, use X because it's faster (and smaller). */
1702 if (crtl->return_rtx == 0)
1704 else if (GET_CODE (crtl->return_rtx) == MEM)
1705 return_size = HARD_REG_SIZE;
1707 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
1709 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1714 /* Pop any 2 byte pseudo hard registers that we saved. */
1715 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1717 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1719 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1720 stack_pop_word, scratch);
1724 /* de-allocate auto variables */
1725 if (TARGET_M6812 && (size > 4 || size == 3))
1727 emit_insn (gen_addhi3 (stack_pointer_rtx,
1728 stack_pointer_rtx, GEN_INT (size)));
1730 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1734 insn = gen_rtx_PARALLEL
1737 gen_rtx_SET (VOIDmode,
1739 gen_rtx_PLUS (HImode,
1742 gen_rtx_CLOBBER (VOIDmode, scratch)));
1749 for (i = 2; i <= size; i += 2)
1750 emit_move_after_reload (scratch, stack_pop_word, scratch);
1752 emit_insn (gen_addhi3 (stack_pointer_rtx,
1753 stack_pointer_rtx, const1_rtx));
1756 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1757 if (current_function_interrupt)
1759 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1760 stack_pop_word, scratch);
1761 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1762 stack_pop_word, scratch);
1763 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1766 /* Restore previous frame pointer. */
1767 if (frame_pointer_needed)
1768 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1770 /* If the trap handler returns some value, copy the value
1771 in D, X onto the stack so that the rti will pop the return value
1773 else if (current_function_trap && return_size != 0)
1775 rtx addr_reg = stack_pointer_rtx;
1779 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1782 emit_move_after_reload (gen_rtx_MEM (HImode,
1783 gen_rtx_PLUS (HImode, addr_reg,
1784 const1_rtx)), d_reg, 0);
1785 if (return_size > HARD_REG_SIZE)
1786 emit_move_after_reload (gen_rtx_MEM (HImode,
1787 gen_rtx_PLUS (HImode, addr_reg,
1788 GEN_INT (3))), ix_reg, 0);
1791 emit_jump_insn (gen_return ());
1795 /* Low and High part extraction for 68HC11. These routines are
1796 similar to gen_lowpart and gen_highpart but they have been
1797 fixed to work for constants and 68HC11 specific registers. */
1800 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1802 /* We assume that the low part of an auto-inc mode is the same with
1803 the mode changed and that the caller split the larger mode in the
1805 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1807 return gen_rtx_MEM (mode, XEXP (x, 0));
1810 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1811 floating-point constant. A CONST_DOUBLE is used whenever the
1812 constant requires more than one word in order to be adequately
1814 if (GET_CODE (x) == CONST_DOUBLE)
1818 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1822 if (GET_MODE (x) == SFmode)
1824 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1825 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1831 split_double (x, &first, &second);
1835 return GEN_INT (l[0]);
1837 return gen_int_mode (l[0], HImode);
1841 l[0] = CONST_DOUBLE_LOW (x);
1846 return GEN_INT (l[0]);
1848 gcc_assert (GET_MODE (x) == SFmode);
1849 return gen_int_mode (l[0], HImode);
1855 if (mode == QImode && D_REG_P (x))
1856 return gen_rtx_REG (mode, HARD_B_REGNUM);
1858 /* gen_lowpart crashes when it is called with a SUBREG. */
1859 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1864 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1866 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1871 x = gen_lowpart (mode, x);
1873 /* Return a different rtx to avoid to share it in several insns
1874 (when used by a split pattern). Sharing addresses within
1875 a MEM breaks the Z register replacement (and reloading). */
1876 if (GET_CODE (x) == MEM)
1882 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1884 /* We assume that the high part of an auto-inc mode is the same with
1885 the mode changed and that the caller split the larger mode in the
1887 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1889 return gen_rtx_MEM (mode, XEXP (x, 0));
1892 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1893 floating-point constant. A CONST_DOUBLE is used whenever the
1894 constant requires more than one word in order to be adequately
1896 if (GET_CODE (x) == CONST_DOUBLE)
1900 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1904 if (GET_MODE (x) == SFmode)
1906 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1907 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1913 split_double (x, &first, &second);
1917 return GEN_INT (l[1]);
1919 return gen_int_mode ((l[1] >> 16), HImode);
1923 l[1] = CONST_DOUBLE_HIGH (x);
1929 return GEN_INT (l[1]);
1931 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1932 return gen_int_mode ((l[0] >> 16), HImode);
1937 if (GET_CODE (x) == CONST_INT)
1939 HOST_WIDE_INT val = INTVAL (x);
1943 return gen_int_mode (val >> 8, QImode);
1945 else if (mode == HImode)
1947 return gen_int_mode (val >> 16, HImode);
1949 else if (mode == SImode)
1951 return gen_int_mode (val >> 32, SImode);
1954 if (mode == QImode && D_REG_P (x))
1955 return gen_rtx_REG (mode, HARD_A_REGNUM);
1957 /* There is no way in GCC to represent the upper part of a word register.
1958 To obtain the 8-bit upper part of a soft register, we change the
1959 reg into a mem rtx. This is possible because they are physically
1960 located in memory. There is no offset because we are big-endian. */
1961 if (mode == QImode && S_REG_P (x))
1965 /* Avoid the '*' for direct addressing mode when this
1966 addressing mode is disabled. */
1967 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1968 return gen_rtx_MEM (QImode,
1969 gen_rtx_SYMBOL_REF (Pmode,
1970 ®_names[REGNO (x)][pos]));
1973 /* gen_highpart crashes when it is called with a SUBREG. */
1974 switch (GET_CODE (x))
1977 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
1979 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1980 return gen_rtx_REG (mode, REGNO (x));
1982 return gen_rtx_SUBREG (mode, x, 0);
1984 x = change_address (x, mode, 0);
1986 /* Return a different rtx to avoid to share it in several insns
1987 (when used by a split pattern). Sharing addresses within
1988 a MEM breaks the Z register replacement (and reloading). */
1989 if (GET_CODE (x) == MEM)
1999 /* Obscure register manipulation. */
2001 /* Finds backward in the instructions to see if register 'reg' is
2002 dead. This is used when generating code to see if we can use 'reg'
2003 as a scratch register. This allows us to choose a better generation
2004 of code when we know that some register dies or can be clobbered. */
2007 dead_register_here (rtx x, rtx reg)
2013 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2017 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2024 if (GET_CODE (body) == CALL_INSN)
2026 if (GET_CODE (body) == JUMP_INSN)
2029 if (GET_CODE (body) == SET)
2031 rtx dst = XEXP (body, 0);
2033 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2035 if (x_reg && rtx_equal_p (dst, x_reg))
2038 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2041 else if (reg_mentioned_p (reg, p)
2042 || (x_reg && reg_mentioned_p (x_reg, p)))
2046 /* Scan forward to see if the register is set in some insns and never
2048 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2052 if (GET_CODE (p) == CODE_LABEL
2053 || GET_CODE (p) == JUMP_INSN
2054 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2057 if (GET_CODE (p) != INSN)
2061 if (GET_CODE (body) == SET)
2063 rtx src = XEXP (body, 1);
2064 rtx dst = XEXP (body, 0);
2066 if (GET_CODE (dst) == REG
2067 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2071 /* Register is used (may be in source or in dest). */
2072 if (reg_mentioned_p (reg, p)
2073 || (x_reg != 0 && GET_MODE (p) == SImode
2074 && reg_mentioned_p (x_reg, p)))
2077 return p == 0 ? 1 : 0;
2081 /* Code generation operations called from machine description file. */
2083 /* Print the name of register 'regno' in the assembly file. */
2085 asm_print_register (FILE *file, int regno)
2087 const char *name = reg_names[regno];
2089 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2092 fprintf (file, "%s", name);
2095 /* A C compound statement to output to stdio stream STREAM the
2096 assembler syntax for an instruction operand X. X is an RTL
2099 CODE is a value that can be used to specify one of several ways
2100 of printing the operand. It is used when identical operands
2101 must be printed differently depending on the context. CODE
2102 comes from the `%' specification that was used to request
2103 printing of the operand. If the specification was just `%DIGIT'
2104 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2105 is the ASCII code for LTR.
2107 If X is a register, this macro should print the register's name.
2108 The names can be found in an array `reg_names' whose type is
2109 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2111 When the machine description has a specification `%PUNCT' (a `%'
2112 followed by a punctuation character), this macro is called with
2113 a null pointer for X and the punctuation character for CODE.
2115 The M68HC11 specific codes are:
2117 'b' for the low part of the operand.
2118 'h' for the high part of the operand
2119 The 'b' or 'h' modifiers have no effect if the operand has
2120 the QImode and is not a S_REG_P (soft register). If the
2121 operand is a hard register, these two modifiers have no effect.
2122 't' generate the temporary scratch register. The operand is
2124 'T' generate the low-part temporary scratch register. The operand is
2128 print_operand (FILE *file, rtx op, int letter)
2132 asm_print_register (file, SOFT_TMP_REGNUM);
2135 else if (letter == 'T')
2137 asm_print_register (file, SOFT_TMP_REGNUM);
2138 fprintf (file, "+1");
2141 else if (letter == '#')
2143 asm_fprintf (file, "%I");
2146 if (GET_CODE (op) == REG)
2148 if (letter == 'b' && S_REG_P (op))
2150 asm_print_register (file, REGNO (op));
2151 fprintf (file, "+1");
2153 else if (letter == 'b' && D_REG_P (op))
2155 asm_print_register (file, HARD_B_REGNUM);
2159 asm_print_register (file, REGNO (op));
2164 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2167 asm_fprintf (file, "%I%%lo(");
2169 asm_fprintf (file, "%I%%hi(");
2171 output_addr_const (file, op);
2172 fprintf (file, ")");
2176 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2177 are specified. If we already have a QImode, there is nothing to do. */
2178 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2182 op = m68hc11_gen_lowpart (QImode, op);
2184 else if (letter == 'h')
2186 op = m68hc11_gen_highpart (QImode, op);
2190 if (GET_CODE (op) == MEM)
2192 rtx base = XEXP (op, 0);
2193 switch (GET_CODE (base))
2196 gcc_assert (TARGET_M6812);
2197 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2198 asm_print_register (file, REGNO (XEXP (base, 0)));
2202 gcc_assert (TARGET_M6812);
2203 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2204 asm_print_register (file, REGNO (XEXP (base, 0)));
2205 fprintf (file, "-");
2209 gcc_assert (TARGET_M6812);
2210 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2211 asm_print_register (file, REGNO (XEXP (base, 0)));
2212 fprintf (file, "+");
2216 gcc_assert (TARGET_M6812);
2217 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2218 asm_print_register (file, REGNO (XEXP (base, 0)));
2222 gcc_assert (TARGET_M6812);
2223 fprintf (file, "[");
2224 print_operand_address (file, XEXP (base, 0));
2225 fprintf (file, "]");
2229 if (m68hc11_page0_symbol_p (base))
2230 fprintf (file, "*");
2232 output_address (base);
2236 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2241 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2242 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2243 asm_fprintf (file, "%I0x%lx", l);
2245 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2249 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2250 sizeof (dstr), 0, 1);
2251 asm_fprintf (file, "%I0r%s", dstr);
2255 int need_parenthesize = 0;
2258 asm_fprintf (file, "%I");
2260 need_parenthesize = must_parenthesize (op);
2262 if (need_parenthesize)
2263 fprintf (file, "(");
2265 output_addr_const (file, op);
2266 if (need_parenthesize)
2267 fprintf (file, ")");
2271 /* Returns true if the operand 'op' must be printed with parenthesis
2272 around it. This must be done only if there is a symbol whose name
2273 is a processor register. */
2275 must_parenthesize (rtx op)
2279 switch (GET_CODE (op))
2282 name = XSTR (op, 0);
2283 /* Avoid a conflict between symbol name and a possible
2285 return (strcasecmp (name, "a") == 0
2286 || strcasecmp (name, "b") == 0
2287 || strcasecmp (name, "d") == 0
2288 || strcasecmp (name, "x") == 0
2289 || strcasecmp (name, "y") == 0
2290 || strcasecmp (name, "ix") == 0
2291 || strcasecmp (name, "iy") == 0
2292 || strcasecmp (name, "pc") == 0
2293 || strcasecmp (name, "sp") == 0
2294 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2298 return must_parenthesize (XEXP (op, 0))
2299 || must_parenthesize (XEXP (op, 1));
2305 return must_parenthesize (XEXP (op, 0));
2316 /* A C compound statement to output to stdio stream STREAM the
2317 assembler syntax for an instruction operand that is a memory
2318 reference whose address is ADDR. ADDR is an RTL expression. */
2321 print_operand_address (FILE *file, rtx addr)
2325 int need_parenthesis = 0;
2327 switch (GET_CODE (addr))
2330 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2332 fprintf (file, "0,");
2333 asm_print_register (file, REGNO (addr));
2337 base = XEXP (addr, 0);
2338 switch (GET_CODE (base))
2341 gcc_assert (TARGET_M6812);
2342 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2343 asm_print_register (file, REGNO (XEXP (base, 0)));
2347 gcc_assert (TARGET_M6812);
2348 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2349 asm_print_register (file, REGNO (XEXP (base, 0)));
2350 fprintf (file, "-");
2354 gcc_assert (TARGET_M6812);
2355 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2356 asm_print_register (file, REGNO (XEXP (base, 0)));
2357 fprintf (file, "+");
2361 gcc_assert (TARGET_M6812);
2362 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2363 asm_print_register (file, REGNO (XEXP (base, 0)));
2367 need_parenthesis = must_parenthesize (base);
2368 if (need_parenthesis)
2369 fprintf (file, "(");
2371 output_addr_const (file, base);
2372 if (need_parenthesis)
2373 fprintf (file, ")");
2379 base = XEXP (addr, 0);
2380 offset = XEXP (addr, 1);
2381 if (!G_REG_P (base) && G_REG_P (offset))
2383 base = XEXP (addr, 1);
2384 offset = XEXP (addr, 0);
2386 if (CONSTANT_ADDRESS_P (base))
2388 need_parenthesis = must_parenthesize (addr);
2390 gcc_assert (CONSTANT_ADDRESS_P (offset));
2391 if (need_parenthesis)
2392 fprintf (file, "(");
2394 output_addr_const (file, base);
2395 fprintf (file, "+");
2396 output_addr_const (file, offset);
2397 if (need_parenthesis)
2398 fprintf (file, ")");
2402 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2405 gcc_assert (TARGET_M6812);
2406 asm_print_register (file, REGNO (offset));
2407 fprintf (file, ",");
2408 asm_print_register (file, REGNO (base));
2412 need_parenthesis = must_parenthesize (offset);
2413 if (need_parenthesis)
2414 fprintf (file, "(");
2416 output_addr_const (file, offset);
2417 if (need_parenthesis)
2418 fprintf (file, ")");
2419 fprintf (file, ",");
2420 asm_print_register (file, REGNO (base));
2426 if (GET_CODE (addr) == CONST_INT
2427 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2429 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2433 need_parenthesis = must_parenthesize (addr);
2434 if (need_parenthesis)
2435 fprintf (file, "(");
2437 output_addr_const (file, addr);
2438 if (need_parenthesis)
2439 fprintf (file, ")");
2446 /* Splitting of some instructions. */
2449 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2453 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2454 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2455 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2456 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2462 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2467 switch (GET_MODE (op0))
2471 tmp = m68hc11_expand_compare (code, op0, op1);
2472 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2473 gen_rtx_LABEL_REF (VOIDmode, label),
2475 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2479 /* SCz: from i386.c */
2482 /* Don't expand the comparison early, so that we get better code
2483 when jump or whoever decides to reverse the comparison. */
2488 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2489 &m68hc11_compare_op1);
2491 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2492 m68hc11_compare_op0, m68hc11_compare_op1);
2493 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2494 gen_rtx_LABEL_REF (VOIDmode, label),
2496 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2498 use_fcomi = ix86_use_fcomi_compare (code);
2499 vec = rtvec_alloc (3 + !use_fcomi);
2500 RTVEC_ELT (vec, 0) = tmp;
2502 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2504 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2507 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2509 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2515 /* Expand SImode branch into multiple compare+branch. */
2517 rtx lo[2], hi[2], label2;
2518 enum rtx_code code1, code2, code3;
2520 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2525 code = swap_condition (code);
2527 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2528 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2529 hi[0] = m68hc11_gen_highpart (HImode, op0);
2530 hi[1] = m68hc11_gen_highpart (HImode, op1);
2532 /* Otherwise, if we are doing less-than, op1 is a constant and the
2533 low word is zero, then we can just examine the high word. */
2535 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2536 && (code == LT || code == LTU))
2538 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2542 /* Otherwise, we need two or three jumps. */
2544 label2 = gen_label_rtx ();
2547 code2 = swap_condition (code);
2548 code3 = unsigned_condition (code);
2589 * if (hi(a) < hi(b)) goto true;
2590 * if (hi(a) > hi(b)) goto false;
2591 * if (lo(a) < lo(b)) goto true;
2594 if (code1 != UNKNOWN)
2595 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2596 if (code2 != UNKNOWN)
2597 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2599 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2601 if (code2 != UNKNOWN)
2602 emit_label (label2);
2612 /* Return the increment/decrement mode of a MEM if it is such.
2613 Return CONST if it is anything else. */
2615 autoinc_mode (rtx x)
2617 if (GET_CODE (x) != MEM)
2621 if (GET_CODE (x) == PRE_INC
2622 || GET_CODE (x) == PRE_DEC
2623 || GET_CODE (x) == POST_INC
2624 || GET_CODE (x) == POST_DEC)
2625 return GET_CODE (x);
2631 m68hc11_make_autoinc_notes (rtx *x, void *data)
2635 switch (GET_CODE (*x))
2642 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2651 /* Split a DI, SI or HI move into several smaller move operations.
2652 The scratch register 'scratch' is used as a temporary to load
2653 store intermediate values. It must be a hard register. */
2655 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2657 rtx low_to, low_from;
2658 rtx high_to, high_from;
2660 enum machine_mode mode;
2662 int autoinc_from = autoinc_mode (from);
2663 int autoinc_to = autoinc_mode (to);
2665 mode = GET_MODE (to);
2667 /* If the TO and FROM contain autoinc modes that are not compatible
2668 together (one pop and the other a push), we must change one to
2669 an offsetable operand and generate an appropriate add at the end. */
2670 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2675 /* The source uses an autoinc mode which is not compatible with
2676 a split (this would result in a word swap). */
2677 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2679 code = GET_CODE (XEXP (from, 0));
2680 reg = XEXP (XEXP (from, 0), 0);
2681 offset = GET_MODE_SIZE (GET_MODE (from));
2682 if (code == POST_DEC)
2685 if (code == PRE_INC)
2686 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2688 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2689 if (code == POST_DEC)
2690 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2694 /* Likewise for destination. */
2695 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2697 code = GET_CODE (XEXP (to, 0));
2698 reg = XEXP (XEXP (to, 0), 0);
2699 offset = GET_MODE_SIZE (GET_MODE (to));
2700 if (code == POST_DEC)
2703 if (code == PRE_INC)
2704 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2706 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2707 if (code == POST_DEC)
2708 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2712 /* The source and destination auto increment modes must be compatible
2713 with each other: same direction. */
2714 if ((autoinc_to != autoinc_from
2715 && autoinc_to != CONST && autoinc_from != CONST)
2716 /* The destination address register must not be used within
2717 the source operand because the source address would change
2718 while doing the copy. */
2719 || (autoinc_to != CONST
2720 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2721 && !IS_STACK_PUSH (to)))
2723 /* Must change the destination. */
2724 code = GET_CODE (XEXP (to, 0));
2725 reg = XEXP (XEXP (to, 0), 0);
2726 offset = GET_MODE_SIZE (GET_MODE (to));
2727 if (code == PRE_DEC || code == POST_DEC)
2730 if (code == PRE_DEC || code == PRE_INC)
2731 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2732 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2733 if (code == POST_DEC || code == POST_INC)
2734 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2739 /* Likewise, the source address register must not be used within
2740 the destination operand. */
2741 if (autoinc_from != CONST
2742 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2743 && !IS_STACK_PUSH (to))
2745 /* Must change the source. */
2746 code = GET_CODE (XEXP (from, 0));
2747 reg = XEXP (XEXP (from, 0), 0);
2748 offset = GET_MODE_SIZE (GET_MODE (from));
2749 if (code == PRE_DEC || code == POST_DEC)
2752 if (code == PRE_DEC || code == PRE_INC)
2753 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2754 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2755 if (code == POST_DEC || code == POST_INC)
2756 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2762 if (GET_MODE_SIZE (mode) == 8)
2764 else if (GET_MODE_SIZE (mode) == 4)
2770 && IS_STACK_PUSH (to)
2771 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2777 else if (mode == HImode)
2785 low_to = m68hc11_gen_lowpart (mode, to);
2786 high_to = m68hc11_gen_highpart (mode, to);
2788 low_from = m68hc11_gen_lowpart (mode, from);
2789 high_from = m68hc11_gen_highpart (mode, from);
2793 high_from = adjust_address (high_from, mode, offset);
2794 low_from = high_from;
2797 /* When copying with a POST_INC mode, we must copy the
2798 high part and then the low part to guarantee a correct
2801 && GET_MODE_SIZE (mode) >= 2
2802 && autoinc_from != autoinc_to
2803 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2812 low_from = high_from;
2817 m68hc11_split_move (low_to, low_from, scratch);
2818 m68hc11_split_move (high_to, high_from, scratch);
2820 else if (H_REG_P (to) || H_REG_P (from)
2821 || (low_from == const0_rtx
2822 && high_from == const0_rtx
2823 && ! push_operand (to, GET_MODE (to))
2824 && ! H_REG_P (scratch))
2826 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2827 || m68hc11_small_indexed_indirect_p (from,
2829 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2830 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2832 insn = emit_move_insn (low_to, low_from);
2833 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2835 insn = emit_move_insn (high_to, high_from);
2836 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2840 insn = emit_move_insn (scratch, low_from);
2841 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2842 insn = emit_move_insn (low_to, scratch);
2843 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2845 insn = emit_move_insn (scratch, high_from);
2846 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2847 insn = emit_move_insn (high_to, scratch);
2848 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2853 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2859 if (GET_CODE (operand) != CONST_INT)
2867 val = INTVAL (operand);
2871 if ((val & mask) == 0)
2873 if ((val & mask) == mask)
2874 *result = constm1_rtx;
2878 if ((val & mask) == 0)
2879 *result = const0_rtx;
2880 if ((val & mask) == mask)
2885 if ((val & mask) == 0)
2893 m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
2898 need_copy = (rtx_equal_p (operands[0], operands[1])
2899 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2901 operands[1] = simplify_logical (mode, code, operands[1], &result);
2902 operands[2] = simplify_logical (mode, code, operands[2], &result);
2904 if (result && GET_CODE (result) == CONST_INT)
2906 if (!H_REG_P (operands[0]) && operands[3]
2907 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2909 emit_move_insn (operands[3], result);
2910 emit_move_insn (operands[0], operands[3]);
2914 emit_move_insn (operands[0], result);
2917 else if (operands[1] != 0 && operands[2] != 0)
2921 if (!H_REG_P (operands[0]) && operands[3])
2923 emit_move_insn (operands[3], operands[1]);
2924 emit_insn (gen_rtx_SET (mode,
2926 gen_rtx_fmt_ee (code, mode,
2927 operands[3], operands[2])));
2928 insn = emit_move_insn (operands[0], operands[3]);
2932 insn = emit_insn (gen_rtx_SET (mode,
2934 gen_rtx_fmt_ee (code, mode,
2940 /* The logical operation is similar to a copy. */
2945 if (GET_CODE (operands[1]) == CONST_INT)
2950 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2952 emit_move_insn (operands[3], src);
2953 emit_move_insn (operands[0], operands[3]);
2957 emit_move_insn (operands[0], src);
2963 m68hc11_split_logical (enum machine_mode mode, enum rtx_code code,
2969 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2970 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2971 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2973 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2974 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2975 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2977 low[3] = operands[3];
2978 high[3] = operands[3];
2981 m68hc11_split_logical (HImode, code, low);
2982 m68hc11_split_logical (HImode, code, high);
2986 m68hc11_emit_logical (mode, code, low);
2987 m68hc11_emit_logical (mode, code, high);
2991 /* Code generation. */
2994 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
2996 /* We have to be careful with the cc_status. An address register swap
2997 is generated for some comparison. The comparison is made with D
2998 but the branch really uses the address register. See the split
2999 pattern for compare. The xgdx/xgdy preserve the flags but after
3000 the exchange, the flags will reflect to the value of X and not D.
3001 Tell this by setting the cc_status according to the cc_prev_status. */
3002 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3004 if (cc_prev_status.value1 != 0
3005 && (D_REG_P (cc_prev_status.value1)
3006 || X_REG_P (cc_prev_status.value1)))
3008 cc_status = cc_prev_status;
3009 if (D_REG_P (cc_status.value1))
3010 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3013 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3019 output_asm_insn ("xgdx", operands);
3023 if (cc_prev_status.value1 != 0
3024 && (D_REG_P (cc_prev_status.value1)
3025 || Y_REG_P (cc_prev_status.value1)))
3027 cc_status = cc_prev_status;
3028 if (D_REG_P (cc_status.value1))
3029 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3032 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3038 output_asm_insn ("xgdy", operands);
3042 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3043 This is used to decide whether a move that set flags should be used
3046 next_insn_test_reg (rtx insn, rtx reg)
3050 insn = next_nonnote_insn (insn);
3051 if (GET_CODE (insn) != INSN)
3054 body = PATTERN (insn);
3055 if (sets_cc0_p (body) != 1)
3058 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3064 /* Generate the code to move a 16-bit operand into another one. */
3067 m68hc11_gen_movhi (rtx insn, rtx *operands)
3071 /* Move a register or memory to the same location.
3072 This is possible because such insn can appear
3073 in a non-optimizing mode. */
3074 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3076 cc_status = cc_prev_status;
3082 rtx from = operands[1];
3083 rtx to = operands[0];
3085 if (IS_STACK_PUSH (to) && H_REG_P (from))
3087 cc_status = cc_prev_status;
3088 switch (REGNO (from))
3093 output_asm_insn ("psh%1", operands);
3095 case HARD_SP_REGNUM:
3096 output_asm_insn ("sts\t2,-sp", operands);
3103 if (IS_STACK_POP (from) && H_REG_P (to))
3105 cc_status = cc_prev_status;
3111 output_asm_insn ("pul%0", operands);
3118 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3120 m68hc11_notice_keep_cc (operands[0]);
3121 output_asm_insn ("tfr\t%1,%0", operands);
3123 else if (H_REG_P (operands[0]))
3125 if (SP_REG_P (operands[0]))
3126 output_asm_insn ("lds\t%1", operands);
3128 output_asm_insn ("ld%0\t%1", operands);
3130 else if (H_REG_P (operands[1]))
3132 if (SP_REG_P (operands[1]))
3133 output_asm_insn ("sts\t%0", operands);
3135 output_asm_insn ("st%1\t%0", operands);
3138 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3139 instruction. We have to use a scratch register as temporary location.
3140 Trying to use a specific pattern or constrain failed. */
3141 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3148 if (dead_register_here (insn, d_reg))
3150 else if (dead_register_here (insn, ix_reg))
3152 else if (dead_register_here (insn, iy_reg))
3158 output_asm_insn ("psh%3", ops);
3163 output_asm_insn ("ld%1\t%2", ops);
3164 output_asm_insn ("st%1\t%0", ops);
3166 output_asm_insn ("pul%3", ops);
3169 /* Use movw for non-null constants or when we are clearing
3170 a volatile memory reference. However, this is possible
3171 only if the memory reference has a small offset or is an
3172 absolute address. */
3173 else if (GET_CODE (from) == CONST_INT
3174 && INTVAL (from) == 0
3175 && (MEM_VOLATILE_P (to) == 0
3176 || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3178 output_asm_insn ("clr\t%h0", operands);
3179 output_asm_insn ("clr\t%b0", operands);
3183 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3184 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3185 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3186 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3192 ops[0] = operands[2];
3195 m68hc11_gen_movhi (insn, ops);
3197 ops[1] = operands[2];
3198 m68hc11_gen_movhi (insn, ops);
3203 /* !!!! SCz wrong here. */
3204 fatal_insn ("move insn not handled", insn);
3209 m68hc11_notice_keep_cc (operands[0]);
3210 output_asm_insn ("movw\t%1,%0", operands);
3216 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3218 cc_status = cc_prev_status;
3219 switch (REGNO (operands[0]))
3223 output_asm_insn ("pul%0", operands);
3226 output_asm_insn ("pula", operands);
3227 output_asm_insn ("pulb", operands);
3234 /* Some moves to a hard register are special. Not all of them
3235 are really supported and we have to use a temporary
3236 location to provide them (either the stack of a temp var). */
3237 if (H_REG_P (operands[0]))
3239 switch (REGNO (operands[0]))
3242 if (X_REG_P (operands[1]))
3244 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3246 m68hc11_output_swap (insn, operands);
3248 else if (next_insn_test_reg (insn, operands[0]))
3250 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3254 m68hc11_notice_keep_cc (operands[0]);
3255 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3258 else if (Y_REG_P (operands[1]))
3260 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3262 m68hc11_output_swap (insn, operands);
3266 /* %t means *ZTMP scratch register. */
3267 output_asm_insn ("sty\t%t1", operands);
3268 output_asm_insn ("ldd\t%t1", operands);
3271 else if (SP_REG_P (operands[1]))
3276 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3277 output_asm_insn ("xgdx", operands);
3278 output_asm_insn ("tsx", operands);
3279 output_asm_insn ("xgdx", operands);
3281 else if (IS_STACK_POP (operands[1]))
3283 output_asm_insn ("pula\n\tpulb", operands);
3285 else if (GET_CODE (operands[1]) == CONST_INT
3286 && INTVAL (operands[1]) == 0)
3288 output_asm_insn ("clra\n\tclrb", operands);
3292 output_asm_insn ("ldd\t%1", operands);
3297 if (D_REG_P (operands[1]))
3299 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3301 m68hc11_output_swap (insn, operands);
3303 else if (next_insn_test_reg (insn, operands[0]))
3305 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3309 m68hc11_notice_keep_cc (operands[0]);
3310 output_asm_insn ("pshb", operands);
3311 output_asm_insn ("psha", operands);
3312 output_asm_insn ("pulx", operands);
3315 else if (Y_REG_P (operands[1]))
3317 /* When both D and Y are dead, use the sequence xgdy, xgdx
3318 to move Y into X. The D and Y registers are modified. */
3319 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3320 && dead_register_here (insn, d_reg))
3322 output_asm_insn ("xgdy", operands);
3323 output_asm_insn ("xgdx", operands);
3326 else if (!optimize_size)
3328 output_asm_insn ("sty\t%t1", operands);
3329 output_asm_insn ("ldx\t%t1", operands);
3334 output_asm_insn ("pshy", operands);
3335 output_asm_insn ("pulx", operands);
3338 else if (SP_REG_P (operands[1]))
3340 /* tsx, tsy preserve the flags */
3341 cc_status = cc_prev_status;
3342 output_asm_insn ("tsx", operands);
3346 output_asm_insn ("ldx\t%1", operands);
3351 if (D_REG_P (operands[1]))
3353 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3355 m68hc11_output_swap (insn, operands);
3359 output_asm_insn ("std\t%t1", operands);
3360 output_asm_insn ("ldy\t%t1", operands);
3363 else if (X_REG_P (operands[1]))
3365 /* When both D and X are dead, use the sequence xgdx, xgdy
3366 to move X into Y. The D and X registers are modified. */
3367 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3368 && dead_register_here (insn, d_reg))
3370 output_asm_insn ("xgdx", operands);
3371 output_asm_insn ("xgdy", operands);
3374 else if (!optimize_size)
3376 output_asm_insn ("stx\t%t1", operands);
3377 output_asm_insn ("ldy\t%t1", operands);
3382 output_asm_insn ("pshx", operands);
3383 output_asm_insn ("puly", operands);
3386 else if (SP_REG_P (operands[1]))
3388 /* tsx, tsy preserve the flags */
3389 cc_status = cc_prev_status;
3390 output_asm_insn ("tsy", operands);
3394 output_asm_insn ("ldy\t%1", operands);
3398 case HARD_SP_REGNUM:
3399 if (D_REG_P (operands[1]))
3401 m68hc11_notice_keep_cc (operands[0]);
3402 output_asm_insn ("xgdx", operands);
3403 output_asm_insn ("txs", operands);
3404 output_asm_insn ("xgdx", operands);
3406 else if (X_REG_P (operands[1]))
3408 /* tys, txs preserve the flags */
3409 cc_status = cc_prev_status;
3410 output_asm_insn ("txs", operands);
3412 else if (Y_REG_P (operands[1]))
3414 /* tys, txs preserve the flags */
3415 cc_status = cc_prev_status;
3416 output_asm_insn ("tys", operands);
3420 /* lds sets the flags but the des does not. */
3422 output_asm_insn ("lds\t%1", operands);
3423 output_asm_insn ("des", operands);
3428 fatal_insn ("invalid register in the move instruction", insn);
3433 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3434 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3436 output_asm_insn ("sts\t%0", operands);
3440 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3442 cc_status = cc_prev_status;
3443 switch (REGNO (operands[1]))
3447 output_asm_insn ("psh%1", operands);
3450 output_asm_insn ("pshb", operands);
3451 output_asm_insn ("psha", operands);
3459 /* Operand 1 must be a hard register. */
3460 if (!H_REG_P (operands[1]))
3462 fatal_insn ("invalid operand in the instruction", insn);
3465 reg = REGNO (operands[1]);
3469 output_asm_insn ("std\t%0", operands);
3473 output_asm_insn ("stx\t%0", operands);
3477 output_asm_insn ("sty\t%0", operands);
3480 case HARD_SP_REGNUM:
3484 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3486 output_asm_insn ("pshx", operands);
3487 output_asm_insn ("tsx", operands);
3488 output_asm_insn ("inx", operands);
3489 output_asm_insn ("inx", operands);
3490 output_asm_insn ("stx\t%0", operands);
3491 output_asm_insn ("pulx", operands);
3494 else if (reg_mentioned_p (ix_reg, operands[0]))
3496 output_asm_insn ("sty\t%t0", operands);
3497 output_asm_insn ("tsy", operands);
3498 output_asm_insn ("sty\t%0", operands);
3499 output_asm_insn ("ldy\t%t0", operands);
3503 output_asm_insn ("stx\t%t0", operands);
3504 output_asm_insn ("tsx", operands);
3505 output_asm_insn ("stx\t%0", operands);
3506 output_asm_insn ("ldx\t%t0", operands);
3512 fatal_insn ("invalid register in the move instruction", insn);
3518 m68hc11_gen_movqi (rtx insn, rtx *operands)
3520 /* Move a register or memory to the same location.
3521 This is possible because such insn can appear
3522 in a non-optimizing mode. */
3523 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3525 cc_status = cc_prev_status;
3532 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3534 m68hc11_notice_keep_cc (operands[0]);
3535 output_asm_insn ("tfr\t%1,%0", operands);
3537 else if (H_REG_P (operands[0]))
3539 if (IS_STACK_POP (operands[1]))
3540 output_asm_insn ("pul%b0", operands);
3541 else if (Q_REG_P (operands[0]))
3542 output_asm_insn ("lda%0\t%b1", operands);
3543 else if (D_REG_P (operands[0]))
3544 output_asm_insn ("ldab\t%b1", operands);
3548 else if (H_REG_P (operands[1]))
3550 if (Q_REG_P (operands[1]))
3551 output_asm_insn ("sta%1\t%b0", operands);
3552 else if (D_REG_P (operands[1]))
3553 output_asm_insn ("stab\t%b0", operands);
3559 rtx from = operands[1];
3560 rtx to = operands[0];
3562 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3563 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3564 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3565 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3571 ops[0] = operands[2];
3574 m68hc11_gen_movqi (insn, ops);
3576 ops[1] = operands[2];
3577 m68hc11_gen_movqi (insn, ops);
3581 /* !!!! SCz wrong here. */
3582 fatal_insn ("move insn not handled", insn);
3587 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3589 output_asm_insn ("clr\t%b0", operands);
3593 m68hc11_notice_keep_cc (operands[0]);
3594 output_asm_insn ("movb\t%b1,%b0", operands);
3602 if (H_REG_P (operands[0]))
3604 switch (REGNO (operands[0]))
3608 if (X_REG_P (operands[1]))
3610 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3612 m68hc11_output_swap (insn, operands);
3616 output_asm_insn ("stx\t%t1", operands);
3617 output_asm_insn ("ldab\t%T0", operands);
3620 else if (Y_REG_P (operands[1]))
3622 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3624 m68hc11_output_swap (insn, operands);
3628 output_asm_insn ("sty\t%t1", operands);
3629 output_asm_insn ("ldab\t%T0", operands);
3632 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3633 && !DA_REG_P (operands[1]))
3635 output_asm_insn ("ldab\t%b1", operands);
3637 else if (DA_REG_P (operands[1]))
3639 output_asm_insn ("tab", operands);
3643 cc_status = cc_prev_status;
3649 if (X_REG_P (operands[1]))
3651 output_asm_insn ("stx\t%t1", operands);
3652 output_asm_insn ("ldaa\t%T0", operands);
3654 else if (Y_REG_P (operands[1]))
3656 output_asm_insn ("sty\t%t1", operands);
3657 output_asm_insn ("ldaa\t%T0", operands);
3659 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3660 && !DA_REG_P (operands[1]))
3662 output_asm_insn ("ldaa\t%b1", operands);
3664 else if (!DA_REG_P (operands[1]))
3666 output_asm_insn ("tba", operands);
3670 cc_status = cc_prev_status;
3675 if (D_REG_P (operands[1]))
3677 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3679 m68hc11_output_swap (insn, operands);
3683 output_asm_insn ("stab\t%T1", operands);
3684 output_asm_insn ("ldx\t%t1", operands);
3688 else if (Y_REG_P (operands[1]))
3690 output_asm_insn ("sty\t%t0", operands);
3691 output_asm_insn ("ldx\t%t0", operands);
3693 else if (GET_CODE (operands[1]) == CONST_INT)
3695 output_asm_insn ("ldx\t%1", operands);
3697 else if (dead_register_here (insn, d_reg))
3699 output_asm_insn ("ldab\t%b1", operands);
3700 output_asm_insn ("xgdx", operands);
3702 else if (!reg_mentioned_p (operands[0], operands[1]))
3704 output_asm_insn ("xgdx", operands);
3705 output_asm_insn ("ldab\t%b1", operands);
3706 output_asm_insn ("xgdx", operands);
3710 output_asm_insn ("pshb", operands);
3711 output_asm_insn ("ldab\t%b1", operands);
3712 output_asm_insn ("stab\t%T1", operands);
3713 output_asm_insn ("ldx\t%t1", operands);
3714 output_asm_insn ("pulb", operands);
3720 if (D_REG_P (operands[1]))
3722 output_asm_insn ("stab\t%T1", operands);
3723 output_asm_insn ("ldy\t%t1", operands);
3726 else if (X_REG_P (operands[1]))
3728 output_asm_insn ("stx\t%t1", operands);
3729 output_asm_insn ("ldy\t%t1", operands);
3732 else if (GET_CODE (operands[1]) == CONST_INT)
3734 output_asm_insn ("ldy\t%1", operands);
3736 else if (dead_register_here (insn, d_reg))
3738 output_asm_insn ("ldab\t%b1", operands);
3739 output_asm_insn ("xgdy", operands);
3741 else if (!reg_mentioned_p (operands[0], operands[1]))
3743 output_asm_insn ("xgdy", operands);
3744 output_asm_insn ("ldab\t%b1", operands);
3745 output_asm_insn ("xgdy", operands);
3749 output_asm_insn ("pshb", operands);
3750 output_asm_insn ("ldab\t%b1", operands);
3751 output_asm_insn ("stab\t%T1", operands);
3752 output_asm_insn ("ldy\t%t1", operands);
3753 output_asm_insn ("pulb", operands);
3759 fatal_insn ("invalid register in the instruction", insn);
3763 else if (H_REG_P (operands[1]))
3765 switch (REGNO (operands[1]))
3769 output_asm_insn ("stab\t%b0", operands);
3773 output_asm_insn ("staa\t%b0", operands);
3777 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3781 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3785 fatal_insn ("invalid register in the move instruction", insn);
3792 fatal_insn ("operand 1 must be a hard register", insn);
3796 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3797 The source and destination must be D or A and the shift must
3800 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3804 if (GET_CODE (operands[2]) != CONST_INT
3805 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3806 fatal_insn ("invalid rotate insn", insn);
3808 val = INTVAL (operands[2]);
3809 if (code == ROTATERT)
3810 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3812 if (GET_MODE (operands[0]) != QImode)
3815 /* Rotate by 8-bits if the shift is within [5..11]. */
3816 if (val >= 5 && val <= 11)
3819 output_asm_insn ("exg\ta,b", operands);
3822 output_asm_insn ("psha", operands);
3823 output_asm_insn ("tba", operands);
3824 output_asm_insn ("pulb", operands);
3829 /* If the shift is big, invert the rotation. */
3839 /* Set the carry to bit-15, but don't change D yet. */
3840 if (GET_MODE (operands[0]) != QImode)
3842 output_asm_insn ("asra", operands);
3843 output_asm_insn ("rola", operands);
3846 /* Rotate B first to move the carry to bit-0. */
3847 if (D_REG_P (operands[0]))
3848 output_asm_insn ("rolb", operands);
3850 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3851 output_asm_insn ("rola", operands);
3858 /* Set the carry to bit-8 of D. */
3859 if (GET_MODE (operands[0]) != QImode)
3860 output_asm_insn ("tap", operands);
3862 /* Rotate B first to move the carry to bit-7. */
3863 if (D_REG_P (operands[0]))
3864 output_asm_insn ("rorb", operands);
3866 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3867 output_asm_insn ("rora", operands);
3874 /* Store in cc_status the expressions that the condition codes will
3875 describe after execution of an instruction whose pattern is EXP.
3876 Do not alter them if the instruction would not alter the cc's. */
3879 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3881 /* recognize SET insn's. */
3882 if (GET_CODE (exp) == SET)
3884 /* Jumps do not alter the cc's. */
3885 if (SET_DEST (exp) == pc_rtx)
3888 /* NOTE: most instructions don't affect the carry bit, but the
3889 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3890 the conditions.h header. */
3892 /* Function calls clobber the cc's. */
3893 else if (GET_CODE (SET_SRC (exp)) == CALL)
3898 /* Tests and compares set the cc's in predictable ways. */
3899 else if (SET_DEST (exp) == cc0_rtx)
3901 cc_status.flags = 0;
3902 cc_status.value1 = XEXP (exp, 0);
3903 if (GET_CODE (XEXP (exp, 1)) == COMPARE
3904 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
3905 cc_status.value2 = XEXP (XEXP (exp, 1), 0);
3907 cc_status.value2 = XEXP (exp, 1);
3911 /* All other instructions affect the condition codes. */
3912 cc_status.flags = 0;
3913 cc_status.value1 = XEXP (exp, 0);
3914 cc_status.value2 = XEXP (exp, 1);
3919 /* Default action if we haven't recognized something
3920 and returned earlier. */
3924 if (cc_status.value2 != 0)
3925 switch (GET_CODE (cc_status.value2))
3927 /* These logical operations can generate several insns.
3928 The flags are setup according to what is generated. */
3934 /* The (not ...) generates several 'com' instructions for
3935 non QImode. We have to invalidate the flags. */
3937 if (GET_MODE (cc_status.value2) != QImode)
3949 if (GET_MODE (cc_status.value2) != VOIDmode)
3950 cc_status.flags |= CC_NO_OVERFLOW;
3953 /* The asl sets the overflow bit in such a way that this
3954 makes the flags unusable for a next compare insn. */
3958 if (GET_MODE (cc_status.value2) != VOIDmode)
3959 cc_status.flags |= CC_NO_OVERFLOW;
3962 /* A load/store instruction does not affect the carry. */
3967 cc_status.flags |= CC_NO_OVERFLOW;
3973 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3975 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3976 cc_status.value2 = 0;
3978 else if (cc_status.value1 && side_effects_p (cc_status.value1))
3979 cc_status.value1 = 0;
3981 else if (cc_status.value2 && side_effects_p (cc_status.value2))
3982 cc_status.value2 = 0;
3985 /* The current instruction does not affect the flags but changes
3986 the register 'reg'. See if the previous flags can be kept for the
3987 next instruction to avoid a comparison. */
3989 m68hc11_notice_keep_cc (rtx reg)
3992 || cc_prev_status.value1 == 0
3993 || rtx_equal_p (reg, cc_prev_status.value1)
3994 || (cc_prev_status.value2
3995 && reg_mentioned_p (reg, cc_prev_status.value2)))
3998 cc_status = cc_prev_status;
4003 /* Machine Specific Reorg. */
4005 /* Z register replacement:
4007 GCC treats the Z register as an index base address register like
4008 X or Y. In general, it uses it during reload to compute the address
4009 of some operand. This helps the reload pass to avoid to fall into the
4010 register spill failure.
4012 The Z register is in the A_REGS class. In the machine description,
4013 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4015 It can appear everywhere an X or Y register can appear, except for
4016 some templates in the clobber section (when a clobber of X or Y is asked).
4017 For a given instruction, the template must ensure that no more than
4018 2 'A' registers are used. Otherwise, the register replacement is not
4021 To replace the Z register, the algorithm is not terrific:
4022 1. Insns that do not use the Z register are not changed
4023 2. When a Z register is used, we scan forward the insns to see
4024 a potential register to use: either X or Y and sometimes D.
4025 We stop when a call, a label or a branch is seen, or when we
4026 detect that both X and Y are used (probably at different times, but it does
4028 3. The register that will be used for the replacement of Z is saved
4029 in a .page0 register or on the stack. If the first instruction that
4030 used Z, uses Z as an input, the value is loaded from another .page0
4031 register. The replacement register is pushed on the stack in the
4032 rare cases where a compare insn uses Z and we couldn't find if X/Y
4034 4. The Z register is replaced in all instructions until we reach
4035 the end of the Z-block, as detected by step 2.
4036 5. If we detect that Z is still alive, its value is saved.
4037 If the replacement register is alive, its old value is loaded.
4039 The Z register can be disabled with -ffixed-z.
4049 int must_restore_reg;
4060 int save_before_last;
4061 int z_loaded_with_sp;
4064 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4065 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4066 static void m68hc11_z_replacement (rtx);
4067 static void m68hc11_reassign_regs (rtx);
4069 int z_replacement_completed = 0;
4071 /* Analyze the insn to find out which replacement register to use and
4072 the boundaries of the replacement.
4073 Returns 0 if we reached the last insn to be replaced, 1 if we can
4074 continue replacement in next insns. */
4077 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4079 int this_insn_uses_ix;
4080 int this_insn_uses_iy;
4081 int this_insn_uses_z;
4082 int this_insn_uses_z_in_dst;
4083 int this_insn_uses_d;
4087 /* A call is said to clobber the Z register, we don't need
4088 to save the value of Z. We also don't need to restore
4089 the replacement register (unless it is used by the call). */
4090 if (GET_CODE (insn) == CALL_INSN)
4092 body = PATTERN (insn);
4094 info->can_use_d = 0;
4096 /* If the call is an indirect call with Z, we have to use the
4097 Y register because X can be used as an input (D+X).
4098 We also must not save Z nor restore Y. */
4099 if (reg_mentioned_p (z_reg, body))
4101 insn = NEXT_INSN (insn);
4104 info->found_call = 1;
4105 info->must_restore_reg = 0;
4106 info->last = NEXT_INSN (insn);
4108 info->need_save_z = 0;
4111 if (GET_CODE (insn) == CODE_LABEL
4112 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4115 if (GET_CODE (insn) == JUMP_INSN)
4117 if (reg_mentioned_p (z_reg, insn) == 0)
4120 info->can_use_d = 0;
4121 info->must_save_reg = 0;
4122 info->must_restore_reg = 0;
4123 info->need_save_z = 0;
4124 info->last = NEXT_INSN (insn);
4127 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4132 /* Z register dies here. */
4133 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4135 body = PATTERN (insn);
4136 if (GET_CODE (body) == SET)
4138 rtx src = XEXP (body, 1);
4139 rtx dst = XEXP (body, 0);
4141 /* Condition code is set here. We have to restore the X/Y and
4142 save into Z before any test/compare insn because once we save/restore
4143 we can change the condition codes. When the compare insn uses Z and
4144 we can't use X/Y, the comparison is made with the *ZREG soft register
4145 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4148 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4149 || (GET_CODE (src) == COMPARE &&
4150 ((rtx_equal_p (XEXP (src, 0), z_reg)
4151 && H_REG_P (XEXP (src, 1)))
4152 || (rtx_equal_p (XEXP (src, 1), z_reg)
4153 && H_REG_P (XEXP (src, 0))))))
4155 if (insn == info->first)
4157 info->must_load_z = 0;
4158 info->must_save_reg = 0;
4159 info->must_restore_reg = 0;
4160 info->need_save_z = 0;
4161 info->found_call = 1;
4162 info->regno = SOFT_Z_REGNUM;
4163 info->last = NEXT_INSN (insn);
4167 if (reg_mentioned_p (z_reg, src) == 0)
4169 info->can_use_d = 0;
4173 if (insn != info->first)
4176 /* Compare insn which uses Z. We have to save/restore the X/Y
4177 register without modifying the condition codes. For this
4178 we have to use a push/pop insn. */
4179 info->must_push_reg = 1;
4183 /* Z reg is set to something new. We don't need to load it. */
4186 if (!reg_mentioned_p (z_reg, src))
4188 /* Z reg is used before being set. Treat this as
4189 a new sequence of Z register replacement. */
4190 if (insn != info->first)
4194 info->must_load_z = 0;
4196 info->z_set_count++;
4197 info->z_value = src;
4199 info->z_loaded_with_sp = 1;
4201 else if (reg_mentioned_p (z_reg, dst))
4202 info->can_use_d = 0;
4204 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4205 | reg_mentioned_p (d_reg, dst);
4206 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4207 | reg_mentioned_p (ix_reg, dst);
4208 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4209 | reg_mentioned_p (iy_reg, dst);
4210 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4212 /* If z is used as an address operand (like (MEM (reg z))),
4213 we can't replace it with d. */
4214 if (this_insn_uses_z && !Z_REG_P (src)
4215 && !(m68hc11_arith_operator (src, GET_MODE (src))
4216 && Z_REG_P (XEXP (src, 0))
4217 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4218 && insn == info->first
4219 && dead_register_here (insn, d_reg)))
4220 info->can_use_d = 0;
4222 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4223 if (TARGET_M6812 && !z_dies_here
4224 && ((this_insn_uses_z && side_effects_p (src))
4225 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4227 info->need_save_z = 1;
4228 info->z_set_count++;
4230 this_insn_uses_z |= this_insn_uses_z_in_dst;
4232 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4234 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4237 if (this_insn_uses_d)
4238 info->can_use_d = 0;
4240 /* IX and IY are used at the same time, we have to restore
4241 the value of the scratch register before this insn. */
4242 if (this_insn_uses_ix && this_insn_uses_iy)
4247 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4248 info->can_use_d = 0;
4250 if (info->x_used == 0 && this_insn_uses_ix)
4254 /* We have a (set (REG:HI X) (REG:HI Z)).
4255 Since we use Z as the replacement register, this insn
4256 is no longer necessary. We turn it into a note. We must
4257 not reload the old value of X. */
4258 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4262 info->need_save_z = 0;
4265 info->must_save_reg = 0;
4266 info->must_restore_reg = 0;
4267 info->found_call = 1;
4268 info->can_use_d = 0;
4269 SET_INSN_DELETED (insn);
4270 info->last = NEXT_INSN (insn);
4275 && (rtx_equal_p (src, z_reg)
4276 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4280 info->need_save_z = 0;
4283 info->last = NEXT_INSN (insn);
4284 info->must_save_reg = 0;
4285 info->must_restore_reg = 0;
4287 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4288 && !reg_mentioned_p (ix_reg, src))
4293 info->need_save_z = 0;
4295 else if (TARGET_M6812 && side_effects_p (src))
4298 info->must_restore_reg = 0;
4303 info->save_before_last = 1;
4305 info->must_restore_reg = 0;
4306 info->last = NEXT_INSN (insn);
4308 else if (info->can_use_d)
4310 info->last = NEXT_INSN (insn);
4316 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4317 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4319 info->need_save_z = 0;
4321 info->last = NEXT_INSN (insn);
4322 info->regno = HARD_X_REGNUM;
4323 info->must_save_reg = 0;
4324 info->must_restore_reg = 0;
4327 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4329 info->regno = HARD_X_REGNUM;
4330 info->must_restore_reg = 0;
4331 info->must_save_reg = 0;
4335 if (info->y_used == 0 && this_insn_uses_iy)
4339 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4343 info->need_save_z = 0;
4346 info->must_save_reg = 0;
4347 info->must_restore_reg = 0;
4348 info->found_call = 1;
4349 info->can_use_d = 0;
4350 SET_INSN_DELETED (insn);
4351 info->last = NEXT_INSN (insn);
4356 && (rtx_equal_p (src, z_reg)
4357 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4362 info->need_save_z = 0;
4364 info->last = NEXT_INSN (insn);
4365 info->must_save_reg = 0;
4366 info->must_restore_reg = 0;
4368 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4369 && !reg_mentioned_p (iy_reg, src))
4374 info->need_save_z = 0;
4376 else if (TARGET_M6812 && side_effects_p (src))
4379 info->must_restore_reg = 0;
4384 info->save_before_last = 1;
4386 info->must_restore_reg = 0;
4387 info->last = NEXT_INSN (insn);
4389 else if (info->can_use_d)
4391 info->last = NEXT_INSN (insn);
4398 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4399 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4401 info->need_save_z = 0;
4403 info->last = NEXT_INSN (insn);
4404 info->regno = HARD_Y_REGNUM;
4405 info->must_save_reg = 0;
4406 info->must_restore_reg = 0;
4409 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4411 info->regno = HARD_Y_REGNUM;
4412 info->must_restore_reg = 0;
4413 info->must_save_reg = 0;
4419 info->need_save_z = 0;
4421 if (info->last == 0)
4422 info->last = NEXT_INSN (insn);
4425 return info->last != NULL_RTX ? 0 : 1;
4427 if (GET_CODE (body) == PARALLEL)
4430 char ix_clobber = 0;
4431 char iy_clobber = 0;
4433 this_insn_uses_iy = 0;
4434 this_insn_uses_ix = 0;
4435 this_insn_uses_z = 0;
4437 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4440 int uses_ix, uses_iy, uses_z;
4442 x = XVECEXP (body, 0, i);
4444 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4445 info->can_use_d = 0;
4447 uses_ix = reg_mentioned_p (ix_reg, x);
4448 uses_iy = reg_mentioned_p (iy_reg, x);
4449 uses_z = reg_mentioned_p (z_reg, x);
4450 if (GET_CODE (x) == CLOBBER)
4452 ix_clobber |= uses_ix;
4453 iy_clobber |= uses_iy;
4454 z_clobber |= uses_z;
4458 this_insn_uses_ix |= uses_ix;
4459 this_insn_uses_iy |= uses_iy;
4460 this_insn_uses_z |= uses_z;
4462 if (uses_z && GET_CODE (x) == SET)
4464 rtx dst = XEXP (x, 0);
4467 info->z_set_count++;
4469 if (TARGET_M6812 && uses_z && side_effects_p (x))
4470 info->need_save_z = 1;
4473 info->need_save_z = 0;
4477 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4478 this_insn_uses_ix, this_insn_uses_iy,
4479 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4482 if (this_insn_uses_z)
4483 info->can_use_d = 0;
4485 if (z_clobber && info->first != insn)
4487 info->need_save_z = 0;
4491 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4493 if (this_insn_uses_z == 0 && insn == info->first)
4495 info->must_load_z = 0;
4497 if (dead_register_here (insn, d_reg))
4499 info->regno = HARD_D_REGNUM;
4500 info->must_save_reg = 0;
4501 info->must_restore_reg = 0;
4503 else if (dead_register_here (insn, ix_reg))
4505 info->regno = HARD_X_REGNUM;
4506 info->must_save_reg = 0;
4507 info->must_restore_reg = 0;
4509 else if (dead_register_here (insn, iy_reg))
4511 info->regno = HARD_Y_REGNUM;
4512 info->must_save_reg = 0;
4513 info->must_restore_reg = 0;
4515 if (info->regno >= 0)
4517 info->last = NEXT_INSN (insn);
4520 if (this_insn_uses_ix == 0)
4522 info->regno = HARD_X_REGNUM;
4523 info->must_save_reg = 1;
4524 info->must_restore_reg = 1;
4526 else if (this_insn_uses_iy == 0)
4528 info->regno = HARD_Y_REGNUM;
4529 info->must_save_reg = 1;
4530 info->must_restore_reg = 1;
4534 info->regno = HARD_D_REGNUM;
4535 info->must_save_reg = 1;
4536 info->must_restore_reg = 1;
4538 info->last = NEXT_INSN (insn);
4542 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4543 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4545 if (this_insn_uses_z)
4547 if (info->y_used == 0 && iy_clobber)
4549 info->regno = HARD_Y_REGNUM;
4550 info->must_save_reg = 0;
4551 info->must_restore_reg = 0;
4553 if (info->first != insn
4554 && ((info->y_used && ix_clobber)
4555 || (info->x_used && iy_clobber)))
4558 info->last = NEXT_INSN (insn);
4559 info->save_before_last = 1;
4563 if (this_insn_uses_ix && this_insn_uses_iy)
4565 if (this_insn_uses_z)
4567 fatal_insn ("cannot do z-register replacement", insn);
4571 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4578 if (iy_clobber || z_clobber)
4580 info->last = NEXT_INSN (insn);
4581 info->save_before_last = 1;
4586 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4593 if (ix_clobber || z_clobber)
4595 info->last = NEXT_INSN (insn);
4596 info->save_before_last = 1;
4603 info->need_save_z = 0;
4607 if (GET_CODE (body) == CLOBBER)
4610 /* IX and IY are used at the same time, we have to restore
4611 the value of the scratch register before this insn. */
4612 if (this_insn_uses_ix && this_insn_uses_iy)
4616 if (info->x_used == 0 && this_insn_uses_ix)
4624 if (info->y_used == 0 && this_insn_uses_iy)
4638 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4642 info->replace_reg = NULL_RTX;
4643 info->must_load_z = 1;
4644 info->need_save_z = 1;
4645 info->must_save_reg = 1;
4646 info->must_restore_reg = 1;
4650 info->can_use_d = TARGET_M6811 ? 1 : 0;
4651 info->found_call = 0;
4655 info->z_set_count = 0;
4656 info->z_value = NULL_RTX;
4657 info->must_push_reg = 0;
4658 info->save_before_last = 0;
4659 info->z_loaded_with_sp = 0;
4661 /* Scan the insn forward to find an address register that is not used.
4663 - the flow of the program changes,
4664 - when we detect that both X and Y are necessary,
4665 - when the Z register dies,
4666 - when the condition codes are set. */
4668 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4670 if (m68hc11_check_z_replacement (insn, info) == 0)
4674 /* May be we can use Y or X if they contain the same value as Z.
4675 This happens very often after the reload. */
4676 if (info->z_set_count == 1)
4678 rtx p = info->first;
4683 v = find_last_value (iy_reg, &p, insn, 1);
4685 else if (info->y_used)
4687 v = find_last_value (ix_reg, &p, insn, 1);
4689 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4692 info->regno = HARD_Y_REGNUM;
4694 info->regno = HARD_X_REGNUM;
4695 info->must_load_z = 0;
4696 info->must_save_reg = 0;
4697 info->must_restore_reg = 0;
4698 info->found_call = 1;
4701 if (info->z_set_count == 0)
4702 info->need_save_z = 0;
4705 info->need_save_z = 0;
4707 if (info->last == 0)
4710 if (info->regno >= 0)
4713 info->replace_reg = gen_rtx_REG (HImode, reg);
4715 else if (info->can_use_d)
4717 reg = HARD_D_REGNUM;
4718 info->replace_reg = d_reg;
4720 else if (info->x_used)
4722 reg = HARD_Y_REGNUM;
4723 info->replace_reg = iy_reg;
4727 reg = HARD_X_REGNUM;
4728 info->replace_reg = ix_reg;
4732 if (info->must_save_reg && info->must_restore_reg)
4734 if (insn && dead_register_here (insn, info->replace_reg))
4736 info->must_save_reg = 0;
4737 info->must_restore_reg = 0;
4742 /* The insn uses the Z register. Find a replacement register for it
4743 (either X or Y) and replace it in the insn and the next ones until
4744 the flow changes or the replacement register is used. Instructions
4745 are emitted before and after the Z-block to preserve the value of
4746 Z and of the replacement register. */
4749 m68hc11_z_replacement (rtx insn)
4753 struct replace_info info;
4755 /* Find trivial case where we only need to replace z with the
4756 equivalent soft register. */
4757 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4759 rtx body = PATTERN (insn);
4760 rtx src = XEXP (body, 1);
4761 rtx dst = XEXP (body, 0);
4763 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4765 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4768 else if (Z_REG_P (src)
4769 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4771 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4774 else if (D_REG_P (dst)
4775 && m68hc11_arith_operator (src, GET_MODE (src))
4776 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4778 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4781 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4782 && INTVAL (src) == 0)
4784 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4785 /* Force it to be re-recognized. */
4786 INSN_CODE (insn) = -1;
4791 m68hc11_find_z_replacement (insn, &info);
4793 replace_reg = info.replace_reg;
4794 replace_reg_qi = NULL_RTX;
4796 /* Save the X register in a .page0 location. */
4797 if (info.must_save_reg && !info.must_push_reg)
4801 if (info.must_push_reg && 0)
4802 dst = gen_rtx_MEM (HImode,
4803 gen_rtx_PRE_DEC (HImode,
4804 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4806 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4808 emit_insn_before (gen_movhi (dst,
4809 gen_rtx_REG (HImode, info.regno)), insn);
4811 if (info.must_load_z && !info.must_push_reg)
4813 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4814 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4819 /* Replace all occurrence of Z by replace_reg.
4820 Stop when the last instruction to replace is reached.
4821 Also stop when we detect a change in the flow (but it's not
4822 necessary; just safeguard). */
4824 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4828 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4831 if (GET_CODE (insn) != INSN
4832 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4835 body = PATTERN (insn);
4836 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4837 || GET_CODE (body) == ASM_OPERANDS
4838 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4842 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4844 printf ("Reg mentioned here...:\n");
4849 /* Stack pointer was decremented by 2 due to the push.
4850 Correct that by adding 2 to the destination. */
4851 if (info.must_push_reg
4852 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4856 src = SET_SRC (body);
4857 dst = SET_DEST (body);
4858 if (SP_REG_P (src) && Z_REG_P (dst))
4859 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4862 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4863 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4865 INSN_CODE (insn) = -1;
4866 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4867 fatal_insn ("cannot do z-register replacement", insn);
4870 /* Likewise for (REG:QI Z). */
4871 if (reg_mentioned_p (z_reg, insn))
4873 if (replace_reg_qi == NULL_RTX)
4874 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4875 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4878 /* If there is a REG_INC note on Z, replace it with a
4879 REG_INC note on the replacement register. This is necessary
4880 to make sure that the flow pass will identify the change
4881 and it will not remove a possible insn that saves Z. */
4882 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4884 if (REG_NOTE_KIND (note) == REG_INC
4885 && GET_CODE (XEXP (note, 0)) == REG
4886 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4888 XEXP (note, 0) = replace_reg;
4892 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4896 /* Save Z before restoring the old value. */
4897 if (insn && info.need_save_z && !info.must_push_reg)
4899 rtx save_pos_insn = insn;
4901 /* If Z is clobber by the last insn, we have to save its value
4902 before the last instruction. */
4903 if (info.save_before_last)
4904 save_pos_insn = PREV_INSN (save_pos_insn);
4906 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4907 gen_rtx_REG (HImode, info.regno)),
4911 if (info.must_push_reg && info.last)
4915 body = PATTERN (info.last);
4916 new_body = gen_rtx_PARALLEL (VOIDmode,
4918 gen_rtx_USE (VOIDmode,
4920 gen_rtx_USE (VOIDmode,
4921 gen_rtx_REG (HImode,
4923 PATTERN (info.last) = new_body;
4925 /* Force recognition on insn since we changed it. */
4926 INSN_CODE (insn) = -1;
4928 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4930 fatal_insn ("invalid Z register replacement for insn", insn);
4932 insn = NEXT_INSN (info.last);
4935 /* Restore replacement register unless it was died. */
4936 if (insn && info.must_restore_reg && !info.must_push_reg)
4940 if (info.must_push_reg && 0)
4941 dst = gen_rtx_MEM (HImode,
4942 gen_rtx_POST_INC (HImode,
4943 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4945 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4947 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4954 /* Scan all the insn and re-affects some registers
4955 - The Z register (if it was used), is affected to X or Y depending
4956 on the instruction. */
4959 m68hc11_reassign_regs (rtx first)
4963 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4964 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4965 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4966 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4968 /* Scan all insns to replace Z by X or Y preserving the old value
4969 of X/Y and restoring it afterward. */
4971 for (insn = first; insn; insn = NEXT_INSN (insn))
4975 if (GET_CODE (insn) == CODE_LABEL
4976 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4982 body = PATTERN (insn);
4983 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4986 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4987 || GET_CODE (body) == ASM_OPERANDS
4988 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4991 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4992 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4995 /* If Z appears in this insn, replace it in the current insn
4996 and the next ones until the flow changes or we have to
4997 restore back the replacement register. */
4999 if (reg_mentioned_p (z_reg, body))
5001 m68hc11_z_replacement (insn);
5006 printf ("insn not handled by Z replacement:\n");
5014 /* Machine-dependent reorg pass.
5015 Specific optimizations are defined here:
5016 - this pass changes the Z register into either X or Y
5017 (it preserves X/Y previous values in a memory slot in page0).
5019 When this pass is finished, the global variable
5020 'z_replacement_completed' is set to 2. */
5023 m68hc11_reorg (void)
5028 z_replacement_completed = 0;
5029 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5030 first = get_insns ();
5032 /* Some RTX are shared at this point. This breaks the Z register
5033 replacement, unshare everything. */
5034 unshare_all_rtl_again (first);
5036 /* Force a split of all splittable insn. This is necessary for the
5037 Z register replacement mechanism because we end up with basic insns. */
5038 split_all_insns_noflow ();
5041 z_replacement_completed = 1;
5042 m68hc11_reassign_regs (first);
5045 compute_bb_for_insn ();
5047 /* After some splitting, there are some opportunities for CSE pass.
5048 This happens quite often when 32-bit or above patterns are split. */
5049 if (optimize > 0 && split_done)
5051 reload_cse_regs (first);
5054 /* Re-create the REG_DEAD notes. These notes are used in the machine
5055 description to use the best assembly directives. */
5058 df_note_add_problem ();
5060 df_remove_problem (df_note);
5063 z_replacement_completed = 2;
5065 /* If optimizing, then go ahead and split insns that must be
5066 split after Z register replacement. This gives more opportunities
5067 for peephole (in particular for consecutives xgdx/xgdy). */
5069 split_all_insns_noflow ();
5071 /* Once insns are split after the z_replacement_completed == 2,
5072 we must not re-run the life_analysis. The xgdx/xgdy patterns
5073 are not recognized and the life_analysis pass removes some
5074 insns because it thinks some (SETs) are noops or made to dead
5075 stores (which is false due to the swap).
5077 Do a simple pass to eliminate the noop set that the final
5078 split could generate (because it was easier for split definition). */
5082 for (insn = first; insn; insn = NEXT_INSN (insn))
5086 if (INSN_DELETED_P (insn))
5091 /* Remove the (set (R) (R)) insns generated by some splits. */
5092 body = PATTERN (insn);
5093 if (GET_CODE (body) == SET
5094 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5096 SET_INSN_DELETED (insn);
5103 /* Override memcpy */
5106 m68hc11_init_libfuncs (void)
5108 memcpy_libfunc = init_one_libfunc ("__memcpy");
5109 memcmp_libfunc = init_one_libfunc ("__memcmp");
5110 memset_libfunc = init_one_libfunc ("__memset");
5115 /* Cost functions. */
5117 /* Cost of moving memory. */
5119 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
5120 int in ATTRIBUTE_UNUSED)
5122 if (rclass <= H_REGS && rclass > NO_REGS)
5124 if (GET_MODE_SIZE (mode) <= 2)
5125 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5127 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5131 if (GET_MODE_SIZE (mode) <= 2)
5132 return COSTS_N_INSNS (3);
5134 return COSTS_N_INSNS (4);
5139 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5140 Reload does not check the constraint of set insns when the two registers
5141 have a move cost of 2. Setting a higher cost will force reload to check
5144 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5147 /* All costs are symmetric, so reduce cases by putting the
5148 lower number class as the destination. */
5151 enum reg_class tmp = to;
5152 to = from, from = tmp;
5155 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5156 else if (from <= S_REGS)
5157 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5159 return COSTS_N_INSNS (2);
5163 /* Provide the costs of an addressing mode that contains ADDR.
5164 If ADDR is not a valid address, its cost is irrelevant. */
5167 m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
5171 switch (GET_CODE (addr))
5174 /* Make the cost of hard registers and specially SP, FP small. */
5175 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5192 register rtx plus0 = XEXP (addr, 0);
5193 register rtx plus1 = XEXP (addr, 1);
5195 if (GET_CODE (plus0) != REG)
5198 switch (GET_CODE (plus1))
5201 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5202 || INTVAL (plus1) < m68hc11_min_offset)
5204 else if (INTVAL (plus1) >= m68hc11_max_offset)
5208 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5230 if (SP_REG_P (XEXP (addr, 0)))
5239 printf ("Address cost: %d for :", cost);
5248 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5252 total = rtx_cost (x, SET, !optimize_size);
5254 total += m68hc11_cost->shiftQI_const[shift % 8];
5255 else if (mode == HImode)
5256 total += m68hc11_cost->shiftHI_const[shift % 16];
5257 else if (shift == 8 || shift == 16 || shift == 32)
5258 total += m68hc11_cost->shiftHI_const[8];
5259 else if (shift != 0 && shift != 16 && shift != 32)
5261 total += m68hc11_cost->shiftHI_const[1] * shift;
5264 /* For SI and others, the cost is higher. */
5265 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5266 total *= GET_MODE_SIZE (mode) / 2;
5268 /* When optimizing for size, make shift more costly so that
5269 multiplications are preferred. */
5270 if (optimize_size && (shift % 8) != 0)
5277 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5278 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5280 enum machine_mode mode = GET_MODE (x);
5291 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5293 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5296 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5297 total += m68hc11_cost->shift_var;
5303 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5304 total += m68hc11_cost->logical;
5306 /* Logical instructions are byte instructions only. */
5307 total *= GET_MODE_SIZE (mode);
5312 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5313 total += m68hc11_cost->add;
5314 if (GET_MODE_SIZE (mode) > 2)
5316 total *= GET_MODE_SIZE (mode) / 2;
5323 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5327 total += m68hc11_cost->divQI;
5331 total += m68hc11_cost->divHI;
5336 total += m68hc11_cost->divSI;
5342 /* mul instruction produces 16-bit result. */
5343 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5344 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5345 return m68hc11_cost->multQI
5346 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5347 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5349 /* emul instruction produces 32-bit result for 68HC12. */
5350 if (TARGET_M6812 && mode == SImode
5351 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5352 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5353 return m68hc11_cost->multHI
5354 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5355 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5357 total = rtx_cost (XEXP (x, 0), code, !optimize_size)
5358 + rtx_cost (XEXP (x, 1), code, !optimize_size);
5362 total += m68hc11_cost->multQI;
5366 total += m68hc11_cost->multHI;
5371 total += m68hc11_cost->multSI;
5378 extra_cost = COSTS_N_INSNS (2);
5386 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
5389 return total + COSTS_N_INSNS (1);
5393 return total + COSTS_N_INSNS (2);
5397 return total + COSTS_N_INSNS (4);
5399 return total + COSTS_N_INSNS (8);
5402 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5403 return COSTS_N_INSNS (1);
5405 return COSTS_N_INSNS (1);
5408 return COSTS_N_INSNS (4);
5413 m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
5414 bool speed ATTRIBUTE_UNUSED)
5416 enum rtx_code code = (enum rtx_code) codearg;
5417 enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
5421 /* Constants are cheap. Moving them in registers must be avoided
5422 because most instructions do not handle two register operands. */
5428 /* Logical and arithmetic operations with a constant operand are
5429 better because they are not supported with two registers. */
5431 if (outer_code == SET && x == const0_rtx)
5432 /* After reload, the reload_cse pass checks the cost to change
5433 a SET into a PLUS. Make const0 cheap then. */
5434 *total = 1 - reload_completed;
5440 if (outer_code != COMPARE)
5463 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5472 /* Worker function for TARGET_ASM_FILE_START. */
5475 m68hc11_file_start (void)
5477 default_file_start ();
5479 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5483 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5486 m68hc11_asm_out_constructor (rtx symbol, int priority)
5488 default_ctor_section_asm_out_constructor (symbol, priority);
5489 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5492 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5495 m68hc11_asm_out_destructor (rtx symbol, int priority)
5497 default_dtor_section_asm_out_destructor (symbol, priority);
5498 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5501 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5504 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5505 int incoming ATTRIBUTE_UNUSED)
5507 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5510 /* Return true if type TYPE should be returned in memory.
5511 Blocks and data types largers than 4 bytes cannot be returned
5512 in the register (D + X = 4). */
5515 m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
5517 if (TYPE_MODE (type) == BLKmode)
5519 HOST_WIDE_INT size = int_size_in_bytes (type);
5520 return (size == -1 || size > 4);
5523 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5526 #include "gt-m68hc11.h"