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);
96 /* Must be set to 1 to produce debug messages. */
99 extern FILE *asm_out_file;
104 rtx m68hc11_soft_tmp_reg;
105 static GTY(()) rtx stack_push_word;
106 static GTY(()) rtx stack_pop_word;
107 static GTY(()) rtx z_reg;
108 static GTY(()) rtx z_reg_qi;
109 static int regs_inited = 0;
111 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
112 int current_function_interrupt;
114 /* Set to 1 by expand_prologue() when the function is a trap handler. */
115 int current_function_trap;
117 /* Set to 1 when the current function is placed in 68HC12 banked
118 memory and must return with rtc. */
119 int current_function_far;
121 /* Min offset that is valid for the indirect addressing mode. */
122 HOST_WIDE_INT m68hc11_min_offset = 0;
124 /* Max offset that is valid for the indirect addressing mode. */
125 HOST_WIDE_INT m68hc11_max_offset = 256;
127 /* The class value for base registers. */
128 enum reg_class m68hc11_base_reg_class = A_REGS;
130 /* The class value for index registers. This is NO_REGS for 68HC11. */
131 enum reg_class m68hc11_index_reg_class = NO_REGS;
133 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
135 /* Tables that tell whether a given hard register is valid for
136 a base or an index register. It is filled at init time depending
137 on the target processor. */
138 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
139 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
141 /* A correction offset which is applied to the stack pointer.
142 This is 1 for 68HC11 and 0 for 68HC12. */
143 int m68hc11_sp_correction;
145 int m68hc11_addr_mode;
146 int m68hc11_mov_addr_mode;
149 const struct processor_costs *m68hc11_cost;
151 /* Costs for a 68HC11. */
152 static const struct processor_costs m6811_cost = {
157 /* non-constant shift */
160 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
161 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
162 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
165 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
166 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
167 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
168 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
169 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
170 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
175 COSTS_N_INSNS (20 * 4),
177 COSTS_N_INSNS (20 * 16),
186 /* Costs for a 68HC12. */
187 static const struct processor_costs m6812_cost = {
192 /* non-constant shift */
195 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
196 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
197 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
200 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
201 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
202 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
203 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
204 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
205 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
212 COSTS_N_INSNS (3 * 4),
221 /* M68HC11 specific attributes. */
223 static const struct attribute_spec m68hc11_attribute_table[] =
225 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
226 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
227 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
228 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
229 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
230 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
231 { NULL, 0, 0, false, false, false, NULL }
234 /* Initialize the GCC target structure. */
235 #undef TARGET_ATTRIBUTE_TABLE
236 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
238 #undef TARGET_ASM_ALIGNED_HI_OP
239 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
241 #undef TARGET_ASM_FUNCTION_EPILOGUE
242 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
244 #undef TARGET_ASM_FILE_START
245 #define TARGET_ASM_FILE_START m68hc11_file_start
246 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
247 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
249 #undef TARGET_DEFAULT_TARGET_FLAGS
250 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
252 #undef TARGET_ENCODE_SECTION_INFO
253 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
255 #undef TARGET_SECTION_TYPE_FLAGS
256 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
258 #undef TARGET_RTX_COSTS
259 #define TARGET_RTX_COSTS m68hc11_rtx_costs
260 #undef TARGET_ADDRESS_COST
261 #define TARGET_ADDRESS_COST m68hc11_address_cost
263 #undef TARGET_MACHINE_DEPENDENT_REORG
264 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
266 #undef TARGET_INIT_LIBFUNCS
267 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
269 #undef TARGET_STRUCT_VALUE_RTX
270 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
271 #undef TARGET_RETURN_IN_MEMORY
272 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
273 #undef TARGET_CALLEE_COPIES
274 #define TARGET_CALLEE_COPIES hook_callee_copies_named
276 #undef TARGET_STRIP_NAME_ENCODING
277 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
279 #undef TARGET_LEGITIMATE_ADDRESS_P
280 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
282 #undef TARGET_CAN_ELIMINATE
283 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
285 struct gcc_target targetm = TARGET_INITIALIZER;
288 m68hc11_override_options (void)
290 memset (m68hc11_reg_valid_for_index, 0,
291 sizeof (m68hc11_reg_valid_for_index));
292 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
294 /* Compilation with -fpic generates a wrong code. */
297 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
298 (flag_pic > 1) ? "PIC" : "pic");
302 /* Do not enable -fweb because it breaks the 32-bit shift patterns
303 by breaking the match_dup of those patterns. The shift patterns
304 will no longer be recognized after that. */
307 /* Configure for a 68hc11 processor. */
310 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
311 m68hc11_cost = &m6811_cost;
312 m68hc11_min_offset = 0;
313 m68hc11_max_offset = 256;
314 m68hc11_index_reg_class = NO_REGS;
315 m68hc11_base_reg_class = A_REGS;
316 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
317 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
318 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
319 m68hc11_sp_correction = 1;
320 m68hc11_tmp_regs_class = D_REGS;
321 m68hc11_addr_mode = ADDR_OFFSET;
322 m68hc11_mov_addr_mode = 0;
323 if (m68hc11_soft_reg_count < 0)
324 m68hc11_soft_reg_count = 4;
327 /* Configure for a 68hc12 processor. */
330 m68hc11_cost = &m6812_cost;
331 m68hc11_min_offset = -65536;
332 m68hc11_max_offset = 65536;
333 m68hc11_index_reg_class = D_REGS;
334 m68hc11_base_reg_class = A_OR_SP_REGS;
335 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
336 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
337 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
338 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
339 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
340 m68hc11_sp_correction = 0;
341 m68hc11_tmp_regs_class = TMP_REGS;
342 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
343 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
344 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
345 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
346 target_flags |= MASK_NO_DIRECT_MODE;
347 if (m68hc11_soft_reg_count < 0)
348 m68hc11_soft_reg_count = 0;
350 if (TARGET_LONG_CALLS)
351 current_function_far = 1;
358 m68hc11_conditional_register_usage (void)
362 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
363 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
365 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
368 call_used_regs[i] = 1;
371 /* For 68HC12, the Z register emulation is not necessary when the
372 frame pointer is not used. The frame pointer is eliminated and
373 replaced by the stack register (which is a BASE_REG_CLASS). */
374 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
376 fixed_regs[HARD_Z_REGNUM] = 1;
381 /* Reload and register operations. */
385 create_regs_rtx (void)
387 /* regs_inited = 1; */
388 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
389 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
390 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
391 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
393 stack_push_word = gen_rtx_MEM (HImode,
394 gen_rtx_PRE_DEC (HImode,
395 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
396 stack_pop_word = gen_rtx_MEM (HImode,
397 gen_rtx_POST_INC (HImode,
398 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
402 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
403 - 8-bit values are stored anywhere (except the SP register).
404 - 16-bit values can be stored in any register whose mode is 16
405 - 32-bit values can be stored in D, X registers or in a soft register
406 (except the last one because we need 2 soft registers)
407 - Values whose size is > 32 bit are not stored in real hard
408 registers. They may be stored in soft registers if there are
411 hard_regno_mode_ok (int regno, enum machine_mode mode)
413 switch (GET_MODE_SIZE (mode))
416 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
419 return (X_REGNO_P (regno)
420 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
423 return G_REGNO_P (regno);
426 /* We have to accept a QImode in X or Y registers. Otherwise, the
427 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
428 in the insns. Reload fails if the insn rejects the register class 'a'
429 as well as if it accepts it. Patterns that failed were
430 zero_extend_qihi2 and iorqi3. */
432 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
440 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
442 /* Don't accept renaming to Z register. We will replace it to
443 X,Y or D during machine reorg pass. */
444 if (reg2 == HARD_Z_REGNUM)
447 /* Don't accept renaming D,X to Y register as the code will be bigger. */
448 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
449 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
456 preferred_reload_class (rtx operand, enum reg_class rclass)
458 enum machine_mode mode;
460 mode = GET_MODE (operand);
464 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
467 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
468 return m68hc11_base_reg_class;
470 if (rclass >= S_REGS && (GET_CODE (operand) == MEM
471 || GET_CODE (operand) == CONST_INT))
473 /* S_REGS class must not be used. The movhi template does not
474 work to move a memory to a soft register.
475 Restrict to a hard reg. */
480 case D_OR_A_OR_S_REGS:
481 rclass = A_OR_D_REGS;
486 case D_OR_SP_OR_S_REGS:
487 rclass = D_OR_SP_REGS;
489 case D_OR_Y_OR_S_REGS:
490 rclass = D_OR_Y_REGS;
492 case D_OR_X_OR_S_REGS:
493 rclass = D_OR_X_REGS;
508 else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
512 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
514 rclass = D_OR_X_REGS;
516 else if (rclass >= S_REGS && S_REG_P (operand))
522 case D_OR_A_OR_S_REGS:
523 rclass = A_OR_D_REGS;
528 case D_OR_SP_OR_S_REGS:
529 rclass = D_OR_SP_REGS;
531 case D_OR_Y_OR_S_REGS:
532 rclass = D_OR_Y_REGS;
534 case D_OR_X_OR_S_REGS:
535 rclass = D_OR_X_REGS;
550 else if (rclass >= S_REGS)
554 printf ("Class = %s for: ", reg_class_names[rclass]);
562 printf (" => class=%s\n", reg_class_names[rclass]);
570 /* Return 1 if the operand is a valid indexed addressing mode.
571 For 68hc11: n,r with n in [0..255] and r in A_REGS class
572 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
574 m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
578 switch (GET_CODE (operand))
581 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
582 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
583 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
590 if (addr_mode & ADDR_INCDEC)
591 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
592 addr_mode & ADDR_STRICT);
596 base = XEXP (operand, 0);
597 if (GET_CODE (base) == MEM)
600 offset = XEXP (operand, 1);
601 if (GET_CODE (offset) == MEM)
604 /* Indexed addressing mode with 2 registers. */
605 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
607 if (!(addr_mode & ADDR_INDEXED))
610 addr_mode &= ADDR_STRICT;
611 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
612 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
615 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
616 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
622 if (!(addr_mode & ADDR_OFFSET))
625 if (GET_CODE (base) == REG)
627 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
630 if (!(addr_mode & ADDR_STRICT))
633 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
636 if (GET_CODE (offset) == REG)
638 if (!VALID_CONSTANT_OFFSET_P (base, mode))
641 if (!(addr_mode & ADDR_STRICT))
644 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
649 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
652 if (addr_mode & ADDR_CONST)
653 return VALID_CONSTANT_OFFSET_P (operand, mode);
661 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
662 a 68HC12 1-byte index addressing mode. */
664 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
669 if (GET_CODE (operand) == REG && reload_in_progress
670 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
671 && reg_equiv_memory_loc[REGNO (operand)])
673 operand = reg_equiv_memory_loc[REGNO (operand)];
674 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
677 if (GET_CODE (operand) != MEM)
680 operand = XEXP (operand, 0);
681 if (CONSTANT_ADDRESS_P (operand))
684 if (PUSH_POP_ADDRESS_P (operand))
687 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
688 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
691 if (TARGET_M6812 && GET_CODE (operand) == PLUS
692 && (reload_completed | reload_in_progress))
694 base = XEXP (operand, 0);
695 offset = XEXP (operand, 1);
697 /* The offset can be a symbol address and this is too big
698 for the operand constraint. */
699 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
702 if (GET_CODE (base) == CONST_INT)
705 switch (GET_MODE_SIZE (mode))
708 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
713 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
718 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
727 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
731 if (GET_CODE (operand) == REG && reload_in_progress
732 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
733 && reg_equiv_memory_loc[REGNO (operand)])
735 operand = reg_equiv_memory_loc[REGNO (operand)];
736 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
738 if (GET_CODE (operand) != MEM)
741 operand = XEXP (operand, 0);
742 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
743 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
747 m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
752 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
754 /* Reject the global variables if they are too wide. This forces
755 a load of their address in a register and generates smaller code. */
756 if (GET_MODE_SIZE (mode) == 8)
761 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
762 if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
766 if (PUSH_POP_ADDRESS_P (operand))
770 if (symbolic_memory_operand (operand, mode))
778 m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
785 printf ("Checking: ");
790 result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
794 printf (" -> %s\n", result == 0 ? "NO" : "YES");
801 printf ("go_if_legitimate%s, ret 0: %d:",
802 (strict ? "_strict" : ""), mode);
812 m68hc11_reload_operands (rtx operands[])
814 enum machine_mode mode;
816 if (regs_inited == 0)
819 mode = GET_MODE (operands[1]);
821 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
822 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
824 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
825 rtx base = XEXP (XEXP (operands[1], 0), 0);
827 if (GET_CODE (base) != REG)
834 /* If the offset is out of range, we have to compute the address
835 with a separate add instruction. We try to do this with an 8-bit
836 add on the A register. This is possible only if the lowest part
837 of the offset (i.e., big_offset % 256) is a valid constant offset
838 with respect to the mode. If it's not, we have to generate a
839 16-bit add on the D register. From:
841 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
845 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
846 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
847 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
848 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
850 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
851 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
854 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
857 rtx reg = operands[0];
859 int val = INTVAL (big_offset);
862 /* We use the 'operands[0]' as a scratch register to compute the
863 address. Make sure 'base' is in that register. */
864 if (!rtx_equal_p (base, operands[0]))
866 emit_move_insn (reg, base);
876 vh = (val >> 8) & 0x0FF;
880 /* Create the lowest part offset that still remains to be added.
881 If it's not a valid offset, do a 16-bit add. */
882 offset = GEN_INT (vl);
883 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
885 emit_insn (gen_rtx_SET (VOIDmode, reg,
886 gen_rtx_PLUS (HImode, reg, big_offset)));
891 emit_insn (gen_rtx_SET (VOIDmode, reg,
892 gen_rtx_PLUS (HImode, reg,
893 GEN_INT (vh << 8))));
895 emit_move_insn (operands[0],
896 gen_rtx_MEM (GET_MODE (operands[1]),
897 gen_rtx_PLUS (Pmode, reg, offset)));
902 /* Use the normal gen_movhi pattern. */
907 m68hc11_emit_libcall (const char *name, enum rtx_code code,
908 enum machine_mode dmode, enum machine_mode smode,
909 int noperands, rtx *operands)
917 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
921 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
922 dmode, 1, operands[1], smode);
923 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
927 ret = emit_library_call_value (libcall, NULL_RTX,
929 operands[1], smode, operands[2],
931 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
938 insns = get_insns ();
940 emit_libcall_block (insns, operands[0], ret, equiv);
943 /* Returns true if X is a PRE/POST increment decrement
944 (same as auto_inc_p() in rtlanal.c but do not take into
945 account the stack). */
947 m68hc11_auto_inc_p (rtx x)
949 return GET_CODE (x) == PRE_DEC
950 || GET_CODE (x) == POST_INC
951 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
955 /* Predicates for machine description. */
958 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
960 return GET_CODE (operand) == MEM
961 && GET_CODE (XEXP (operand, 0)) == PLUS
962 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
963 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
964 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
965 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
969 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
971 if (GET_CODE (operand) == MEM)
973 rtx op = XEXP (operand, 0);
975 if (symbolic_memory_operand (op, mode))
982 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
984 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
986 rtx op = XEXP (operand, 0);
989 if (m68hc11_page0_symbol_p (op))
992 if (symbolic_memory_operand (op, mode))
995 if (reload_in_progress)
998 operand = XEXP (operand, 0);
999 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1000 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
1006 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1008 if (GET_CODE (operand) != MEM)
1011 operand = XEXP (operand, 0);
1012 if (GET_CODE (operand) == PLUS)
1014 if (GET_CODE (XEXP (operand, 0)) == REG)
1015 operand = XEXP (operand, 0);
1016 else if (GET_CODE (XEXP (operand, 1)) == REG)
1017 operand = XEXP (operand, 1);
1019 return GET_CODE (operand) == REG
1020 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1021 || A_REGNO_P (REGNO (operand)));
1025 push_pop_operand_p (rtx operand)
1027 if (GET_CODE (operand) != MEM)
1031 operand = XEXP (operand, 0);
1032 return PUSH_POP_ADDRESS_P (operand);
1035 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1036 reference and a constant. */
1039 symbolic_memory_operand (rtx op, enum machine_mode mode)
1041 switch (GET_CODE (op))
1049 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1050 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1051 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1053 /* ??? This clause seems to be irrelevant. */
1055 return GET_MODE (op) == mode;
1058 return symbolic_memory_operand (XEXP (op, 0), mode)
1059 && symbolic_memory_operand (XEXP (op, 1), mode);
1066 /* Emit the code to build the trampoline used to call a nested function.
1070 ldy #&CXT movw #&CXT,*_.d1
1071 sty *_.d1 jmp FNADDR
1076 m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1078 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1081 if (*static_chain_reg == '*')
1085 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1086 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1087 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1089 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1090 gen_rtx_CONST (QImode,
1091 gen_rtx_SYMBOL_REF (Pmode,
1092 static_chain_reg)));
1093 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1095 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1099 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1100 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1101 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1102 gen_rtx_CONST (HImode,
1103 gen_rtx_SYMBOL_REF (Pmode,
1104 static_chain_reg)));
1105 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1107 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1111 /* Declaration of types. */
1113 /* Handle an "tiny_data" attribute; arguments as in
1114 struct attribute_spec.handler. */
1116 m68hc11_handle_page0_attribute (tree *node, tree name,
1117 tree args ATTRIBUTE_UNUSED,
1118 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1122 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1124 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1128 warning (OPT_Wattributes, "%qE attribute ignored",
1130 *no_add_attrs = true;
1136 /* Keep track of the symbol which has a `trap' attribute and which uses
1137 the `swi' calling convention. Since there is only one trap, we only
1138 record one such symbol. If there are several, a warning is reported. */
1139 static rtx trap_handler_symbol = 0;
1141 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1142 arguments as in struct attribute_spec.handler. */
1144 m68hc11_handle_fntype_attribute (tree *node, tree name,
1145 tree args ATTRIBUTE_UNUSED,
1146 int flags ATTRIBUTE_UNUSED,
1149 if (TREE_CODE (*node) != FUNCTION_TYPE
1150 && TREE_CODE (*node) != METHOD_TYPE
1151 && TREE_CODE (*node) != FIELD_DECL
1152 && TREE_CODE (*node) != TYPE_DECL)
1154 warning (OPT_Wattributes, "%qE attribute only applies to functions",
1156 *no_add_attrs = true;
1161 /* Undo the effects of the above. */
1164 m68hc11_strip_name_encoding (const char *str)
1166 return str + (*str == '*' || *str == '@' || *str == '&');
1170 m68hc11_encode_label (tree decl)
1172 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1173 int len = strlen (str);
1174 char *newstr = XALLOCAVEC (char, len + 2);
1177 strcpy (&newstr[1], str);
1179 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1182 /* Return 1 if this is a symbol in page0 */
1184 m68hc11_page0_symbol_p (rtx x)
1186 switch (GET_CODE (x))
1189 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1192 return m68hc11_page0_symbol_p (XEXP (x, 0));
1195 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1198 return GET_CODE (XEXP (x, 1)) == CONST_INT
1199 && INTVAL (XEXP (x, 1)) < 256
1200 && INTVAL (XEXP (x, 1)) >= 0;
1207 /* We want to recognize trap handlers so that we handle calls to traps
1208 in a special manner (by issuing the trap). This information is stored
1209 in SYMBOL_REF_FLAG. */
1212 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1218 if (TREE_CODE (decl) == VAR_DECL)
1220 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1221 m68hc11_encode_label (decl);
1225 if (TREE_CODE (decl) != FUNCTION_DECL)
1228 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1231 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1233 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1234 is_far = TARGET_LONG_CALLS != 0;
1236 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1237 if (trap_handler && is_far)
1239 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1240 "not compatible, ignoring %<far%>");
1245 if (trap_handler_symbol != 0)
1246 warning (OPT_Wattributes, "%<trap%> attribute is already used");
1248 trap_handler_symbol = XEXP (rtl, 0);
1250 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1254 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1256 unsigned int flags = default_section_type_flags (decl, name, reloc);
1258 if (strncmp (name, ".eeprom", 7) == 0)
1260 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1267 m68hc11_is_far_symbol (rtx sym)
1269 if (GET_CODE (sym) == MEM)
1270 sym = XEXP (sym, 0);
1272 return SYMBOL_REF_FLAG (sym);
1276 m68hc11_is_trap_symbol (rtx sym)
1278 if (GET_CODE (sym) == MEM)
1279 sym = XEXP (sym, 0);
1281 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1285 /* Argument support functions. */
1287 /* Given FROM and TO register numbers, say whether this elimination is
1288 allowed. Frame pointer elimination is automatically handled.
1290 All other eliminations are valid. */
1293 m68hc11_can_eliminate (const int from, const int to)
1295 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
1296 ? ! frame_pointer_needed
1300 /* Define the offset between two registers, one to be eliminated, and the
1301 other its replacement, at the start of a routine. */
1303 m68hc11_initial_elimination_offset (int from, int to)
1310 /* For a trap handler, we must take into account the registers which
1311 are pushed on the stack during the trap (except the PC). */
1312 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1313 current_function_interrupt = lookup_attribute ("interrupt",
1314 func_attr) != NULL_TREE;
1315 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1317 if (lookup_attribute ("far", func_attr) != 0)
1318 current_function_far = 1;
1319 else if (lookup_attribute ("near", func_attr) != 0)
1320 current_function_far = 0;
1322 current_function_far = (TARGET_LONG_CALLS != 0
1323 && !current_function_interrupt
1326 if (trap_handler && from == ARG_POINTER_REGNUM)
1329 /* For a function using 'call/rtc' we must take into account the
1330 page register which is pushed in the call. */
1331 else if (current_function_far && from == ARG_POINTER_REGNUM)
1336 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1338 /* 2 is for the saved frame.
1339 1 is for the 'sts' correction when creating the frame. */
1340 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1343 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1345 return m68hc11_sp_correction;
1348 /* Push any 2 byte pseudo hard registers that we need to save. */
1349 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1351 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1357 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1359 return get_frame_size () + size;
1362 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1369 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1370 for a call to a function whose data type is FNTYPE.
1371 For a library call, FNTYPE is 0. */
1374 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1378 z_replacement_completed = 0;
1382 /* For a library call, we must find out the type of the return value.
1383 When the return value is bigger than 4 bytes, it is returned in
1384 memory. In that case, the first argument of the library call is a
1385 pointer to the memory location. Because the first argument is passed in
1386 register D, we have to identify this, so that the first function
1387 parameter is not passed in D either. */
1393 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1396 /* If the library ends in 'di' or in 'df', we assume it's
1397 returning some DImode or some DFmode which are 64-bit wide. */
1398 name = XSTR (libname, 0);
1399 len = strlen (name);
1401 && ((name[len - 2] == 'd'
1402 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1403 || (name[len - 3] == 'd'
1404 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1406 /* We are in. Mark the first parameter register as already used. */
1413 ret_type = TREE_TYPE (fntype);
1415 if (ret_type && aggregate_value_p (ret_type, fntype))
1422 /* Update the data in CUM to advance over an argument
1423 of mode MODE and data type TYPE.
1424 (TYPE is null for libcalls where that information may not be available.) */
1427 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1428 tree type, int named ATTRIBUTE_UNUSED)
1430 if (mode != BLKmode)
1432 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1435 cum->words = GET_MODE_SIZE (mode);
1439 cum->words += GET_MODE_SIZE (mode);
1440 if (cum->words <= HARD_REG_SIZE)
1446 cum->words += int_size_in_bytes (type);
1451 /* Define where to put the arguments to a function.
1452 Value is zero to push the argument on the stack,
1453 or a hard register in which to store the argument.
1455 MODE is the argument's machine mode.
1456 TYPE is the data type of the argument (as a tree).
1457 This is null for libcalls where that information may
1459 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1460 the preceding args and about the function being called.
1461 NAMED is nonzero if this argument is a named parameter
1462 (otherwise it is an extra parameter matching an ellipsis). */
1465 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1466 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1468 if (cum->words != 0)
1473 if (mode != BLKmode)
1475 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1476 return gen_rtx_REG (mode, HARD_X_REGNUM);
1478 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1482 return gen_rtx_REG (mode, HARD_D_REGNUM);
1487 /* If defined, a C expression which determines whether, and in which direction,
1488 to pad out an argument with extra space. The value should be of type
1489 `enum direction': either `upward' to pad above the argument,
1490 `downward' to pad below, or `none' to inhibit padding.
1492 Structures are stored left shifted in their argument slot. */
1494 m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
1496 if (type != 0 && AGGREGATE_TYPE_P (type))
1499 /* Fall back to the default. */
1500 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1504 /* Function prologue and epilogue. */
1506 /* Emit a move after the reload pass has completed. This is used to
1507 emit the prologue and epilogue. */
1509 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1513 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1515 insn = emit_move_insn (to, from);
1519 emit_move_insn (scratch, from);
1520 insn = emit_move_insn (to, scratch);
1523 /* Put a REG_INC note to tell the flow analysis that the instruction
1525 if (IS_STACK_PUSH (to))
1526 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
1527 else if (IS_STACK_POP (from))
1528 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
1530 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1531 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1532 The problem is that we are lying to gcc and use `txs' for x = sp
1533 (which is not really true because txs is really x = sp + 1). */
1534 else if (TARGET_M6811 && SP_REG_P (from))
1535 add_reg_note (insn, REG_INC, from);
1539 m68hc11_total_frame_size (void)
1544 size = get_frame_size ();
1545 if (current_function_interrupt)
1547 size += 3 * HARD_REG_SIZE;
1549 if (frame_pointer_needed)
1550 size += HARD_REG_SIZE;
1552 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1553 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1554 size += HARD_REG_SIZE;
1560 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1561 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1563 /* We catch the function epilogue generation to have a chance
1564 to clear the z_replacement_completed flag. */
1565 z_replacement_completed = 0;
1569 expand_prologue (void)
1576 gcc_assert (reload_completed == 1);
1578 size = get_frame_size ();
1582 /* Generate specific prologue for interrupt handlers. */
1583 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1584 current_function_interrupt = lookup_attribute ("interrupt",
1585 func_attr) != NULL_TREE;
1586 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1587 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1588 current_function_far = 1;
1589 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1590 current_function_far = 0;
1592 current_function_far = (TARGET_LONG_CALLS != 0
1593 && !current_function_interrupt
1594 && !current_function_trap);
1596 /* Get the scratch register to build the frame and push registers.
1597 If the first argument is a 32-bit quantity, the D+X registers
1598 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1599 For 68HC12, this scratch register is not used. */
1600 if (crtl->args.info.nregs == 2)
1605 /* Save current stack frame. */
1606 if (frame_pointer_needed)
1607 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1609 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1610 Other soft registers in page0 need not to be saved because they
1611 will be restored by C functions. For a trap handler, we don't
1612 need to preserve these registers because this is a synchronous call. */
1613 if (current_function_interrupt)
1615 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1616 emit_move_after_reload (stack_push_word,
1617 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1618 emit_move_after_reload (stack_push_word,
1619 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1623 /* Allocate local variables. */
1624 if (TARGET_M6812 && (size > 4 || size == 3))
1626 emit_insn (gen_addhi3 (stack_pointer_rtx,
1627 stack_pointer_rtx, GEN_INT (-size)));
1629 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1633 insn = gen_rtx_PARALLEL
1636 gen_rtx_SET (VOIDmode,
1638 gen_rtx_PLUS (HImode,
1641 gen_rtx_CLOBBER (VOIDmode, scratch)));
1648 /* Allocate by pushing scratch values. */
1649 for (i = 2; i <= size; i += 2)
1650 emit_move_after_reload (stack_push_word, ix_reg, 0);
1653 emit_insn (gen_addhi3 (stack_pointer_rtx,
1654 stack_pointer_rtx, constm1_rtx));
1657 /* Create the frame pointer. */
1658 if (frame_pointer_needed)
1659 emit_move_after_reload (hard_frame_pointer_rtx,
1660 stack_pointer_rtx, scratch);
1662 /* Push any 2 byte pseudo hard registers that we need to save. */
1663 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1665 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1667 emit_move_after_reload (stack_push_word,
1668 gen_rtx_REG (HImode, regno), scratch);
1674 expand_epilogue (void)
1681 gcc_assert (reload_completed == 1);
1683 size = get_frame_size ();
1685 /* If we are returning a value in two registers, we have to preserve the
1686 X register and use the Y register to restore the stack and the saved
1687 registers. Otherwise, use X because it's faster (and smaller). */
1688 if (crtl->return_rtx == 0)
1690 else if (GET_CODE (crtl->return_rtx) == MEM)
1691 return_size = HARD_REG_SIZE;
1693 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
1695 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1700 /* Pop any 2 byte pseudo hard registers that we saved. */
1701 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1703 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1705 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1706 stack_pop_word, scratch);
1710 /* de-allocate auto variables */
1711 if (TARGET_M6812 && (size > 4 || size == 3))
1713 emit_insn (gen_addhi3 (stack_pointer_rtx,
1714 stack_pointer_rtx, GEN_INT (size)));
1716 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1720 insn = gen_rtx_PARALLEL
1723 gen_rtx_SET (VOIDmode,
1725 gen_rtx_PLUS (HImode,
1728 gen_rtx_CLOBBER (VOIDmode, scratch)));
1735 for (i = 2; i <= size; i += 2)
1736 emit_move_after_reload (scratch, stack_pop_word, scratch);
1738 emit_insn (gen_addhi3 (stack_pointer_rtx,
1739 stack_pointer_rtx, const1_rtx));
1742 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1743 if (current_function_interrupt)
1745 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1746 stack_pop_word, scratch);
1747 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1748 stack_pop_word, scratch);
1749 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1752 /* Restore previous frame pointer. */
1753 if (frame_pointer_needed)
1754 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1756 /* If the trap handler returns some value, copy the value
1757 in D, X onto the stack so that the rti will pop the return value
1759 else if (current_function_trap && return_size != 0)
1761 rtx addr_reg = stack_pointer_rtx;
1765 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1768 emit_move_after_reload (gen_rtx_MEM (HImode,
1769 gen_rtx_PLUS (HImode, addr_reg,
1770 const1_rtx)), d_reg, 0);
1771 if (return_size > HARD_REG_SIZE)
1772 emit_move_after_reload (gen_rtx_MEM (HImode,
1773 gen_rtx_PLUS (HImode, addr_reg,
1774 GEN_INT (3))), ix_reg, 0);
1777 emit_jump_insn (gen_return ());
1781 /* Low and High part extraction for 68HC11. These routines are
1782 similar to gen_lowpart and gen_highpart but they have been
1783 fixed to work for constants and 68HC11 specific registers. */
1786 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1788 /* We assume that the low part of an auto-inc mode is the same with
1789 the mode changed and that the caller split the larger mode in the
1791 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1793 return gen_rtx_MEM (mode, XEXP (x, 0));
1796 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1797 floating-point constant. A CONST_DOUBLE is used whenever the
1798 constant requires more than one word in order to be adequately
1800 if (GET_CODE (x) == CONST_DOUBLE)
1804 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1808 if (GET_MODE (x) == SFmode)
1810 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1811 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1817 split_double (x, &first, &second);
1821 return GEN_INT (l[0]);
1823 return gen_int_mode (l[0], HImode);
1827 l[0] = CONST_DOUBLE_LOW (x);
1832 return GEN_INT (l[0]);
1834 gcc_assert (GET_MODE (x) == SFmode);
1835 return gen_int_mode (l[0], HImode);
1841 if (mode == QImode && D_REG_P (x))
1842 return gen_rtx_REG (mode, HARD_B_REGNUM);
1844 /* gen_lowpart crashes when it is called with a SUBREG. */
1845 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1850 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1852 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1857 x = gen_lowpart (mode, x);
1859 /* Return a different rtx to avoid to share it in several insns
1860 (when used by a split pattern). Sharing addresses within
1861 a MEM breaks the Z register replacement (and reloading). */
1862 if (GET_CODE (x) == MEM)
1868 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1870 /* We assume that the high part of an auto-inc mode is the same with
1871 the mode changed and that the caller split the larger mode in the
1873 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1875 return gen_rtx_MEM (mode, XEXP (x, 0));
1878 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1879 floating-point constant. A CONST_DOUBLE is used whenever the
1880 constant requires more than one word in order to be adequately
1882 if (GET_CODE (x) == CONST_DOUBLE)
1886 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1890 if (GET_MODE (x) == SFmode)
1892 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1893 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1899 split_double (x, &first, &second);
1903 return GEN_INT (l[1]);
1905 return gen_int_mode ((l[1] >> 16), HImode);
1909 l[1] = CONST_DOUBLE_HIGH (x);
1915 return GEN_INT (l[1]);
1917 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1918 return gen_int_mode ((l[0] >> 16), HImode);
1923 if (GET_CODE (x) == CONST_INT)
1925 HOST_WIDE_INT val = INTVAL (x);
1929 return gen_int_mode (val >> 8, QImode);
1931 else if (mode == HImode)
1933 return gen_int_mode (val >> 16, HImode);
1935 else if (mode == SImode)
1937 return gen_int_mode (val >> 32, SImode);
1940 if (mode == QImode && D_REG_P (x))
1941 return gen_rtx_REG (mode, HARD_A_REGNUM);
1943 /* There is no way in GCC to represent the upper part of a word register.
1944 To obtain the 8-bit upper part of a soft register, we change the
1945 reg into a mem rtx. This is possible because they are physically
1946 located in memory. There is no offset because we are big-endian. */
1947 if (mode == QImode && S_REG_P (x))
1951 /* Avoid the '*' for direct addressing mode when this
1952 addressing mode is disabled. */
1953 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1954 return gen_rtx_MEM (QImode,
1955 gen_rtx_SYMBOL_REF (Pmode,
1956 ®_names[REGNO (x)][pos]));
1959 /* gen_highpart crashes when it is called with a SUBREG. */
1960 switch (GET_CODE (x))
1963 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
1965 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1966 return gen_rtx_REG (mode, REGNO (x));
1968 return gen_rtx_SUBREG (mode, x, 0);
1970 x = change_address (x, mode, 0);
1972 /* Return a different rtx to avoid to share it in several insns
1973 (when used by a split pattern). Sharing addresses within
1974 a MEM breaks the Z register replacement (and reloading). */
1975 if (GET_CODE (x) == MEM)
1985 /* Obscure register manipulation. */
1987 /* Finds backward in the instructions to see if register 'reg' is
1988 dead. This is used when generating code to see if we can use 'reg'
1989 as a scratch register. This allows us to choose a better generation
1990 of code when we know that some register dies or can be clobbered. */
1993 dead_register_here (rtx x, rtx reg)
1999 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2003 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2010 if (GET_CODE (body) == CALL_INSN)
2012 if (GET_CODE (body) == JUMP_INSN)
2015 if (GET_CODE (body) == SET)
2017 rtx dst = XEXP (body, 0);
2019 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2021 if (x_reg && rtx_equal_p (dst, x_reg))
2024 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2027 else if (reg_mentioned_p (reg, p)
2028 || (x_reg && reg_mentioned_p (x_reg, p)))
2032 /* Scan forward to see if the register is set in some insns and never
2034 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2038 if (GET_CODE (p) == CODE_LABEL
2039 || GET_CODE (p) == JUMP_INSN
2040 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2043 if (GET_CODE (p) != INSN)
2047 if (GET_CODE (body) == SET)
2049 rtx src = XEXP (body, 1);
2050 rtx dst = XEXP (body, 0);
2052 if (GET_CODE (dst) == REG
2053 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2057 /* Register is used (may be in source or in dest). */
2058 if (reg_mentioned_p (reg, p)
2059 || (x_reg != 0 && GET_MODE (p) == SImode
2060 && reg_mentioned_p (x_reg, p)))
2063 return p == 0 ? 1 : 0;
2067 /* Code generation operations called from machine description file. */
2069 /* Print the name of register 'regno' in the assembly file. */
2071 asm_print_register (FILE *file, int regno)
2073 const char *name = reg_names[regno];
2075 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2078 fprintf (file, "%s", name);
2081 /* A C compound statement to output to stdio stream STREAM the
2082 assembler syntax for an instruction operand X. X is an RTL
2085 CODE is a value that can be used to specify one of several ways
2086 of printing the operand. It is used when identical operands
2087 must be printed differently depending on the context. CODE
2088 comes from the `%' specification that was used to request
2089 printing of the operand. If the specification was just `%DIGIT'
2090 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2091 is the ASCII code for LTR.
2093 If X is a register, this macro should print the register's name.
2094 The names can be found in an array `reg_names' whose type is
2095 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2097 When the machine description has a specification `%PUNCT' (a `%'
2098 followed by a punctuation character), this macro is called with
2099 a null pointer for X and the punctuation character for CODE.
2101 The M68HC11 specific codes are:
2103 'b' for the low part of the operand.
2104 'h' for the high part of the operand
2105 The 'b' or 'h' modifiers have no effect if the operand has
2106 the QImode and is not a S_REG_P (soft register). If the
2107 operand is a hard register, these two modifiers have no effect.
2108 't' generate the temporary scratch register. The operand is
2110 'T' generate the low-part temporary scratch register. The operand is
2114 print_operand (FILE *file, rtx op, int letter)
2118 asm_print_register (file, SOFT_TMP_REGNUM);
2121 else if (letter == 'T')
2123 asm_print_register (file, SOFT_TMP_REGNUM);
2124 fprintf (file, "+1");
2127 else if (letter == '#')
2129 asm_fprintf (file, "%I");
2132 if (GET_CODE (op) == REG)
2134 if (letter == 'b' && S_REG_P (op))
2136 asm_print_register (file, REGNO (op));
2137 fprintf (file, "+1");
2139 else if (letter == 'b' && D_REG_P (op))
2141 asm_print_register (file, HARD_B_REGNUM);
2145 asm_print_register (file, REGNO (op));
2150 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2153 asm_fprintf (file, "%I%%lo(");
2155 asm_fprintf (file, "%I%%hi(");
2157 output_addr_const (file, op);
2158 fprintf (file, ")");
2162 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2163 are specified. If we already have a QImode, there is nothing to do. */
2164 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2168 op = m68hc11_gen_lowpart (QImode, op);
2170 else if (letter == 'h')
2172 op = m68hc11_gen_highpart (QImode, op);
2176 if (GET_CODE (op) == MEM)
2178 rtx base = XEXP (op, 0);
2179 switch (GET_CODE (base))
2182 gcc_assert (TARGET_M6812);
2183 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2184 asm_print_register (file, REGNO (XEXP (base, 0)));
2188 gcc_assert (TARGET_M6812);
2189 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2190 asm_print_register (file, REGNO (XEXP (base, 0)));
2191 fprintf (file, "-");
2195 gcc_assert (TARGET_M6812);
2196 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2197 asm_print_register (file, REGNO (XEXP (base, 0)));
2198 fprintf (file, "+");
2202 gcc_assert (TARGET_M6812);
2203 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2204 asm_print_register (file, REGNO (XEXP (base, 0)));
2208 gcc_assert (TARGET_M6812);
2209 fprintf (file, "[");
2210 print_operand_address (file, XEXP (base, 0));
2211 fprintf (file, "]");
2215 if (m68hc11_page0_symbol_p (base))
2216 fprintf (file, "*");
2218 output_address (base);
2222 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2227 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2228 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2229 asm_fprintf (file, "%I0x%lx", l);
2231 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2235 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2236 sizeof (dstr), 0, 1);
2237 asm_fprintf (file, "%I0r%s", dstr);
2241 int need_parenthesize = 0;
2244 asm_fprintf (file, "%I");
2246 need_parenthesize = must_parenthesize (op);
2248 if (need_parenthesize)
2249 fprintf (file, "(");
2251 output_addr_const (file, op);
2252 if (need_parenthesize)
2253 fprintf (file, ")");
2257 /* Returns true if the operand 'op' must be printed with parenthesis
2258 around it. This must be done only if there is a symbol whose name
2259 is a processor register. */
2261 must_parenthesize (rtx op)
2265 switch (GET_CODE (op))
2268 name = XSTR (op, 0);
2269 /* Avoid a conflict between symbol name and a possible
2271 return (strcasecmp (name, "a") == 0
2272 || strcasecmp (name, "b") == 0
2273 || strcasecmp (name, "d") == 0
2274 || strcasecmp (name, "x") == 0
2275 || strcasecmp (name, "y") == 0
2276 || strcasecmp (name, "ix") == 0
2277 || strcasecmp (name, "iy") == 0
2278 || strcasecmp (name, "pc") == 0
2279 || strcasecmp (name, "sp") == 0
2280 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2284 return must_parenthesize (XEXP (op, 0))
2285 || must_parenthesize (XEXP (op, 1));
2291 return must_parenthesize (XEXP (op, 0));
2302 /* A C compound statement to output to stdio stream STREAM the
2303 assembler syntax for an instruction operand that is a memory
2304 reference whose address is ADDR. ADDR is an RTL expression. */
2307 print_operand_address (FILE *file, rtx addr)
2311 int need_parenthesis = 0;
2313 switch (GET_CODE (addr))
2316 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2318 fprintf (file, "0,");
2319 asm_print_register (file, REGNO (addr));
2323 base = XEXP (addr, 0);
2324 switch (GET_CODE (base))
2327 gcc_assert (TARGET_M6812);
2328 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2329 asm_print_register (file, REGNO (XEXP (base, 0)));
2333 gcc_assert (TARGET_M6812);
2334 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2335 asm_print_register (file, REGNO (XEXP (base, 0)));
2336 fprintf (file, "-");
2340 gcc_assert (TARGET_M6812);
2341 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2342 asm_print_register (file, REGNO (XEXP (base, 0)));
2343 fprintf (file, "+");
2347 gcc_assert (TARGET_M6812);
2348 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2349 asm_print_register (file, REGNO (XEXP (base, 0)));
2353 need_parenthesis = must_parenthesize (base);
2354 if (need_parenthesis)
2355 fprintf (file, "(");
2357 output_addr_const (file, base);
2358 if (need_parenthesis)
2359 fprintf (file, ")");
2365 base = XEXP (addr, 0);
2366 offset = XEXP (addr, 1);
2367 if (!G_REG_P (base) && G_REG_P (offset))
2369 base = XEXP (addr, 1);
2370 offset = XEXP (addr, 0);
2372 if (CONSTANT_ADDRESS_P (base))
2374 need_parenthesis = must_parenthesize (addr);
2376 gcc_assert (CONSTANT_ADDRESS_P (offset));
2377 if (need_parenthesis)
2378 fprintf (file, "(");
2380 output_addr_const (file, base);
2381 fprintf (file, "+");
2382 output_addr_const (file, offset);
2383 if (need_parenthesis)
2384 fprintf (file, ")");
2388 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2391 gcc_assert (TARGET_M6812);
2392 asm_print_register (file, REGNO (offset));
2393 fprintf (file, ",");
2394 asm_print_register (file, REGNO (base));
2398 need_parenthesis = must_parenthesize (offset);
2399 if (need_parenthesis)
2400 fprintf (file, "(");
2402 output_addr_const (file, offset);
2403 if (need_parenthesis)
2404 fprintf (file, ")");
2405 fprintf (file, ",");
2406 asm_print_register (file, REGNO (base));
2412 if (GET_CODE (addr) == CONST_INT
2413 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2415 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2419 need_parenthesis = must_parenthesize (addr);
2420 if (need_parenthesis)
2421 fprintf (file, "(");
2423 output_addr_const (file, addr);
2424 if (need_parenthesis)
2425 fprintf (file, ")");
2432 /* Splitting of some instructions. */
2435 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2439 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2440 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2441 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2442 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2448 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2453 switch (GET_MODE (op0))
2457 tmp = m68hc11_expand_compare (code, op0, op1);
2458 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2459 gen_rtx_LABEL_REF (VOIDmode, label),
2461 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2465 /* SCz: from i386.c */
2468 /* Don't expand the comparison early, so that we get better code
2469 when jump or whoever decides to reverse the comparison. */
2474 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2475 &m68hc11_compare_op1);
2477 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2478 m68hc11_compare_op0, m68hc11_compare_op1);
2479 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2480 gen_rtx_LABEL_REF (VOIDmode, label),
2482 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2484 use_fcomi = ix86_use_fcomi_compare (code);
2485 vec = rtvec_alloc (3 + !use_fcomi);
2486 RTVEC_ELT (vec, 0) = tmp;
2488 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2490 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2493 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2495 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2501 /* Expand SImode branch into multiple compare+branch. */
2503 rtx lo[2], hi[2], label2;
2504 enum rtx_code code1, code2, code3;
2506 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2511 code = swap_condition (code);
2513 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2514 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2515 hi[0] = m68hc11_gen_highpart (HImode, op0);
2516 hi[1] = m68hc11_gen_highpart (HImode, op1);
2518 /* Otherwise, if we are doing less-than, op1 is a constant and the
2519 low word is zero, then we can just examine the high word. */
2521 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2522 && (code == LT || code == LTU))
2524 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2528 /* Otherwise, we need two or three jumps. */
2530 label2 = gen_label_rtx ();
2533 code2 = swap_condition (code);
2534 code3 = unsigned_condition (code);
2575 * if (hi(a) < hi(b)) goto true;
2576 * if (hi(a) > hi(b)) goto false;
2577 * if (lo(a) < lo(b)) goto true;
2580 if (code1 != UNKNOWN)
2581 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2582 if (code2 != UNKNOWN)
2583 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2585 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2587 if (code2 != UNKNOWN)
2588 emit_label (label2);
2598 /* Return the increment/decrement mode of a MEM if it is such.
2599 Return CONST if it is anything else. */
2601 autoinc_mode (rtx x)
2603 if (GET_CODE (x) != MEM)
2607 if (GET_CODE (x) == PRE_INC
2608 || GET_CODE (x) == PRE_DEC
2609 || GET_CODE (x) == POST_INC
2610 || GET_CODE (x) == POST_DEC)
2611 return GET_CODE (x);
2617 m68hc11_make_autoinc_notes (rtx *x, void *data)
2621 switch (GET_CODE (*x))
2628 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2637 /* Split a DI, SI or HI move into several smaller move operations.
2638 The scratch register 'scratch' is used as a temporary to load
2639 store intermediate values. It must be a hard register. */
2641 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2643 rtx low_to, low_from;
2644 rtx high_to, high_from;
2646 enum machine_mode mode;
2648 int autoinc_from = autoinc_mode (from);
2649 int autoinc_to = autoinc_mode (to);
2651 mode = GET_MODE (to);
2653 /* If the TO and FROM contain autoinc modes that are not compatible
2654 together (one pop and the other a push), we must change one to
2655 an offsetable operand and generate an appropriate add at the end. */
2656 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2661 /* The source uses an autoinc mode which is not compatible with
2662 a split (this would result in a word swap). */
2663 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2665 code = GET_CODE (XEXP (from, 0));
2666 reg = XEXP (XEXP (from, 0), 0);
2667 offset = GET_MODE_SIZE (GET_MODE (from));
2668 if (code == POST_DEC)
2671 if (code == PRE_INC)
2672 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2674 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2675 if (code == POST_DEC)
2676 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2680 /* Likewise for destination. */
2681 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2683 code = GET_CODE (XEXP (to, 0));
2684 reg = XEXP (XEXP (to, 0), 0);
2685 offset = GET_MODE_SIZE (GET_MODE (to));
2686 if (code == POST_DEC)
2689 if (code == PRE_INC)
2690 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2692 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2693 if (code == POST_DEC)
2694 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2698 /* The source and destination auto increment modes must be compatible
2699 with each other: same direction. */
2700 if ((autoinc_to != autoinc_from
2701 && autoinc_to != CONST && autoinc_from != CONST)
2702 /* The destination address register must not be used within
2703 the source operand because the source address would change
2704 while doing the copy. */
2705 || (autoinc_to != CONST
2706 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2707 && !IS_STACK_PUSH (to)))
2709 /* Must change the destination. */
2710 code = GET_CODE (XEXP (to, 0));
2711 reg = XEXP (XEXP (to, 0), 0);
2712 offset = GET_MODE_SIZE (GET_MODE (to));
2713 if (code == PRE_DEC || code == POST_DEC)
2716 if (code == PRE_DEC || code == PRE_INC)
2717 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2718 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2719 if (code == POST_DEC || code == POST_INC)
2720 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2725 /* Likewise, the source address register must not be used within
2726 the destination operand. */
2727 if (autoinc_from != CONST
2728 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2729 && !IS_STACK_PUSH (to))
2731 /* Must change the source. */
2732 code = GET_CODE (XEXP (from, 0));
2733 reg = XEXP (XEXP (from, 0), 0);
2734 offset = GET_MODE_SIZE (GET_MODE (from));
2735 if (code == PRE_DEC || code == POST_DEC)
2738 if (code == PRE_DEC || code == PRE_INC)
2739 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2740 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2741 if (code == POST_DEC || code == POST_INC)
2742 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2748 if (GET_MODE_SIZE (mode) == 8)
2750 else if (GET_MODE_SIZE (mode) == 4)
2756 && IS_STACK_PUSH (to)
2757 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2763 else if (mode == HImode)
2771 low_to = m68hc11_gen_lowpart (mode, to);
2772 high_to = m68hc11_gen_highpart (mode, to);
2774 low_from = m68hc11_gen_lowpart (mode, from);
2775 high_from = m68hc11_gen_highpart (mode, from);
2779 high_from = adjust_address (high_from, mode, offset);
2780 low_from = high_from;
2783 /* When copying with a POST_INC mode, we must copy the
2784 high part and then the low part to guarantee a correct
2787 && GET_MODE_SIZE (mode) >= 2
2788 && autoinc_from != autoinc_to
2789 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2798 low_from = high_from;
2803 m68hc11_split_move (low_to, low_from, scratch);
2804 m68hc11_split_move (high_to, high_from, scratch);
2806 else if (H_REG_P (to) || H_REG_P (from)
2807 || (low_from == const0_rtx
2808 && high_from == const0_rtx
2809 && ! push_operand (to, GET_MODE (to))
2810 && ! H_REG_P (scratch))
2812 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2813 || m68hc11_small_indexed_indirect_p (from,
2815 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2816 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2818 insn = emit_move_insn (low_to, low_from);
2819 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2821 insn = emit_move_insn (high_to, high_from);
2822 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2826 insn = emit_move_insn (scratch, low_from);
2827 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2828 insn = emit_move_insn (low_to, scratch);
2829 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2831 insn = emit_move_insn (scratch, high_from);
2832 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2833 insn = emit_move_insn (high_to, scratch);
2834 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2839 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2845 if (GET_CODE (operand) != CONST_INT)
2853 val = INTVAL (operand);
2857 if ((val & mask) == 0)
2859 if ((val & mask) == mask)
2860 *result = constm1_rtx;
2864 if ((val & mask) == 0)
2865 *result = const0_rtx;
2866 if ((val & mask) == mask)
2871 if ((val & mask) == 0)
2879 m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
2884 need_copy = (rtx_equal_p (operands[0], operands[1])
2885 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2887 operands[1] = simplify_logical (mode, code, operands[1], &result);
2888 operands[2] = simplify_logical (mode, code, operands[2], &result);
2890 if (result && GET_CODE (result) == CONST_INT)
2892 if (!H_REG_P (operands[0]) && operands[3]
2893 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2895 emit_move_insn (operands[3], result);
2896 emit_move_insn (operands[0], operands[3]);
2900 emit_move_insn (operands[0], result);
2903 else if (operands[1] != 0 && operands[2] != 0)
2907 if (!H_REG_P (operands[0]) && operands[3])
2909 emit_move_insn (operands[3], operands[1]);
2910 emit_insn (gen_rtx_SET (mode,
2912 gen_rtx_fmt_ee (code, mode,
2913 operands[3], operands[2])));
2914 insn = emit_move_insn (operands[0], operands[3]);
2918 insn = emit_insn (gen_rtx_SET (mode,
2920 gen_rtx_fmt_ee (code, mode,
2926 /* The logical operation is similar to a copy. */
2931 if (GET_CODE (operands[1]) == CONST_INT)
2936 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2938 emit_move_insn (operands[3], src);
2939 emit_move_insn (operands[0], operands[3]);
2943 emit_move_insn (operands[0], src);
2949 m68hc11_split_logical (enum machine_mode mode, enum rtx_code code,
2955 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2956 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2957 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2959 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2960 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2961 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2963 low[3] = operands[3];
2964 high[3] = operands[3];
2967 m68hc11_split_logical (HImode, code, low);
2968 m68hc11_split_logical (HImode, code, high);
2972 m68hc11_emit_logical (mode, code, low);
2973 m68hc11_emit_logical (mode, code, high);
2977 /* Code generation. */
2980 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
2982 /* We have to be careful with the cc_status. An address register swap
2983 is generated for some comparison. The comparison is made with D
2984 but the branch really uses the address register. See the split
2985 pattern for compare. The xgdx/xgdy preserve the flags but after
2986 the exchange, the flags will reflect to the value of X and not D.
2987 Tell this by setting the cc_status according to the cc_prev_status. */
2988 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2990 if (cc_prev_status.value1 != 0
2991 && (D_REG_P (cc_prev_status.value1)
2992 || X_REG_P (cc_prev_status.value1)))
2994 cc_status = cc_prev_status;
2995 if (D_REG_P (cc_status.value1))
2996 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
2999 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3005 output_asm_insn ("xgdx", operands);
3009 if (cc_prev_status.value1 != 0
3010 && (D_REG_P (cc_prev_status.value1)
3011 || Y_REG_P (cc_prev_status.value1)))
3013 cc_status = cc_prev_status;
3014 if (D_REG_P (cc_status.value1))
3015 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3018 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3024 output_asm_insn ("xgdy", operands);
3028 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3029 This is used to decide whether a move that set flags should be used
3032 next_insn_test_reg (rtx insn, rtx reg)
3036 insn = next_nonnote_insn (insn);
3037 if (GET_CODE (insn) != INSN)
3040 body = PATTERN (insn);
3041 if (sets_cc0_p (body) != 1)
3044 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3050 /* Generate the code to move a 16-bit operand into another one. */
3053 m68hc11_gen_movhi (rtx insn, rtx *operands)
3057 /* Move a register or memory to the same location.
3058 This is possible because such insn can appear
3059 in a non-optimizing mode. */
3060 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3062 cc_status = cc_prev_status;
3068 rtx from = operands[1];
3069 rtx to = operands[0];
3071 if (IS_STACK_PUSH (to) && H_REG_P (from))
3073 cc_status = cc_prev_status;
3074 switch (REGNO (from))
3079 output_asm_insn ("psh%1", operands);
3081 case HARD_SP_REGNUM:
3082 output_asm_insn ("sts\t2,-sp", operands);
3089 if (IS_STACK_POP (from) && H_REG_P (to))
3091 cc_status = cc_prev_status;
3097 output_asm_insn ("pul%0", operands);
3104 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3106 m68hc11_notice_keep_cc (operands[0]);
3107 output_asm_insn ("tfr\t%1,%0", operands);
3109 else if (H_REG_P (operands[0]))
3111 if (SP_REG_P (operands[0]))
3112 output_asm_insn ("lds\t%1", operands);
3114 output_asm_insn ("ld%0\t%1", operands);
3116 else if (H_REG_P (operands[1]))
3118 if (SP_REG_P (operands[1]))
3119 output_asm_insn ("sts\t%0", operands);
3121 output_asm_insn ("st%1\t%0", operands);
3124 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3125 instruction. We have to use a scratch register as temporary location.
3126 Trying to use a specific pattern or constrain failed. */
3127 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3134 if (dead_register_here (insn, d_reg))
3136 else if (dead_register_here (insn, ix_reg))
3138 else if (dead_register_here (insn, iy_reg))
3144 output_asm_insn ("psh%3", ops);
3149 output_asm_insn ("ld%1\t%2", ops);
3150 output_asm_insn ("st%1\t%0", ops);
3152 output_asm_insn ("pul%3", ops);
3155 /* Use movw for non-null constants or when we are clearing
3156 a volatile memory reference. However, this is possible
3157 only if the memory reference has a small offset or is an
3158 absolute address. */
3159 else if (GET_CODE (from) == CONST_INT
3160 && INTVAL (from) == 0
3161 && (MEM_VOLATILE_P (to) == 0
3162 || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3164 output_asm_insn ("clr\t%h0", operands);
3165 output_asm_insn ("clr\t%b0", operands);
3169 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3170 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3171 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3172 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3178 ops[0] = operands[2];
3181 m68hc11_gen_movhi (insn, ops);
3183 ops[1] = operands[2];
3184 m68hc11_gen_movhi (insn, ops);
3189 /* !!!! SCz wrong here. */
3190 fatal_insn ("move insn not handled", insn);
3195 m68hc11_notice_keep_cc (operands[0]);
3196 output_asm_insn ("movw\t%1,%0", operands);
3202 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3204 cc_status = cc_prev_status;
3205 switch (REGNO (operands[0]))
3209 output_asm_insn ("pul%0", operands);
3212 output_asm_insn ("pula", operands);
3213 output_asm_insn ("pulb", operands);
3220 /* Some moves to a hard register are special. Not all of them
3221 are really supported and we have to use a temporary
3222 location to provide them (either the stack of a temp var). */
3223 if (H_REG_P (operands[0]))
3225 switch (REGNO (operands[0]))
3228 if (X_REG_P (operands[1]))
3230 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3232 m68hc11_output_swap (insn, operands);
3234 else if (next_insn_test_reg (insn, operands[0]))
3236 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3240 m68hc11_notice_keep_cc (operands[0]);
3241 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3244 else if (Y_REG_P (operands[1]))
3246 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3248 m68hc11_output_swap (insn, operands);
3252 /* %t means *ZTMP scratch register. */
3253 output_asm_insn ("sty\t%t1", operands);
3254 output_asm_insn ("ldd\t%t1", operands);
3257 else if (SP_REG_P (operands[1]))
3262 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3263 output_asm_insn ("xgdx", operands);
3264 output_asm_insn ("tsx", operands);
3265 output_asm_insn ("xgdx", operands);
3267 else if (IS_STACK_POP (operands[1]))
3269 output_asm_insn ("pula\n\tpulb", operands);
3271 else if (GET_CODE (operands[1]) == CONST_INT
3272 && INTVAL (operands[1]) == 0)
3274 output_asm_insn ("clra\n\tclrb", operands);
3278 output_asm_insn ("ldd\t%1", operands);
3283 if (D_REG_P (operands[1]))
3285 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3287 m68hc11_output_swap (insn, operands);
3289 else if (next_insn_test_reg (insn, operands[0]))
3291 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3295 m68hc11_notice_keep_cc (operands[0]);
3296 output_asm_insn ("pshb", operands);
3297 output_asm_insn ("psha", operands);
3298 output_asm_insn ("pulx", operands);
3301 else if (Y_REG_P (operands[1]))
3303 /* When both D and Y are dead, use the sequence xgdy, xgdx
3304 to move Y into X. The D and Y registers are modified. */
3305 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3306 && dead_register_here (insn, d_reg))
3308 output_asm_insn ("xgdy", operands);
3309 output_asm_insn ("xgdx", operands);
3312 else if (!optimize_size)
3314 output_asm_insn ("sty\t%t1", operands);
3315 output_asm_insn ("ldx\t%t1", operands);
3320 output_asm_insn ("pshy", operands);
3321 output_asm_insn ("pulx", operands);
3324 else if (SP_REG_P (operands[1]))
3326 /* tsx, tsy preserve the flags */
3327 cc_status = cc_prev_status;
3328 output_asm_insn ("tsx", operands);
3332 output_asm_insn ("ldx\t%1", operands);
3337 if (D_REG_P (operands[1]))
3339 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3341 m68hc11_output_swap (insn, operands);
3345 output_asm_insn ("std\t%t1", operands);
3346 output_asm_insn ("ldy\t%t1", operands);
3349 else if (X_REG_P (operands[1]))
3351 /* When both D and X are dead, use the sequence xgdx, xgdy
3352 to move X into Y. The D and X registers are modified. */
3353 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3354 && dead_register_here (insn, d_reg))
3356 output_asm_insn ("xgdx", operands);
3357 output_asm_insn ("xgdy", operands);
3360 else if (!optimize_size)
3362 output_asm_insn ("stx\t%t1", operands);
3363 output_asm_insn ("ldy\t%t1", operands);
3368 output_asm_insn ("pshx", operands);
3369 output_asm_insn ("puly", operands);
3372 else if (SP_REG_P (operands[1]))
3374 /* tsx, tsy preserve the flags */
3375 cc_status = cc_prev_status;
3376 output_asm_insn ("tsy", operands);
3380 output_asm_insn ("ldy\t%1", operands);
3384 case HARD_SP_REGNUM:
3385 if (D_REG_P (operands[1]))
3387 m68hc11_notice_keep_cc (operands[0]);
3388 output_asm_insn ("xgdx", operands);
3389 output_asm_insn ("txs", operands);
3390 output_asm_insn ("xgdx", operands);
3392 else if (X_REG_P (operands[1]))
3394 /* tys, txs preserve the flags */
3395 cc_status = cc_prev_status;
3396 output_asm_insn ("txs", operands);
3398 else if (Y_REG_P (operands[1]))
3400 /* tys, txs preserve the flags */
3401 cc_status = cc_prev_status;
3402 output_asm_insn ("tys", operands);
3406 /* lds sets the flags but the des does not. */
3408 output_asm_insn ("lds\t%1", operands);
3409 output_asm_insn ("des", operands);
3414 fatal_insn ("invalid register in the move instruction", insn);
3419 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3420 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3422 output_asm_insn ("sts\t%0", operands);
3426 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3428 cc_status = cc_prev_status;
3429 switch (REGNO (operands[1]))
3433 output_asm_insn ("psh%1", operands);
3436 output_asm_insn ("pshb", operands);
3437 output_asm_insn ("psha", operands);
3445 /* Operand 1 must be a hard register. */
3446 if (!H_REG_P (operands[1]))
3448 fatal_insn ("invalid operand in the instruction", insn);
3451 reg = REGNO (operands[1]);
3455 output_asm_insn ("std\t%0", operands);
3459 output_asm_insn ("stx\t%0", operands);
3463 output_asm_insn ("sty\t%0", operands);
3466 case HARD_SP_REGNUM:
3470 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3472 output_asm_insn ("pshx", operands);
3473 output_asm_insn ("tsx", operands);
3474 output_asm_insn ("inx", operands);
3475 output_asm_insn ("inx", operands);
3476 output_asm_insn ("stx\t%0", operands);
3477 output_asm_insn ("pulx", operands);
3480 else if (reg_mentioned_p (ix_reg, operands[0]))
3482 output_asm_insn ("sty\t%t0", operands);
3483 output_asm_insn ("tsy", operands);
3484 output_asm_insn ("sty\t%0", operands);
3485 output_asm_insn ("ldy\t%t0", operands);
3489 output_asm_insn ("stx\t%t0", operands);
3490 output_asm_insn ("tsx", operands);
3491 output_asm_insn ("stx\t%0", operands);
3492 output_asm_insn ("ldx\t%t0", operands);
3498 fatal_insn ("invalid register in the move instruction", insn);
3504 m68hc11_gen_movqi (rtx insn, rtx *operands)
3506 /* Move a register or memory to the same location.
3507 This is possible because such insn can appear
3508 in a non-optimizing mode. */
3509 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3511 cc_status = cc_prev_status;
3518 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3520 m68hc11_notice_keep_cc (operands[0]);
3521 output_asm_insn ("tfr\t%1,%0", operands);
3523 else if (H_REG_P (operands[0]))
3525 if (IS_STACK_POP (operands[1]))
3526 output_asm_insn ("pul%b0", operands);
3527 else if (Q_REG_P (operands[0]))
3528 output_asm_insn ("lda%0\t%b1", operands);
3529 else if (D_REG_P (operands[0]))
3530 output_asm_insn ("ldab\t%b1", operands);
3534 else if (H_REG_P (operands[1]))
3536 if (Q_REG_P (operands[1]))
3537 output_asm_insn ("sta%1\t%b0", operands);
3538 else if (D_REG_P (operands[1]))
3539 output_asm_insn ("stab\t%b0", operands);
3545 rtx from = operands[1];
3546 rtx to = operands[0];
3548 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3549 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3550 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3551 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3557 ops[0] = operands[2];
3560 m68hc11_gen_movqi (insn, ops);
3562 ops[1] = operands[2];
3563 m68hc11_gen_movqi (insn, ops);
3567 /* !!!! SCz wrong here. */
3568 fatal_insn ("move insn not handled", insn);
3573 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3575 output_asm_insn ("clr\t%b0", operands);
3579 m68hc11_notice_keep_cc (operands[0]);
3580 output_asm_insn ("movb\t%b1,%b0", operands);
3588 if (H_REG_P (operands[0]))
3590 switch (REGNO (operands[0]))
3594 if (X_REG_P (operands[1]))
3596 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3598 m68hc11_output_swap (insn, operands);
3602 output_asm_insn ("stx\t%t1", operands);
3603 output_asm_insn ("ldab\t%T0", operands);
3606 else if (Y_REG_P (operands[1]))
3608 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3610 m68hc11_output_swap (insn, operands);
3614 output_asm_insn ("sty\t%t1", operands);
3615 output_asm_insn ("ldab\t%T0", operands);
3618 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3619 && !DA_REG_P (operands[1]))
3621 output_asm_insn ("ldab\t%b1", operands);
3623 else if (DA_REG_P (operands[1]))
3625 output_asm_insn ("tab", operands);
3629 cc_status = cc_prev_status;
3635 if (X_REG_P (operands[1]))
3637 output_asm_insn ("stx\t%t1", operands);
3638 output_asm_insn ("ldaa\t%T0", operands);
3640 else if (Y_REG_P (operands[1]))
3642 output_asm_insn ("sty\t%t1", operands);
3643 output_asm_insn ("ldaa\t%T0", operands);
3645 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3646 && !DA_REG_P (operands[1]))
3648 output_asm_insn ("ldaa\t%b1", operands);
3650 else if (!DA_REG_P (operands[1]))
3652 output_asm_insn ("tba", operands);
3656 cc_status = cc_prev_status;
3661 if (D_REG_P (operands[1]))
3663 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3665 m68hc11_output_swap (insn, operands);
3669 output_asm_insn ("stab\t%T1", operands);
3670 output_asm_insn ("ldx\t%t1", operands);
3674 else if (Y_REG_P (operands[1]))
3676 output_asm_insn ("sty\t%t0", operands);
3677 output_asm_insn ("ldx\t%t0", operands);
3679 else if (GET_CODE (operands[1]) == CONST_INT)
3681 output_asm_insn ("ldx\t%1", operands);
3683 else if (dead_register_here (insn, d_reg))
3685 output_asm_insn ("ldab\t%b1", operands);
3686 output_asm_insn ("xgdx", operands);
3688 else if (!reg_mentioned_p (operands[0], operands[1]))
3690 output_asm_insn ("xgdx", operands);
3691 output_asm_insn ("ldab\t%b1", operands);
3692 output_asm_insn ("xgdx", operands);
3696 output_asm_insn ("pshb", operands);
3697 output_asm_insn ("ldab\t%b1", operands);
3698 output_asm_insn ("stab\t%T1", operands);
3699 output_asm_insn ("ldx\t%t1", operands);
3700 output_asm_insn ("pulb", operands);
3706 if (D_REG_P (operands[1]))
3708 output_asm_insn ("stab\t%T1", operands);
3709 output_asm_insn ("ldy\t%t1", operands);
3712 else if (X_REG_P (operands[1]))
3714 output_asm_insn ("stx\t%t1", operands);
3715 output_asm_insn ("ldy\t%t1", operands);
3718 else if (GET_CODE (operands[1]) == CONST_INT)
3720 output_asm_insn ("ldy\t%1", operands);
3722 else if (dead_register_here (insn, d_reg))
3724 output_asm_insn ("ldab\t%b1", operands);
3725 output_asm_insn ("xgdy", operands);
3727 else if (!reg_mentioned_p (operands[0], operands[1]))
3729 output_asm_insn ("xgdy", operands);
3730 output_asm_insn ("ldab\t%b1", operands);
3731 output_asm_insn ("xgdy", operands);
3735 output_asm_insn ("pshb", operands);
3736 output_asm_insn ("ldab\t%b1", operands);
3737 output_asm_insn ("stab\t%T1", operands);
3738 output_asm_insn ("ldy\t%t1", operands);
3739 output_asm_insn ("pulb", operands);
3745 fatal_insn ("invalid register in the instruction", insn);
3749 else if (H_REG_P (operands[1]))
3751 switch (REGNO (operands[1]))
3755 output_asm_insn ("stab\t%b0", operands);
3759 output_asm_insn ("staa\t%b0", operands);
3763 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3767 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3771 fatal_insn ("invalid register in the move instruction", insn);
3778 fatal_insn ("operand 1 must be a hard register", insn);
3782 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3783 The source and destination must be D or A and the shift must
3786 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3790 if (GET_CODE (operands[2]) != CONST_INT
3791 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3792 fatal_insn ("invalid rotate insn", insn);
3794 val = INTVAL (operands[2]);
3795 if (code == ROTATERT)
3796 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3798 if (GET_MODE (operands[0]) != QImode)
3801 /* Rotate by 8-bits if the shift is within [5..11]. */
3802 if (val >= 5 && val <= 11)
3805 output_asm_insn ("exg\ta,b", operands);
3808 output_asm_insn ("psha", operands);
3809 output_asm_insn ("tba", operands);
3810 output_asm_insn ("pulb", operands);
3815 /* If the shift is big, invert the rotation. */
3825 /* Set the carry to bit-15, but don't change D yet. */
3826 if (GET_MODE (operands[0]) != QImode)
3828 output_asm_insn ("asra", operands);
3829 output_asm_insn ("rola", operands);
3832 /* Rotate B first to move the carry to bit-0. */
3833 if (D_REG_P (operands[0]))
3834 output_asm_insn ("rolb", operands);
3836 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3837 output_asm_insn ("rola", operands);
3844 /* Set the carry to bit-8 of D. */
3845 if (GET_MODE (operands[0]) != QImode)
3846 output_asm_insn ("tap", operands);
3848 /* Rotate B first to move the carry to bit-7. */
3849 if (D_REG_P (operands[0]))
3850 output_asm_insn ("rorb", operands);
3852 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3853 output_asm_insn ("rora", operands);
3860 /* Store in cc_status the expressions that the condition codes will
3861 describe after execution of an instruction whose pattern is EXP.
3862 Do not alter them if the instruction would not alter the cc's. */
3865 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3867 /* recognize SET insn's. */
3868 if (GET_CODE (exp) == SET)
3870 /* Jumps do not alter the cc's. */
3871 if (SET_DEST (exp) == pc_rtx)
3874 /* NOTE: most instructions don't affect the carry bit, but the
3875 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3876 the conditions.h header. */
3878 /* Function calls clobber the cc's. */
3879 else if (GET_CODE (SET_SRC (exp)) == CALL)
3884 /* Tests and compares set the cc's in predictable ways. */
3885 else if (SET_DEST (exp) == cc0_rtx)
3887 cc_status.flags = 0;
3888 cc_status.value1 = XEXP (exp, 0);
3889 if (GET_CODE (XEXP (exp, 1)) == COMPARE
3890 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
3891 cc_status.value2 = XEXP (XEXP (exp, 1), 0);
3893 cc_status.value2 = XEXP (exp, 1);
3897 /* All other instructions affect the condition codes. */
3898 cc_status.flags = 0;
3899 cc_status.value1 = XEXP (exp, 0);
3900 cc_status.value2 = XEXP (exp, 1);
3905 /* Default action if we haven't recognized something
3906 and returned earlier. */
3910 if (cc_status.value2 != 0)
3911 switch (GET_CODE (cc_status.value2))
3913 /* These logical operations can generate several insns.
3914 The flags are setup according to what is generated. */
3920 /* The (not ...) generates several 'com' instructions for
3921 non QImode. We have to invalidate the flags. */
3923 if (GET_MODE (cc_status.value2) != QImode)
3935 if (GET_MODE (cc_status.value2) != VOIDmode)
3936 cc_status.flags |= CC_NO_OVERFLOW;
3939 /* The asl sets the overflow bit in such a way that this
3940 makes the flags unusable for a next compare insn. */
3944 if (GET_MODE (cc_status.value2) != VOIDmode)
3945 cc_status.flags |= CC_NO_OVERFLOW;
3948 /* A load/store instruction does not affect the carry. */
3953 cc_status.flags |= CC_NO_OVERFLOW;
3959 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3961 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3962 cc_status.value2 = 0;
3964 else if (cc_status.value1 && side_effects_p (cc_status.value1))
3965 cc_status.value1 = 0;
3967 else if (cc_status.value2 && side_effects_p (cc_status.value2))
3968 cc_status.value2 = 0;
3971 /* The current instruction does not affect the flags but changes
3972 the register 'reg'. See if the previous flags can be kept for the
3973 next instruction to avoid a comparison. */
3975 m68hc11_notice_keep_cc (rtx reg)
3978 || cc_prev_status.value1 == 0
3979 || rtx_equal_p (reg, cc_prev_status.value1)
3980 || (cc_prev_status.value2
3981 && reg_mentioned_p (reg, cc_prev_status.value2)))
3984 cc_status = cc_prev_status;
3989 /* Machine Specific Reorg. */
3991 /* Z register replacement:
3993 GCC treats the Z register as an index base address register like
3994 X or Y. In general, it uses it during reload to compute the address
3995 of some operand. This helps the reload pass to avoid to fall into the
3996 register spill failure.
3998 The Z register is in the A_REGS class. In the machine description,
3999 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4001 It can appear everywhere an X or Y register can appear, except for
4002 some templates in the clobber section (when a clobber of X or Y is asked).
4003 For a given instruction, the template must ensure that no more than
4004 2 'A' registers are used. Otherwise, the register replacement is not
4007 To replace the Z register, the algorithm is not terrific:
4008 1. Insns that do not use the Z register are not changed
4009 2. When a Z register is used, we scan forward the insns to see
4010 a potential register to use: either X or Y and sometimes D.
4011 We stop when a call, a label or a branch is seen, or when we
4012 detect that both X and Y are used (probably at different times, but it does
4014 3. The register that will be used for the replacement of Z is saved
4015 in a .page0 register or on the stack. If the first instruction that
4016 used Z, uses Z as an input, the value is loaded from another .page0
4017 register. The replacement register is pushed on the stack in the
4018 rare cases where a compare insn uses Z and we couldn't find if X/Y
4020 4. The Z register is replaced in all instructions until we reach
4021 the end of the Z-block, as detected by step 2.
4022 5. If we detect that Z is still alive, its value is saved.
4023 If the replacement register is alive, its old value is loaded.
4025 The Z register can be disabled with -ffixed-z.
4035 int must_restore_reg;
4046 int save_before_last;
4047 int z_loaded_with_sp;
4050 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4051 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4052 static void m68hc11_z_replacement (rtx);
4053 static void m68hc11_reassign_regs (rtx);
4055 int z_replacement_completed = 0;
4057 /* Analyze the insn to find out which replacement register to use and
4058 the boundaries of the replacement.
4059 Returns 0 if we reached the last insn to be replaced, 1 if we can
4060 continue replacement in next insns. */
4063 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4065 int this_insn_uses_ix;
4066 int this_insn_uses_iy;
4067 int this_insn_uses_z;
4068 int this_insn_uses_z_in_dst;
4069 int this_insn_uses_d;
4073 /* A call is said to clobber the Z register, we don't need
4074 to save the value of Z. We also don't need to restore
4075 the replacement register (unless it is used by the call). */
4076 if (GET_CODE (insn) == CALL_INSN)
4078 body = PATTERN (insn);
4080 info->can_use_d = 0;
4082 /* If the call is an indirect call with Z, we have to use the
4083 Y register because X can be used as an input (D+X).
4084 We also must not save Z nor restore Y. */
4085 if (reg_mentioned_p (z_reg, body))
4087 insn = NEXT_INSN (insn);
4090 info->found_call = 1;
4091 info->must_restore_reg = 0;
4092 info->last = NEXT_INSN (insn);
4094 info->need_save_z = 0;
4097 if (GET_CODE (insn) == CODE_LABEL
4098 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4101 if (GET_CODE (insn) == JUMP_INSN)
4103 if (reg_mentioned_p (z_reg, insn) == 0)
4106 info->can_use_d = 0;
4107 info->must_save_reg = 0;
4108 info->must_restore_reg = 0;
4109 info->need_save_z = 0;
4110 info->last = NEXT_INSN (insn);
4113 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4118 /* Z register dies here. */
4119 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4121 body = PATTERN (insn);
4122 if (GET_CODE (body) == SET)
4124 rtx src = XEXP (body, 1);
4125 rtx dst = XEXP (body, 0);
4127 /* Condition code is set here. We have to restore the X/Y and
4128 save into Z before any test/compare insn because once we save/restore
4129 we can change the condition codes. When the compare insn uses Z and
4130 we can't use X/Y, the comparison is made with the *ZREG soft register
4131 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4134 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4135 || (GET_CODE (src) == COMPARE &&
4136 ((rtx_equal_p (XEXP (src, 0), z_reg)
4137 && H_REG_P (XEXP (src, 1)))
4138 || (rtx_equal_p (XEXP (src, 1), z_reg)
4139 && H_REG_P (XEXP (src, 0))))))
4141 if (insn == info->first)
4143 info->must_load_z = 0;
4144 info->must_save_reg = 0;
4145 info->must_restore_reg = 0;
4146 info->need_save_z = 0;
4147 info->found_call = 1;
4148 info->regno = SOFT_Z_REGNUM;
4149 info->last = NEXT_INSN (insn);
4153 if (reg_mentioned_p (z_reg, src) == 0)
4155 info->can_use_d = 0;
4159 if (insn != info->first)
4162 /* Compare insn which uses Z. We have to save/restore the X/Y
4163 register without modifying the condition codes. For this
4164 we have to use a push/pop insn. */
4165 info->must_push_reg = 1;
4169 /* Z reg is set to something new. We don't need to load it. */
4172 if (!reg_mentioned_p (z_reg, src))
4174 /* Z reg is used before being set. Treat this as
4175 a new sequence of Z register replacement. */
4176 if (insn != info->first)
4180 info->must_load_z = 0;
4182 info->z_set_count++;
4183 info->z_value = src;
4185 info->z_loaded_with_sp = 1;
4187 else if (reg_mentioned_p (z_reg, dst))
4188 info->can_use_d = 0;
4190 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4191 | reg_mentioned_p (d_reg, dst);
4192 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4193 | reg_mentioned_p (ix_reg, dst);
4194 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4195 | reg_mentioned_p (iy_reg, dst);
4196 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4198 /* If z is used as an address operand (like (MEM (reg z))),
4199 we can't replace it with d. */
4200 if (this_insn_uses_z && !Z_REG_P (src)
4201 && !(m68hc11_arith_operator (src, GET_MODE (src))
4202 && Z_REG_P (XEXP (src, 0))
4203 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4204 && insn == info->first
4205 && dead_register_here (insn, d_reg)))
4206 info->can_use_d = 0;
4208 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4209 if (TARGET_M6812 && !z_dies_here
4210 && ((this_insn_uses_z && side_effects_p (src))
4211 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4213 info->need_save_z = 1;
4214 info->z_set_count++;
4216 this_insn_uses_z |= this_insn_uses_z_in_dst;
4218 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4220 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4223 if (this_insn_uses_d)
4224 info->can_use_d = 0;
4226 /* IX and IY are used at the same time, we have to restore
4227 the value of the scratch register before this insn. */
4228 if (this_insn_uses_ix && this_insn_uses_iy)
4233 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4234 info->can_use_d = 0;
4236 if (info->x_used == 0 && this_insn_uses_ix)
4240 /* We have a (set (REG:HI X) (REG:HI Z)).
4241 Since we use Z as the replacement register, this insn
4242 is no longer necessary. We turn it into a note. We must
4243 not reload the old value of X. */
4244 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4248 info->need_save_z = 0;
4251 info->must_save_reg = 0;
4252 info->must_restore_reg = 0;
4253 info->found_call = 1;
4254 info->can_use_d = 0;
4255 SET_INSN_DELETED (insn);
4256 info->last = NEXT_INSN (insn);
4261 && (rtx_equal_p (src, z_reg)
4262 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4266 info->need_save_z = 0;
4269 info->last = NEXT_INSN (insn);
4270 info->must_save_reg = 0;
4271 info->must_restore_reg = 0;
4273 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4274 && !reg_mentioned_p (ix_reg, src))
4279 info->need_save_z = 0;
4281 else if (TARGET_M6812 && side_effects_p (src))
4284 info->must_restore_reg = 0;
4289 info->save_before_last = 1;
4291 info->must_restore_reg = 0;
4292 info->last = NEXT_INSN (insn);
4294 else if (info->can_use_d)
4296 info->last = NEXT_INSN (insn);
4302 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4303 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4305 info->need_save_z = 0;
4307 info->last = NEXT_INSN (insn);
4308 info->regno = HARD_X_REGNUM;
4309 info->must_save_reg = 0;
4310 info->must_restore_reg = 0;
4313 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4315 info->regno = HARD_X_REGNUM;
4316 info->must_restore_reg = 0;
4317 info->must_save_reg = 0;
4321 if (info->y_used == 0 && this_insn_uses_iy)
4325 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4329 info->need_save_z = 0;
4332 info->must_save_reg = 0;
4333 info->must_restore_reg = 0;
4334 info->found_call = 1;
4335 info->can_use_d = 0;
4336 SET_INSN_DELETED (insn);
4337 info->last = NEXT_INSN (insn);
4342 && (rtx_equal_p (src, z_reg)
4343 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4348 info->need_save_z = 0;
4350 info->last = NEXT_INSN (insn);
4351 info->must_save_reg = 0;
4352 info->must_restore_reg = 0;
4354 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4355 && !reg_mentioned_p (iy_reg, src))
4360 info->need_save_z = 0;
4362 else if (TARGET_M6812 && side_effects_p (src))
4365 info->must_restore_reg = 0;
4370 info->save_before_last = 1;
4372 info->must_restore_reg = 0;
4373 info->last = NEXT_INSN (insn);
4375 else if (info->can_use_d)
4377 info->last = NEXT_INSN (insn);
4384 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4385 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4387 info->need_save_z = 0;
4389 info->last = NEXT_INSN (insn);
4390 info->regno = HARD_Y_REGNUM;
4391 info->must_save_reg = 0;
4392 info->must_restore_reg = 0;
4395 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4397 info->regno = HARD_Y_REGNUM;
4398 info->must_restore_reg = 0;
4399 info->must_save_reg = 0;
4405 info->need_save_z = 0;
4407 if (info->last == 0)
4408 info->last = NEXT_INSN (insn);
4411 return info->last != NULL_RTX ? 0 : 1;
4413 if (GET_CODE (body) == PARALLEL)
4416 char ix_clobber = 0;
4417 char iy_clobber = 0;
4419 this_insn_uses_iy = 0;
4420 this_insn_uses_ix = 0;
4421 this_insn_uses_z = 0;
4423 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4426 int uses_ix, uses_iy, uses_z;
4428 x = XVECEXP (body, 0, i);
4430 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4431 info->can_use_d = 0;
4433 uses_ix = reg_mentioned_p (ix_reg, x);
4434 uses_iy = reg_mentioned_p (iy_reg, x);
4435 uses_z = reg_mentioned_p (z_reg, x);
4436 if (GET_CODE (x) == CLOBBER)
4438 ix_clobber |= uses_ix;
4439 iy_clobber |= uses_iy;
4440 z_clobber |= uses_z;
4444 this_insn_uses_ix |= uses_ix;
4445 this_insn_uses_iy |= uses_iy;
4446 this_insn_uses_z |= uses_z;
4448 if (uses_z && GET_CODE (x) == SET)
4450 rtx dst = XEXP (x, 0);
4453 info->z_set_count++;
4455 if (TARGET_M6812 && uses_z && side_effects_p (x))
4456 info->need_save_z = 1;
4459 info->need_save_z = 0;
4463 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4464 this_insn_uses_ix, this_insn_uses_iy,
4465 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4468 if (this_insn_uses_z)
4469 info->can_use_d = 0;
4471 if (z_clobber && info->first != insn)
4473 info->need_save_z = 0;
4477 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4479 if (this_insn_uses_z == 0 && insn == info->first)
4481 info->must_load_z = 0;
4483 if (dead_register_here (insn, d_reg))
4485 info->regno = HARD_D_REGNUM;
4486 info->must_save_reg = 0;
4487 info->must_restore_reg = 0;
4489 else if (dead_register_here (insn, ix_reg))
4491 info->regno = HARD_X_REGNUM;
4492 info->must_save_reg = 0;
4493 info->must_restore_reg = 0;
4495 else if (dead_register_here (insn, iy_reg))
4497 info->regno = HARD_Y_REGNUM;
4498 info->must_save_reg = 0;
4499 info->must_restore_reg = 0;
4501 if (info->regno >= 0)
4503 info->last = NEXT_INSN (insn);
4506 if (this_insn_uses_ix == 0)
4508 info->regno = HARD_X_REGNUM;
4509 info->must_save_reg = 1;
4510 info->must_restore_reg = 1;
4512 else if (this_insn_uses_iy == 0)
4514 info->regno = HARD_Y_REGNUM;
4515 info->must_save_reg = 1;
4516 info->must_restore_reg = 1;
4520 info->regno = HARD_D_REGNUM;
4521 info->must_save_reg = 1;
4522 info->must_restore_reg = 1;
4524 info->last = NEXT_INSN (insn);
4528 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4529 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4531 if (this_insn_uses_z)
4533 if (info->y_used == 0 && iy_clobber)
4535 info->regno = HARD_Y_REGNUM;
4536 info->must_save_reg = 0;
4537 info->must_restore_reg = 0;
4539 if (info->first != insn
4540 && ((info->y_used && ix_clobber)
4541 || (info->x_used && iy_clobber)))
4544 info->last = NEXT_INSN (insn);
4545 info->save_before_last = 1;
4549 if (this_insn_uses_ix && this_insn_uses_iy)
4551 if (this_insn_uses_z)
4553 fatal_insn ("cannot do z-register replacement", insn);
4557 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4564 if (iy_clobber || z_clobber)
4566 info->last = NEXT_INSN (insn);
4567 info->save_before_last = 1;
4572 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4579 if (ix_clobber || z_clobber)
4581 info->last = NEXT_INSN (insn);
4582 info->save_before_last = 1;
4589 info->need_save_z = 0;
4593 if (GET_CODE (body) == CLOBBER)
4596 /* IX and IY are used at the same time, we have to restore
4597 the value of the scratch register before this insn. */
4598 if (this_insn_uses_ix && this_insn_uses_iy)
4602 if (info->x_used == 0 && this_insn_uses_ix)
4610 if (info->y_used == 0 && this_insn_uses_iy)
4624 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4628 info->replace_reg = NULL_RTX;
4629 info->must_load_z = 1;
4630 info->need_save_z = 1;
4631 info->must_save_reg = 1;
4632 info->must_restore_reg = 1;
4636 info->can_use_d = TARGET_M6811 ? 1 : 0;
4637 info->found_call = 0;
4641 info->z_set_count = 0;
4642 info->z_value = NULL_RTX;
4643 info->must_push_reg = 0;
4644 info->save_before_last = 0;
4645 info->z_loaded_with_sp = 0;
4647 /* Scan the insn forward to find an address register that is not used.
4649 - the flow of the program changes,
4650 - when we detect that both X and Y are necessary,
4651 - when the Z register dies,
4652 - when the condition codes are set. */
4654 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4656 if (m68hc11_check_z_replacement (insn, info) == 0)
4660 /* May be we can use Y or X if they contain the same value as Z.
4661 This happens very often after the reload. */
4662 if (info->z_set_count == 1)
4664 rtx p = info->first;
4669 v = find_last_value (iy_reg, &p, insn, 1);
4671 else if (info->y_used)
4673 v = find_last_value (ix_reg, &p, insn, 1);
4675 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4678 info->regno = HARD_Y_REGNUM;
4680 info->regno = HARD_X_REGNUM;
4681 info->must_load_z = 0;
4682 info->must_save_reg = 0;
4683 info->must_restore_reg = 0;
4684 info->found_call = 1;
4687 if (info->z_set_count == 0)
4688 info->need_save_z = 0;
4691 info->need_save_z = 0;
4693 if (info->last == 0)
4696 if (info->regno >= 0)
4699 info->replace_reg = gen_rtx_REG (HImode, reg);
4701 else if (info->can_use_d)
4703 reg = HARD_D_REGNUM;
4704 info->replace_reg = d_reg;
4706 else if (info->x_used)
4708 reg = HARD_Y_REGNUM;
4709 info->replace_reg = iy_reg;
4713 reg = HARD_X_REGNUM;
4714 info->replace_reg = ix_reg;
4718 if (info->must_save_reg && info->must_restore_reg)
4720 if (insn && dead_register_here (insn, info->replace_reg))
4722 info->must_save_reg = 0;
4723 info->must_restore_reg = 0;
4728 /* The insn uses the Z register. Find a replacement register for it
4729 (either X or Y) and replace it in the insn and the next ones until
4730 the flow changes or the replacement register is used. Instructions
4731 are emitted before and after the Z-block to preserve the value of
4732 Z and of the replacement register. */
4735 m68hc11_z_replacement (rtx insn)
4739 struct replace_info info;
4741 /* Find trivial case where we only need to replace z with the
4742 equivalent soft register. */
4743 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4745 rtx body = PATTERN (insn);
4746 rtx src = XEXP (body, 1);
4747 rtx dst = XEXP (body, 0);
4749 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4751 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4754 else if (Z_REG_P (src)
4755 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4757 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4760 else if (D_REG_P (dst)
4761 && m68hc11_arith_operator (src, GET_MODE (src))
4762 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4764 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4767 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4768 && INTVAL (src) == 0)
4770 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4771 /* Force it to be re-recognized. */
4772 INSN_CODE (insn) = -1;
4777 m68hc11_find_z_replacement (insn, &info);
4779 replace_reg = info.replace_reg;
4780 replace_reg_qi = NULL_RTX;
4782 /* Save the X register in a .page0 location. */
4783 if (info.must_save_reg && !info.must_push_reg)
4787 if (info.must_push_reg && 0)
4788 dst = gen_rtx_MEM (HImode,
4789 gen_rtx_PRE_DEC (HImode,
4790 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4792 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4794 emit_insn_before (gen_movhi (dst,
4795 gen_rtx_REG (HImode, info.regno)), insn);
4797 if (info.must_load_z && !info.must_push_reg)
4799 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4800 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4805 /* Replace all occurrence of Z by replace_reg.
4806 Stop when the last instruction to replace is reached.
4807 Also stop when we detect a change in the flow (but it's not
4808 necessary; just safeguard). */
4810 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4814 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4817 if (GET_CODE (insn) != INSN
4818 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4821 body = PATTERN (insn);
4822 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4823 || GET_CODE (body) == ASM_OPERANDS
4824 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4828 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4830 printf ("Reg mentioned here...:\n");
4835 /* Stack pointer was decremented by 2 due to the push.
4836 Correct that by adding 2 to the destination. */
4837 if (info.must_push_reg
4838 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4842 src = SET_SRC (body);
4843 dst = SET_DEST (body);
4844 if (SP_REG_P (src) && Z_REG_P (dst))
4845 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4848 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4849 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4851 INSN_CODE (insn) = -1;
4852 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4853 fatal_insn ("cannot do z-register replacement", insn);
4856 /* Likewise for (REG:QI Z). */
4857 if (reg_mentioned_p (z_reg, insn))
4859 if (replace_reg_qi == NULL_RTX)
4860 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4861 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4864 /* If there is a REG_INC note on Z, replace it with a
4865 REG_INC note on the replacement register. This is necessary
4866 to make sure that the flow pass will identify the change
4867 and it will not remove a possible insn that saves Z. */
4868 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4870 if (REG_NOTE_KIND (note) == REG_INC
4871 && GET_CODE (XEXP (note, 0)) == REG
4872 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4874 XEXP (note, 0) = replace_reg;
4878 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4882 /* Save Z before restoring the old value. */
4883 if (insn && info.need_save_z && !info.must_push_reg)
4885 rtx save_pos_insn = insn;
4887 /* If Z is clobber by the last insn, we have to save its value
4888 before the last instruction. */
4889 if (info.save_before_last)
4890 save_pos_insn = PREV_INSN (save_pos_insn);
4892 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4893 gen_rtx_REG (HImode, info.regno)),
4897 if (info.must_push_reg && info.last)
4901 body = PATTERN (info.last);
4902 new_body = gen_rtx_PARALLEL (VOIDmode,
4904 gen_rtx_USE (VOIDmode,
4906 gen_rtx_USE (VOIDmode,
4907 gen_rtx_REG (HImode,
4909 PATTERN (info.last) = new_body;
4911 /* Force recognition on insn since we changed it. */
4912 INSN_CODE (insn) = -1;
4914 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4916 fatal_insn ("invalid Z register replacement for insn", insn);
4918 insn = NEXT_INSN (info.last);
4921 /* Restore replacement register unless it was died. */
4922 if (insn && info.must_restore_reg && !info.must_push_reg)
4926 if (info.must_push_reg && 0)
4927 dst = gen_rtx_MEM (HImode,
4928 gen_rtx_POST_INC (HImode,
4929 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4931 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4933 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4940 /* Scan all the insn and re-affects some registers
4941 - The Z register (if it was used), is affected to X or Y depending
4942 on the instruction. */
4945 m68hc11_reassign_regs (rtx first)
4949 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4950 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4951 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4952 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4954 /* Scan all insns to replace Z by X or Y preserving the old value
4955 of X/Y and restoring it afterward. */
4957 for (insn = first; insn; insn = NEXT_INSN (insn))
4961 if (GET_CODE (insn) == CODE_LABEL
4962 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4968 body = PATTERN (insn);
4969 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4972 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4973 || GET_CODE (body) == ASM_OPERANDS
4974 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4977 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4978 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4981 /* If Z appears in this insn, replace it in the current insn
4982 and the next ones until the flow changes or we have to
4983 restore back the replacement register. */
4985 if (reg_mentioned_p (z_reg, body))
4987 m68hc11_z_replacement (insn);
4992 printf ("insn not handled by Z replacement:\n");
5000 /* Machine-dependent reorg pass.
5001 Specific optimizations are defined here:
5002 - this pass changes the Z register into either X or Y
5003 (it preserves X/Y previous values in a memory slot in page0).
5005 When this pass is finished, the global variable
5006 'z_replacement_completed' is set to 2. */
5009 m68hc11_reorg (void)
5014 z_replacement_completed = 0;
5015 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5016 first = get_insns ();
5018 /* Some RTX are shared at this point. This breaks the Z register
5019 replacement, unshare everything. */
5020 unshare_all_rtl_again (first);
5022 /* Force a split of all splittable insn. This is necessary for the
5023 Z register replacement mechanism because we end up with basic insns. */
5024 split_all_insns_noflow ();
5027 z_replacement_completed = 1;
5028 m68hc11_reassign_regs (first);
5031 compute_bb_for_insn ();
5033 /* After some splitting, there are some opportunities for CSE pass.
5034 This happens quite often when 32-bit or above patterns are split. */
5035 if (optimize > 0 && split_done)
5037 reload_cse_regs (first);
5040 /* Re-create the REG_DEAD notes. These notes are used in the machine
5041 description to use the best assembly directives. */
5044 df_note_add_problem ();
5046 df_remove_problem (df_note);
5049 z_replacement_completed = 2;
5051 /* If optimizing, then go ahead and split insns that must be
5052 split after Z register replacement. This gives more opportunities
5053 for peephole (in particular for consecutives xgdx/xgdy). */
5055 split_all_insns_noflow ();
5057 /* Once insns are split after the z_replacement_completed == 2,
5058 we must not re-run the life_analysis. The xgdx/xgdy patterns
5059 are not recognized and the life_analysis pass removes some
5060 insns because it thinks some (SETs) are noops or made to dead
5061 stores (which is false due to the swap).
5063 Do a simple pass to eliminate the noop set that the final
5064 split could generate (because it was easier for split definition). */
5068 for (insn = first; insn; insn = NEXT_INSN (insn))
5072 if (INSN_DELETED_P (insn))
5077 /* Remove the (set (R) (R)) insns generated by some splits. */
5078 body = PATTERN (insn);
5079 if (GET_CODE (body) == SET
5080 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5082 SET_INSN_DELETED (insn);
5089 /* Override memcpy */
5092 m68hc11_init_libfuncs (void)
5094 memcpy_libfunc = init_one_libfunc ("__memcpy");
5095 memcmp_libfunc = init_one_libfunc ("__memcmp");
5096 memset_libfunc = init_one_libfunc ("__memset");
5101 /* Cost functions. */
5103 /* Cost of moving memory. */
5105 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
5106 int in ATTRIBUTE_UNUSED)
5108 if (rclass <= H_REGS && rclass > NO_REGS)
5110 if (GET_MODE_SIZE (mode) <= 2)
5111 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5113 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5117 if (GET_MODE_SIZE (mode) <= 2)
5118 return COSTS_N_INSNS (3);
5120 return COSTS_N_INSNS (4);
5125 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5126 Reload does not check the constraint of set insns when the two registers
5127 have a move cost of 2. Setting a higher cost will force reload to check
5130 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5133 /* All costs are symmetric, so reduce cases by putting the
5134 lower number class as the destination. */
5137 enum reg_class tmp = to;
5138 to = from, from = tmp;
5141 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5142 else if (from <= S_REGS)
5143 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5145 return COSTS_N_INSNS (2);
5149 /* Provide the costs of an addressing mode that contains ADDR.
5150 If ADDR is not a valid address, its cost is irrelevant. */
5153 m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
5157 switch (GET_CODE (addr))
5160 /* Make the cost of hard registers and specially SP, FP small. */
5161 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5178 register rtx plus0 = XEXP (addr, 0);
5179 register rtx plus1 = XEXP (addr, 1);
5181 if (GET_CODE (plus0) != REG)
5184 switch (GET_CODE (plus1))
5187 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5188 || INTVAL (plus1) < m68hc11_min_offset)
5190 else if (INTVAL (plus1) >= m68hc11_max_offset)
5194 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5216 if (SP_REG_P (XEXP (addr, 0)))
5225 printf ("Address cost: %d for :", cost);
5234 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5238 total = rtx_cost (x, SET, !optimize_size);
5240 total += m68hc11_cost->shiftQI_const[shift % 8];
5241 else if (mode == HImode)
5242 total += m68hc11_cost->shiftHI_const[shift % 16];
5243 else if (shift == 8 || shift == 16 || shift == 32)
5244 total += m68hc11_cost->shiftHI_const[8];
5245 else if (shift != 0 && shift != 16 && shift != 32)
5247 total += m68hc11_cost->shiftHI_const[1] * shift;
5250 /* For SI and others, the cost is higher. */
5251 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5252 total *= GET_MODE_SIZE (mode) / 2;
5254 /* When optimizing for size, make shift more costly so that
5255 multiplications are preferred. */
5256 if (optimize_size && (shift % 8) != 0)
5263 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5264 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5266 enum machine_mode mode = GET_MODE (x);
5277 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5279 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5282 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5283 total += m68hc11_cost->shift_var;
5289 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5290 total += m68hc11_cost->logical;
5292 /* Logical instructions are byte instructions only. */
5293 total *= GET_MODE_SIZE (mode);
5298 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5299 total += m68hc11_cost->add;
5300 if (GET_MODE_SIZE (mode) > 2)
5302 total *= GET_MODE_SIZE (mode) / 2;
5309 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5313 total += m68hc11_cost->divQI;
5317 total += m68hc11_cost->divHI;
5322 total += m68hc11_cost->divSI;
5328 /* mul instruction produces 16-bit result. */
5329 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5330 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5331 return m68hc11_cost->multQI
5332 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5333 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5335 /* emul instruction produces 32-bit result for 68HC12. */
5336 if (TARGET_M6812 && mode == SImode
5337 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5338 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5339 return m68hc11_cost->multHI
5340 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5341 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5343 total = rtx_cost (XEXP (x, 0), code, !optimize_size)
5344 + rtx_cost (XEXP (x, 1), code, !optimize_size);
5348 total += m68hc11_cost->multQI;
5352 total += m68hc11_cost->multHI;
5357 total += m68hc11_cost->multSI;
5364 extra_cost = COSTS_N_INSNS (2);
5372 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
5375 return total + COSTS_N_INSNS (1);
5379 return total + COSTS_N_INSNS (2);
5383 return total + COSTS_N_INSNS (4);
5385 return total + COSTS_N_INSNS (8);
5388 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5389 return COSTS_N_INSNS (1);
5391 return COSTS_N_INSNS (1);
5394 return COSTS_N_INSNS (4);
5399 m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
5400 bool speed ATTRIBUTE_UNUSED)
5402 enum rtx_code code = (enum rtx_code) codearg;
5403 enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
5407 /* Constants are cheap. Moving them in registers must be avoided
5408 because most instructions do not handle two register operands. */
5414 /* Logical and arithmetic operations with a constant operand are
5415 better because they are not supported with two registers. */
5417 if (outer_code == SET && x == const0_rtx)
5418 /* After reload, the reload_cse pass checks the cost to change
5419 a SET into a PLUS. Make const0 cheap then. */
5420 *total = 1 - reload_completed;
5426 if (outer_code != COMPARE)
5449 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5458 /* Worker function for TARGET_ASM_FILE_START. */
5461 m68hc11_file_start (void)
5463 default_file_start ();
5465 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5469 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5472 m68hc11_asm_out_constructor (rtx symbol, int priority)
5474 default_ctor_section_asm_out_constructor (symbol, priority);
5475 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5478 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5481 m68hc11_asm_out_destructor (rtx symbol, int priority)
5483 default_dtor_section_asm_out_destructor (symbol, priority);
5484 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5487 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5490 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5491 int incoming ATTRIBUTE_UNUSED)
5493 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5496 /* Return true if type TYPE should be returned in memory.
5497 Blocks and data types largers than 4 bytes cannot be returned
5498 in the register (D + X = 4). */
5501 m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
5503 if (TYPE_MODE (type) == BLKmode)
5505 HOST_WIDE_INT size = int_size_in_bytes (type);
5506 return (size == -1 || size > 4);
5509 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5512 #include "gt-m68hc11.h"