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);
95 /* Must be set to 1 to produce debug messages. */
98 extern FILE *asm_out_file;
103 rtx m68hc11_soft_tmp_reg;
104 static GTY(()) rtx stack_push_word;
105 static GTY(()) rtx stack_pop_word;
106 static GTY(()) rtx z_reg;
107 static GTY(()) rtx z_reg_qi;
108 static int regs_inited = 0;
110 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
111 int current_function_interrupt;
113 /* Set to 1 by expand_prologue() when the function is a trap handler. */
114 int current_function_trap;
116 /* Set to 1 when the current function is placed in 68HC12 banked
117 memory and must return with rtc. */
118 int current_function_far;
120 /* Min offset that is valid for the indirect addressing mode. */
121 HOST_WIDE_INT m68hc11_min_offset = 0;
123 /* Max offset that is valid for the indirect addressing mode. */
124 HOST_WIDE_INT m68hc11_max_offset = 256;
126 /* The class value for base registers. */
127 enum reg_class m68hc11_base_reg_class = A_REGS;
129 /* The class value for index registers. This is NO_REGS for 68HC11. */
130 enum reg_class m68hc11_index_reg_class = NO_REGS;
132 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
134 /* Tables that tell whether a given hard register is valid for
135 a base or an index register. It is filled at init time depending
136 on the target processor. */
137 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
138 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
140 /* A correction offset which is applied to the stack pointer.
141 This is 1 for 68HC11 and 0 for 68HC12. */
142 int m68hc11_sp_correction;
144 int m68hc11_addr_mode;
145 int m68hc11_mov_addr_mode;
148 const struct processor_costs *m68hc11_cost;
150 /* Costs for a 68HC11. */
151 static const struct processor_costs m6811_cost = {
156 /* non-constant shift */
159 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
160 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
161 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
164 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
165 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
166 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
167 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
168 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
169 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
174 COSTS_N_INSNS (20 * 4),
176 COSTS_N_INSNS (20 * 16),
185 /* Costs for a 68HC12. */
186 static const struct processor_costs m6812_cost = {
191 /* non-constant shift */
194 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
195 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
196 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
199 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
200 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
201 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
202 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
203 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
204 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
211 COSTS_N_INSNS (3 * 4),
220 /* M68HC11 specific attributes. */
222 static const struct attribute_spec m68hc11_attribute_table[] =
224 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
225 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
226 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
227 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
228 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
229 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
230 { NULL, 0, 0, false, false, false, NULL }
233 /* Initialize the GCC target structure. */
234 #undef TARGET_ATTRIBUTE_TABLE
235 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
237 #undef TARGET_ASM_ALIGNED_HI_OP
238 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
240 #undef TARGET_ASM_FUNCTION_EPILOGUE
241 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
243 #undef TARGET_ASM_FILE_START
244 #define TARGET_ASM_FILE_START m68hc11_file_start
245 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
246 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
248 #undef TARGET_DEFAULT_TARGET_FLAGS
249 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
251 #undef TARGET_ENCODE_SECTION_INFO
252 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
254 #undef TARGET_SECTION_TYPE_FLAGS
255 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
257 #undef TARGET_RTX_COSTS
258 #define TARGET_RTX_COSTS m68hc11_rtx_costs
259 #undef TARGET_ADDRESS_COST
260 #define TARGET_ADDRESS_COST m68hc11_address_cost
262 #undef TARGET_MACHINE_DEPENDENT_REORG
263 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
265 #undef TARGET_INIT_LIBFUNCS
266 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
268 #undef TARGET_STRUCT_VALUE_RTX
269 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
270 #undef TARGET_RETURN_IN_MEMORY
271 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
272 #undef TARGET_CALLEE_COPIES
273 #define TARGET_CALLEE_COPIES hook_callee_copies_named
275 #undef TARGET_STRIP_NAME_ENCODING
276 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
278 #undef TARGET_LEGITIMATE_ADDRESS_P
279 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
281 struct gcc_target targetm = TARGET_INITIALIZER;
284 m68hc11_override_options (void)
286 memset (m68hc11_reg_valid_for_index, 0,
287 sizeof (m68hc11_reg_valid_for_index));
288 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
290 /* Compilation with -fpic generates a wrong code. */
293 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
294 (flag_pic > 1) ? "PIC" : "pic");
298 /* Do not enable -fweb because it breaks the 32-bit shift patterns
299 by breaking the match_dup of those patterns. The shift patterns
300 will no longer be recognized after that. */
303 /* Configure for a 68hc11 processor. */
306 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
307 m68hc11_cost = &m6811_cost;
308 m68hc11_min_offset = 0;
309 m68hc11_max_offset = 256;
310 m68hc11_index_reg_class = NO_REGS;
311 m68hc11_base_reg_class = A_REGS;
312 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
313 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
314 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
315 m68hc11_sp_correction = 1;
316 m68hc11_tmp_regs_class = D_REGS;
317 m68hc11_addr_mode = ADDR_OFFSET;
318 m68hc11_mov_addr_mode = 0;
319 if (m68hc11_soft_reg_count < 0)
320 m68hc11_soft_reg_count = 4;
323 /* Configure for a 68hc12 processor. */
326 m68hc11_cost = &m6812_cost;
327 m68hc11_min_offset = -65536;
328 m68hc11_max_offset = 65536;
329 m68hc11_index_reg_class = D_REGS;
330 m68hc11_base_reg_class = A_OR_SP_REGS;
331 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
332 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
333 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
334 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
335 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
336 m68hc11_sp_correction = 0;
337 m68hc11_tmp_regs_class = TMP_REGS;
338 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
339 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
340 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
341 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
342 target_flags |= MASK_NO_DIRECT_MODE;
343 if (m68hc11_soft_reg_count < 0)
344 m68hc11_soft_reg_count = 0;
346 if (TARGET_LONG_CALLS)
347 current_function_far = 1;
354 m68hc11_conditional_register_usage (void)
358 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
359 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
361 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
364 call_used_regs[i] = 1;
367 /* For 68HC12, the Z register emulation is not necessary when the
368 frame pointer is not used. The frame pointer is eliminated and
369 replaced by the stack register (which is a BASE_REG_CLASS). */
370 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
372 fixed_regs[HARD_Z_REGNUM] = 1;
377 /* Reload and register operations. */
381 create_regs_rtx (void)
383 /* regs_inited = 1; */
384 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
385 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
386 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
387 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
389 stack_push_word = gen_rtx_MEM (HImode,
390 gen_rtx_PRE_DEC (HImode,
391 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
392 stack_pop_word = gen_rtx_MEM (HImode,
393 gen_rtx_POST_INC (HImode,
394 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
398 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
399 - 8-bit values are stored anywhere (except the SP register).
400 - 16-bit values can be stored in any register whose mode is 16
401 - 32-bit values can be stored in D, X registers or in a soft register
402 (except the last one because we need 2 soft registers)
403 - Values whose size is > 32 bit are not stored in real hard
404 registers. They may be stored in soft registers if there are
407 hard_regno_mode_ok (int regno, enum machine_mode mode)
409 switch (GET_MODE_SIZE (mode))
412 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
415 return (X_REGNO_P (regno)
416 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
419 return G_REGNO_P (regno);
422 /* We have to accept a QImode in X or Y registers. Otherwise, the
423 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
424 in the insns. Reload fails if the insn rejects the register class 'a'
425 as well as if it accepts it. Patterns that failed were
426 zero_extend_qihi2 and iorqi3. */
428 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
436 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
438 /* Don't accept renaming to Z register. We will replace it to
439 X,Y or D during machine reorg pass. */
440 if (reg2 == HARD_Z_REGNUM)
443 /* Don't accept renaming D,X to Y register as the code will be bigger. */
444 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
445 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
452 preferred_reload_class (rtx operand, enum reg_class rclass)
454 enum machine_mode mode;
456 mode = GET_MODE (operand);
460 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
463 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
464 return m68hc11_base_reg_class;
466 if (rclass >= S_REGS && (GET_CODE (operand) == MEM
467 || GET_CODE (operand) == CONST_INT))
469 /* S_REGS class must not be used. The movhi template does not
470 work to move a memory to a soft register.
471 Restrict to a hard reg. */
476 case D_OR_A_OR_S_REGS:
477 rclass = A_OR_D_REGS;
482 case D_OR_SP_OR_S_REGS:
483 rclass = D_OR_SP_REGS;
485 case D_OR_Y_OR_S_REGS:
486 rclass = D_OR_Y_REGS;
488 case D_OR_X_OR_S_REGS:
489 rclass = D_OR_X_REGS;
504 else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
508 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
510 rclass = D_OR_X_REGS;
512 else if (rclass >= S_REGS && S_REG_P (operand))
518 case D_OR_A_OR_S_REGS:
519 rclass = A_OR_D_REGS;
524 case D_OR_SP_OR_S_REGS:
525 rclass = D_OR_SP_REGS;
527 case D_OR_Y_OR_S_REGS:
528 rclass = D_OR_Y_REGS;
530 case D_OR_X_OR_S_REGS:
531 rclass = D_OR_X_REGS;
546 else if (rclass >= S_REGS)
550 printf ("Class = %s for: ", reg_class_names[rclass]);
558 printf (" => class=%s\n", reg_class_names[rclass]);
566 /* Return 1 if the operand is a valid indexed addressing mode.
567 For 68hc11: n,r with n in [0..255] and r in A_REGS class
568 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
570 m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
574 switch (GET_CODE (operand))
577 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
578 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
579 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
586 if (addr_mode & ADDR_INCDEC)
587 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
588 addr_mode & ADDR_STRICT);
592 base = XEXP (operand, 0);
593 if (GET_CODE (base) == MEM)
596 offset = XEXP (operand, 1);
597 if (GET_CODE (offset) == MEM)
600 /* Indexed addressing mode with 2 registers. */
601 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
603 if (!(addr_mode & ADDR_INDEXED))
606 addr_mode &= ADDR_STRICT;
607 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
608 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
611 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
612 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
618 if (!(addr_mode & ADDR_OFFSET))
621 if (GET_CODE (base) == REG)
623 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
626 if (!(addr_mode & ADDR_STRICT))
629 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
632 if (GET_CODE (offset) == REG)
634 if (!VALID_CONSTANT_OFFSET_P (base, mode))
637 if (!(addr_mode & ADDR_STRICT))
640 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
645 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
648 if (addr_mode & ADDR_CONST)
649 return VALID_CONSTANT_OFFSET_P (operand, mode);
657 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
658 a 68HC12 1-byte index addressing mode. */
660 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
665 if (GET_CODE (operand) == REG && reload_in_progress
666 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
667 && reg_equiv_memory_loc[REGNO (operand)])
669 operand = reg_equiv_memory_loc[REGNO (operand)];
670 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
673 if (GET_CODE (operand) != MEM)
676 operand = XEXP (operand, 0);
677 if (CONSTANT_ADDRESS_P (operand))
680 if (PUSH_POP_ADDRESS_P (operand))
683 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
684 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
687 if (TARGET_M6812 && GET_CODE (operand) == PLUS
688 && (reload_completed | reload_in_progress))
690 base = XEXP (operand, 0);
691 offset = XEXP (operand, 1);
693 /* The offset can be a symbol address and this is too big
694 for the operand constraint. */
695 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
698 if (GET_CODE (base) == CONST_INT)
701 switch (GET_MODE_SIZE (mode))
704 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
709 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
714 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
723 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
727 if (GET_CODE (operand) == REG && reload_in_progress
728 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
729 && reg_equiv_memory_loc[REGNO (operand)])
731 operand = reg_equiv_memory_loc[REGNO (operand)];
732 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
734 if (GET_CODE (operand) != MEM)
737 operand = XEXP (operand, 0);
738 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
739 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
743 m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
748 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
750 /* Reject the global variables if they are too wide. This forces
751 a load of their address in a register and generates smaller code. */
752 if (GET_MODE_SIZE (mode) == 8)
757 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
758 if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
762 if (PUSH_POP_ADDRESS_P (operand))
766 if (symbolic_memory_operand (operand, mode))
774 m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
781 printf ("Checking: ");
786 result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
790 printf (" -> %s\n", result == 0 ? "NO" : "YES");
797 printf ("go_if_legitimate%s, ret 0: %d:",
798 (strict ? "_strict" : ""), mode);
808 m68hc11_reload_operands (rtx operands[])
810 enum machine_mode mode;
812 if (regs_inited == 0)
815 mode = GET_MODE (operands[1]);
817 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
818 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
820 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
821 rtx base = XEXP (XEXP (operands[1], 0), 0);
823 if (GET_CODE (base) != REG)
830 /* If the offset is out of range, we have to compute the address
831 with a separate add instruction. We try to do this with an 8-bit
832 add on the A register. This is possible only if the lowest part
833 of the offset (i.e., big_offset % 256) is a valid constant offset
834 with respect to the mode. If it's not, we have to generate a
835 16-bit add on the D register. From:
837 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
841 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
842 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
843 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
844 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
846 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
847 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
850 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
853 rtx reg = operands[0];
855 int val = INTVAL (big_offset);
858 /* We use the 'operands[0]' as a scratch register to compute the
859 address. Make sure 'base' is in that register. */
860 if (!rtx_equal_p (base, operands[0]))
862 emit_move_insn (reg, base);
872 vh = (val >> 8) & 0x0FF;
876 /* Create the lowest part offset that still remains to be added.
877 If it's not a valid offset, do a 16-bit add. */
878 offset = GEN_INT (vl);
879 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
881 emit_insn (gen_rtx_SET (VOIDmode, reg,
882 gen_rtx_PLUS (HImode, reg, big_offset)));
887 emit_insn (gen_rtx_SET (VOIDmode, reg,
888 gen_rtx_PLUS (HImode, reg,
889 GEN_INT (vh << 8))));
891 emit_move_insn (operands[0],
892 gen_rtx_MEM (GET_MODE (operands[1]),
893 gen_rtx_PLUS (Pmode, reg, offset)));
898 /* Use the normal gen_movhi pattern. */
903 m68hc11_emit_libcall (const char *name, enum rtx_code code,
904 enum machine_mode dmode, enum machine_mode smode,
905 int noperands, rtx *operands)
913 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
917 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
918 dmode, 1, operands[1], smode);
919 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
923 ret = emit_library_call_value (libcall, NULL_RTX,
925 operands[1], smode, operands[2],
927 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
934 insns = get_insns ();
936 emit_libcall_block (insns, operands[0], ret, equiv);
939 /* Returns true if X is a PRE/POST increment decrement
940 (same as auto_inc_p() in rtlanal.c but do not take into
941 account the stack). */
943 m68hc11_auto_inc_p (rtx x)
945 return GET_CODE (x) == PRE_DEC
946 || GET_CODE (x) == POST_INC
947 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
951 /* Predicates for machine description. */
954 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
956 return GET_CODE (operand) == MEM
957 && GET_CODE (XEXP (operand, 0)) == PLUS
958 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
959 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
960 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
961 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
965 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
967 if (GET_CODE (operand) == MEM)
969 rtx op = XEXP (operand, 0);
971 if (symbolic_memory_operand (op, mode))
978 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
980 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
982 rtx op = XEXP (operand, 0);
985 if (m68hc11_page0_symbol_p (op))
988 if (symbolic_memory_operand (op, mode))
991 if (reload_in_progress)
994 operand = XEXP (operand, 0);
995 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
996 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
1002 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1004 if (GET_CODE (operand) != MEM)
1007 operand = XEXP (operand, 0);
1008 if (GET_CODE (operand) == PLUS)
1010 if (GET_CODE (XEXP (operand, 0)) == REG)
1011 operand = XEXP (operand, 0);
1012 else if (GET_CODE (XEXP (operand, 1)) == REG)
1013 operand = XEXP (operand, 1);
1015 return GET_CODE (operand) == REG
1016 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1017 || A_REGNO_P (REGNO (operand)));
1021 push_pop_operand_p (rtx operand)
1023 if (GET_CODE (operand) != MEM)
1027 operand = XEXP (operand, 0);
1028 return PUSH_POP_ADDRESS_P (operand);
1031 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1032 reference and a constant. */
1035 symbolic_memory_operand (rtx op, enum machine_mode mode)
1037 switch (GET_CODE (op))
1045 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1046 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1047 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1049 /* ??? This clause seems to be irrelevant. */
1051 return GET_MODE (op) == mode;
1054 return symbolic_memory_operand (XEXP (op, 0), mode)
1055 && symbolic_memory_operand (XEXP (op, 1), mode);
1062 /* Emit the code to build the trampoline used to call a nested function.
1066 ldy #&CXT movw #&CXT,*_.d1
1067 sty *_.d1 jmp FNADDR
1072 m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1074 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1077 if (*static_chain_reg == '*')
1081 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1082 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1083 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1085 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1086 gen_rtx_CONST (QImode,
1087 gen_rtx_SYMBOL_REF (Pmode,
1088 static_chain_reg)));
1089 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1091 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1095 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1096 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1097 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1098 gen_rtx_CONST (HImode,
1099 gen_rtx_SYMBOL_REF (Pmode,
1100 static_chain_reg)));
1101 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1103 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1107 /* Declaration of types. */
1109 /* Handle an "tiny_data" attribute; arguments as in
1110 struct attribute_spec.handler. */
1112 m68hc11_handle_page0_attribute (tree *node, tree name,
1113 tree args ATTRIBUTE_UNUSED,
1114 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1118 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1120 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1124 warning (OPT_Wattributes, "%qE attribute ignored",
1126 *no_add_attrs = true;
1132 /* Keep track of the symbol which has a `trap' attribute and which uses
1133 the `swi' calling convention. Since there is only one trap, we only
1134 record one such symbol. If there are several, a warning is reported. */
1135 static rtx trap_handler_symbol = 0;
1137 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1138 arguments as in struct attribute_spec.handler. */
1140 m68hc11_handle_fntype_attribute (tree *node, tree name,
1141 tree args ATTRIBUTE_UNUSED,
1142 int flags ATTRIBUTE_UNUSED,
1145 if (TREE_CODE (*node) != FUNCTION_TYPE
1146 && TREE_CODE (*node) != METHOD_TYPE
1147 && TREE_CODE (*node) != FIELD_DECL
1148 && TREE_CODE (*node) != TYPE_DECL)
1150 warning (OPT_Wattributes, "%qE attribute only applies to functions",
1152 *no_add_attrs = true;
1157 /* Undo the effects of the above. */
1160 m68hc11_strip_name_encoding (const char *str)
1162 return str + (*str == '*' || *str == '@' || *str == '&');
1166 m68hc11_encode_label (tree decl)
1168 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1169 int len = strlen (str);
1170 char *newstr = XALLOCAVEC (char, len + 2);
1173 strcpy (&newstr[1], str);
1175 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1178 /* Return 1 if this is a symbol in page0 */
1180 m68hc11_page0_symbol_p (rtx x)
1182 switch (GET_CODE (x))
1185 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1188 return m68hc11_page0_symbol_p (XEXP (x, 0));
1191 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1194 return GET_CODE (XEXP (x, 1)) == CONST_INT
1195 && INTVAL (XEXP (x, 1)) < 256
1196 && INTVAL (XEXP (x, 1)) >= 0;
1203 /* We want to recognize trap handlers so that we handle calls to traps
1204 in a special manner (by issuing the trap). This information is stored
1205 in SYMBOL_REF_FLAG. */
1208 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1214 if (TREE_CODE (decl) == VAR_DECL)
1216 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1217 m68hc11_encode_label (decl);
1221 if (TREE_CODE (decl) != FUNCTION_DECL)
1224 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1227 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1229 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1230 is_far = TARGET_LONG_CALLS != 0;
1232 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1233 if (trap_handler && is_far)
1235 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1236 "not compatible, ignoring %<far%>");
1241 if (trap_handler_symbol != 0)
1242 warning (OPT_Wattributes, "%<trap%> attribute is already used");
1244 trap_handler_symbol = XEXP (rtl, 0);
1246 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1250 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1252 unsigned int flags = default_section_type_flags (decl, name, reloc);
1254 if (strncmp (name, ".eeprom", 7) == 0)
1256 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1263 m68hc11_is_far_symbol (rtx sym)
1265 if (GET_CODE (sym) == MEM)
1266 sym = XEXP (sym, 0);
1268 return SYMBOL_REF_FLAG (sym);
1272 m68hc11_is_trap_symbol (rtx sym)
1274 if (GET_CODE (sym) == MEM)
1275 sym = XEXP (sym, 0);
1277 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1281 /* Argument support functions. */
1283 /* Define the offset between two registers, one to be eliminated, and the
1284 other its replacement, at the start of a routine. */
1286 m68hc11_initial_elimination_offset (int from, int to)
1293 /* For a trap handler, we must take into account the registers which
1294 are pushed on the stack during the trap (except the PC). */
1295 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1296 current_function_interrupt = lookup_attribute ("interrupt",
1297 func_attr) != NULL_TREE;
1298 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1300 if (lookup_attribute ("far", func_attr) != 0)
1301 current_function_far = 1;
1302 else if (lookup_attribute ("near", func_attr) != 0)
1303 current_function_far = 0;
1305 current_function_far = (TARGET_LONG_CALLS != 0
1306 && !current_function_interrupt
1309 if (trap_handler && from == ARG_POINTER_REGNUM)
1312 /* For a function using 'call/rtc' we must take into account the
1313 page register which is pushed in the call. */
1314 else if (current_function_far && from == ARG_POINTER_REGNUM)
1319 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1321 /* 2 is for the saved frame.
1322 1 is for the 'sts' correction when creating the frame. */
1323 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1326 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1328 return m68hc11_sp_correction;
1331 /* Push any 2 byte pseudo hard registers that we need to save. */
1332 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1334 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1340 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1342 return get_frame_size () + size;
1345 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1352 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1353 for a call to a function whose data type is FNTYPE.
1354 For a library call, FNTYPE is 0. */
1357 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1361 z_replacement_completed = 0;
1365 /* For a library call, we must find out the type of the return value.
1366 When the return value is bigger than 4 bytes, it is returned in
1367 memory. In that case, the first argument of the library call is a
1368 pointer to the memory location. Because the first argument is passed in
1369 register D, we have to identify this, so that the first function
1370 parameter is not passed in D either. */
1376 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1379 /* If the library ends in 'di' or in 'df', we assume it's
1380 returning some DImode or some DFmode which are 64-bit wide. */
1381 name = XSTR (libname, 0);
1382 len = strlen (name);
1384 && ((name[len - 2] == 'd'
1385 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1386 || (name[len - 3] == 'd'
1387 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1389 /* We are in. Mark the first parameter register as already used. */
1396 ret_type = TREE_TYPE (fntype);
1398 if (ret_type && aggregate_value_p (ret_type, fntype))
1405 /* Update the data in CUM to advance over an argument
1406 of mode MODE and data type TYPE.
1407 (TYPE is null for libcalls where that information may not be available.) */
1410 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1411 tree type, int named ATTRIBUTE_UNUSED)
1413 if (mode != BLKmode)
1415 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1418 cum->words = GET_MODE_SIZE (mode);
1422 cum->words += GET_MODE_SIZE (mode);
1423 if (cum->words <= HARD_REG_SIZE)
1429 cum->words += int_size_in_bytes (type);
1434 /* Define where to put the arguments to a function.
1435 Value is zero to push the argument on the stack,
1436 or a hard register in which to store the argument.
1438 MODE is the argument's machine mode.
1439 TYPE is the data type of the argument (as a tree).
1440 This is null for libcalls where that information may
1442 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1443 the preceding args and about the function being called.
1444 NAMED is nonzero if this argument is a named parameter
1445 (otherwise it is an extra parameter matching an ellipsis). */
1448 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1449 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1451 if (cum->words != 0)
1456 if (mode != BLKmode)
1458 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1459 return gen_rtx_REG (mode, HARD_X_REGNUM);
1461 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1465 return gen_rtx_REG (mode, HARD_D_REGNUM);
1470 /* If defined, a C expression which determines whether, and in which direction,
1471 to pad out an argument with extra space. The value should be of type
1472 `enum direction': either `upward' to pad above the argument,
1473 `downward' to pad below, or `none' to inhibit padding.
1475 Structures are stored left shifted in their argument slot. */
1477 m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
1479 if (type != 0 && AGGREGATE_TYPE_P (type))
1482 /* Fall back to the default. */
1483 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1487 /* Function prologue and epilogue. */
1489 /* Emit a move after the reload pass has completed. This is used to
1490 emit the prologue and epilogue. */
1492 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1496 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1498 insn = emit_move_insn (to, from);
1502 emit_move_insn (scratch, from);
1503 insn = emit_move_insn (to, scratch);
1506 /* Put a REG_INC note to tell the flow analysis that the instruction
1508 if (IS_STACK_PUSH (to))
1509 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
1510 else if (IS_STACK_POP (from))
1511 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
1513 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1514 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1515 The problem is that we are lying to gcc and use `txs' for x = sp
1516 (which is not really true because txs is really x = sp + 1). */
1517 else if (TARGET_M6811 && SP_REG_P (from))
1518 add_reg_note (insn, REG_INC, from);
1522 m68hc11_total_frame_size (void)
1527 size = get_frame_size ();
1528 if (current_function_interrupt)
1530 size += 3 * HARD_REG_SIZE;
1532 if (frame_pointer_needed)
1533 size += HARD_REG_SIZE;
1535 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1536 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1537 size += HARD_REG_SIZE;
1543 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1544 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1546 /* We catch the function epilogue generation to have a chance
1547 to clear the z_replacement_completed flag. */
1548 z_replacement_completed = 0;
1552 expand_prologue (void)
1559 gcc_assert (reload_completed == 1);
1561 size = get_frame_size ();
1565 /* Generate specific prologue for interrupt handlers. */
1566 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1567 current_function_interrupt = lookup_attribute ("interrupt",
1568 func_attr) != NULL_TREE;
1569 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1570 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1571 current_function_far = 1;
1572 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1573 current_function_far = 0;
1575 current_function_far = (TARGET_LONG_CALLS != 0
1576 && !current_function_interrupt
1577 && !current_function_trap);
1579 /* Get the scratch register to build the frame and push registers.
1580 If the first argument is a 32-bit quantity, the D+X registers
1581 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1582 For 68HC12, this scratch register is not used. */
1583 if (crtl->args.info.nregs == 2)
1588 /* Save current stack frame. */
1589 if (frame_pointer_needed)
1590 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1592 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1593 Other soft registers in page0 need not to be saved because they
1594 will be restored by C functions. For a trap handler, we don't
1595 need to preserve these registers because this is a synchronous call. */
1596 if (current_function_interrupt)
1598 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1599 emit_move_after_reload (stack_push_word,
1600 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1601 emit_move_after_reload (stack_push_word,
1602 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1606 /* Allocate local variables. */
1607 if (TARGET_M6812 && (size > 4 || size == 3))
1609 emit_insn (gen_addhi3 (stack_pointer_rtx,
1610 stack_pointer_rtx, GEN_INT (-size)));
1612 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1616 insn = gen_rtx_PARALLEL
1619 gen_rtx_SET (VOIDmode,
1621 gen_rtx_PLUS (HImode,
1624 gen_rtx_CLOBBER (VOIDmode, scratch)));
1631 /* Allocate by pushing scratch values. */
1632 for (i = 2; i <= size; i += 2)
1633 emit_move_after_reload (stack_push_word, ix_reg, 0);
1636 emit_insn (gen_addhi3 (stack_pointer_rtx,
1637 stack_pointer_rtx, constm1_rtx));
1640 /* Create the frame pointer. */
1641 if (frame_pointer_needed)
1642 emit_move_after_reload (hard_frame_pointer_rtx,
1643 stack_pointer_rtx, scratch);
1645 /* Push any 2 byte pseudo hard registers that we need to save. */
1646 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1648 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1650 emit_move_after_reload (stack_push_word,
1651 gen_rtx_REG (HImode, regno), scratch);
1657 expand_epilogue (void)
1664 gcc_assert (reload_completed == 1);
1666 size = get_frame_size ();
1668 /* If we are returning a value in two registers, we have to preserve the
1669 X register and use the Y register to restore the stack and the saved
1670 registers. Otherwise, use X because it's faster (and smaller). */
1671 if (crtl->return_rtx == 0)
1673 else if (GET_CODE (crtl->return_rtx) == MEM)
1674 return_size = HARD_REG_SIZE;
1676 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
1678 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1683 /* Pop any 2 byte pseudo hard registers that we saved. */
1684 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1686 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1688 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1689 stack_pop_word, scratch);
1693 /* de-allocate auto variables */
1694 if (TARGET_M6812 && (size > 4 || size == 3))
1696 emit_insn (gen_addhi3 (stack_pointer_rtx,
1697 stack_pointer_rtx, GEN_INT (size)));
1699 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1703 insn = gen_rtx_PARALLEL
1706 gen_rtx_SET (VOIDmode,
1708 gen_rtx_PLUS (HImode,
1711 gen_rtx_CLOBBER (VOIDmode, scratch)));
1718 for (i = 2; i <= size; i += 2)
1719 emit_move_after_reload (scratch, stack_pop_word, scratch);
1721 emit_insn (gen_addhi3 (stack_pointer_rtx,
1722 stack_pointer_rtx, const1_rtx));
1725 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1726 if (current_function_interrupt)
1728 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1729 stack_pop_word, scratch);
1730 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1731 stack_pop_word, scratch);
1732 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1735 /* Restore previous frame pointer. */
1736 if (frame_pointer_needed)
1737 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1739 /* If the trap handler returns some value, copy the value
1740 in D, X onto the stack so that the rti will pop the return value
1742 else if (current_function_trap && return_size != 0)
1744 rtx addr_reg = stack_pointer_rtx;
1748 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1751 emit_move_after_reload (gen_rtx_MEM (HImode,
1752 gen_rtx_PLUS (HImode, addr_reg,
1753 const1_rtx)), d_reg, 0);
1754 if (return_size > HARD_REG_SIZE)
1755 emit_move_after_reload (gen_rtx_MEM (HImode,
1756 gen_rtx_PLUS (HImode, addr_reg,
1757 GEN_INT (3))), ix_reg, 0);
1760 emit_jump_insn (gen_return ());
1764 /* Low and High part extraction for 68HC11. These routines are
1765 similar to gen_lowpart and gen_highpart but they have been
1766 fixed to work for constants and 68HC11 specific registers. */
1769 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1771 /* We assume that the low part of an auto-inc mode is the same with
1772 the mode changed and that the caller split the larger mode in the
1774 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1776 return gen_rtx_MEM (mode, XEXP (x, 0));
1779 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1780 floating-point constant. A CONST_DOUBLE is used whenever the
1781 constant requires more than one word in order to be adequately
1783 if (GET_CODE (x) == CONST_DOUBLE)
1787 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1791 if (GET_MODE (x) == SFmode)
1793 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1794 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1800 split_double (x, &first, &second);
1804 return GEN_INT (l[0]);
1806 return gen_int_mode (l[0], HImode);
1810 l[0] = CONST_DOUBLE_LOW (x);
1815 return GEN_INT (l[0]);
1817 gcc_assert (GET_MODE (x) == SFmode);
1818 return gen_int_mode (l[0], HImode);
1824 if (mode == QImode && D_REG_P (x))
1825 return gen_rtx_REG (mode, HARD_B_REGNUM);
1827 /* gen_lowpart crashes when it is called with a SUBREG. */
1828 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1833 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1835 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1840 x = gen_lowpart (mode, x);
1842 /* Return a different rtx to avoid to share it in several insns
1843 (when used by a split pattern). Sharing addresses within
1844 a MEM breaks the Z register replacement (and reloading). */
1845 if (GET_CODE (x) == MEM)
1851 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1853 /* We assume that the high part of an auto-inc mode is the same with
1854 the mode changed and that the caller split the larger mode in the
1856 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1858 return gen_rtx_MEM (mode, XEXP (x, 0));
1861 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1862 floating-point constant. A CONST_DOUBLE is used whenever the
1863 constant requires more than one word in order to be adequately
1865 if (GET_CODE (x) == CONST_DOUBLE)
1869 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1873 if (GET_MODE (x) == SFmode)
1875 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1876 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1882 split_double (x, &first, &second);
1886 return GEN_INT (l[1]);
1888 return gen_int_mode ((l[1] >> 16), HImode);
1892 l[1] = CONST_DOUBLE_HIGH (x);
1898 return GEN_INT (l[1]);
1900 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1901 return gen_int_mode ((l[0] >> 16), HImode);
1906 if (GET_CODE (x) == CONST_INT)
1908 HOST_WIDE_INT val = INTVAL (x);
1912 return gen_int_mode (val >> 8, QImode);
1914 else if (mode == HImode)
1916 return gen_int_mode (val >> 16, HImode);
1918 else if (mode == SImode)
1920 return gen_int_mode (val >> 32, SImode);
1923 if (mode == QImode && D_REG_P (x))
1924 return gen_rtx_REG (mode, HARD_A_REGNUM);
1926 /* There is no way in GCC to represent the upper part of a word register.
1927 To obtain the 8-bit upper part of a soft register, we change the
1928 reg into a mem rtx. This is possible because they are physically
1929 located in memory. There is no offset because we are big-endian. */
1930 if (mode == QImode && S_REG_P (x))
1934 /* Avoid the '*' for direct addressing mode when this
1935 addressing mode is disabled. */
1936 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1937 return gen_rtx_MEM (QImode,
1938 gen_rtx_SYMBOL_REF (Pmode,
1939 ®_names[REGNO (x)][pos]));
1942 /* gen_highpart crashes when it is called with a SUBREG. */
1943 switch (GET_CODE (x))
1946 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
1948 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1949 return gen_rtx_REG (mode, REGNO (x));
1951 return gen_rtx_SUBREG (mode, x, 0);
1953 x = change_address (x, mode, 0);
1955 /* Return a different rtx to avoid to share it in several insns
1956 (when used by a split pattern). Sharing addresses within
1957 a MEM breaks the Z register replacement (and reloading). */
1958 if (GET_CODE (x) == MEM)
1968 /* Obscure register manipulation. */
1970 /* Finds backward in the instructions to see if register 'reg' is
1971 dead. This is used when generating code to see if we can use 'reg'
1972 as a scratch register. This allows us to choose a better generation
1973 of code when we know that some register dies or can be clobbered. */
1976 dead_register_here (rtx x, rtx reg)
1982 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
1986 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1993 if (GET_CODE (body) == CALL_INSN)
1995 if (GET_CODE (body) == JUMP_INSN)
1998 if (GET_CODE (body) == SET)
2000 rtx dst = XEXP (body, 0);
2002 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2004 if (x_reg && rtx_equal_p (dst, x_reg))
2007 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2010 else if (reg_mentioned_p (reg, p)
2011 || (x_reg && reg_mentioned_p (x_reg, p)))
2015 /* Scan forward to see if the register is set in some insns and never
2017 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2021 if (GET_CODE (p) == CODE_LABEL
2022 || GET_CODE (p) == JUMP_INSN
2023 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2026 if (GET_CODE (p) != INSN)
2030 if (GET_CODE (body) == SET)
2032 rtx src = XEXP (body, 1);
2033 rtx dst = XEXP (body, 0);
2035 if (GET_CODE (dst) == REG
2036 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2040 /* Register is used (may be in source or in dest). */
2041 if (reg_mentioned_p (reg, p)
2042 || (x_reg != 0 && GET_MODE (p) == SImode
2043 && reg_mentioned_p (x_reg, p)))
2046 return p == 0 ? 1 : 0;
2050 /* Code generation operations called from machine description file. */
2052 /* Print the name of register 'regno' in the assembly file. */
2054 asm_print_register (FILE *file, int regno)
2056 const char *name = reg_names[regno];
2058 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2061 fprintf (file, "%s", name);
2064 /* A C compound statement to output to stdio stream STREAM the
2065 assembler syntax for an instruction operand X. X is an RTL
2068 CODE is a value that can be used to specify one of several ways
2069 of printing the operand. It is used when identical operands
2070 must be printed differently depending on the context. CODE
2071 comes from the `%' specification that was used to request
2072 printing of the operand. If the specification was just `%DIGIT'
2073 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2074 is the ASCII code for LTR.
2076 If X is a register, this macro should print the register's name.
2077 The names can be found in an array `reg_names' whose type is
2078 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2080 When the machine description has a specification `%PUNCT' (a `%'
2081 followed by a punctuation character), this macro is called with
2082 a null pointer for X and the punctuation character for CODE.
2084 The M68HC11 specific codes are:
2086 'b' for the low part of the operand.
2087 'h' for the high part of the operand
2088 The 'b' or 'h' modifiers have no effect if the operand has
2089 the QImode and is not a S_REG_P (soft register). If the
2090 operand is a hard register, these two modifiers have no effect.
2091 't' generate the temporary scratch register. The operand is
2093 'T' generate the low-part temporary scratch register. The operand is
2097 print_operand (FILE *file, rtx op, int letter)
2101 asm_print_register (file, SOFT_TMP_REGNUM);
2104 else if (letter == 'T')
2106 asm_print_register (file, SOFT_TMP_REGNUM);
2107 fprintf (file, "+1");
2110 else if (letter == '#')
2112 asm_fprintf (file, "%I");
2115 if (GET_CODE (op) == REG)
2117 if (letter == 'b' && S_REG_P (op))
2119 asm_print_register (file, REGNO (op));
2120 fprintf (file, "+1");
2122 else if (letter == 'b' && D_REG_P (op))
2124 asm_print_register (file, HARD_B_REGNUM);
2128 asm_print_register (file, REGNO (op));
2133 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2136 asm_fprintf (file, "%I%%lo(");
2138 asm_fprintf (file, "%I%%hi(");
2140 output_addr_const (file, op);
2141 fprintf (file, ")");
2145 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2146 are specified. If we already have a QImode, there is nothing to do. */
2147 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2151 op = m68hc11_gen_lowpart (QImode, op);
2153 else if (letter == 'h')
2155 op = m68hc11_gen_highpart (QImode, op);
2159 if (GET_CODE (op) == MEM)
2161 rtx base = XEXP (op, 0);
2162 switch (GET_CODE (base))
2165 gcc_assert (TARGET_M6812);
2166 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2167 asm_print_register (file, REGNO (XEXP (base, 0)));
2171 gcc_assert (TARGET_M6812);
2172 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2173 asm_print_register (file, REGNO (XEXP (base, 0)));
2174 fprintf (file, "-");
2178 gcc_assert (TARGET_M6812);
2179 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2180 asm_print_register (file, REGNO (XEXP (base, 0)));
2181 fprintf (file, "+");
2185 gcc_assert (TARGET_M6812);
2186 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2187 asm_print_register (file, REGNO (XEXP (base, 0)));
2191 gcc_assert (TARGET_M6812);
2192 fprintf (file, "[");
2193 print_operand_address (file, XEXP (base, 0));
2194 fprintf (file, "]");
2198 if (m68hc11_page0_symbol_p (base))
2199 fprintf (file, "*");
2201 output_address (base);
2205 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2210 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2211 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2212 asm_fprintf (file, "%I0x%lx", l);
2214 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2218 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2219 sizeof (dstr), 0, 1);
2220 asm_fprintf (file, "%I0r%s", dstr);
2224 int need_parenthesize = 0;
2227 asm_fprintf (file, "%I");
2229 need_parenthesize = must_parenthesize (op);
2231 if (need_parenthesize)
2232 fprintf (file, "(");
2234 output_addr_const (file, op);
2235 if (need_parenthesize)
2236 fprintf (file, ")");
2240 /* Returns true if the operand 'op' must be printed with parenthesis
2241 around it. This must be done only if there is a symbol whose name
2242 is a processor register. */
2244 must_parenthesize (rtx op)
2248 switch (GET_CODE (op))
2251 name = XSTR (op, 0);
2252 /* Avoid a conflict between symbol name and a possible
2254 return (strcasecmp (name, "a") == 0
2255 || strcasecmp (name, "b") == 0
2256 || strcasecmp (name, "d") == 0
2257 || strcasecmp (name, "x") == 0
2258 || strcasecmp (name, "y") == 0
2259 || strcasecmp (name, "ix") == 0
2260 || strcasecmp (name, "iy") == 0
2261 || strcasecmp (name, "pc") == 0
2262 || strcasecmp (name, "sp") == 0
2263 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2267 return must_parenthesize (XEXP (op, 0))
2268 || must_parenthesize (XEXP (op, 1));
2274 return must_parenthesize (XEXP (op, 0));
2285 /* A C compound statement to output to stdio stream STREAM the
2286 assembler syntax for an instruction operand that is a memory
2287 reference whose address is ADDR. ADDR is an RTL expression. */
2290 print_operand_address (FILE *file, rtx addr)
2294 int need_parenthesis = 0;
2296 switch (GET_CODE (addr))
2299 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2301 fprintf (file, "0,");
2302 asm_print_register (file, REGNO (addr));
2306 base = XEXP (addr, 0);
2307 switch (GET_CODE (base))
2310 gcc_assert (TARGET_M6812);
2311 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2312 asm_print_register (file, REGNO (XEXP (base, 0)));
2316 gcc_assert (TARGET_M6812);
2317 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2318 asm_print_register (file, REGNO (XEXP (base, 0)));
2319 fprintf (file, "-");
2323 gcc_assert (TARGET_M6812);
2324 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2325 asm_print_register (file, REGNO (XEXP (base, 0)));
2326 fprintf (file, "+");
2330 gcc_assert (TARGET_M6812);
2331 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2332 asm_print_register (file, REGNO (XEXP (base, 0)));
2336 need_parenthesis = must_parenthesize (base);
2337 if (need_parenthesis)
2338 fprintf (file, "(");
2340 output_addr_const (file, base);
2341 if (need_parenthesis)
2342 fprintf (file, ")");
2348 base = XEXP (addr, 0);
2349 offset = XEXP (addr, 1);
2350 if (!G_REG_P (base) && G_REG_P (offset))
2352 base = XEXP (addr, 1);
2353 offset = XEXP (addr, 0);
2355 if (CONSTANT_ADDRESS_P (base))
2357 need_parenthesis = must_parenthesize (addr);
2359 gcc_assert (CONSTANT_ADDRESS_P (offset));
2360 if (need_parenthesis)
2361 fprintf (file, "(");
2363 output_addr_const (file, base);
2364 fprintf (file, "+");
2365 output_addr_const (file, offset);
2366 if (need_parenthesis)
2367 fprintf (file, ")");
2371 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2374 gcc_assert (TARGET_M6812);
2375 asm_print_register (file, REGNO (offset));
2376 fprintf (file, ",");
2377 asm_print_register (file, REGNO (base));
2381 need_parenthesis = must_parenthesize (offset);
2382 if (need_parenthesis)
2383 fprintf (file, "(");
2385 output_addr_const (file, offset);
2386 if (need_parenthesis)
2387 fprintf (file, ")");
2388 fprintf (file, ",");
2389 asm_print_register (file, REGNO (base));
2395 if (GET_CODE (addr) == CONST_INT
2396 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2398 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2402 need_parenthesis = must_parenthesize (addr);
2403 if (need_parenthesis)
2404 fprintf (file, "(");
2406 output_addr_const (file, addr);
2407 if (need_parenthesis)
2408 fprintf (file, ")");
2415 /* Splitting of some instructions. */
2418 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2422 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2423 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2424 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2425 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2431 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2436 switch (GET_MODE (op0))
2440 tmp = m68hc11_expand_compare (code, op0, op1);
2441 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2442 gen_rtx_LABEL_REF (VOIDmode, label),
2444 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2448 /* SCz: from i386.c */
2451 /* Don't expand the comparison early, so that we get better code
2452 when jump or whoever decides to reverse the comparison. */
2457 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2458 &m68hc11_compare_op1);
2460 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2461 m68hc11_compare_op0, m68hc11_compare_op1);
2462 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2463 gen_rtx_LABEL_REF (VOIDmode, label),
2465 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2467 use_fcomi = ix86_use_fcomi_compare (code);
2468 vec = rtvec_alloc (3 + !use_fcomi);
2469 RTVEC_ELT (vec, 0) = tmp;
2471 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2473 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2476 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2478 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2484 /* Expand SImode branch into multiple compare+branch. */
2486 rtx lo[2], hi[2], label2;
2487 enum rtx_code code1, code2, code3;
2489 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2494 code = swap_condition (code);
2496 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2497 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2498 hi[0] = m68hc11_gen_highpart (HImode, op0);
2499 hi[1] = m68hc11_gen_highpart (HImode, op1);
2501 /* Otherwise, if we are doing less-than, op1 is a constant and the
2502 low word is zero, then we can just examine the high word. */
2504 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2505 && (code == LT || code == LTU))
2507 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2511 /* Otherwise, we need two or three jumps. */
2513 label2 = gen_label_rtx ();
2516 code2 = swap_condition (code);
2517 code3 = unsigned_condition (code);
2558 * if (hi(a) < hi(b)) goto true;
2559 * if (hi(a) > hi(b)) goto false;
2560 * if (lo(a) < lo(b)) goto true;
2563 if (code1 != UNKNOWN)
2564 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2565 if (code2 != UNKNOWN)
2566 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2568 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2570 if (code2 != UNKNOWN)
2571 emit_label (label2);
2581 /* Return the increment/decrement mode of a MEM if it is such.
2582 Return CONST if it is anything else. */
2584 autoinc_mode (rtx x)
2586 if (GET_CODE (x) != MEM)
2590 if (GET_CODE (x) == PRE_INC
2591 || GET_CODE (x) == PRE_DEC
2592 || GET_CODE (x) == POST_INC
2593 || GET_CODE (x) == POST_DEC)
2594 return GET_CODE (x);
2600 m68hc11_make_autoinc_notes (rtx *x, void *data)
2604 switch (GET_CODE (*x))
2611 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2620 /* Split a DI, SI or HI move into several smaller move operations.
2621 The scratch register 'scratch' is used as a temporary to load
2622 store intermediate values. It must be a hard register. */
2624 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2626 rtx low_to, low_from;
2627 rtx high_to, high_from;
2629 enum machine_mode mode;
2631 int autoinc_from = autoinc_mode (from);
2632 int autoinc_to = autoinc_mode (to);
2634 mode = GET_MODE (to);
2636 /* If the TO and FROM contain autoinc modes that are not compatible
2637 together (one pop and the other a push), we must change one to
2638 an offsetable operand and generate an appropriate add at the end. */
2639 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2644 /* The source uses an autoinc mode which is not compatible with
2645 a split (this would result in a word swap). */
2646 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2648 code = GET_CODE (XEXP (from, 0));
2649 reg = XEXP (XEXP (from, 0), 0);
2650 offset = GET_MODE_SIZE (GET_MODE (from));
2651 if (code == POST_DEC)
2654 if (code == PRE_INC)
2655 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2657 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2658 if (code == POST_DEC)
2659 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2663 /* Likewise for destination. */
2664 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2666 code = GET_CODE (XEXP (to, 0));
2667 reg = XEXP (XEXP (to, 0), 0);
2668 offset = GET_MODE_SIZE (GET_MODE (to));
2669 if (code == POST_DEC)
2672 if (code == PRE_INC)
2673 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2675 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2676 if (code == POST_DEC)
2677 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2681 /* The source and destination auto increment modes must be compatible
2682 with each other: same direction. */
2683 if ((autoinc_to != autoinc_from
2684 && autoinc_to != CONST && autoinc_from != CONST)
2685 /* The destination address register must not be used within
2686 the source operand because the source address would change
2687 while doing the copy. */
2688 || (autoinc_to != CONST
2689 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2690 && !IS_STACK_PUSH (to)))
2692 /* Must change the destination. */
2693 code = GET_CODE (XEXP (to, 0));
2694 reg = XEXP (XEXP (to, 0), 0);
2695 offset = GET_MODE_SIZE (GET_MODE (to));
2696 if (code == PRE_DEC || code == POST_DEC)
2699 if (code == PRE_DEC || code == PRE_INC)
2700 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2701 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2702 if (code == POST_DEC || code == POST_INC)
2703 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2708 /* Likewise, the source address register must not be used within
2709 the destination operand. */
2710 if (autoinc_from != CONST
2711 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2712 && !IS_STACK_PUSH (to))
2714 /* Must change the source. */
2715 code = GET_CODE (XEXP (from, 0));
2716 reg = XEXP (XEXP (from, 0), 0);
2717 offset = GET_MODE_SIZE (GET_MODE (from));
2718 if (code == PRE_DEC || code == POST_DEC)
2721 if (code == PRE_DEC || code == PRE_INC)
2722 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2723 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2724 if (code == POST_DEC || code == POST_INC)
2725 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2731 if (GET_MODE_SIZE (mode) == 8)
2733 else if (GET_MODE_SIZE (mode) == 4)
2739 && IS_STACK_PUSH (to)
2740 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2746 else if (mode == HImode)
2754 low_to = m68hc11_gen_lowpart (mode, to);
2755 high_to = m68hc11_gen_highpart (mode, to);
2757 low_from = m68hc11_gen_lowpart (mode, from);
2758 high_from = m68hc11_gen_highpart (mode, from);
2762 high_from = adjust_address (high_from, mode, offset);
2763 low_from = high_from;
2766 /* When copying with a POST_INC mode, we must copy the
2767 high part and then the low part to guarantee a correct
2770 && GET_MODE_SIZE (mode) >= 2
2771 && autoinc_from != autoinc_to
2772 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2781 low_from = high_from;
2786 m68hc11_split_move (low_to, low_from, scratch);
2787 m68hc11_split_move (high_to, high_from, scratch);
2789 else if (H_REG_P (to) || H_REG_P (from)
2790 || (low_from == const0_rtx
2791 && high_from == const0_rtx
2792 && ! push_operand (to, GET_MODE (to))
2793 && ! H_REG_P (scratch))
2795 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2796 || m68hc11_small_indexed_indirect_p (from,
2798 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2799 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2801 insn = emit_move_insn (low_to, low_from);
2802 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2804 insn = emit_move_insn (high_to, high_from);
2805 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2809 insn = emit_move_insn (scratch, low_from);
2810 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2811 insn = emit_move_insn (low_to, scratch);
2812 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2814 insn = emit_move_insn (scratch, high_from);
2815 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2816 insn = emit_move_insn (high_to, scratch);
2817 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2822 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2828 if (GET_CODE (operand) != CONST_INT)
2836 val = INTVAL (operand);
2840 if ((val & mask) == 0)
2842 if ((val & mask) == mask)
2843 *result = constm1_rtx;
2847 if ((val & mask) == 0)
2848 *result = const0_rtx;
2849 if ((val & mask) == mask)
2854 if ((val & mask) == 0)
2862 m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
2867 need_copy = (rtx_equal_p (operands[0], operands[1])
2868 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2870 operands[1] = simplify_logical (mode, code, operands[1], &result);
2871 operands[2] = simplify_logical (mode, code, operands[2], &result);
2873 if (result && GET_CODE (result) == CONST_INT)
2875 if (!H_REG_P (operands[0]) && operands[3]
2876 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2878 emit_move_insn (operands[3], result);
2879 emit_move_insn (operands[0], operands[3]);
2883 emit_move_insn (operands[0], result);
2886 else if (operands[1] != 0 && operands[2] != 0)
2890 if (!H_REG_P (operands[0]) && operands[3])
2892 emit_move_insn (operands[3], operands[1]);
2893 emit_insn (gen_rtx_SET (mode,
2895 gen_rtx_fmt_ee (code, mode,
2896 operands[3], operands[2])));
2897 insn = emit_move_insn (operands[0], operands[3]);
2901 insn = emit_insn (gen_rtx_SET (mode,
2903 gen_rtx_fmt_ee (code, mode,
2909 /* The logical operation is similar to a copy. */
2914 if (GET_CODE (operands[1]) == CONST_INT)
2919 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2921 emit_move_insn (operands[3], src);
2922 emit_move_insn (operands[0], operands[3]);
2926 emit_move_insn (operands[0], src);
2932 m68hc11_split_logical (enum machine_mode mode, enum rtx_code code,
2938 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2939 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2940 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2942 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2943 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2944 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2946 low[3] = operands[3];
2947 high[3] = operands[3];
2950 m68hc11_split_logical (HImode, code, low);
2951 m68hc11_split_logical (HImode, code, high);
2955 m68hc11_emit_logical (mode, code, low);
2956 m68hc11_emit_logical (mode, code, high);
2960 /* Code generation. */
2963 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
2965 /* We have to be careful with the cc_status. An address register swap
2966 is generated for some comparison. The comparison is made with D
2967 but the branch really uses the address register. See the split
2968 pattern for compare. The xgdx/xgdy preserve the flags but after
2969 the exchange, the flags will reflect to the value of X and not D.
2970 Tell this by setting the cc_status according to the cc_prev_status. */
2971 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2973 if (cc_prev_status.value1 != 0
2974 && (D_REG_P (cc_prev_status.value1)
2975 || X_REG_P (cc_prev_status.value1)))
2977 cc_status = cc_prev_status;
2978 if (D_REG_P (cc_status.value1))
2979 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
2982 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
2988 output_asm_insn ("xgdx", operands);
2992 if (cc_prev_status.value1 != 0
2993 && (D_REG_P (cc_prev_status.value1)
2994 || Y_REG_P (cc_prev_status.value1)))
2996 cc_status = cc_prev_status;
2997 if (D_REG_P (cc_status.value1))
2998 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3001 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3007 output_asm_insn ("xgdy", operands);
3011 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3012 This is used to decide whether a move that set flags should be used
3015 next_insn_test_reg (rtx insn, rtx reg)
3019 insn = next_nonnote_insn (insn);
3020 if (GET_CODE (insn) != INSN)
3023 body = PATTERN (insn);
3024 if (sets_cc0_p (body) != 1)
3027 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3033 /* Generate the code to move a 16-bit operand into another one. */
3036 m68hc11_gen_movhi (rtx insn, rtx *operands)
3040 /* Move a register or memory to the same location.
3041 This is possible because such insn can appear
3042 in a non-optimizing mode. */
3043 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3045 cc_status = cc_prev_status;
3051 rtx from = operands[1];
3052 rtx to = operands[0];
3054 if (IS_STACK_PUSH (to) && H_REG_P (from))
3056 cc_status = cc_prev_status;
3057 switch (REGNO (from))
3062 output_asm_insn ("psh%1", operands);
3064 case HARD_SP_REGNUM:
3065 output_asm_insn ("sts\t2,-sp", operands);
3072 if (IS_STACK_POP (from) && H_REG_P (to))
3074 cc_status = cc_prev_status;
3080 output_asm_insn ("pul%0", operands);
3087 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3089 m68hc11_notice_keep_cc (operands[0]);
3090 output_asm_insn ("tfr\t%1,%0", operands);
3092 else if (H_REG_P (operands[0]))
3094 if (SP_REG_P (operands[0]))
3095 output_asm_insn ("lds\t%1", operands);
3097 output_asm_insn ("ld%0\t%1", operands);
3099 else if (H_REG_P (operands[1]))
3101 if (SP_REG_P (operands[1]))
3102 output_asm_insn ("sts\t%0", operands);
3104 output_asm_insn ("st%1\t%0", operands);
3107 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3108 instruction. We have to use a scratch register as temporary location.
3109 Trying to use a specific pattern or constrain failed. */
3110 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3117 if (dead_register_here (insn, d_reg))
3119 else if (dead_register_here (insn, ix_reg))
3121 else if (dead_register_here (insn, iy_reg))
3127 output_asm_insn ("psh%3", ops);
3132 output_asm_insn ("ld%1\t%2", ops);
3133 output_asm_insn ("st%1\t%0", ops);
3135 output_asm_insn ("pul%3", ops);
3138 /* Use movw for non-null constants or when we are clearing
3139 a volatile memory reference. However, this is possible
3140 only if the memory reference has a small offset or is an
3141 absolute address. */
3142 else if (GET_CODE (from) == CONST_INT
3143 && INTVAL (from) == 0
3144 && (MEM_VOLATILE_P (to) == 0
3145 || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3147 output_asm_insn ("clr\t%h0", operands);
3148 output_asm_insn ("clr\t%b0", operands);
3152 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3153 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3154 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3155 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3161 ops[0] = operands[2];
3164 m68hc11_gen_movhi (insn, ops);
3166 ops[1] = operands[2];
3167 m68hc11_gen_movhi (insn, ops);
3172 /* !!!! SCz wrong here. */
3173 fatal_insn ("move insn not handled", insn);
3178 m68hc11_notice_keep_cc (operands[0]);
3179 output_asm_insn ("movw\t%1,%0", operands);
3185 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3187 cc_status = cc_prev_status;
3188 switch (REGNO (operands[0]))
3192 output_asm_insn ("pul%0", operands);
3195 output_asm_insn ("pula", operands);
3196 output_asm_insn ("pulb", operands);
3203 /* Some moves to a hard register are special. Not all of them
3204 are really supported and we have to use a temporary
3205 location to provide them (either the stack of a temp var). */
3206 if (H_REG_P (operands[0]))
3208 switch (REGNO (operands[0]))
3211 if (X_REG_P (operands[1]))
3213 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3215 m68hc11_output_swap (insn, operands);
3217 else if (next_insn_test_reg (insn, operands[0]))
3219 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3223 m68hc11_notice_keep_cc (operands[0]);
3224 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3227 else if (Y_REG_P (operands[1]))
3229 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3231 m68hc11_output_swap (insn, operands);
3235 /* %t means *ZTMP scratch register. */
3236 output_asm_insn ("sty\t%t1", operands);
3237 output_asm_insn ("ldd\t%t1", operands);
3240 else if (SP_REG_P (operands[1]))
3245 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3246 output_asm_insn ("xgdx", operands);
3247 output_asm_insn ("tsx", operands);
3248 output_asm_insn ("xgdx", operands);
3250 else if (IS_STACK_POP (operands[1]))
3252 output_asm_insn ("pula\n\tpulb", operands);
3254 else if (GET_CODE (operands[1]) == CONST_INT
3255 && INTVAL (operands[1]) == 0)
3257 output_asm_insn ("clra\n\tclrb", operands);
3261 output_asm_insn ("ldd\t%1", operands);
3266 if (D_REG_P (operands[1]))
3268 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3270 m68hc11_output_swap (insn, operands);
3272 else if (next_insn_test_reg (insn, operands[0]))
3274 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3278 m68hc11_notice_keep_cc (operands[0]);
3279 output_asm_insn ("pshb", operands);
3280 output_asm_insn ("psha", operands);
3281 output_asm_insn ("pulx", operands);
3284 else if (Y_REG_P (operands[1]))
3286 /* When both D and Y are dead, use the sequence xgdy, xgdx
3287 to move Y into X. The D and Y registers are modified. */
3288 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3289 && dead_register_here (insn, d_reg))
3291 output_asm_insn ("xgdy", operands);
3292 output_asm_insn ("xgdx", operands);
3295 else if (!optimize_size)
3297 output_asm_insn ("sty\t%t1", operands);
3298 output_asm_insn ("ldx\t%t1", operands);
3303 output_asm_insn ("pshy", operands);
3304 output_asm_insn ("pulx", operands);
3307 else if (SP_REG_P (operands[1]))
3309 /* tsx, tsy preserve the flags */
3310 cc_status = cc_prev_status;
3311 output_asm_insn ("tsx", operands);
3315 output_asm_insn ("ldx\t%1", operands);
3320 if (D_REG_P (operands[1]))
3322 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3324 m68hc11_output_swap (insn, operands);
3328 output_asm_insn ("std\t%t1", operands);
3329 output_asm_insn ("ldy\t%t1", operands);
3332 else if (X_REG_P (operands[1]))
3334 /* When both D and X are dead, use the sequence xgdx, xgdy
3335 to move X into Y. The D and X registers are modified. */
3336 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3337 && dead_register_here (insn, d_reg))
3339 output_asm_insn ("xgdx", operands);
3340 output_asm_insn ("xgdy", operands);
3343 else if (!optimize_size)
3345 output_asm_insn ("stx\t%t1", operands);
3346 output_asm_insn ("ldy\t%t1", operands);
3351 output_asm_insn ("pshx", operands);
3352 output_asm_insn ("puly", operands);
3355 else if (SP_REG_P (operands[1]))
3357 /* tsx, tsy preserve the flags */
3358 cc_status = cc_prev_status;
3359 output_asm_insn ("tsy", operands);
3363 output_asm_insn ("ldy\t%1", operands);
3367 case HARD_SP_REGNUM:
3368 if (D_REG_P (operands[1]))
3370 m68hc11_notice_keep_cc (operands[0]);
3371 output_asm_insn ("xgdx", operands);
3372 output_asm_insn ("txs", operands);
3373 output_asm_insn ("xgdx", operands);
3375 else if (X_REG_P (operands[1]))
3377 /* tys, txs preserve the flags */
3378 cc_status = cc_prev_status;
3379 output_asm_insn ("txs", operands);
3381 else if (Y_REG_P (operands[1]))
3383 /* tys, txs preserve the flags */
3384 cc_status = cc_prev_status;
3385 output_asm_insn ("tys", operands);
3389 /* lds sets the flags but the des does not. */
3391 output_asm_insn ("lds\t%1", operands);
3392 output_asm_insn ("des", operands);
3397 fatal_insn ("invalid register in the move instruction", insn);
3402 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3403 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3405 output_asm_insn ("sts\t%0", operands);
3409 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3411 cc_status = cc_prev_status;
3412 switch (REGNO (operands[1]))
3416 output_asm_insn ("psh%1", operands);
3419 output_asm_insn ("pshb", operands);
3420 output_asm_insn ("psha", operands);
3428 /* Operand 1 must be a hard register. */
3429 if (!H_REG_P (operands[1]))
3431 fatal_insn ("invalid operand in the instruction", insn);
3434 reg = REGNO (operands[1]);
3438 output_asm_insn ("std\t%0", operands);
3442 output_asm_insn ("stx\t%0", operands);
3446 output_asm_insn ("sty\t%0", operands);
3449 case HARD_SP_REGNUM:
3453 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3455 output_asm_insn ("pshx", operands);
3456 output_asm_insn ("tsx", operands);
3457 output_asm_insn ("inx", operands);
3458 output_asm_insn ("inx", operands);
3459 output_asm_insn ("stx\t%0", operands);
3460 output_asm_insn ("pulx", operands);
3463 else if (reg_mentioned_p (ix_reg, operands[0]))
3465 output_asm_insn ("sty\t%t0", operands);
3466 output_asm_insn ("tsy", operands);
3467 output_asm_insn ("sty\t%0", operands);
3468 output_asm_insn ("ldy\t%t0", operands);
3472 output_asm_insn ("stx\t%t0", operands);
3473 output_asm_insn ("tsx", operands);
3474 output_asm_insn ("stx\t%0", operands);
3475 output_asm_insn ("ldx\t%t0", operands);
3481 fatal_insn ("invalid register in the move instruction", insn);
3487 m68hc11_gen_movqi (rtx insn, rtx *operands)
3489 /* Move a register or memory to the same location.
3490 This is possible because such insn can appear
3491 in a non-optimizing mode. */
3492 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3494 cc_status = cc_prev_status;
3501 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3503 m68hc11_notice_keep_cc (operands[0]);
3504 output_asm_insn ("tfr\t%1,%0", operands);
3506 else if (H_REG_P (operands[0]))
3508 if (IS_STACK_POP (operands[1]))
3509 output_asm_insn ("pul%b0", operands);
3510 else if (Q_REG_P (operands[0]))
3511 output_asm_insn ("lda%0\t%b1", operands);
3512 else if (D_REG_P (operands[0]))
3513 output_asm_insn ("ldab\t%b1", operands);
3517 else if (H_REG_P (operands[1]))
3519 if (Q_REG_P (operands[1]))
3520 output_asm_insn ("sta%1\t%b0", operands);
3521 else if (D_REG_P (operands[1]))
3522 output_asm_insn ("stab\t%b0", operands);
3528 rtx from = operands[1];
3529 rtx to = operands[0];
3531 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3532 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3533 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3534 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3540 ops[0] = operands[2];
3543 m68hc11_gen_movqi (insn, ops);
3545 ops[1] = operands[2];
3546 m68hc11_gen_movqi (insn, ops);
3550 /* !!!! SCz wrong here. */
3551 fatal_insn ("move insn not handled", insn);
3556 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3558 output_asm_insn ("clr\t%b0", operands);
3562 m68hc11_notice_keep_cc (operands[0]);
3563 output_asm_insn ("movb\t%b1,%b0", operands);
3571 if (H_REG_P (operands[0]))
3573 switch (REGNO (operands[0]))
3577 if (X_REG_P (operands[1]))
3579 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3581 m68hc11_output_swap (insn, operands);
3585 output_asm_insn ("stx\t%t1", operands);
3586 output_asm_insn ("ldab\t%T0", operands);
3589 else if (Y_REG_P (operands[1]))
3591 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3593 m68hc11_output_swap (insn, operands);
3597 output_asm_insn ("sty\t%t1", operands);
3598 output_asm_insn ("ldab\t%T0", operands);
3601 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3602 && !DA_REG_P (operands[1]))
3604 output_asm_insn ("ldab\t%b1", operands);
3606 else if (DA_REG_P (operands[1]))
3608 output_asm_insn ("tab", operands);
3612 cc_status = cc_prev_status;
3618 if (X_REG_P (operands[1]))
3620 output_asm_insn ("stx\t%t1", operands);
3621 output_asm_insn ("ldaa\t%T0", operands);
3623 else if (Y_REG_P (operands[1]))
3625 output_asm_insn ("sty\t%t1", operands);
3626 output_asm_insn ("ldaa\t%T0", operands);
3628 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3629 && !DA_REG_P (operands[1]))
3631 output_asm_insn ("ldaa\t%b1", operands);
3633 else if (!DA_REG_P (operands[1]))
3635 output_asm_insn ("tba", operands);
3639 cc_status = cc_prev_status;
3644 if (D_REG_P (operands[1]))
3646 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3648 m68hc11_output_swap (insn, operands);
3652 output_asm_insn ("stab\t%T1", operands);
3653 output_asm_insn ("ldx\t%t1", operands);
3657 else if (Y_REG_P (operands[1]))
3659 output_asm_insn ("sty\t%t0", operands);
3660 output_asm_insn ("ldx\t%t0", operands);
3662 else if (GET_CODE (operands[1]) == CONST_INT)
3664 output_asm_insn ("ldx\t%1", operands);
3666 else if (dead_register_here (insn, d_reg))
3668 output_asm_insn ("ldab\t%b1", operands);
3669 output_asm_insn ("xgdx", operands);
3671 else if (!reg_mentioned_p (operands[0], operands[1]))
3673 output_asm_insn ("xgdx", operands);
3674 output_asm_insn ("ldab\t%b1", operands);
3675 output_asm_insn ("xgdx", operands);
3679 output_asm_insn ("pshb", operands);
3680 output_asm_insn ("ldab\t%b1", operands);
3681 output_asm_insn ("stab\t%T1", operands);
3682 output_asm_insn ("ldx\t%t1", operands);
3683 output_asm_insn ("pulb", operands);
3689 if (D_REG_P (operands[1]))
3691 output_asm_insn ("stab\t%T1", operands);
3692 output_asm_insn ("ldy\t%t1", operands);
3695 else if (X_REG_P (operands[1]))
3697 output_asm_insn ("stx\t%t1", operands);
3698 output_asm_insn ("ldy\t%t1", operands);
3701 else if (GET_CODE (operands[1]) == CONST_INT)
3703 output_asm_insn ("ldy\t%1", operands);
3705 else if (dead_register_here (insn, d_reg))
3707 output_asm_insn ("ldab\t%b1", operands);
3708 output_asm_insn ("xgdy", operands);
3710 else if (!reg_mentioned_p (operands[0], operands[1]))
3712 output_asm_insn ("xgdy", operands);
3713 output_asm_insn ("ldab\t%b1", operands);
3714 output_asm_insn ("xgdy", operands);
3718 output_asm_insn ("pshb", operands);
3719 output_asm_insn ("ldab\t%b1", operands);
3720 output_asm_insn ("stab\t%T1", operands);
3721 output_asm_insn ("ldy\t%t1", operands);
3722 output_asm_insn ("pulb", operands);
3728 fatal_insn ("invalid register in the instruction", insn);
3732 else if (H_REG_P (operands[1]))
3734 switch (REGNO (operands[1]))
3738 output_asm_insn ("stab\t%b0", operands);
3742 output_asm_insn ("staa\t%b0", operands);
3746 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3750 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3754 fatal_insn ("invalid register in the move instruction", insn);
3761 fatal_insn ("operand 1 must be a hard register", insn);
3765 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3766 The source and destination must be D or A and the shift must
3769 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3773 if (GET_CODE (operands[2]) != CONST_INT
3774 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3775 fatal_insn ("invalid rotate insn", insn);
3777 val = INTVAL (operands[2]);
3778 if (code == ROTATERT)
3779 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3781 if (GET_MODE (operands[0]) != QImode)
3784 /* Rotate by 8-bits if the shift is within [5..11]. */
3785 if (val >= 5 && val <= 11)
3788 output_asm_insn ("exg\ta,b", operands);
3791 output_asm_insn ("psha", operands);
3792 output_asm_insn ("tba", operands);
3793 output_asm_insn ("pulb", operands);
3798 /* If the shift is big, invert the rotation. */
3808 /* Set the carry to bit-15, but don't change D yet. */
3809 if (GET_MODE (operands[0]) != QImode)
3811 output_asm_insn ("asra", operands);
3812 output_asm_insn ("rola", operands);
3815 /* Rotate B first to move the carry to bit-0. */
3816 if (D_REG_P (operands[0]))
3817 output_asm_insn ("rolb", operands);
3819 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3820 output_asm_insn ("rola", operands);
3827 /* Set the carry to bit-8 of D. */
3828 if (GET_MODE (operands[0]) != QImode)
3829 output_asm_insn ("tap", operands);
3831 /* Rotate B first to move the carry to bit-7. */
3832 if (D_REG_P (operands[0]))
3833 output_asm_insn ("rorb", operands);
3835 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3836 output_asm_insn ("rora", operands);
3843 /* Store in cc_status the expressions that the condition codes will
3844 describe after execution of an instruction whose pattern is EXP.
3845 Do not alter them if the instruction would not alter the cc's. */
3848 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3850 /* recognize SET insn's. */
3851 if (GET_CODE (exp) == SET)
3853 /* Jumps do not alter the cc's. */
3854 if (SET_DEST (exp) == pc_rtx)
3857 /* NOTE: most instructions don't affect the carry bit, but the
3858 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3859 the conditions.h header. */
3861 /* Function calls clobber the cc's. */
3862 else if (GET_CODE (SET_SRC (exp)) == CALL)
3867 /* Tests and compares set the cc's in predictable ways. */
3868 else if (SET_DEST (exp) == cc0_rtx)
3870 cc_status.flags = 0;
3871 cc_status.value1 = XEXP (exp, 0);
3872 if (GET_CODE (XEXP (exp, 1)) == COMPARE
3873 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
3874 cc_status.value2 = XEXP (XEXP (exp, 1), 0);
3876 cc_status.value2 = XEXP (exp, 1);
3880 /* All other instructions affect the condition codes. */
3881 cc_status.flags = 0;
3882 cc_status.value1 = XEXP (exp, 0);
3883 cc_status.value2 = XEXP (exp, 1);
3888 /* Default action if we haven't recognized something
3889 and returned earlier. */
3893 if (cc_status.value2 != 0)
3894 switch (GET_CODE (cc_status.value2))
3896 /* These logical operations can generate several insns.
3897 The flags are setup according to what is generated. */
3903 /* The (not ...) generates several 'com' instructions for
3904 non QImode. We have to invalidate the flags. */
3906 if (GET_MODE (cc_status.value2) != QImode)
3918 if (GET_MODE (cc_status.value2) != VOIDmode)
3919 cc_status.flags |= CC_NO_OVERFLOW;
3922 /* The asl sets the overflow bit in such a way that this
3923 makes the flags unusable for a next compare insn. */
3927 if (GET_MODE (cc_status.value2) != VOIDmode)
3928 cc_status.flags |= CC_NO_OVERFLOW;
3931 /* A load/store instruction does not affect the carry. */
3936 cc_status.flags |= CC_NO_OVERFLOW;
3942 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3944 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3945 cc_status.value2 = 0;
3947 else if (cc_status.value1 && side_effects_p (cc_status.value1))
3948 cc_status.value1 = 0;
3950 else if (cc_status.value2 && side_effects_p (cc_status.value2))
3951 cc_status.value2 = 0;
3954 /* The current instruction does not affect the flags but changes
3955 the register 'reg'. See if the previous flags can be kept for the
3956 next instruction to avoid a comparison. */
3958 m68hc11_notice_keep_cc (rtx reg)
3961 || cc_prev_status.value1 == 0
3962 || rtx_equal_p (reg, cc_prev_status.value1)
3963 || (cc_prev_status.value2
3964 && reg_mentioned_p (reg, cc_prev_status.value2)))
3967 cc_status = cc_prev_status;
3972 /* Machine Specific Reorg. */
3974 /* Z register replacement:
3976 GCC treats the Z register as an index base address register like
3977 X or Y. In general, it uses it during reload to compute the address
3978 of some operand. This helps the reload pass to avoid to fall into the
3979 register spill failure.
3981 The Z register is in the A_REGS class. In the machine description,
3982 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3984 It can appear everywhere an X or Y register can appear, except for
3985 some templates in the clobber section (when a clobber of X or Y is asked).
3986 For a given instruction, the template must ensure that no more than
3987 2 'A' registers are used. Otherwise, the register replacement is not
3990 To replace the Z register, the algorithm is not terrific:
3991 1. Insns that do not use the Z register are not changed
3992 2. When a Z register is used, we scan forward the insns to see
3993 a potential register to use: either X or Y and sometimes D.
3994 We stop when a call, a label or a branch is seen, or when we
3995 detect that both X and Y are used (probably at different times, but it does
3997 3. The register that will be used for the replacement of Z is saved
3998 in a .page0 register or on the stack. If the first instruction that
3999 used Z, uses Z as an input, the value is loaded from another .page0
4000 register. The replacement register is pushed on the stack in the
4001 rare cases where a compare insn uses Z and we couldn't find if X/Y
4003 4. The Z register is replaced in all instructions until we reach
4004 the end of the Z-block, as detected by step 2.
4005 5. If we detect that Z is still alive, its value is saved.
4006 If the replacement register is alive, its old value is loaded.
4008 The Z register can be disabled with -ffixed-z.
4018 int must_restore_reg;
4029 int save_before_last;
4030 int z_loaded_with_sp;
4033 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4034 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4035 static void m68hc11_z_replacement (rtx);
4036 static void m68hc11_reassign_regs (rtx);
4038 int z_replacement_completed = 0;
4040 /* Analyze the insn to find out which replacement register to use and
4041 the boundaries of the replacement.
4042 Returns 0 if we reached the last insn to be replaced, 1 if we can
4043 continue replacement in next insns. */
4046 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4048 int this_insn_uses_ix;
4049 int this_insn_uses_iy;
4050 int this_insn_uses_z;
4051 int this_insn_uses_z_in_dst;
4052 int this_insn_uses_d;
4056 /* A call is said to clobber the Z register, we don't need
4057 to save the value of Z. We also don't need to restore
4058 the replacement register (unless it is used by the call). */
4059 if (GET_CODE (insn) == CALL_INSN)
4061 body = PATTERN (insn);
4063 info->can_use_d = 0;
4065 /* If the call is an indirect call with Z, we have to use the
4066 Y register because X can be used as an input (D+X).
4067 We also must not save Z nor restore Y. */
4068 if (reg_mentioned_p (z_reg, body))
4070 insn = NEXT_INSN (insn);
4073 info->found_call = 1;
4074 info->must_restore_reg = 0;
4075 info->last = NEXT_INSN (insn);
4077 info->need_save_z = 0;
4080 if (GET_CODE (insn) == CODE_LABEL
4081 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4084 if (GET_CODE (insn) == JUMP_INSN)
4086 if (reg_mentioned_p (z_reg, insn) == 0)
4089 info->can_use_d = 0;
4090 info->must_save_reg = 0;
4091 info->must_restore_reg = 0;
4092 info->need_save_z = 0;
4093 info->last = NEXT_INSN (insn);
4096 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4101 /* Z register dies here. */
4102 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4104 body = PATTERN (insn);
4105 if (GET_CODE (body) == SET)
4107 rtx src = XEXP (body, 1);
4108 rtx dst = XEXP (body, 0);
4110 /* Condition code is set here. We have to restore the X/Y and
4111 save into Z before any test/compare insn because once we save/restore
4112 we can change the condition codes. When the compare insn uses Z and
4113 we can't use X/Y, the comparison is made with the *ZREG soft register
4114 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4117 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4118 || (GET_CODE (src) == COMPARE &&
4119 ((rtx_equal_p (XEXP (src, 0), z_reg)
4120 && H_REG_P (XEXP (src, 1)))
4121 || (rtx_equal_p (XEXP (src, 1), z_reg)
4122 && H_REG_P (XEXP (src, 0))))))
4124 if (insn == info->first)
4126 info->must_load_z = 0;
4127 info->must_save_reg = 0;
4128 info->must_restore_reg = 0;
4129 info->need_save_z = 0;
4130 info->found_call = 1;
4131 info->regno = SOFT_Z_REGNUM;
4132 info->last = NEXT_INSN (insn);
4136 if (reg_mentioned_p (z_reg, src) == 0)
4138 info->can_use_d = 0;
4142 if (insn != info->first)
4145 /* Compare insn which uses Z. We have to save/restore the X/Y
4146 register without modifying the condition codes. For this
4147 we have to use a push/pop insn. */
4148 info->must_push_reg = 1;
4152 /* Z reg is set to something new. We don't need to load it. */
4155 if (!reg_mentioned_p (z_reg, src))
4157 /* Z reg is used before being set. Treat this as
4158 a new sequence of Z register replacement. */
4159 if (insn != info->first)
4163 info->must_load_z = 0;
4165 info->z_set_count++;
4166 info->z_value = src;
4168 info->z_loaded_with_sp = 1;
4170 else if (reg_mentioned_p (z_reg, dst))
4171 info->can_use_d = 0;
4173 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4174 | reg_mentioned_p (d_reg, dst);
4175 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4176 | reg_mentioned_p (ix_reg, dst);
4177 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4178 | reg_mentioned_p (iy_reg, dst);
4179 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4181 /* If z is used as an address operand (like (MEM (reg z))),
4182 we can't replace it with d. */
4183 if (this_insn_uses_z && !Z_REG_P (src)
4184 && !(m68hc11_arith_operator (src, GET_MODE (src))
4185 && Z_REG_P (XEXP (src, 0))
4186 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4187 && insn == info->first
4188 && dead_register_here (insn, d_reg)))
4189 info->can_use_d = 0;
4191 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4192 if (TARGET_M6812 && !z_dies_here
4193 && ((this_insn_uses_z && side_effects_p (src))
4194 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4196 info->need_save_z = 1;
4197 info->z_set_count++;
4199 this_insn_uses_z |= this_insn_uses_z_in_dst;
4201 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4203 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4206 if (this_insn_uses_d)
4207 info->can_use_d = 0;
4209 /* IX and IY are used at the same time, we have to restore
4210 the value of the scratch register before this insn. */
4211 if (this_insn_uses_ix && this_insn_uses_iy)
4216 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4217 info->can_use_d = 0;
4219 if (info->x_used == 0 && this_insn_uses_ix)
4223 /* We have a (set (REG:HI X) (REG:HI Z)).
4224 Since we use Z as the replacement register, this insn
4225 is no longer necessary. We turn it into a note. We must
4226 not reload the old value of X. */
4227 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4231 info->need_save_z = 0;
4234 info->must_save_reg = 0;
4235 info->must_restore_reg = 0;
4236 info->found_call = 1;
4237 info->can_use_d = 0;
4238 SET_INSN_DELETED (insn);
4239 info->last = NEXT_INSN (insn);
4244 && (rtx_equal_p (src, z_reg)
4245 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4249 info->need_save_z = 0;
4252 info->last = NEXT_INSN (insn);
4253 info->must_save_reg = 0;
4254 info->must_restore_reg = 0;
4256 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4257 && !reg_mentioned_p (ix_reg, src))
4262 info->need_save_z = 0;
4264 else if (TARGET_M6812 && side_effects_p (src))
4267 info->must_restore_reg = 0;
4272 info->save_before_last = 1;
4274 info->must_restore_reg = 0;
4275 info->last = NEXT_INSN (insn);
4277 else if (info->can_use_d)
4279 info->last = NEXT_INSN (insn);
4285 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4286 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4288 info->need_save_z = 0;
4290 info->last = NEXT_INSN (insn);
4291 info->regno = HARD_X_REGNUM;
4292 info->must_save_reg = 0;
4293 info->must_restore_reg = 0;
4296 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4298 info->regno = HARD_X_REGNUM;
4299 info->must_restore_reg = 0;
4300 info->must_save_reg = 0;
4304 if (info->y_used == 0 && this_insn_uses_iy)
4308 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4312 info->need_save_z = 0;
4315 info->must_save_reg = 0;
4316 info->must_restore_reg = 0;
4317 info->found_call = 1;
4318 info->can_use_d = 0;
4319 SET_INSN_DELETED (insn);
4320 info->last = NEXT_INSN (insn);
4325 && (rtx_equal_p (src, z_reg)
4326 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4331 info->need_save_z = 0;
4333 info->last = NEXT_INSN (insn);
4334 info->must_save_reg = 0;
4335 info->must_restore_reg = 0;
4337 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4338 && !reg_mentioned_p (iy_reg, src))
4343 info->need_save_z = 0;
4345 else if (TARGET_M6812 && side_effects_p (src))
4348 info->must_restore_reg = 0;
4353 info->save_before_last = 1;
4355 info->must_restore_reg = 0;
4356 info->last = NEXT_INSN (insn);
4358 else if (info->can_use_d)
4360 info->last = NEXT_INSN (insn);
4367 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4368 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4370 info->need_save_z = 0;
4372 info->last = NEXT_INSN (insn);
4373 info->regno = HARD_Y_REGNUM;
4374 info->must_save_reg = 0;
4375 info->must_restore_reg = 0;
4378 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4380 info->regno = HARD_Y_REGNUM;
4381 info->must_restore_reg = 0;
4382 info->must_save_reg = 0;
4388 info->need_save_z = 0;
4390 if (info->last == 0)
4391 info->last = NEXT_INSN (insn);
4394 return info->last != NULL_RTX ? 0 : 1;
4396 if (GET_CODE (body) == PARALLEL)
4399 char ix_clobber = 0;
4400 char iy_clobber = 0;
4402 this_insn_uses_iy = 0;
4403 this_insn_uses_ix = 0;
4404 this_insn_uses_z = 0;
4406 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4409 int uses_ix, uses_iy, uses_z;
4411 x = XVECEXP (body, 0, i);
4413 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4414 info->can_use_d = 0;
4416 uses_ix = reg_mentioned_p (ix_reg, x);
4417 uses_iy = reg_mentioned_p (iy_reg, x);
4418 uses_z = reg_mentioned_p (z_reg, x);
4419 if (GET_CODE (x) == CLOBBER)
4421 ix_clobber |= uses_ix;
4422 iy_clobber |= uses_iy;
4423 z_clobber |= uses_z;
4427 this_insn_uses_ix |= uses_ix;
4428 this_insn_uses_iy |= uses_iy;
4429 this_insn_uses_z |= uses_z;
4431 if (uses_z && GET_CODE (x) == SET)
4433 rtx dst = XEXP (x, 0);
4436 info->z_set_count++;
4438 if (TARGET_M6812 && uses_z && side_effects_p (x))
4439 info->need_save_z = 1;
4442 info->need_save_z = 0;
4446 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4447 this_insn_uses_ix, this_insn_uses_iy,
4448 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4451 if (this_insn_uses_z)
4452 info->can_use_d = 0;
4454 if (z_clobber && info->first != insn)
4456 info->need_save_z = 0;
4460 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4462 if (this_insn_uses_z == 0 && insn == info->first)
4464 info->must_load_z = 0;
4466 if (dead_register_here (insn, d_reg))
4468 info->regno = HARD_D_REGNUM;
4469 info->must_save_reg = 0;
4470 info->must_restore_reg = 0;
4472 else if (dead_register_here (insn, ix_reg))
4474 info->regno = HARD_X_REGNUM;
4475 info->must_save_reg = 0;
4476 info->must_restore_reg = 0;
4478 else if (dead_register_here (insn, iy_reg))
4480 info->regno = HARD_Y_REGNUM;
4481 info->must_save_reg = 0;
4482 info->must_restore_reg = 0;
4484 if (info->regno >= 0)
4486 info->last = NEXT_INSN (insn);
4489 if (this_insn_uses_ix == 0)
4491 info->regno = HARD_X_REGNUM;
4492 info->must_save_reg = 1;
4493 info->must_restore_reg = 1;
4495 else if (this_insn_uses_iy == 0)
4497 info->regno = HARD_Y_REGNUM;
4498 info->must_save_reg = 1;
4499 info->must_restore_reg = 1;
4503 info->regno = HARD_D_REGNUM;
4504 info->must_save_reg = 1;
4505 info->must_restore_reg = 1;
4507 info->last = NEXT_INSN (insn);
4511 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4512 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4514 if (this_insn_uses_z)
4516 if (info->y_used == 0 && iy_clobber)
4518 info->regno = HARD_Y_REGNUM;
4519 info->must_save_reg = 0;
4520 info->must_restore_reg = 0;
4522 if (info->first != insn
4523 && ((info->y_used && ix_clobber)
4524 || (info->x_used && iy_clobber)))
4527 info->last = NEXT_INSN (insn);
4528 info->save_before_last = 1;
4532 if (this_insn_uses_ix && this_insn_uses_iy)
4534 if (this_insn_uses_z)
4536 fatal_insn ("cannot do z-register replacement", insn);
4540 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4547 if (iy_clobber || z_clobber)
4549 info->last = NEXT_INSN (insn);
4550 info->save_before_last = 1;
4555 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4562 if (ix_clobber || z_clobber)
4564 info->last = NEXT_INSN (insn);
4565 info->save_before_last = 1;
4572 info->need_save_z = 0;
4576 if (GET_CODE (body) == CLOBBER)
4579 /* IX and IY are used at the same time, we have to restore
4580 the value of the scratch register before this insn. */
4581 if (this_insn_uses_ix && this_insn_uses_iy)
4585 if (info->x_used == 0 && this_insn_uses_ix)
4593 if (info->y_used == 0 && this_insn_uses_iy)
4607 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4611 info->replace_reg = NULL_RTX;
4612 info->must_load_z = 1;
4613 info->need_save_z = 1;
4614 info->must_save_reg = 1;
4615 info->must_restore_reg = 1;
4619 info->can_use_d = TARGET_M6811 ? 1 : 0;
4620 info->found_call = 0;
4624 info->z_set_count = 0;
4625 info->z_value = NULL_RTX;
4626 info->must_push_reg = 0;
4627 info->save_before_last = 0;
4628 info->z_loaded_with_sp = 0;
4630 /* Scan the insn forward to find an address register that is not used.
4632 - the flow of the program changes,
4633 - when we detect that both X and Y are necessary,
4634 - when the Z register dies,
4635 - when the condition codes are set. */
4637 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4639 if (m68hc11_check_z_replacement (insn, info) == 0)
4643 /* May be we can use Y or X if they contain the same value as Z.
4644 This happens very often after the reload. */
4645 if (info->z_set_count == 1)
4647 rtx p = info->first;
4652 v = find_last_value (iy_reg, &p, insn, 1);
4654 else if (info->y_used)
4656 v = find_last_value (ix_reg, &p, insn, 1);
4658 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4661 info->regno = HARD_Y_REGNUM;
4663 info->regno = HARD_X_REGNUM;
4664 info->must_load_z = 0;
4665 info->must_save_reg = 0;
4666 info->must_restore_reg = 0;
4667 info->found_call = 1;
4670 if (info->z_set_count == 0)
4671 info->need_save_z = 0;
4674 info->need_save_z = 0;
4676 if (info->last == 0)
4679 if (info->regno >= 0)
4682 info->replace_reg = gen_rtx_REG (HImode, reg);
4684 else if (info->can_use_d)
4686 reg = HARD_D_REGNUM;
4687 info->replace_reg = d_reg;
4689 else if (info->x_used)
4691 reg = HARD_Y_REGNUM;
4692 info->replace_reg = iy_reg;
4696 reg = HARD_X_REGNUM;
4697 info->replace_reg = ix_reg;
4701 if (info->must_save_reg && info->must_restore_reg)
4703 if (insn && dead_register_here (insn, info->replace_reg))
4705 info->must_save_reg = 0;
4706 info->must_restore_reg = 0;
4711 /* The insn uses the Z register. Find a replacement register for it
4712 (either X or Y) and replace it in the insn and the next ones until
4713 the flow changes or the replacement register is used. Instructions
4714 are emitted before and after the Z-block to preserve the value of
4715 Z and of the replacement register. */
4718 m68hc11_z_replacement (rtx insn)
4722 struct replace_info info;
4724 /* Find trivial case where we only need to replace z with the
4725 equivalent soft register. */
4726 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4728 rtx body = PATTERN (insn);
4729 rtx src = XEXP (body, 1);
4730 rtx dst = XEXP (body, 0);
4732 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4734 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4737 else if (Z_REG_P (src)
4738 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4740 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4743 else if (D_REG_P (dst)
4744 && m68hc11_arith_operator (src, GET_MODE (src))
4745 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4747 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4750 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4751 && INTVAL (src) == 0)
4753 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4754 /* Force it to be re-recognized. */
4755 INSN_CODE (insn) = -1;
4760 m68hc11_find_z_replacement (insn, &info);
4762 replace_reg = info.replace_reg;
4763 replace_reg_qi = NULL_RTX;
4765 /* Save the X register in a .page0 location. */
4766 if (info.must_save_reg && !info.must_push_reg)
4770 if (info.must_push_reg && 0)
4771 dst = gen_rtx_MEM (HImode,
4772 gen_rtx_PRE_DEC (HImode,
4773 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4775 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4777 emit_insn_before (gen_movhi (dst,
4778 gen_rtx_REG (HImode, info.regno)), insn);
4780 if (info.must_load_z && !info.must_push_reg)
4782 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4783 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4788 /* Replace all occurrence of Z by replace_reg.
4789 Stop when the last instruction to replace is reached.
4790 Also stop when we detect a change in the flow (but it's not
4791 necessary; just safeguard). */
4793 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4797 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4800 if (GET_CODE (insn) != INSN
4801 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4804 body = PATTERN (insn);
4805 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4806 || GET_CODE (body) == ASM_OPERANDS
4807 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4811 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4813 printf ("Reg mentioned here...:\n");
4818 /* Stack pointer was decremented by 2 due to the push.
4819 Correct that by adding 2 to the destination. */
4820 if (info.must_push_reg
4821 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4825 src = SET_SRC (body);
4826 dst = SET_DEST (body);
4827 if (SP_REG_P (src) && Z_REG_P (dst))
4828 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4831 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4832 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4834 INSN_CODE (insn) = -1;
4835 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4836 fatal_insn ("cannot do z-register replacement", insn);
4839 /* Likewise for (REG:QI Z). */
4840 if (reg_mentioned_p (z_reg, insn))
4842 if (replace_reg_qi == NULL_RTX)
4843 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4844 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4847 /* If there is a REG_INC note on Z, replace it with a
4848 REG_INC note on the replacement register. This is necessary
4849 to make sure that the flow pass will identify the change
4850 and it will not remove a possible insn that saves Z. */
4851 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4853 if (REG_NOTE_KIND (note) == REG_INC
4854 && GET_CODE (XEXP (note, 0)) == REG
4855 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4857 XEXP (note, 0) = replace_reg;
4861 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4865 /* Save Z before restoring the old value. */
4866 if (insn && info.need_save_z && !info.must_push_reg)
4868 rtx save_pos_insn = insn;
4870 /* If Z is clobber by the last insn, we have to save its value
4871 before the last instruction. */
4872 if (info.save_before_last)
4873 save_pos_insn = PREV_INSN (save_pos_insn);
4875 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4876 gen_rtx_REG (HImode, info.regno)),
4880 if (info.must_push_reg && info.last)
4884 body = PATTERN (info.last);
4885 new_body = gen_rtx_PARALLEL (VOIDmode,
4887 gen_rtx_USE (VOIDmode,
4889 gen_rtx_USE (VOIDmode,
4890 gen_rtx_REG (HImode,
4892 PATTERN (info.last) = new_body;
4894 /* Force recognition on insn since we changed it. */
4895 INSN_CODE (insn) = -1;
4897 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4899 fatal_insn ("invalid Z register replacement for insn", insn);
4901 insn = NEXT_INSN (info.last);
4904 /* Restore replacement register unless it was died. */
4905 if (insn && info.must_restore_reg && !info.must_push_reg)
4909 if (info.must_push_reg && 0)
4910 dst = gen_rtx_MEM (HImode,
4911 gen_rtx_POST_INC (HImode,
4912 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4914 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4916 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4923 /* Scan all the insn and re-affects some registers
4924 - The Z register (if it was used), is affected to X or Y depending
4925 on the instruction. */
4928 m68hc11_reassign_regs (rtx first)
4932 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4933 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4934 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4935 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4937 /* Scan all insns to replace Z by X or Y preserving the old value
4938 of X/Y and restoring it afterward. */
4940 for (insn = first; insn; insn = NEXT_INSN (insn))
4944 if (GET_CODE (insn) == CODE_LABEL
4945 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4951 body = PATTERN (insn);
4952 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4955 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4956 || GET_CODE (body) == ASM_OPERANDS
4957 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4960 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4961 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4964 /* If Z appears in this insn, replace it in the current insn
4965 and the next ones until the flow changes or we have to
4966 restore back the replacement register. */
4968 if (reg_mentioned_p (z_reg, body))
4970 m68hc11_z_replacement (insn);
4975 printf ("insn not handled by Z replacement:\n");
4983 /* Machine-dependent reorg pass.
4984 Specific optimizations are defined here:
4985 - this pass changes the Z register into either X or Y
4986 (it preserves X/Y previous values in a memory slot in page0).
4988 When this pass is finished, the global variable
4989 'z_replacement_completed' is set to 2. */
4992 m68hc11_reorg (void)
4997 z_replacement_completed = 0;
4998 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4999 first = get_insns ();
5001 /* Some RTX are shared at this point. This breaks the Z register
5002 replacement, unshare everything. */
5003 unshare_all_rtl_again (first);
5005 /* Force a split of all splittable insn. This is necessary for the
5006 Z register replacement mechanism because we end up with basic insns. */
5007 split_all_insns_noflow ();
5010 z_replacement_completed = 1;
5011 m68hc11_reassign_regs (first);
5014 compute_bb_for_insn ();
5016 /* After some splitting, there are some opportunities for CSE pass.
5017 This happens quite often when 32-bit or above patterns are split. */
5018 if (optimize > 0 && split_done)
5020 reload_cse_regs (first);
5023 /* Re-create the REG_DEAD notes. These notes are used in the machine
5024 description to use the best assembly directives. */
5027 df_note_add_problem ();
5029 df_remove_problem (df_note);
5032 z_replacement_completed = 2;
5034 /* If optimizing, then go ahead and split insns that must be
5035 split after Z register replacement. This gives more opportunities
5036 for peephole (in particular for consecutives xgdx/xgdy). */
5038 split_all_insns_noflow ();
5040 /* Once insns are split after the z_replacement_completed == 2,
5041 we must not re-run the life_analysis. The xgdx/xgdy patterns
5042 are not recognized and the life_analysis pass removes some
5043 insns because it thinks some (SETs) are noops or made to dead
5044 stores (which is false due to the swap).
5046 Do a simple pass to eliminate the noop set that the final
5047 split could generate (because it was easier for split definition). */
5051 for (insn = first; insn; insn = NEXT_INSN (insn))
5055 if (INSN_DELETED_P (insn))
5060 /* Remove the (set (R) (R)) insns generated by some splits. */
5061 body = PATTERN (insn);
5062 if (GET_CODE (body) == SET
5063 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5065 SET_INSN_DELETED (insn);
5072 /* Override memcpy */
5075 m68hc11_init_libfuncs (void)
5077 memcpy_libfunc = init_one_libfunc ("__memcpy");
5078 memcmp_libfunc = init_one_libfunc ("__memcmp");
5079 memset_libfunc = init_one_libfunc ("__memset");
5084 /* Cost functions. */
5086 /* Cost of moving memory. */
5088 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
5089 int in ATTRIBUTE_UNUSED)
5091 if (rclass <= H_REGS && rclass > NO_REGS)
5093 if (GET_MODE_SIZE (mode) <= 2)
5094 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5096 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5100 if (GET_MODE_SIZE (mode) <= 2)
5101 return COSTS_N_INSNS (3);
5103 return COSTS_N_INSNS (4);
5108 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5109 Reload does not check the constraint of set insns when the two registers
5110 have a move cost of 2. Setting a higher cost will force reload to check
5113 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5116 /* All costs are symmetric, so reduce cases by putting the
5117 lower number class as the destination. */
5120 enum reg_class tmp = to;
5121 to = from, from = tmp;
5124 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5125 else if (from <= S_REGS)
5126 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5128 return COSTS_N_INSNS (2);
5132 /* Provide the costs of an addressing mode that contains ADDR.
5133 If ADDR is not a valid address, its cost is irrelevant. */
5136 m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
5140 switch (GET_CODE (addr))
5143 /* Make the cost of hard registers and specially SP, FP small. */
5144 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5161 register rtx plus0 = XEXP (addr, 0);
5162 register rtx plus1 = XEXP (addr, 1);
5164 if (GET_CODE (plus0) != REG)
5167 switch (GET_CODE (plus1))
5170 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5171 || INTVAL (plus1) < m68hc11_min_offset)
5173 else if (INTVAL (plus1) >= m68hc11_max_offset)
5177 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5199 if (SP_REG_P (XEXP (addr, 0)))
5208 printf ("Address cost: %d for :", cost);
5217 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5221 total = rtx_cost (x, SET, !optimize_size);
5223 total += m68hc11_cost->shiftQI_const[shift % 8];
5224 else if (mode == HImode)
5225 total += m68hc11_cost->shiftHI_const[shift % 16];
5226 else if (shift == 8 || shift == 16 || shift == 32)
5227 total += m68hc11_cost->shiftHI_const[8];
5228 else if (shift != 0 && shift != 16 && shift != 32)
5230 total += m68hc11_cost->shiftHI_const[1] * shift;
5233 /* For SI and others, the cost is higher. */
5234 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5235 total *= GET_MODE_SIZE (mode) / 2;
5237 /* When optimizing for size, make shift more costly so that
5238 multiplications are preferred. */
5239 if (optimize_size && (shift % 8) != 0)
5246 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5247 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5249 enum machine_mode mode = GET_MODE (x);
5260 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5262 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5265 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5266 total += m68hc11_cost->shift_var;
5272 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5273 total += m68hc11_cost->logical;
5275 /* Logical instructions are byte instructions only. */
5276 total *= GET_MODE_SIZE (mode);
5281 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5282 total += m68hc11_cost->add;
5283 if (GET_MODE_SIZE (mode) > 2)
5285 total *= GET_MODE_SIZE (mode) / 2;
5292 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5296 total += m68hc11_cost->divQI;
5300 total += m68hc11_cost->divHI;
5305 total += m68hc11_cost->divSI;
5311 /* mul instruction produces 16-bit result. */
5312 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5313 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5314 return m68hc11_cost->multQI
5315 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5316 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5318 /* emul instruction produces 32-bit result for 68HC12. */
5319 if (TARGET_M6812 && mode == SImode
5320 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5321 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5322 return m68hc11_cost->multHI
5323 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5324 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5326 total = rtx_cost (XEXP (x, 0), code, !optimize_size)
5327 + rtx_cost (XEXP (x, 1), code, !optimize_size);
5331 total += m68hc11_cost->multQI;
5335 total += m68hc11_cost->multHI;
5340 total += m68hc11_cost->multSI;
5347 extra_cost = COSTS_N_INSNS (2);
5355 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
5358 return total + COSTS_N_INSNS (1);
5362 return total + COSTS_N_INSNS (2);
5366 return total + COSTS_N_INSNS (4);
5368 return total + COSTS_N_INSNS (8);
5371 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5372 return COSTS_N_INSNS (1);
5374 return COSTS_N_INSNS (1);
5377 return COSTS_N_INSNS (4);
5382 m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
5383 bool speed ATTRIBUTE_UNUSED)
5385 enum rtx_code code = (enum rtx_code) codearg;
5386 enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
5390 /* Constants are cheap. Moving them in registers must be avoided
5391 because most instructions do not handle two register operands. */
5397 /* Logical and arithmetic operations with a constant operand are
5398 better because they are not supported with two registers. */
5400 if (outer_code == SET && x == const0_rtx)
5401 /* After reload, the reload_cse pass checks the cost to change
5402 a SET into a PLUS. Make const0 cheap then. */
5403 *total = 1 - reload_completed;
5409 if (outer_code != COMPARE)
5432 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5441 /* Worker function for TARGET_ASM_FILE_START. */
5444 m68hc11_file_start (void)
5446 default_file_start ();
5448 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5452 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5455 m68hc11_asm_out_constructor (rtx symbol, int priority)
5457 default_ctor_section_asm_out_constructor (symbol, priority);
5458 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5461 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5464 m68hc11_asm_out_destructor (rtx symbol, int priority)
5466 default_dtor_section_asm_out_destructor (symbol, priority);
5467 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5470 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5473 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5474 int incoming ATTRIBUTE_UNUSED)
5476 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5479 /* Return true if type TYPE should be returned in memory.
5480 Blocks and data types largers than 4 bytes cannot be returned
5481 in the register (D + X = 4). */
5484 m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
5486 if (TYPE_MODE (type) == BLKmode)
5488 HOST_WIDE_INT size = int_size_in_bytes (type);
5489 return (size == -1 || size > 4);
5492 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5495 #include "gt-m68hc11.h"