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, 2010 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
37 #include "coretypes.h"
44 #include "hard-reg-set.h"
45 #include "insn-config.h"
46 #include "conditions.h"
48 #include "insn-attr.h"
53 #include "diagnostic-core.h"
54 #include "basic-block.h"
59 #include "target-def.h"
62 static void m68hc11_option_override (void);
63 static void emit_move_after_reload (rtx, rtx, rtx);
64 static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
65 static void m68hc11_emit_logical (enum machine_mode, enum rtx_code, rtx *);
66 static void m68hc11_reorg (void);
67 static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool);
68 static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool);
69 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
70 static int must_parenthesize (rtx);
71 static int m68hc11_address_cost (rtx, bool);
72 static int m68hc11_shift_cost (enum machine_mode, rtx, int);
73 static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
74 static bool m68hc11_rtx_costs (rtx, int, int, int *, bool);
75 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
76 static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *);
77 static bool m68hc11_class_likely_spilled_p (reg_class_t);
79 void create_regs_rtx (void);
81 static void asm_print_register (FILE *, int);
82 static void m68hc11_print_operand (FILE *, rtx, int);
83 static void m68hc11_print_operand_address (FILE *, rtx);
84 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
85 static void m68hc11_asm_out_constructor (rtx, int);
86 static void m68hc11_asm_out_destructor (rtx, int);
87 static void m68hc11_file_start (void);
88 static void m68hc11_encode_section_info (tree, rtx, int);
89 static const char *m68hc11_strip_name_encoding (const char* str);
90 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
91 static int autoinc_mode (rtx);
92 static int m68hc11_make_autoinc_notes (rtx *, void *);
93 static void m68hc11_init_libfuncs (void);
94 static rtx m68hc11_struct_value_rtx (tree, int);
95 static bool m68hc11_return_in_memory (const_tree, const_tree);
96 static bool m68hc11_can_eliminate (const int, const int);
97 static void m68hc11_conditional_register_usage (void);
98 static void m68hc11_trampoline_init (rtx, tree, rtx);
100 static rtx m68hc11_function_arg (CUMULATIVE_ARGS*, enum machine_mode,
102 static void m68hc11_function_arg_advance (CUMULATIVE_ARGS*, enum machine_mode,
105 /* Must be set to 1 to produce debug messages. */
108 extern FILE *asm_out_file;
113 rtx m68hc11_soft_tmp_reg;
114 static GTY(()) rtx stack_push_word;
115 static GTY(()) rtx stack_pop_word;
116 static GTY(()) rtx z_reg;
117 static GTY(()) rtx z_reg_qi;
118 static int regs_inited = 0;
120 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
121 int current_function_interrupt;
123 /* Set to 1 by expand_prologue() when the function is a trap handler. */
124 int current_function_trap;
126 /* Set to 1 when the current function is placed in 68HC12 banked
127 memory and must return with rtc. */
128 int current_function_far;
130 /* Min offset that is valid for the indirect addressing mode. */
131 HOST_WIDE_INT m68hc11_min_offset = 0;
133 /* Max offset that is valid for the indirect addressing mode. */
134 HOST_WIDE_INT m68hc11_max_offset = 256;
136 /* The class value for base registers. */
137 enum reg_class m68hc11_base_reg_class = A_REGS;
139 /* The class value for index registers. This is NO_REGS for 68HC11. */
140 enum reg_class m68hc11_index_reg_class = NO_REGS;
142 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
144 /* Tables that tell whether a given hard register is valid for
145 a base or an index register. It is filled at init time depending
146 on the target processor. */
147 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
148 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
150 /* A correction offset which is applied to the stack pointer.
151 This is 1 for 68HC11 and 0 for 68HC12. */
152 int m68hc11_sp_correction;
154 int m68hc11_addr_mode;
155 int m68hc11_mov_addr_mode;
158 const struct processor_costs *m68hc11_cost;
160 /* Costs for a 68HC11. */
161 static const struct processor_costs m6811_cost = {
166 /* non-constant shift */
169 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
170 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
171 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
174 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
175 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
176 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
177 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
178 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
179 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
184 COSTS_N_INSNS (20 * 4),
186 COSTS_N_INSNS (20 * 16),
195 /* Costs for a 68HC12. */
196 static const struct processor_costs m6812_cost = {
201 /* non-constant shift */
204 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
205 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
206 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
209 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
210 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
211 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
212 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
213 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
214 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
221 COSTS_N_INSNS (3 * 4),
230 /* M68HC11 specific attributes. */
232 static const struct attribute_spec m68hc11_attribute_table[] =
234 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
235 affects_type_identity } */
236 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
238 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
240 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
242 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute,
244 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute,
246 { NULL, 0, 0, false, false, false, NULL, false }
249 /* Initialize the GCC target structure. */
250 #undef TARGET_ATTRIBUTE_TABLE
251 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
253 #undef TARGET_ASM_ALIGNED_HI_OP
254 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
256 #undef TARGET_PRINT_OPERAND
257 #define TARGET_PRINT_OPERAND m68hc11_print_operand
258 #undef TARGET_PRINT_OPERAND_ADDRESS
259 #define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
261 #undef TARGET_ASM_FUNCTION_EPILOGUE
262 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
264 #undef TARGET_ASM_FILE_START
265 #define TARGET_ASM_FILE_START m68hc11_file_start
266 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
267 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
269 #undef TARGET_DEFAULT_TARGET_FLAGS
270 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
272 #undef TARGET_ENCODE_SECTION_INFO
273 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
275 #undef TARGET_SECTION_TYPE_FLAGS
276 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
278 #undef TARGET_RTX_COSTS
279 #define TARGET_RTX_COSTS m68hc11_rtx_costs
280 #undef TARGET_ADDRESS_COST
281 #define TARGET_ADDRESS_COST m68hc11_address_cost
283 #undef TARGET_MACHINE_DEPENDENT_REORG
284 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
286 #undef TARGET_INIT_LIBFUNCS
287 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
289 #undef TARGET_FUNCTION_ARG
290 #define TARGET_FUNCTION_ARG m68hc11_function_arg
291 #undef TARGET_FUNCTION_ARG_ADVANCE
292 #define TARGET_FUNCTION_ARG_ADVANCE m68hc11_function_arg_advance
294 #undef TARGET_STRUCT_VALUE_RTX
295 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
296 #undef TARGET_RETURN_IN_MEMORY
297 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
298 #undef TARGET_CALLEE_COPIES
299 #define TARGET_CALLEE_COPIES hook_callee_copies_named
301 #undef TARGET_STRIP_NAME_ENCODING
302 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
304 #undef TARGET_LEGITIMATE_ADDRESS_P
305 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
307 #undef TARGET_CAN_ELIMINATE
308 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
310 #undef TARGET_CONDITIONAL_REGISTER_USAGE
311 #define TARGET_CONDITIONAL_REGISTER_USAGE m68hc11_conditional_register_usage
313 #undef TARGET_CLASS_LIKELY_SPILLED_P
314 #define TARGET_CLASS_LIKELY_SPILLED_P m68hc11_class_likely_spilled_p
316 #undef TARGET_TRAMPOLINE_INIT
317 #define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
319 #undef TARGET_OPTION_OVERRIDE
320 #define TARGET_OPTION_OVERRIDE m68hc11_option_override
322 struct gcc_target targetm = TARGET_INITIALIZER;
325 m68hc11_option_override (void)
327 memset (m68hc11_reg_valid_for_index, 0,
328 sizeof (m68hc11_reg_valid_for_index));
329 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
331 /* Compilation with -fpic generates a wrong code. */
334 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
335 (flag_pic > 1) ? "PIC" : "pic");
339 /* Do not enable -fweb because it breaks the 32-bit shift patterns
340 by breaking the match_dup of those patterns. The shift patterns
341 will no longer be recognized after that. */
344 /* Configure for a 68hc11 processor. */
347 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
348 m68hc11_cost = &m6811_cost;
349 m68hc11_min_offset = 0;
350 m68hc11_max_offset = 256;
351 m68hc11_index_reg_class = NO_REGS;
352 m68hc11_base_reg_class = A_REGS;
353 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
354 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
355 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
356 m68hc11_sp_correction = 1;
357 m68hc11_tmp_regs_class = D_REGS;
358 m68hc11_addr_mode = ADDR_OFFSET;
359 m68hc11_mov_addr_mode = 0;
360 if (m68hc11_soft_reg_count < 0)
361 m68hc11_soft_reg_count = 4;
364 /* Configure for a 68hc12 processor. */
367 m68hc11_cost = &m6812_cost;
368 m68hc11_min_offset = -65536;
369 m68hc11_max_offset = 65536;
370 m68hc11_index_reg_class = D_REGS;
371 m68hc11_base_reg_class = A_OR_SP_REGS;
372 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
373 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
374 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
375 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
376 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
377 m68hc11_sp_correction = 0;
378 m68hc11_tmp_regs_class = TMP_REGS;
379 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
380 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
381 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
382 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
383 target_flags |= MASK_NO_DIRECT_MODE;
384 if (m68hc11_soft_reg_count < 0)
385 m68hc11_soft_reg_count = 0;
387 if (TARGET_LONG_CALLS)
388 current_function_far = 1;
393 /* The soft-registers are disabled or enabled according to the
394 -msoft-reg-count=<n> option. */
397 m68hc11_conditional_register_usage (void)
401 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
402 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
404 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
407 call_used_regs[i] = 1;
410 /* For 68HC12, the Z register emulation is not necessary when the
411 frame pointer is not used. The frame pointer is eliminated and
412 replaced by the stack register (which is a BASE_REG_CLASS). */
413 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
415 fixed_regs[HARD_Z_REGNUM] = 1;
420 /* Reload and register operations. */
424 create_regs_rtx (void)
426 /* regs_inited = 1; */
427 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
428 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
429 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
430 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
432 stack_push_word = gen_rtx_MEM (HImode,
433 gen_rtx_PRE_DEC (HImode,
434 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
435 stack_pop_word = gen_rtx_MEM (HImode,
436 gen_rtx_POST_INC (HImode,
437 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
441 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
442 - 8-bit values are stored anywhere (except the SP register).
443 - 16-bit values can be stored in any register whose mode is 16
444 - 32-bit values can be stored in D, X registers or in a soft register
445 (except the last one because we need 2 soft registers)
446 - Values whose size is > 32 bit are not stored in real hard
447 registers. They may be stored in soft registers if there are
450 hard_regno_mode_ok (int regno, enum machine_mode mode)
452 switch (GET_MODE_SIZE (mode))
455 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
458 return (X_REGNO_P (regno)
459 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
462 return G_REGNO_P (regno);
465 /* We have to accept a QImode in X or Y registers. Otherwise, the
466 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
467 in the insns. Reload fails if the insn rejects the register class 'a'
468 as well as if it accepts it. Patterns that failed were
469 zero_extend_qihi2 and iorqi3. */
471 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
479 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
481 /* Don't accept renaming to Z register. We will replace it to
482 X,Y or D during machine reorg pass. */
483 if (reg2 == HARD_Z_REGNUM)
486 /* Don't accept renaming D,X to Y register as the code will be bigger. */
487 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
488 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
495 preferred_reload_class (rtx operand, enum reg_class rclass)
497 enum machine_mode mode;
499 mode = GET_MODE (operand);
503 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
506 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
507 return m68hc11_base_reg_class;
509 if (rclass >= S_REGS && (GET_CODE (operand) == MEM
510 || GET_CODE (operand) == CONST_INT))
512 /* S_REGS class must not be used. The movhi template does not
513 work to move a memory to a soft register.
514 Restrict to a hard reg. */
519 case D_OR_A_OR_S_REGS:
520 rclass = A_OR_D_REGS;
525 case D_OR_SP_OR_S_REGS:
526 rclass = D_OR_SP_REGS;
528 case D_OR_Y_OR_S_REGS:
529 rclass = D_OR_Y_REGS;
531 case D_OR_X_OR_S_REGS:
532 rclass = D_OR_X_REGS;
547 else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
551 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
553 rclass = D_OR_X_REGS;
555 else if (rclass >= S_REGS && S_REG_P (operand))
561 case D_OR_A_OR_S_REGS:
562 rclass = A_OR_D_REGS;
567 case D_OR_SP_OR_S_REGS:
568 rclass = D_OR_SP_REGS;
570 case D_OR_Y_OR_S_REGS:
571 rclass = D_OR_Y_REGS;
573 case D_OR_X_OR_S_REGS:
574 rclass = D_OR_X_REGS;
589 else if (rclass >= S_REGS)
593 printf ("Class = %s for: ", reg_class_names[rclass]);
601 printf (" => class=%s\n", reg_class_names[rclass]);
609 /* Implement TARGET_CLASS_LIKELY_SPILLED_P. */
612 m68hc11_class_likely_spilled_p (reg_class_t rclass)
635 /* Return 1 if the operand is a valid indexed addressing mode.
636 For 68hc11: n,r with n in [0..255] and r in A_REGS class
637 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
639 m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
643 switch (GET_CODE (operand))
646 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
647 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
648 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
655 if (addr_mode & ADDR_INCDEC)
656 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
657 addr_mode & ADDR_STRICT);
661 base = XEXP (operand, 0);
662 if (GET_CODE (base) == MEM)
665 offset = XEXP (operand, 1);
666 if (GET_CODE (offset) == MEM)
669 /* Indexed addressing mode with 2 registers. */
670 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
672 if (!(addr_mode & ADDR_INDEXED))
675 addr_mode &= ADDR_STRICT;
676 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
677 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
680 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
681 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
687 if (!(addr_mode & ADDR_OFFSET))
690 if (GET_CODE (base) == REG)
692 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
695 if (!(addr_mode & ADDR_STRICT))
698 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
701 if (GET_CODE (offset) == REG)
703 if (!VALID_CONSTANT_OFFSET_P (base, mode))
706 if (!(addr_mode & ADDR_STRICT))
709 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
714 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
717 if (addr_mode & ADDR_CONST)
718 return VALID_CONSTANT_OFFSET_P (operand, mode);
726 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
727 a 68HC12 1-byte index addressing mode. */
729 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
734 if (GET_CODE (operand) == REG && reload_in_progress
735 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
736 && reg_equiv_memory_loc[REGNO (operand)])
738 operand = reg_equiv_memory_loc[REGNO (operand)];
739 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
742 if (GET_CODE (operand) != MEM)
745 operand = XEXP (operand, 0);
746 if (CONSTANT_ADDRESS_P (operand))
749 if (PUSH_POP_ADDRESS_P (operand))
752 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
753 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
756 if (TARGET_M6812 && GET_CODE (operand) == PLUS
757 && (reload_completed | reload_in_progress))
759 base = XEXP (operand, 0);
760 offset = XEXP (operand, 1);
762 /* The offset can be a symbol address and this is too big
763 for the operand constraint. */
764 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
767 if (GET_CODE (base) == CONST_INT)
770 switch (GET_MODE_SIZE (mode))
773 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
778 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
783 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
792 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
796 if (GET_CODE (operand) == REG && reload_in_progress
797 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
798 && reg_equiv_memory_loc[REGNO (operand)])
800 operand = reg_equiv_memory_loc[REGNO (operand)];
801 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
803 if (GET_CODE (operand) != MEM)
806 operand = XEXP (operand, 0);
807 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
808 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
812 m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
817 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
819 /* Reject the global variables if they are too wide. This forces
820 a load of their address in a register and generates smaller code. */
821 if (GET_MODE_SIZE (mode) == 8)
826 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
827 if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
831 if (PUSH_POP_ADDRESS_P (operand))
835 if (symbolic_memory_operand (operand, mode))
843 m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
850 printf ("Checking: ");
855 result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
859 printf (" -> %s\n", result == 0 ? "NO" : "YES");
866 printf ("go_if_legitimate%s, ret 0: %d:",
867 (strict ? "_strict" : ""), mode);
877 m68hc11_reload_operands (rtx operands[])
879 enum machine_mode mode;
881 if (regs_inited == 0)
884 mode = GET_MODE (operands[1]);
886 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
887 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
889 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
890 rtx base = XEXP (XEXP (operands[1], 0), 0);
892 if (GET_CODE (base) != REG)
899 /* If the offset is out of range, we have to compute the address
900 with a separate add instruction. We try to do this with an 8-bit
901 add on the A register. This is possible only if the lowest part
902 of the offset (i.e., big_offset % 256) is a valid constant offset
903 with respect to the mode. If it's not, we have to generate a
904 16-bit add on the D register. From:
906 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
910 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
911 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
912 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
913 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
915 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
916 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
919 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
922 rtx reg = operands[0];
924 int val = INTVAL (big_offset);
927 /* We use the 'operands[0]' as a scratch register to compute the
928 address. Make sure 'base' is in that register. */
929 if (!rtx_equal_p (base, operands[0]))
931 emit_move_insn (reg, base);
941 vh = (val >> 8) & 0x0FF;
945 /* Create the lowest part offset that still remains to be added.
946 If it's not a valid offset, do a 16-bit add. */
947 offset = GEN_INT (vl);
948 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
950 emit_insn (gen_rtx_SET (VOIDmode, reg,
951 gen_rtx_PLUS (HImode, reg, big_offset)));
956 emit_insn (gen_rtx_SET (VOIDmode, reg,
957 gen_rtx_PLUS (HImode, reg,
958 GEN_INT (vh << 8))));
960 emit_move_insn (operands[0],
961 gen_rtx_MEM (GET_MODE (operands[1]),
962 gen_rtx_PLUS (Pmode, reg, offset)));
967 /* Use the normal gen_movhi pattern. */
972 m68hc11_emit_libcall (const char *name, enum rtx_code code,
973 enum machine_mode dmode, enum machine_mode smode,
974 int noperands, rtx *operands)
982 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
986 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
987 dmode, 1, operands[1], smode);
988 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
992 ret = emit_library_call_value (libcall, NULL_RTX,
994 operands[1], smode, operands[2],
996 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
1003 insns = get_insns ();
1005 emit_libcall_block (insns, operands[0], ret, equiv);
1008 /* Returns true if X is a PRE/POST increment decrement
1009 (same as auto_inc_p() in rtlanal.c but do not take into
1010 account the stack). */
1012 m68hc11_auto_inc_p (rtx x)
1014 return GET_CODE (x) == PRE_DEC
1015 || GET_CODE (x) == POST_INC
1016 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
1020 /* Predicates for machine description. */
1023 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1025 return GET_CODE (operand) == MEM
1026 && GET_CODE (XEXP (operand, 0)) == PLUS
1027 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
1028 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
1029 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
1030 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
1034 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
1036 if (GET_CODE (operand) == MEM)
1038 rtx op = XEXP (operand, 0);
1040 if (symbolic_memory_operand (op, mode))
1047 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
1049 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
1051 rtx op = XEXP (operand, 0);
1054 if (m68hc11_page0_symbol_p (op))
1057 if (symbolic_memory_operand (op, mode))
1058 return TARGET_M6812;
1060 if (reload_in_progress)
1063 operand = XEXP (operand, 0);
1064 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1065 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
1071 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1073 if (GET_CODE (operand) != MEM)
1076 operand = XEXP (operand, 0);
1077 if (GET_CODE (operand) == PLUS)
1079 if (GET_CODE (XEXP (operand, 0)) == REG)
1080 operand = XEXP (operand, 0);
1081 else if (GET_CODE (XEXP (operand, 1)) == REG)
1082 operand = XEXP (operand, 1);
1084 return GET_CODE (operand) == REG
1085 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1086 || A_REGNO_P (REGNO (operand)));
1090 push_pop_operand_p (rtx operand)
1092 if (GET_CODE (operand) != MEM)
1096 operand = XEXP (operand, 0);
1097 return PUSH_POP_ADDRESS_P (operand);
1100 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1101 reference and a constant. */
1104 symbolic_memory_operand (rtx op, enum machine_mode mode)
1106 switch (GET_CODE (op))
1114 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1115 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1116 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1118 /* ??? This clause seems to be irrelevant. */
1120 return GET_MODE (op) == mode;
1123 return symbolic_memory_operand (XEXP (op, 0), mode)
1124 && symbolic_memory_operand (XEXP (op, 1), mode);
1131 /* Emit the code to build the trampoline used to call a nested function.
1135 ldy #&CXT movw #&CXT,*_.d1
1136 sty *_.d1 jmp FNADDR
1141 m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
1143 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1144 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
1148 if (*static_chain_reg == '*')
1152 mem = adjust_address (m_tramp, HImode, 0);
1153 emit_move_insn (mem, GEN_INT (0x18ce));
1154 mem = adjust_address (m_tramp, HImode, 2);
1155 emit_move_insn (mem, cxt);
1156 mem = adjust_address (m_tramp, HImode, 4);
1157 emit_move_insn (mem, GEN_INT (0x18df));
1158 mem = adjust_address (m_tramp, QImode, 6);
1159 emit_move_insn (mem,
1160 gen_rtx_CONST (QImode,
1161 gen_rtx_SYMBOL_REF (Pmode,
1162 static_chain_reg)));
1163 mem = adjust_address (m_tramp, QImode, 7);
1164 emit_move_insn (mem, GEN_INT (0x7e));
1165 mem = adjust_address (m_tramp, HImode, 8);
1166 emit_move_insn (mem, fnaddr);
1170 mem = adjust_address (m_tramp, HImode, 0);
1171 emit_move_insn (mem, GEN_INT (0x1803));
1172 mem = adjust_address (m_tramp, HImode, 2);
1173 emit_move_insn (mem, cxt);
1174 mem = adjust_address (m_tramp, HImode, 4);
1175 emit_move_insn (mem,
1176 gen_rtx_CONST (HImode,
1177 gen_rtx_SYMBOL_REF (Pmode,
1178 static_chain_reg)));
1179 mem = adjust_address (m_tramp, QImode, 6);
1180 emit_move_insn (mem, GEN_INT (0x06));
1181 mem = adjust_address (m_tramp, HImode, 7);
1182 emit_move_insn (mem, fnaddr);
1186 /* Declaration of types. */
1188 /* Handle an "tiny_data" attribute; arguments as in
1189 struct attribute_spec.handler. */
1191 m68hc11_handle_page0_attribute (tree *node, tree name,
1192 tree args ATTRIBUTE_UNUSED,
1193 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1197 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1199 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1203 warning (OPT_Wattributes, "%qE attribute ignored",
1205 *no_add_attrs = true;
1211 /* Keep track of the symbol which has a `trap' attribute and which uses
1212 the `swi' calling convention. Since there is only one trap, we only
1213 record one such symbol. If there are several, a warning is reported. */
1214 static rtx trap_handler_symbol = 0;
1216 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1217 arguments as in struct attribute_spec.handler. */
1219 m68hc11_handle_fntype_attribute (tree *node, tree name,
1220 tree args ATTRIBUTE_UNUSED,
1221 int flags ATTRIBUTE_UNUSED,
1224 if (TREE_CODE (*node) != FUNCTION_TYPE
1225 && TREE_CODE (*node) != METHOD_TYPE
1226 && TREE_CODE (*node) != FIELD_DECL
1227 && TREE_CODE (*node) != TYPE_DECL)
1229 warning (OPT_Wattributes, "%qE attribute only applies to functions",
1231 *no_add_attrs = true;
1236 /* Undo the effects of the above. */
1239 m68hc11_strip_name_encoding (const char *str)
1241 return str + (*str == '*' || *str == '@' || *str == '&');
1245 m68hc11_encode_label (tree decl)
1247 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1248 int len = strlen (str);
1249 char *newstr = XALLOCAVEC (char, len + 2);
1252 strcpy (&newstr[1], str);
1254 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1257 /* Return 1 if this is a symbol in page0 */
1259 m68hc11_page0_symbol_p (rtx x)
1261 switch (GET_CODE (x))
1264 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1267 return m68hc11_page0_symbol_p (XEXP (x, 0));
1270 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1273 return GET_CODE (XEXP (x, 1)) == CONST_INT
1274 && INTVAL (XEXP (x, 1)) < 256
1275 && INTVAL (XEXP (x, 1)) >= 0;
1282 /* We want to recognize trap handlers so that we handle calls to traps
1283 in a special manner (by issuing the trap). This information is stored
1284 in SYMBOL_REF_FLAG. */
1287 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1293 if (TREE_CODE (decl) == VAR_DECL)
1295 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1296 m68hc11_encode_label (decl);
1300 if (TREE_CODE (decl) != FUNCTION_DECL)
1303 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1306 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1308 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1309 is_far = TARGET_LONG_CALLS != 0;
1311 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1312 if (trap_handler && is_far)
1314 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1315 "not compatible, ignoring %<far%>");
1320 if (trap_handler_symbol != 0)
1321 warning (OPT_Wattributes, "%<trap%> attribute is already used");
1323 trap_handler_symbol = XEXP (rtl, 0);
1325 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1329 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1331 unsigned int flags = default_section_type_flags (decl, name, reloc);
1333 if (strncmp (name, ".eeprom", 7) == 0)
1335 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1342 m68hc11_is_far_symbol (rtx sym)
1344 if (GET_CODE (sym) == MEM)
1345 sym = XEXP (sym, 0);
1347 return SYMBOL_REF_FLAG (sym);
1351 m68hc11_is_trap_symbol (rtx sym)
1353 if (GET_CODE (sym) == MEM)
1354 sym = XEXP (sym, 0);
1356 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1360 /* Argument support functions. */
1362 /* Given FROM and TO register numbers, say whether this elimination is
1363 allowed. Frame pointer elimination is automatically handled.
1365 All other eliminations are valid. */
1368 m68hc11_can_eliminate (const int from, const int to)
1370 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
1371 ? ! frame_pointer_needed
1375 /* Define the offset between two registers, one to be eliminated, and the
1376 other its replacement, at the start of a routine. */
1378 m68hc11_initial_elimination_offset (int from, int to)
1385 /* For a trap handler, we must take into account the registers which
1386 are pushed on the stack during the trap (except the PC). */
1387 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1388 current_function_interrupt = lookup_attribute ("interrupt",
1389 func_attr) != NULL_TREE;
1390 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1392 if (lookup_attribute ("far", func_attr) != 0)
1393 current_function_far = 1;
1394 else if (lookup_attribute ("near", func_attr) != 0)
1395 current_function_far = 0;
1397 current_function_far = (TARGET_LONG_CALLS != 0
1398 && !current_function_interrupt
1401 if (trap_handler && from == ARG_POINTER_REGNUM)
1404 /* For a function using 'call/rtc' we must take into account the
1405 page register which is pushed in the call. */
1406 else if (current_function_far && from == ARG_POINTER_REGNUM)
1411 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1413 /* 2 is for the saved frame.
1414 1 is for the 'sts' correction when creating the frame. */
1415 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1418 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1420 return m68hc11_sp_correction;
1423 /* Push any 2 byte pseudo hard registers that we need to save. */
1424 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1426 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1432 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1434 return get_frame_size () + size;
1437 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1444 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1445 for a call to a function whose data type is FNTYPE.
1446 For a library call, FNTYPE is 0. */
1449 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1453 z_replacement_completed = 0;
1457 /* For a library call, we must find out the type of the return value.
1458 When the return value is bigger than 4 bytes, it is returned in
1459 memory. In that case, the first argument of the library call is a
1460 pointer to the memory location. Because the first argument is passed in
1461 register D, we have to identify this, so that the first function
1462 parameter is not passed in D either. */
1468 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1471 /* If the library ends in 'di' or in 'df', we assume it's
1472 returning some DImode or some DFmode which are 64-bit wide. */
1473 name = XSTR (libname, 0);
1474 len = strlen (name);
1476 && ((name[len - 2] == 'd'
1477 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1478 || (name[len - 3] == 'd'
1479 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1481 /* We are in. Mark the first parameter register as already used. */
1488 ret_type = TREE_TYPE (fntype);
1490 if (ret_type && aggregate_value_p (ret_type, fntype))
1497 /* Update the data in CUM to advance over an argument
1498 of mode MODE and data type TYPE.
1499 (TYPE is null for libcalls where that information may not be available.) */
1502 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1503 const_tree type, bool named ATTRIBUTE_UNUSED)
1505 if (mode != BLKmode)
1507 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1510 cum->words = GET_MODE_SIZE (mode);
1514 cum->words += GET_MODE_SIZE (mode);
1515 if (cum->words <= HARD_REG_SIZE)
1521 cum->words += int_size_in_bytes (type);
1526 /* Define where to put the arguments to a function.
1527 Value is zero to push the argument on the stack,
1528 or a hard register in which to store the argument.
1530 MODE is the argument's machine mode.
1531 TYPE is the data type of the argument (as a tree).
1532 This is null for libcalls where that information may
1534 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1535 the preceding args and about the function being called.
1536 NAMED is nonzero if this argument is a named parameter
1537 (otherwise it is an extra parameter matching an ellipsis). */
1540 m68hc11_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1541 const_tree type ATTRIBUTE_UNUSED,
1542 bool named ATTRIBUTE_UNUSED)
1544 if (cum->words != 0)
1549 if (mode != BLKmode)
1551 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1552 return gen_rtx_REG (mode, HARD_X_REGNUM);
1554 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1558 return gen_rtx_REG (mode, HARD_D_REGNUM);
1563 /* If defined, a C expression which determines whether, and in which direction,
1564 to pad out an argument with extra space. The value should be of type
1565 `enum direction': either `upward' to pad above the argument,
1566 `downward' to pad below, or `none' to inhibit padding.
1568 Structures are stored left shifted in their argument slot. */
1570 m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
1572 if (type != 0 && AGGREGATE_TYPE_P (type))
1575 /* Fall back to the default. */
1576 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1580 /* Function prologue and epilogue. */
1582 /* Emit a move after the reload pass has completed. This is used to
1583 emit the prologue and epilogue. */
1585 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1589 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1591 insn = emit_move_insn (to, from);
1595 emit_move_insn (scratch, from);
1596 insn = emit_move_insn (to, scratch);
1599 /* Put a REG_INC note to tell the flow analysis that the instruction
1601 if (IS_STACK_PUSH (to))
1602 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
1603 else if (IS_STACK_POP (from))
1604 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
1606 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1607 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1608 The problem is that we are lying to gcc and use `txs' for x = sp
1609 (which is not really true because txs is really x = sp + 1). */
1610 else if (TARGET_M6811 && SP_REG_P (from))
1611 add_reg_note (insn, REG_INC, from);
1615 m68hc11_total_frame_size (void)
1620 size = get_frame_size ();
1621 if (current_function_interrupt)
1623 size += 3 * HARD_REG_SIZE;
1625 if (frame_pointer_needed)
1626 size += HARD_REG_SIZE;
1628 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1629 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1630 size += HARD_REG_SIZE;
1636 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1637 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1639 /* We catch the function epilogue generation to have a chance
1640 to clear the z_replacement_completed flag. */
1641 z_replacement_completed = 0;
1645 expand_prologue (void)
1652 gcc_assert (reload_completed == 1);
1654 size = get_frame_size ();
1658 /* Generate specific prologue for interrupt handlers. */
1659 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1660 current_function_interrupt = lookup_attribute ("interrupt",
1661 func_attr) != NULL_TREE;
1662 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1663 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1664 current_function_far = 1;
1665 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1666 current_function_far = 0;
1668 current_function_far = (TARGET_LONG_CALLS != 0
1669 && !current_function_interrupt
1670 && !current_function_trap);
1672 /* Get the scratch register to build the frame and push registers.
1673 If the first argument is a 32-bit quantity, the D+X registers
1674 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1675 For 68HC12, this scratch register is not used. */
1676 if (crtl->args.info.nregs == 2)
1681 /* Save current stack frame. */
1682 if (frame_pointer_needed)
1683 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1685 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1686 Other soft registers in page0 need not to be saved because they
1687 will be restored by C functions. For a trap handler, we don't
1688 need to preserve these registers because this is a synchronous call. */
1689 if (current_function_interrupt)
1691 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1692 emit_move_after_reload (stack_push_word,
1693 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1694 emit_move_after_reload (stack_push_word,
1695 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1699 /* Allocate local variables. */
1700 if (TARGET_M6812 && (size > 4 || size == 3))
1702 emit_insn (gen_addhi3 (stack_pointer_rtx,
1703 stack_pointer_rtx, GEN_INT (-size)));
1705 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1709 insn = gen_rtx_PARALLEL
1712 gen_rtx_SET (VOIDmode,
1714 gen_rtx_PLUS (HImode,
1717 gen_rtx_CLOBBER (VOIDmode, scratch)));
1724 /* Allocate by pushing scratch values. */
1725 for (i = 2; i <= size; i += 2)
1726 emit_move_after_reload (stack_push_word, ix_reg, 0);
1729 emit_insn (gen_addhi3 (stack_pointer_rtx,
1730 stack_pointer_rtx, constm1_rtx));
1733 /* Create the frame pointer. */
1734 if (frame_pointer_needed)
1735 emit_move_after_reload (hard_frame_pointer_rtx,
1736 stack_pointer_rtx, scratch);
1738 /* Push any 2 byte pseudo hard registers that we need to save. */
1739 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1741 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1743 emit_move_after_reload (stack_push_word,
1744 gen_rtx_REG (HImode, regno), scratch);
1750 expand_epilogue (void)
1757 gcc_assert (reload_completed == 1);
1759 size = get_frame_size ();
1761 /* If we are returning a value in two registers, we have to preserve the
1762 X register and use the Y register to restore the stack and the saved
1763 registers. Otherwise, use X because it's faster (and smaller). */
1764 if (crtl->return_rtx == 0)
1766 else if (GET_CODE (crtl->return_rtx) == MEM)
1767 return_size = HARD_REG_SIZE;
1769 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
1771 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1776 /* Pop any 2 byte pseudo hard registers that we saved. */
1777 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1779 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1781 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1782 stack_pop_word, scratch);
1786 /* de-allocate auto variables */
1787 if (TARGET_M6812 && (size > 4 || size == 3))
1789 emit_insn (gen_addhi3 (stack_pointer_rtx,
1790 stack_pointer_rtx, GEN_INT (size)));
1792 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1796 insn = gen_rtx_PARALLEL
1799 gen_rtx_SET (VOIDmode,
1801 gen_rtx_PLUS (HImode,
1804 gen_rtx_CLOBBER (VOIDmode, scratch)));
1811 for (i = 2; i <= size; i += 2)
1812 emit_move_after_reload (scratch, stack_pop_word, scratch);
1814 emit_insn (gen_addhi3 (stack_pointer_rtx,
1815 stack_pointer_rtx, const1_rtx));
1818 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1819 if (current_function_interrupt)
1821 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1822 stack_pop_word, scratch);
1823 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1824 stack_pop_word, scratch);
1825 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1828 /* Restore previous frame pointer. */
1829 if (frame_pointer_needed)
1830 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1832 /* If the trap handler returns some value, copy the value
1833 in D, X onto the stack so that the rti will pop the return value
1835 else if (current_function_trap && return_size != 0)
1837 rtx addr_reg = stack_pointer_rtx;
1841 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1844 emit_move_after_reload (gen_rtx_MEM (HImode,
1845 gen_rtx_PLUS (HImode, addr_reg,
1846 const1_rtx)), d_reg, 0);
1847 if (return_size > HARD_REG_SIZE)
1848 emit_move_after_reload (gen_rtx_MEM (HImode,
1849 gen_rtx_PLUS (HImode, addr_reg,
1850 GEN_INT (3))), ix_reg, 0);
1853 emit_jump_insn (gen_return ());
1857 /* Low and High part extraction for 68HC11. These routines are
1858 similar to gen_lowpart and gen_highpart but they have been
1859 fixed to work for constants and 68HC11 specific registers. */
1862 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1864 /* We assume that the low part of an auto-inc mode is the same with
1865 the mode changed and that the caller split the larger mode in the
1867 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1869 return gen_rtx_MEM (mode, XEXP (x, 0));
1872 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1873 floating-point constant. A CONST_DOUBLE is used whenever the
1874 constant requires more than one word in order to be adequately
1876 if (GET_CODE (x) == CONST_DOUBLE)
1880 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1884 if (GET_MODE (x) == SFmode)
1886 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1887 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1893 split_double (x, &first, &second);
1897 return GEN_INT (l[0]);
1899 return gen_int_mode (l[0], HImode);
1903 l[0] = CONST_DOUBLE_LOW (x);
1908 return GEN_INT (l[0]);
1910 gcc_assert (GET_MODE (x) == SFmode);
1911 return gen_int_mode (l[0], HImode);
1917 if (mode == QImode && D_REG_P (x))
1918 return gen_rtx_REG (mode, HARD_B_REGNUM);
1920 /* gen_lowpart crashes when it is called with a SUBREG. */
1921 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1926 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1928 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1933 x = gen_lowpart (mode, x);
1935 /* Return a different rtx to avoid to share it in several insns
1936 (when used by a split pattern). Sharing addresses within
1937 a MEM breaks the Z register replacement (and reloading). */
1938 if (GET_CODE (x) == MEM)
1944 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1946 /* We assume that the high part of an auto-inc mode is the same with
1947 the mode changed and that the caller split the larger mode in the
1949 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1951 return gen_rtx_MEM (mode, XEXP (x, 0));
1954 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1955 floating-point constant. A CONST_DOUBLE is used whenever the
1956 constant requires more than one word in order to be adequately
1958 if (GET_CODE (x) == CONST_DOUBLE)
1962 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1966 if (GET_MODE (x) == SFmode)
1968 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1969 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1975 split_double (x, &first, &second);
1979 return GEN_INT (l[1]);
1981 return gen_int_mode ((l[1] >> 16), HImode);
1985 l[1] = CONST_DOUBLE_HIGH (x);
1991 return GEN_INT (l[1]);
1993 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1994 return gen_int_mode ((l[0] >> 16), HImode);
1999 if (GET_CODE (x) == CONST_INT)
2001 HOST_WIDE_INT val = INTVAL (x);
2005 return gen_int_mode (val >> 8, QImode);
2007 else if (mode == HImode)
2009 return gen_int_mode (val >> 16, HImode);
2011 else if (mode == SImode)
2013 return gen_int_mode ((val >> 16) >> 16, SImode);
2016 if (mode == QImode && D_REG_P (x))
2017 return gen_rtx_REG (mode, HARD_A_REGNUM);
2019 /* There is no way in GCC to represent the upper part of a word register.
2020 To obtain the 8-bit upper part of a soft register, we change the
2021 reg into a mem rtx. This is possible because they are physically
2022 located in memory. There is no offset because we are big-endian. */
2023 if (mode == QImode && S_REG_P (x))
2027 /* Avoid the '*' for direct addressing mode when this
2028 addressing mode is disabled. */
2029 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
2030 return gen_rtx_MEM (QImode,
2031 gen_rtx_SYMBOL_REF (Pmode,
2032 ®_names[REGNO (x)][pos]));
2035 /* gen_highpart crashes when it is called with a SUBREG. */
2036 switch (GET_CODE (x))
2039 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
2041 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
2042 return gen_rtx_REG (mode, REGNO (x));
2044 return gen_rtx_SUBREG (mode, x, 0);
2046 x = change_address (x, mode, 0);
2048 /* Return a different rtx to avoid to share it in several insns
2049 (when used by a split pattern). Sharing addresses within
2050 a MEM breaks the Z register replacement (and reloading). */
2051 if (GET_CODE (x) == MEM)
2061 /* Obscure register manipulation. */
2063 /* Finds backward in the instructions to see if register 'reg' is
2064 dead. This is used when generating code to see if we can use 'reg'
2065 as a scratch register. This allows us to choose a better generation
2066 of code when we know that some register dies or can be clobbered. */
2069 dead_register_here (rtx x, rtx reg)
2075 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2079 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2086 if (GET_CODE (body) == CALL_INSN)
2088 if (GET_CODE (body) == JUMP_INSN)
2091 if (GET_CODE (body) == SET)
2093 rtx dst = XEXP (body, 0);
2095 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2097 if (x_reg && rtx_equal_p (dst, x_reg))
2100 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2103 else if (reg_mentioned_p (reg, p)
2104 || (x_reg && reg_mentioned_p (x_reg, p)))
2108 /* Scan forward to see if the register is set in some insns and never
2110 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2114 if (GET_CODE (p) == CODE_LABEL
2115 || GET_CODE (p) == JUMP_INSN
2116 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2119 if (GET_CODE (p) != INSN)
2123 if (GET_CODE (body) == SET)
2125 rtx src = XEXP (body, 1);
2126 rtx dst = XEXP (body, 0);
2128 if (GET_CODE (dst) == REG
2129 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2133 /* Register is used (may be in source or in dest). */
2134 if (reg_mentioned_p (reg, p)
2135 || (x_reg != 0 && GET_MODE (p) == SImode
2136 && reg_mentioned_p (x_reg, p)))
2139 return p == 0 ? 1 : 0;
2143 /* Code generation operations called from machine description file. */
2145 /* Print the name of register 'regno' in the assembly file. */
2147 asm_print_register (FILE *file, int regno)
2149 const char *name = reg_names[regno];
2151 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2154 fprintf (file, "%s", name);
2157 /* A C compound statement to output to stdio stream STREAM the
2158 assembler syntax for an instruction operand X. X is an RTL
2161 CODE is a value that can be used to specify one of several ways
2162 of printing the operand. It is used when identical operands
2163 must be printed differently depending on the context. CODE
2164 comes from the `%' specification that was used to request
2165 printing of the operand. If the specification was just `%DIGIT'
2166 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2167 is the ASCII code for LTR.
2169 If X is a register, this macro should print the register's name.
2170 The names can be found in an array `reg_names' whose type is
2171 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2173 When the machine description has a specification `%PUNCT' (a `%'
2174 followed by a punctuation character), this macro is called with
2175 a null pointer for X and the punctuation character for CODE.
2177 The M68HC11 specific codes are:
2179 'b' for the low part of the operand.
2180 'h' for the high part of the operand
2181 The 'b' or 'h' modifiers have no effect if the operand has
2182 the QImode and is not a S_REG_P (soft register). If the
2183 operand is a hard register, these two modifiers have no effect.
2184 't' generate the temporary scratch register. The operand is
2186 'T' generate the low-part temporary scratch register. The operand is
2190 m68hc11_print_operand (FILE *file, rtx op, int letter)
2194 asm_print_register (file, SOFT_TMP_REGNUM);
2197 else if (letter == 'T')
2199 asm_print_register (file, SOFT_TMP_REGNUM);
2200 fprintf (file, "+1");
2203 else if (letter == '#')
2205 asm_fprintf (file, "%I");
2208 if (GET_CODE (op) == REG)
2210 if (letter == 'b' && S_REG_P (op))
2212 asm_print_register (file, REGNO (op));
2213 fprintf (file, "+1");
2215 else if (letter == 'b' && D_REG_P (op))
2217 asm_print_register (file, HARD_B_REGNUM);
2221 asm_print_register (file, REGNO (op));
2226 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2229 asm_fprintf (file, "%I%%lo(");
2231 asm_fprintf (file, "%I%%hi(");
2233 output_addr_const (file, op);
2234 fprintf (file, ")");
2238 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2239 are specified. If we already have a QImode, there is nothing to do. */
2240 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2244 op = m68hc11_gen_lowpart (QImode, op);
2246 else if (letter == 'h')
2248 op = m68hc11_gen_highpart (QImode, op);
2252 if (GET_CODE (op) == MEM)
2254 rtx base = XEXP (op, 0);
2255 switch (GET_CODE (base))
2258 gcc_assert (TARGET_M6812);
2259 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2260 asm_print_register (file, REGNO (XEXP (base, 0)));
2264 gcc_assert (TARGET_M6812);
2265 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2266 asm_print_register (file, REGNO (XEXP (base, 0)));
2267 fprintf (file, "-");
2271 gcc_assert (TARGET_M6812);
2272 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2273 asm_print_register (file, REGNO (XEXP (base, 0)));
2274 fprintf (file, "+");
2278 gcc_assert (TARGET_M6812);
2279 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2280 asm_print_register (file, REGNO (XEXP (base, 0)));
2284 gcc_assert (TARGET_M6812);
2285 fprintf (file, "[");
2286 m68hc11_print_operand_address (file, XEXP (base, 0));
2287 fprintf (file, "]");
2291 if (m68hc11_page0_symbol_p (base))
2292 fprintf (file, "*");
2294 output_address (base);
2298 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2303 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2304 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2305 asm_fprintf (file, "%I0x%lx", l);
2307 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2311 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2312 sizeof (dstr), 0, 1);
2313 asm_fprintf (file, "%I0r%s", dstr);
2317 int need_parenthesize = 0;
2320 asm_fprintf (file, "%I");
2322 need_parenthesize = must_parenthesize (op);
2324 if (need_parenthesize)
2325 fprintf (file, "(");
2327 output_addr_const (file, op);
2328 if (need_parenthesize)
2329 fprintf (file, ")");
2333 /* Returns true if the operand 'op' must be printed with parenthesis
2334 around it. This must be done only if there is a symbol whose name
2335 is a processor register. */
2337 must_parenthesize (rtx op)
2341 switch (GET_CODE (op))
2344 name = XSTR (op, 0);
2345 /* Avoid a conflict between symbol name and a possible
2347 return (strcasecmp (name, "a") == 0
2348 || strcasecmp (name, "b") == 0
2349 || strcasecmp (name, "d") == 0
2350 || strcasecmp (name, "x") == 0
2351 || strcasecmp (name, "y") == 0
2352 || strcasecmp (name, "ix") == 0
2353 || strcasecmp (name, "iy") == 0
2354 || strcasecmp (name, "pc") == 0
2355 || strcasecmp (name, "sp") == 0
2356 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2360 return must_parenthesize (XEXP (op, 0))
2361 || must_parenthesize (XEXP (op, 1));
2367 return must_parenthesize (XEXP (op, 0));
2378 /* A C compound statement to output to stdio stream STREAM the
2379 assembler syntax for an instruction operand that is a memory
2380 reference whose address is ADDR. ADDR is an RTL expression. */
2383 m68hc11_print_operand_address (FILE *file, rtx addr)
2387 int need_parenthesis = 0;
2389 switch (GET_CODE (addr))
2392 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2394 fprintf (file, "0,");
2395 asm_print_register (file, REGNO (addr));
2399 base = XEXP (addr, 0);
2400 switch (GET_CODE (base))
2403 gcc_assert (TARGET_M6812);
2404 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2405 asm_print_register (file, REGNO (XEXP (base, 0)));
2409 gcc_assert (TARGET_M6812);
2410 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2411 asm_print_register (file, REGNO (XEXP (base, 0)));
2412 fprintf (file, "-");
2416 gcc_assert (TARGET_M6812);
2417 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2418 asm_print_register (file, REGNO (XEXP (base, 0)));
2419 fprintf (file, "+");
2423 gcc_assert (TARGET_M6812);
2424 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2425 asm_print_register (file, REGNO (XEXP (base, 0)));
2429 need_parenthesis = must_parenthesize (base);
2430 if (need_parenthesis)
2431 fprintf (file, "(");
2433 output_addr_const (file, base);
2434 if (need_parenthesis)
2435 fprintf (file, ")");
2441 base = XEXP (addr, 0);
2442 offset = XEXP (addr, 1);
2443 if (!G_REG_P (base) && G_REG_P (offset))
2445 base = XEXP (addr, 1);
2446 offset = XEXP (addr, 0);
2448 if (CONSTANT_ADDRESS_P (base))
2450 need_parenthesis = must_parenthesize (addr);
2452 gcc_assert (CONSTANT_ADDRESS_P (offset));
2453 if (need_parenthesis)
2454 fprintf (file, "(");
2456 output_addr_const (file, base);
2457 fprintf (file, "+");
2458 output_addr_const (file, offset);
2459 if (need_parenthesis)
2460 fprintf (file, ")");
2464 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2467 gcc_assert (TARGET_M6812);
2468 asm_print_register (file, REGNO (offset));
2469 fprintf (file, ",");
2470 asm_print_register (file, REGNO (base));
2474 need_parenthesis = must_parenthesize (offset);
2475 if (need_parenthesis)
2476 fprintf (file, "(");
2478 output_addr_const (file, offset);
2479 if (need_parenthesis)
2480 fprintf (file, ")");
2481 fprintf (file, ",");
2482 asm_print_register (file, REGNO (base));
2488 if (GET_CODE (addr) == CONST_INT
2489 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2491 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2495 need_parenthesis = must_parenthesize (addr);
2496 if (need_parenthesis)
2497 fprintf (file, "(");
2499 output_addr_const (file, addr);
2500 if (need_parenthesis)
2501 fprintf (file, ")");
2508 /* Splitting of some instructions. */
2511 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2515 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2516 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2517 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2518 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2524 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2529 switch (GET_MODE (op0))
2533 tmp = m68hc11_expand_compare (code, op0, op1);
2534 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2535 gen_rtx_LABEL_REF (VOIDmode, label),
2537 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2541 /* SCz: from i386.c */
2544 /* Don't expand the comparison early, so that we get better code
2545 when jump or whoever decides to reverse the comparison. */
2550 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2551 &m68hc11_compare_op1);
2553 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2554 m68hc11_compare_op0, m68hc11_compare_op1);
2555 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2556 gen_rtx_LABEL_REF (VOIDmode, label),
2558 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2560 use_fcomi = ix86_use_fcomi_compare (code);
2561 vec = rtvec_alloc (3 + !use_fcomi);
2562 RTVEC_ELT (vec, 0) = tmp;
2564 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2566 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2569 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2571 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2577 /* Expand SImode branch into multiple compare+branch. */
2579 rtx lo[2], hi[2], label2;
2580 enum rtx_code code1, code2, code3;
2582 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2587 code = swap_condition (code);
2589 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2590 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2591 hi[0] = m68hc11_gen_highpart (HImode, op0);
2592 hi[1] = m68hc11_gen_highpart (HImode, op1);
2594 /* Otherwise, if we are doing less-than, op1 is a constant and the
2595 low word is zero, then we can just examine the high word. */
2597 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2598 && (code == LT || code == LTU))
2600 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2604 /* Otherwise, we need two or three jumps. */
2606 label2 = gen_label_rtx ();
2609 code2 = swap_condition (code);
2610 code3 = unsigned_condition (code);
2651 * if (hi(a) < hi(b)) goto true;
2652 * if (hi(a) > hi(b)) goto false;
2653 * if (lo(a) < lo(b)) goto true;
2656 if (code1 != UNKNOWN)
2657 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2658 if (code2 != UNKNOWN)
2659 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2661 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2663 if (code2 != UNKNOWN)
2664 emit_label (label2);
2674 /* Return the increment/decrement mode of a MEM if it is such.
2675 Return CONST if it is anything else. */
2677 autoinc_mode (rtx x)
2679 if (GET_CODE (x) != MEM)
2683 if (GET_CODE (x) == PRE_INC
2684 || GET_CODE (x) == PRE_DEC
2685 || GET_CODE (x) == POST_INC
2686 || GET_CODE (x) == POST_DEC)
2687 return GET_CODE (x);
2693 m68hc11_make_autoinc_notes (rtx *x, void *data)
2697 switch (GET_CODE (*x))
2704 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2713 /* Split a DI, SI or HI move into several smaller move operations.
2714 The scratch register 'scratch' is used as a temporary to load
2715 store intermediate values. It must be a hard register. */
2717 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2719 rtx low_to, low_from;
2720 rtx high_to, high_from;
2722 enum machine_mode mode;
2724 int autoinc_from = autoinc_mode (from);
2725 int autoinc_to = autoinc_mode (to);
2727 mode = GET_MODE (to);
2729 /* If the TO and FROM contain autoinc modes that are not compatible
2730 together (one pop and the other a push), we must change one to
2731 an offsetable operand and generate an appropriate add at the end. */
2732 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2737 /* The source uses an autoinc mode which is not compatible with
2738 a split (this would result in a word swap). */
2739 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2741 code = GET_CODE (XEXP (from, 0));
2742 reg = XEXP (XEXP (from, 0), 0);
2743 offset = GET_MODE_SIZE (GET_MODE (from));
2744 if (code == POST_DEC)
2747 if (code == PRE_INC)
2748 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2750 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2751 if (code == POST_DEC)
2752 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2756 /* Likewise for destination. */
2757 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2759 code = GET_CODE (XEXP (to, 0));
2760 reg = XEXP (XEXP (to, 0), 0);
2761 offset = GET_MODE_SIZE (GET_MODE (to));
2762 if (code == POST_DEC)
2765 if (code == PRE_INC)
2766 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2768 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2769 if (code == POST_DEC)
2770 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2774 /* The source and destination auto increment modes must be compatible
2775 with each other: same direction. */
2776 if ((autoinc_to != autoinc_from
2777 && autoinc_to != CONST && autoinc_from != CONST)
2778 /* The destination address register must not be used within
2779 the source operand because the source address would change
2780 while doing the copy. */
2781 || (autoinc_to != CONST
2782 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2783 && !IS_STACK_PUSH (to)))
2785 /* Must change the destination. */
2786 code = GET_CODE (XEXP (to, 0));
2787 reg = XEXP (XEXP (to, 0), 0);
2788 offset = GET_MODE_SIZE (GET_MODE (to));
2789 if (code == PRE_DEC || code == POST_DEC)
2792 if (code == PRE_DEC || code == PRE_INC)
2793 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2794 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2795 if (code == POST_DEC || code == POST_INC)
2796 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2801 /* Likewise, the source address register must not be used within
2802 the destination operand. */
2803 if (autoinc_from != CONST
2804 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2805 && !IS_STACK_PUSH (to))
2807 /* Must change the source. */
2808 code = GET_CODE (XEXP (from, 0));
2809 reg = XEXP (XEXP (from, 0), 0);
2810 offset = GET_MODE_SIZE (GET_MODE (from));
2811 if (code == PRE_DEC || code == POST_DEC)
2814 if (code == PRE_DEC || code == PRE_INC)
2815 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2816 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2817 if (code == POST_DEC || code == POST_INC)
2818 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2824 if (GET_MODE_SIZE (mode) == 8)
2826 else if (GET_MODE_SIZE (mode) == 4)
2832 && IS_STACK_PUSH (to)
2833 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2839 else if (mode == HImode)
2847 low_to = m68hc11_gen_lowpart (mode, to);
2848 high_to = m68hc11_gen_highpart (mode, to);
2850 low_from = m68hc11_gen_lowpart (mode, from);
2851 high_from = m68hc11_gen_highpart (mode, from);
2855 high_from = adjust_address (high_from, mode, offset);
2856 low_from = high_from;
2859 /* When copying with a POST_INC mode, we must copy the
2860 high part and then the low part to guarantee a correct
2863 && GET_MODE_SIZE (mode) >= 2
2864 && autoinc_from != autoinc_to
2865 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2874 low_from = high_from;
2879 m68hc11_split_move (low_to, low_from, scratch);
2880 m68hc11_split_move (high_to, high_from, scratch);
2882 else if (H_REG_P (to) || H_REG_P (from)
2883 || (low_from == const0_rtx
2884 && high_from == const0_rtx
2885 && ! push_operand (to, GET_MODE (to))
2886 && ! H_REG_P (scratch))
2888 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2889 || m68hc11_small_indexed_indirect_p (from,
2891 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2892 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2894 insn = emit_move_insn (low_to, low_from);
2895 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2897 insn = emit_move_insn (high_to, high_from);
2898 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2902 insn = emit_move_insn (scratch, low_from);
2903 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2904 insn = emit_move_insn (low_to, scratch);
2905 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2907 insn = emit_move_insn (scratch, high_from);
2908 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2909 insn = emit_move_insn (high_to, scratch);
2910 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2915 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2921 if (GET_CODE (operand) != CONST_INT)
2929 val = INTVAL (operand);
2933 if ((val & mask) == 0)
2935 if ((val & mask) == mask)
2936 *result = constm1_rtx;
2940 if ((val & mask) == 0)
2941 *result = const0_rtx;
2942 if ((val & mask) == mask)
2947 if ((val & mask) == 0)
2955 m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
2960 need_copy = (rtx_equal_p (operands[0], operands[1])
2961 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2963 operands[1] = simplify_logical (mode, code, operands[1], &result);
2964 operands[2] = simplify_logical (mode, code, operands[2], &result);
2966 if (result && GET_CODE (result) == CONST_INT)
2968 if (!H_REG_P (operands[0]) && operands[3]
2969 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2971 emit_move_insn (operands[3], result);
2972 emit_move_insn (operands[0], operands[3]);
2976 emit_move_insn (operands[0], result);
2979 else if (operands[1] != 0 && operands[2] != 0)
2981 if (!H_REG_P (operands[0]) && operands[3])
2983 emit_move_insn (operands[3], operands[1]);
2984 emit_insn (gen_rtx_SET (mode,
2986 gen_rtx_fmt_ee (code, mode,
2987 operands[3], operands[2])));
2988 emit_move_insn (operands[0], operands[3]);
2992 emit_insn (gen_rtx_SET (mode, operands[0],
2993 gen_rtx_fmt_ee (code, mode,
2994 operands[0], operands[2])));
2998 /* The logical operation is similar to a copy. */
3003 if (GET_CODE (operands[1]) == CONST_INT)
3008 if (!H_REG_P (operands[0]) && !H_REG_P (src))
3010 emit_move_insn (operands[3], src);
3011 emit_move_insn (operands[0], operands[3]);
3015 emit_move_insn (operands[0], src);
3021 m68hc11_split_logical (enum machine_mode mode, enum rtx_code code,
3027 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3028 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3029 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3031 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3032 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3033 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3035 low[3] = operands[3];
3036 high[3] = operands[3];
3039 m68hc11_split_logical (HImode, code, low);
3040 m68hc11_split_logical (HImode, code, high);
3044 m68hc11_emit_logical (mode, code, low);
3045 m68hc11_emit_logical (mode, code, high);
3049 /* Code generation. */
3052 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3054 /* We have to be careful with the cc_status. An address register swap
3055 is generated for some comparison. The comparison is made with D
3056 but the branch really uses the address register. See the split
3057 pattern for compare. The xgdx/xgdy preserve the flags but after
3058 the exchange, the flags will reflect to the value of X and not D.
3059 Tell this by setting the cc_status according to the cc_prev_status. */
3060 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3062 if (cc_prev_status.value1 != 0
3063 && (D_REG_P (cc_prev_status.value1)
3064 || X_REG_P (cc_prev_status.value1)))
3066 cc_status = cc_prev_status;
3067 if (D_REG_P (cc_status.value1))
3068 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3071 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3077 output_asm_insn ("xgdx", operands);
3081 if (cc_prev_status.value1 != 0
3082 && (D_REG_P (cc_prev_status.value1)
3083 || Y_REG_P (cc_prev_status.value1)))
3085 cc_status = cc_prev_status;
3086 if (D_REG_P (cc_status.value1))
3087 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3090 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3096 output_asm_insn ("xgdy", operands);
3100 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3101 This is used to decide whether a move that set flags should be used
3104 next_insn_test_reg (rtx insn, rtx reg)
3108 insn = next_nonnote_insn (insn);
3109 if (GET_CODE (insn) != INSN)
3112 body = PATTERN (insn);
3113 if (sets_cc0_p (body) != 1)
3116 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3122 /* Generate the code to move a 16-bit operand into another one. */
3125 m68hc11_gen_movhi (rtx insn, rtx *operands)
3129 /* Move a register or memory to the same location.
3130 This is possible because such insn can appear
3131 in a non-optimizing mode. */
3132 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3134 cc_status = cc_prev_status;
3140 rtx from = operands[1];
3141 rtx to = operands[0];
3143 if (IS_STACK_PUSH (to) && H_REG_P (from))
3145 cc_status = cc_prev_status;
3146 switch (REGNO (from))
3151 output_asm_insn ("psh%1", operands);
3153 case HARD_SP_REGNUM:
3154 output_asm_insn ("sts\t2,-sp", operands);
3161 if (IS_STACK_POP (from) && H_REG_P (to))
3163 cc_status = cc_prev_status;
3169 output_asm_insn ("pul%0", operands);
3176 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3178 m68hc11_notice_keep_cc (operands[0]);
3179 output_asm_insn ("tfr\t%1,%0", operands);
3181 else if (H_REG_P (operands[0]))
3183 if (SP_REG_P (operands[0]))
3184 output_asm_insn ("lds\t%1", operands);
3186 output_asm_insn ("ld%0\t%1", operands);
3188 else if (H_REG_P (operands[1]))
3190 if (SP_REG_P (operands[1]))
3191 output_asm_insn ("sts\t%0", operands);
3193 output_asm_insn ("st%1\t%0", operands);
3196 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3197 instruction. We have to use a scratch register as temporary location.
3198 Trying to use a specific pattern or constrain failed. */
3199 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3206 if (dead_register_here (insn, d_reg))
3208 else if (dead_register_here (insn, ix_reg))
3210 else if (dead_register_here (insn, iy_reg))
3216 output_asm_insn ("psh%3", ops);
3221 output_asm_insn ("ld%1\t%2", ops);
3222 output_asm_insn ("st%1\t%0", ops);
3224 output_asm_insn ("pul%3", ops);
3227 /* Use movw for non-null constants or when we are clearing
3228 a volatile memory reference. However, this is possible
3229 only if the memory reference has a small offset or is an
3230 absolute address. */
3231 else if (GET_CODE (from) == CONST_INT
3232 && INTVAL (from) == 0
3233 && (MEM_VOLATILE_P (to) == 0
3234 || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3236 output_asm_insn ("clr\t%h0", operands);
3237 output_asm_insn ("clr\t%b0", operands);
3241 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3242 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3243 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3244 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3250 ops[0] = operands[2];
3253 m68hc11_gen_movhi (insn, ops);
3255 ops[1] = operands[2];
3256 m68hc11_gen_movhi (insn, ops);
3261 /* !!!! SCz wrong here. */
3262 fatal_insn ("move insn not handled", insn);
3267 m68hc11_notice_keep_cc (operands[0]);
3268 output_asm_insn ("movw\t%1,%0", operands);
3274 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3276 cc_status = cc_prev_status;
3277 switch (REGNO (operands[0]))
3281 output_asm_insn ("pul%0", operands);
3284 output_asm_insn ("pula", operands);
3285 output_asm_insn ("pulb", operands);
3292 /* Some moves to a hard register are special. Not all of them
3293 are really supported and we have to use a temporary
3294 location to provide them (either the stack of a temp var). */
3295 if (H_REG_P (operands[0]))
3297 switch (REGNO (operands[0]))
3300 if (X_REG_P (operands[1]))
3302 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3304 m68hc11_output_swap (insn, operands);
3306 else if (next_insn_test_reg (insn, operands[0]))
3308 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3312 m68hc11_notice_keep_cc (operands[0]);
3313 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3316 else if (Y_REG_P (operands[1]))
3318 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3320 m68hc11_output_swap (insn, operands);
3324 /* %t means *ZTMP scratch register. */
3325 output_asm_insn ("sty\t%t1", operands);
3326 output_asm_insn ("ldd\t%t1", operands);
3329 else if (SP_REG_P (operands[1]))
3334 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3335 output_asm_insn ("xgdx", operands);
3336 output_asm_insn ("tsx", operands);
3337 output_asm_insn ("xgdx", operands);
3339 else if (IS_STACK_POP (operands[1]))
3341 output_asm_insn ("pula\n\tpulb", operands);
3343 else if (GET_CODE (operands[1]) == CONST_INT
3344 && INTVAL (operands[1]) == 0)
3346 output_asm_insn ("clra\n\tclrb", operands);
3350 output_asm_insn ("ldd\t%1", operands);
3355 if (D_REG_P (operands[1]))
3357 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3359 m68hc11_output_swap (insn, operands);
3361 else if (next_insn_test_reg (insn, operands[0]))
3363 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3367 m68hc11_notice_keep_cc (operands[0]);
3368 output_asm_insn ("pshb", operands);
3369 output_asm_insn ("psha", operands);
3370 output_asm_insn ("pulx", operands);
3373 else if (Y_REG_P (operands[1]))
3375 /* When both D and Y are dead, use the sequence xgdy, xgdx
3376 to move Y into X. The D and Y registers are modified. */
3377 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3378 && dead_register_here (insn, d_reg))
3380 output_asm_insn ("xgdy", operands);
3381 output_asm_insn ("xgdx", operands);
3384 else if (!optimize_size)
3386 output_asm_insn ("sty\t%t1", operands);
3387 output_asm_insn ("ldx\t%t1", operands);
3392 output_asm_insn ("pshy", operands);
3393 output_asm_insn ("pulx", operands);
3396 else if (SP_REG_P (operands[1]))
3398 /* tsx, tsy preserve the flags */
3399 cc_status = cc_prev_status;
3400 output_asm_insn ("tsx", operands);
3404 output_asm_insn ("ldx\t%1", operands);
3409 if (D_REG_P (operands[1]))
3411 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3413 m68hc11_output_swap (insn, operands);
3417 output_asm_insn ("std\t%t1", operands);
3418 output_asm_insn ("ldy\t%t1", operands);
3421 else if (X_REG_P (operands[1]))
3423 /* When both D and X are dead, use the sequence xgdx, xgdy
3424 to move X into Y. The D and X registers are modified. */
3425 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3426 && dead_register_here (insn, d_reg))
3428 output_asm_insn ("xgdx", operands);
3429 output_asm_insn ("xgdy", operands);
3432 else if (!optimize_size)
3434 output_asm_insn ("stx\t%t1", operands);
3435 output_asm_insn ("ldy\t%t1", operands);
3440 output_asm_insn ("pshx", operands);
3441 output_asm_insn ("puly", operands);
3444 else if (SP_REG_P (operands[1]))
3446 /* tsx, tsy preserve the flags */
3447 cc_status = cc_prev_status;
3448 output_asm_insn ("tsy", operands);
3452 output_asm_insn ("ldy\t%1", operands);
3456 case HARD_SP_REGNUM:
3457 if (D_REG_P (operands[1]))
3459 m68hc11_notice_keep_cc (operands[0]);
3460 output_asm_insn ("xgdx", operands);
3461 output_asm_insn ("txs", operands);
3462 output_asm_insn ("xgdx", operands);
3464 else if (X_REG_P (operands[1]))
3466 /* tys, txs preserve the flags */
3467 cc_status = cc_prev_status;
3468 output_asm_insn ("txs", operands);
3470 else if (Y_REG_P (operands[1]))
3472 /* tys, txs preserve the flags */
3473 cc_status = cc_prev_status;
3474 output_asm_insn ("tys", operands);
3478 /* lds sets the flags but the des does not. */
3480 output_asm_insn ("lds\t%1", operands);
3481 output_asm_insn ("des", operands);
3486 fatal_insn ("invalid register in the move instruction", insn);
3491 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3492 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3494 output_asm_insn ("sts\t%0", operands);
3498 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3500 cc_status = cc_prev_status;
3501 switch (REGNO (operands[1]))
3505 output_asm_insn ("psh%1", operands);
3508 output_asm_insn ("pshb", operands);
3509 output_asm_insn ("psha", operands);
3517 /* Operand 1 must be a hard register. */
3518 if (!H_REG_P (operands[1]))
3520 fatal_insn ("invalid operand in the instruction", insn);
3523 reg = REGNO (operands[1]);
3527 output_asm_insn ("std\t%0", operands);
3531 output_asm_insn ("stx\t%0", operands);
3535 output_asm_insn ("sty\t%0", operands);
3538 case HARD_SP_REGNUM:
3542 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3544 output_asm_insn ("pshx", operands);
3545 output_asm_insn ("tsx", operands);
3546 output_asm_insn ("inx", operands);
3547 output_asm_insn ("inx", operands);
3548 output_asm_insn ("stx\t%0", operands);
3549 output_asm_insn ("pulx", operands);
3552 else if (reg_mentioned_p (ix_reg, operands[0]))
3554 output_asm_insn ("sty\t%t0", operands);
3555 output_asm_insn ("tsy", operands);
3556 output_asm_insn ("sty\t%0", operands);
3557 output_asm_insn ("ldy\t%t0", operands);
3561 output_asm_insn ("stx\t%t0", operands);
3562 output_asm_insn ("tsx", operands);
3563 output_asm_insn ("stx\t%0", operands);
3564 output_asm_insn ("ldx\t%t0", operands);
3570 fatal_insn ("invalid register in the move instruction", insn);
3576 m68hc11_gen_movqi (rtx insn, rtx *operands)
3578 /* Move a register or memory to the same location.
3579 This is possible because such insn can appear
3580 in a non-optimizing mode. */
3581 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3583 cc_status = cc_prev_status;
3590 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3592 m68hc11_notice_keep_cc (operands[0]);
3593 output_asm_insn ("tfr\t%1,%0", operands);
3595 else if (H_REG_P (operands[0]))
3597 if (IS_STACK_POP (operands[1]))
3598 output_asm_insn ("pul%b0", operands);
3599 else if (Q_REG_P (operands[0]))
3600 output_asm_insn ("lda%0\t%b1", operands);
3601 else if (D_REG_P (operands[0]))
3602 output_asm_insn ("ldab\t%b1", operands);
3606 else if (H_REG_P (operands[1]))
3608 if (Q_REG_P (operands[1]))
3609 output_asm_insn ("sta%1\t%b0", operands);
3610 else if (D_REG_P (operands[1]))
3611 output_asm_insn ("stab\t%b0", operands);
3617 rtx from = operands[1];
3618 rtx to = operands[0];
3620 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3621 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3622 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3623 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3629 ops[0] = operands[2];
3632 m68hc11_gen_movqi (insn, ops);
3634 ops[1] = operands[2];
3635 m68hc11_gen_movqi (insn, ops);
3639 /* !!!! SCz wrong here. */
3640 fatal_insn ("move insn not handled", insn);
3645 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3647 output_asm_insn ("clr\t%b0", operands);
3651 m68hc11_notice_keep_cc (operands[0]);
3652 output_asm_insn ("movb\t%b1,%b0", operands);
3660 if (H_REG_P (operands[0]))
3662 switch (REGNO (operands[0]))
3666 if (X_REG_P (operands[1]))
3668 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3670 m68hc11_output_swap (insn, operands);
3674 output_asm_insn ("stx\t%t1", operands);
3675 output_asm_insn ("ldab\t%T0", operands);
3678 else if (Y_REG_P (operands[1]))
3680 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3682 m68hc11_output_swap (insn, operands);
3686 output_asm_insn ("sty\t%t1", operands);
3687 output_asm_insn ("ldab\t%T0", operands);
3690 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3691 && !DA_REG_P (operands[1]))
3693 output_asm_insn ("ldab\t%b1", operands);
3695 else if (DA_REG_P (operands[1]))
3697 output_asm_insn ("tab", operands);
3701 cc_status = cc_prev_status;
3707 if (X_REG_P (operands[1]))
3709 output_asm_insn ("stx\t%t1", operands);
3710 output_asm_insn ("ldaa\t%T0", operands);
3712 else if (Y_REG_P (operands[1]))
3714 output_asm_insn ("sty\t%t1", operands);
3715 output_asm_insn ("ldaa\t%T0", operands);
3717 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3718 && !DA_REG_P (operands[1]))
3720 output_asm_insn ("ldaa\t%b1", operands);
3722 else if (!DA_REG_P (operands[1]))
3724 output_asm_insn ("tba", operands);
3728 cc_status = cc_prev_status;
3733 if (D_REG_P (operands[1]))
3735 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3737 m68hc11_output_swap (insn, operands);
3741 output_asm_insn ("stab\t%T1", operands);
3742 output_asm_insn ("ldx\t%t1", operands);
3746 else if (Y_REG_P (operands[1]))
3748 output_asm_insn ("sty\t%t0", operands);
3749 output_asm_insn ("ldx\t%t0", operands);
3751 else if (GET_CODE (operands[1]) == CONST_INT)
3753 output_asm_insn ("ldx\t%1", operands);
3755 else if (dead_register_here (insn, d_reg))
3757 output_asm_insn ("ldab\t%b1", operands);
3758 output_asm_insn ("xgdx", operands);
3760 else if (!reg_mentioned_p (operands[0], operands[1]))
3762 output_asm_insn ("xgdx", operands);
3763 output_asm_insn ("ldab\t%b1", operands);
3764 output_asm_insn ("xgdx", operands);
3768 output_asm_insn ("pshb", operands);
3769 output_asm_insn ("ldab\t%b1", operands);
3770 output_asm_insn ("stab\t%T1", operands);
3771 output_asm_insn ("ldx\t%t1", operands);
3772 output_asm_insn ("pulb", operands);
3778 if (D_REG_P (operands[1]))
3780 output_asm_insn ("stab\t%T1", operands);
3781 output_asm_insn ("ldy\t%t1", operands);
3784 else if (X_REG_P (operands[1]))
3786 output_asm_insn ("stx\t%t1", operands);
3787 output_asm_insn ("ldy\t%t1", operands);
3790 else if (GET_CODE (operands[1]) == CONST_INT)
3792 output_asm_insn ("ldy\t%1", operands);
3794 else if (dead_register_here (insn, d_reg))
3796 output_asm_insn ("ldab\t%b1", operands);
3797 output_asm_insn ("xgdy", operands);
3799 else if (!reg_mentioned_p (operands[0], operands[1]))
3801 output_asm_insn ("xgdy", operands);
3802 output_asm_insn ("ldab\t%b1", operands);
3803 output_asm_insn ("xgdy", operands);
3807 output_asm_insn ("pshb", operands);
3808 output_asm_insn ("ldab\t%b1", operands);
3809 output_asm_insn ("stab\t%T1", operands);
3810 output_asm_insn ("ldy\t%t1", operands);
3811 output_asm_insn ("pulb", operands);
3817 fatal_insn ("invalid register in the instruction", insn);
3821 else if (H_REG_P (operands[1]))
3823 switch (REGNO (operands[1]))
3827 output_asm_insn ("stab\t%b0", operands);
3831 output_asm_insn ("staa\t%b0", operands);
3835 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3839 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3843 fatal_insn ("invalid register in the move instruction", insn);
3850 fatal_insn ("operand 1 must be a hard register", insn);
3854 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3855 The source and destination must be D or A and the shift must
3858 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3862 if (GET_CODE (operands[2]) != CONST_INT
3863 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3864 fatal_insn ("invalid rotate insn", insn);
3866 val = INTVAL (operands[2]);
3867 if (code == ROTATERT)
3868 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3870 if (GET_MODE (operands[0]) != QImode)
3873 /* Rotate by 8-bits if the shift is within [5..11]. */
3874 if (val >= 5 && val <= 11)
3877 output_asm_insn ("exg\ta,b", operands);
3880 output_asm_insn ("psha", operands);
3881 output_asm_insn ("tba", operands);
3882 output_asm_insn ("pulb", operands);
3887 /* If the shift is big, invert the rotation. */
3897 /* Set the carry to bit-15, but don't change D yet. */
3898 if (GET_MODE (operands[0]) != QImode)
3900 output_asm_insn ("asra", operands);
3901 output_asm_insn ("rola", operands);
3904 /* Rotate B first to move the carry to bit-0. */
3905 if (D_REG_P (operands[0]))
3906 output_asm_insn ("rolb", operands);
3908 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3909 output_asm_insn ("rola", operands);
3916 /* Set the carry to bit-8 of D. */
3917 if (GET_MODE (operands[0]) != QImode)
3918 output_asm_insn ("tap", operands);
3920 /* Rotate B first to move the carry to bit-7. */
3921 if (D_REG_P (operands[0]))
3922 output_asm_insn ("rorb", operands);
3924 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3925 output_asm_insn ("rora", operands);
3932 /* Store in cc_status the expressions that the condition codes will
3933 describe after execution of an instruction whose pattern is EXP.
3934 Do not alter them if the instruction would not alter the cc's. */
3937 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3939 /* recognize SET insn's. */
3940 if (GET_CODE (exp) == SET)
3942 /* Jumps do not alter the cc's. */
3943 if (SET_DEST (exp) == pc_rtx)
3946 /* NOTE: most instructions don't affect the carry bit, but the
3947 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3948 the conditions.h header. */
3950 /* Function calls clobber the cc's. */
3951 else if (GET_CODE (SET_SRC (exp)) == CALL)
3956 /* Tests and compares set the cc's in predictable ways. */
3957 else if (SET_DEST (exp) == cc0_rtx)
3959 cc_status.flags = 0;
3960 cc_status.value1 = XEXP (exp, 0);
3961 if (GET_CODE (XEXP (exp, 1)) == COMPARE
3962 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
3963 cc_status.value2 = XEXP (XEXP (exp, 1), 0);
3965 cc_status.value2 = XEXP (exp, 1);
3969 /* All other instructions affect the condition codes. */
3970 cc_status.flags = 0;
3971 cc_status.value1 = XEXP (exp, 0);
3972 cc_status.value2 = XEXP (exp, 1);
3977 /* Default action if we haven't recognized something
3978 and returned earlier. */
3982 if (cc_status.value2 != 0)
3983 switch (GET_CODE (cc_status.value2))
3985 /* These logical operations can generate several insns.
3986 The flags are setup according to what is generated. */
3992 /* The (not ...) generates several 'com' instructions for
3993 non QImode. We have to invalidate the flags. */
3995 if (GET_MODE (cc_status.value2) != QImode)
4007 if (GET_MODE (cc_status.value2) != VOIDmode)
4008 cc_status.flags |= CC_NO_OVERFLOW;
4011 /* The asl sets the overflow bit in such a way that this
4012 makes the flags unusable for a next compare insn. */
4016 if (GET_MODE (cc_status.value2) != VOIDmode)
4017 cc_status.flags |= CC_NO_OVERFLOW;
4020 /* A load/store instruction does not affect the carry. */
4025 cc_status.flags |= CC_NO_OVERFLOW;
4031 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
4033 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
4034 cc_status.value2 = 0;
4036 else if (cc_status.value1 && side_effects_p (cc_status.value1))
4037 cc_status.value1 = 0;
4039 else if (cc_status.value2 && side_effects_p (cc_status.value2))
4040 cc_status.value2 = 0;
4043 /* The current instruction does not affect the flags but changes
4044 the register 'reg'. See if the previous flags can be kept for the
4045 next instruction to avoid a comparison. */
4047 m68hc11_notice_keep_cc (rtx reg)
4050 || cc_prev_status.value1 == 0
4051 || rtx_equal_p (reg, cc_prev_status.value1)
4052 || (cc_prev_status.value2
4053 && reg_mentioned_p (reg, cc_prev_status.value2)))
4056 cc_status = cc_prev_status;
4061 /* Machine Specific Reorg. */
4063 /* Z register replacement:
4065 GCC treats the Z register as an index base address register like
4066 X or Y. In general, it uses it during reload to compute the address
4067 of some operand. This helps the reload pass to avoid to fall into the
4068 register spill failure.
4070 The Z register is in the A_REGS class. In the machine description,
4071 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4073 It can appear everywhere an X or Y register can appear, except for
4074 some templates in the clobber section (when a clobber of X or Y is asked).
4075 For a given instruction, the template must ensure that no more than
4076 2 'A' registers are used. Otherwise, the register replacement is not
4079 To replace the Z register, the algorithm is not terrific:
4080 1. Insns that do not use the Z register are not changed
4081 2. When a Z register is used, we scan forward the insns to see
4082 a potential register to use: either X or Y and sometimes D.
4083 We stop when a call, a label or a branch is seen, or when we
4084 detect that both X and Y are used (probably at different times, but it does
4086 3. The register that will be used for the replacement of Z is saved
4087 in a .page0 register or on the stack. If the first instruction that
4088 used Z, uses Z as an input, the value is loaded from another .page0
4089 register. The replacement register is pushed on the stack in the
4090 rare cases where a compare insn uses Z and we couldn't find if X/Y
4092 4. The Z register is replaced in all instructions until we reach
4093 the end of the Z-block, as detected by step 2.
4094 5. If we detect that Z is still alive, its value is saved.
4095 If the replacement register is alive, its old value is loaded.
4097 The Z register can be disabled with -ffixed-z.
4107 int must_restore_reg;
4118 int save_before_last;
4119 int z_loaded_with_sp;
4122 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4123 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4124 static void m68hc11_z_replacement (rtx);
4125 static void m68hc11_reassign_regs (rtx);
4127 int z_replacement_completed = 0;
4129 /* Analyze the insn to find out which replacement register to use and
4130 the boundaries of the replacement.
4131 Returns 0 if we reached the last insn to be replaced, 1 if we can
4132 continue replacement in next insns. */
4135 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4137 int this_insn_uses_ix;
4138 int this_insn_uses_iy;
4139 int this_insn_uses_z;
4140 int this_insn_uses_z_in_dst;
4141 int this_insn_uses_d;
4145 /* A call is said to clobber the Z register, we don't need
4146 to save the value of Z. We also don't need to restore
4147 the replacement register (unless it is used by the call). */
4148 if (GET_CODE (insn) == CALL_INSN)
4150 body = PATTERN (insn);
4152 info->can_use_d = 0;
4154 /* If the call is an indirect call with Z, we have to use the
4155 Y register because X can be used as an input (D+X).
4156 We also must not save Z nor restore Y. */
4157 if (reg_mentioned_p (z_reg, body))
4159 insn = NEXT_INSN (insn);
4162 info->found_call = 1;
4163 info->must_restore_reg = 0;
4164 info->last = NEXT_INSN (insn);
4166 info->need_save_z = 0;
4169 if (GET_CODE (insn) == CODE_LABEL
4170 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4173 if (GET_CODE (insn) == JUMP_INSN)
4175 if (reg_mentioned_p (z_reg, insn) == 0)
4178 info->can_use_d = 0;
4179 info->must_save_reg = 0;
4180 info->must_restore_reg = 0;
4181 info->need_save_z = 0;
4182 info->last = NEXT_INSN (insn);
4185 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4190 /* Z register dies here. */
4191 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4193 body = PATTERN (insn);
4194 if (GET_CODE (body) == SET)
4196 rtx src = XEXP (body, 1);
4197 rtx dst = XEXP (body, 0);
4199 /* Condition code is set here. We have to restore the X/Y and
4200 save into Z before any test/compare insn because once we save/restore
4201 we can change the condition codes. When the compare insn uses Z and
4202 we can't use X/Y, the comparison is made with the *ZREG soft register
4203 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4206 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4207 || (GET_CODE (src) == COMPARE &&
4208 ((rtx_equal_p (XEXP (src, 0), z_reg)
4209 && H_REG_P (XEXP (src, 1)))
4210 || (rtx_equal_p (XEXP (src, 1), z_reg)
4211 && H_REG_P (XEXP (src, 0))))))
4213 if (insn == info->first)
4215 info->must_load_z = 0;
4216 info->must_save_reg = 0;
4217 info->must_restore_reg = 0;
4218 info->need_save_z = 0;
4219 info->found_call = 1;
4220 info->regno = SOFT_Z_REGNUM;
4221 info->last = NEXT_INSN (insn);
4225 if (reg_mentioned_p (z_reg, src) == 0)
4227 info->can_use_d = 0;
4231 if (insn != info->first)
4234 /* Compare insn which uses Z. We have to save/restore the X/Y
4235 register without modifying the condition codes. For this
4236 we have to use a push/pop insn. */
4237 info->must_push_reg = 1;
4241 /* Z reg is set to something new. We don't need to load it. */
4244 if (!reg_mentioned_p (z_reg, src))
4246 /* Z reg is used before being set. Treat this as
4247 a new sequence of Z register replacement. */
4248 if (insn != info->first)
4252 info->must_load_z = 0;
4254 info->z_set_count++;
4255 info->z_value = src;
4257 info->z_loaded_with_sp = 1;
4259 else if (reg_mentioned_p (z_reg, dst))
4260 info->can_use_d = 0;
4262 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4263 | reg_mentioned_p (d_reg, dst);
4264 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4265 | reg_mentioned_p (ix_reg, dst);
4266 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4267 | reg_mentioned_p (iy_reg, dst);
4268 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4270 /* If z is used as an address operand (like (MEM (reg z))),
4271 we can't replace it with d. */
4272 if (this_insn_uses_z && !Z_REG_P (src)
4273 && !(m68hc11_arith_operator (src, GET_MODE (src))
4274 && Z_REG_P (XEXP (src, 0))
4275 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4276 && insn == info->first
4277 && dead_register_here (insn, d_reg)))
4278 info->can_use_d = 0;
4280 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4281 if (TARGET_M6812 && !z_dies_here
4282 && ((this_insn_uses_z && side_effects_p (src))
4283 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4285 info->need_save_z = 1;
4286 info->z_set_count++;
4288 this_insn_uses_z |= this_insn_uses_z_in_dst;
4290 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4292 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4295 if (this_insn_uses_d)
4296 info->can_use_d = 0;
4298 /* IX and IY are used at the same time, we have to restore
4299 the value of the scratch register before this insn. */
4300 if (this_insn_uses_ix && this_insn_uses_iy)
4305 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4306 info->can_use_d = 0;
4308 if (info->x_used == 0 && this_insn_uses_ix)
4312 /* We have a (set (REG:HI X) (REG:HI Z)).
4313 Since we use Z as the replacement register, this insn
4314 is no longer necessary. We turn it into a note. We must
4315 not reload the old value of X. */
4316 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4320 info->need_save_z = 0;
4323 info->must_save_reg = 0;
4324 info->must_restore_reg = 0;
4325 info->found_call = 1;
4326 info->can_use_d = 0;
4327 SET_INSN_DELETED (insn);
4328 info->last = NEXT_INSN (insn);
4333 && (rtx_equal_p (src, z_reg)
4334 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4338 info->need_save_z = 0;
4341 info->last = NEXT_INSN (insn);
4342 info->must_save_reg = 0;
4343 info->must_restore_reg = 0;
4345 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4346 && !reg_mentioned_p (ix_reg, src))
4351 info->need_save_z = 0;
4353 else if (TARGET_M6812 && side_effects_p (src))
4356 info->must_restore_reg = 0;
4361 info->save_before_last = 1;
4363 info->must_restore_reg = 0;
4364 info->last = NEXT_INSN (insn);
4366 else if (info->can_use_d)
4368 info->last = NEXT_INSN (insn);
4374 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4375 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4377 info->need_save_z = 0;
4379 info->last = NEXT_INSN (insn);
4380 info->regno = HARD_X_REGNUM;
4381 info->must_save_reg = 0;
4382 info->must_restore_reg = 0;
4385 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4387 info->regno = HARD_X_REGNUM;
4388 info->must_restore_reg = 0;
4389 info->must_save_reg = 0;
4393 if (info->y_used == 0 && this_insn_uses_iy)
4397 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4401 info->need_save_z = 0;
4404 info->must_save_reg = 0;
4405 info->must_restore_reg = 0;
4406 info->found_call = 1;
4407 info->can_use_d = 0;
4408 SET_INSN_DELETED (insn);
4409 info->last = NEXT_INSN (insn);
4414 && (rtx_equal_p (src, z_reg)
4415 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4420 info->need_save_z = 0;
4422 info->last = NEXT_INSN (insn);
4423 info->must_save_reg = 0;
4424 info->must_restore_reg = 0;
4426 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4427 && !reg_mentioned_p (iy_reg, src))
4432 info->need_save_z = 0;
4434 else if (TARGET_M6812 && side_effects_p (src))
4437 info->must_restore_reg = 0;
4442 info->save_before_last = 1;
4444 info->must_restore_reg = 0;
4445 info->last = NEXT_INSN (insn);
4447 else if (info->can_use_d)
4449 info->last = NEXT_INSN (insn);
4456 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4457 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4459 info->need_save_z = 0;
4461 info->last = NEXT_INSN (insn);
4462 info->regno = HARD_Y_REGNUM;
4463 info->must_save_reg = 0;
4464 info->must_restore_reg = 0;
4467 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4469 info->regno = HARD_Y_REGNUM;
4470 info->must_restore_reg = 0;
4471 info->must_save_reg = 0;
4477 info->need_save_z = 0;
4479 if (info->last == 0)
4480 info->last = NEXT_INSN (insn);
4483 return info->last != NULL_RTX ? 0 : 1;
4485 if (GET_CODE (body) == PARALLEL)
4488 char ix_clobber = 0;
4489 char iy_clobber = 0;
4491 this_insn_uses_iy = 0;
4492 this_insn_uses_ix = 0;
4493 this_insn_uses_z = 0;
4495 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4498 int uses_ix, uses_iy, uses_z;
4500 x = XVECEXP (body, 0, i);
4502 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4503 info->can_use_d = 0;
4505 uses_ix = reg_mentioned_p (ix_reg, x);
4506 uses_iy = reg_mentioned_p (iy_reg, x);
4507 uses_z = reg_mentioned_p (z_reg, x);
4508 if (GET_CODE (x) == CLOBBER)
4510 ix_clobber |= uses_ix;
4511 iy_clobber |= uses_iy;
4512 z_clobber |= uses_z;
4516 this_insn_uses_ix |= uses_ix;
4517 this_insn_uses_iy |= uses_iy;
4518 this_insn_uses_z |= uses_z;
4520 if (uses_z && GET_CODE (x) == SET)
4522 rtx dst = XEXP (x, 0);
4525 info->z_set_count++;
4527 if (TARGET_M6812 && uses_z && side_effects_p (x))
4528 info->need_save_z = 1;
4531 info->need_save_z = 0;
4535 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4536 this_insn_uses_ix, this_insn_uses_iy,
4537 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4540 if (this_insn_uses_z)
4541 info->can_use_d = 0;
4543 if (z_clobber && info->first != insn)
4545 info->need_save_z = 0;
4549 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4551 if (this_insn_uses_z == 0 && insn == info->first)
4553 info->must_load_z = 0;
4555 if (dead_register_here (insn, d_reg))
4557 info->regno = HARD_D_REGNUM;
4558 info->must_save_reg = 0;
4559 info->must_restore_reg = 0;
4561 else if (dead_register_here (insn, ix_reg))
4563 info->regno = HARD_X_REGNUM;
4564 info->must_save_reg = 0;
4565 info->must_restore_reg = 0;
4567 else if (dead_register_here (insn, iy_reg))
4569 info->regno = HARD_Y_REGNUM;
4570 info->must_save_reg = 0;
4571 info->must_restore_reg = 0;
4573 if (info->regno >= 0)
4575 info->last = NEXT_INSN (insn);
4578 if (this_insn_uses_ix == 0)
4580 info->regno = HARD_X_REGNUM;
4581 info->must_save_reg = 1;
4582 info->must_restore_reg = 1;
4584 else if (this_insn_uses_iy == 0)
4586 info->regno = HARD_Y_REGNUM;
4587 info->must_save_reg = 1;
4588 info->must_restore_reg = 1;
4592 info->regno = HARD_D_REGNUM;
4593 info->must_save_reg = 1;
4594 info->must_restore_reg = 1;
4596 info->last = NEXT_INSN (insn);
4600 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4601 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4603 if (this_insn_uses_z)
4605 if (info->y_used == 0 && iy_clobber)
4607 info->regno = HARD_Y_REGNUM;
4608 info->must_save_reg = 0;
4609 info->must_restore_reg = 0;
4611 if (info->first != insn
4612 && ((info->y_used && ix_clobber)
4613 || (info->x_used && iy_clobber)))
4616 info->last = NEXT_INSN (insn);
4617 info->save_before_last = 1;
4621 if (this_insn_uses_ix && this_insn_uses_iy)
4623 if (this_insn_uses_z)
4625 fatal_insn ("cannot do z-register replacement", insn);
4629 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4636 if (iy_clobber || z_clobber)
4638 info->last = NEXT_INSN (insn);
4639 info->save_before_last = 1;
4644 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4651 if (ix_clobber || z_clobber)
4653 info->last = NEXT_INSN (insn);
4654 info->save_before_last = 1;
4661 info->need_save_z = 0;
4665 if (GET_CODE (body) == CLOBBER)
4667 rtx dst = XEXP (body, 0);
4669 this_insn_uses_ix = reg_mentioned_p (ix_reg, dst);
4670 this_insn_uses_iy = reg_mentioned_p (iy_reg, dst);
4672 /* IX and IY are used at the same time, we have to restore
4673 the value of the scratch register before this insn. */
4674 if (this_insn_uses_ix && this_insn_uses_iy)
4678 if (info->x_used == 0 && this_insn_uses_ix)
4686 if (info->y_used == 0 && this_insn_uses_iy)
4700 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4704 info->replace_reg = NULL_RTX;
4705 info->must_load_z = 1;
4706 info->need_save_z = 1;
4707 info->must_save_reg = 1;
4708 info->must_restore_reg = 1;
4712 info->can_use_d = TARGET_M6811 ? 1 : 0;
4713 info->found_call = 0;
4717 info->z_set_count = 0;
4718 info->z_value = NULL_RTX;
4719 info->must_push_reg = 0;
4720 info->save_before_last = 0;
4721 info->z_loaded_with_sp = 0;
4723 /* Scan the insn forward to find an address register that is not used.
4725 - the flow of the program changes,
4726 - when we detect that both X and Y are necessary,
4727 - when the Z register dies,
4728 - when the condition codes are set. */
4730 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4732 if (m68hc11_check_z_replacement (insn, info) == 0)
4736 /* May be we can use Y or X if they contain the same value as Z.
4737 This happens very often after the reload. */
4738 if (info->z_set_count == 1)
4740 rtx p = info->first;
4745 v = find_last_value (iy_reg, &p, insn, 1);
4747 else if (info->y_used)
4749 v = find_last_value (ix_reg, &p, insn, 1);
4751 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4754 info->regno = HARD_Y_REGNUM;
4756 info->regno = HARD_X_REGNUM;
4757 info->must_load_z = 0;
4758 info->must_save_reg = 0;
4759 info->must_restore_reg = 0;
4760 info->found_call = 1;
4763 if (info->z_set_count == 0)
4764 info->need_save_z = 0;
4767 info->need_save_z = 0;
4769 if (info->last == 0)
4772 if (info->regno >= 0)
4775 info->replace_reg = gen_rtx_REG (HImode, reg);
4777 else if (info->can_use_d)
4779 reg = HARD_D_REGNUM;
4780 info->replace_reg = d_reg;
4782 else if (info->x_used)
4784 reg = HARD_Y_REGNUM;
4785 info->replace_reg = iy_reg;
4789 reg = HARD_X_REGNUM;
4790 info->replace_reg = ix_reg;
4794 if (info->must_save_reg && info->must_restore_reg)
4796 if (insn && dead_register_here (insn, info->replace_reg))
4798 info->must_save_reg = 0;
4799 info->must_restore_reg = 0;
4804 /* The insn uses the Z register. Find a replacement register for it
4805 (either X or Y) and replace it in the insn and the next ones until
4806 the flow changes or the replacement register is used. Instructions
4807 are emitted before and after the Z-block to preserve the value of
4808 Z and of the replacement register. */
4811 m68hc11_z_replacement (rtx insn)
4815 struct replace_info info;
4817 /* Find trivial case where we only need to replace z with the
4818 equivalent soft register. */
4819 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4821 rtx body = PATTERN (insn);
4822 rtx src = XEXP (body, 1);
4823 rtx dst = XEXP (body, 0);
4825 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4827 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4830 else if (Z_REG_P (src)
4831 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4833 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4836 else if (D_REG_P (dst)
4837 && m68hc11_arith_operator (src, GET_MODE (src))
4838 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4840 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4843 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4844 && INTVAL (src) == 0)
4846 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4847 /* Force it to be re-recognized. */
4848 INSN_CODE (insn) = -1;
4853 m68hc11_find_z_replacement (insn, &info);
4855 replace_reg = info.replace_reg;
4856 replace_reg_qi = NULL_RTX;
4858 /* Save the X register in a .page0 location. */
4859 if (info.must_save_reg && !info.must_push_reg)
4863 if (info.must_push_reg && 0)
4864 dst = gen_rtx_MEM (HImode,
4865 gen_rtx_PRE_DEC (HImode,
4866 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4868 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4870 emit_insn_before (gen_movhi (dst,
4871 gen_rtx_REG (HImode, info.regno)), insn);
4873 if (info.must_load_z && !info.must_push_reg)
4875 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4876 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4881 /* Replace all occurrence of Z by replace_reg.
4882 Stop when the last instruction to replace is reached.
4883 Also stop when we detect a change in the flow (but it's not
4884 necessary; just safeguard). */
4886 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4890 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4893 if (GET_CODE (insn) != INSN
4894 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4897 body = PATTERN (insn);
4898 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4899 || GET_CODE (body) == ASM_OPERANDS
4900 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4904 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4906 printf ("Reg mentioned here...:\n");
4911 /* Stack pointer was decremented by 2 due to the push.
4912 Correct that by adding 2 to the destination. */
4913 if (info.must_push_reg
4914 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4918 src = SET_SRC (body);
4919 dst = SET_DEST (body);
4920 if (SP_REG_P (src) && Z_REG_P (dst))
4921 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4924 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4925 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4927 INSN_CODE (insn) = -1;
4928 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4929 fatal_insn ("cannot do z-register replacement", insn);
4932 /* Likewise for (REG:QI Z). */
4933 if (reg_mentioned_p (z_reg, insn))
4935 if (replace_reg_qi == NULL_RTX)
4936 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4937 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4940 /* If there is a REG_INC note on Z, replace it with a
4941 REG_INC note on the replacement register. This is necessary
4942 to make sure that the flow pass will identify the change
4943 and it will not remove a possible insn that saves Z. */
4944 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4946 if (REG_NOTE_KIND (note) == REG_INC
4947 && GET_CODE (XEXP (note, 0)) == REG
4948 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4950 XEXP (note, 0) = replace_reg;
4954 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4958 /* Save Z before restoring the old value. */
4959 if (insn && info.need_save_z && !info.must_push_reg)
4961 rtx save_pos_insn = insn;
4963 /* If Z is clobber by the last insn, we have to save its value
4964 before the last instruction. */
4965 if (info.save_before_last)
4966 save_pos_insn = PREV_INSN (save_pos_insn);
4968 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4969 gen_rtx_REG (HImode, info.regno)),
4973 if (info.must_push_reg && info.last)
4977 body = PATTERN (info.last);
4978 new_body = gen_rtx_PARALLEL (VOIDmode,
4980 gen_rtx_USE (VOIDmode,
4982 gen_rtx_USE (VOIDmode,
4983 gen_rtx_REG (HImode,
4985 PATTERN (info.last) = new_body;
4987 /* Force recognition on insn since we changed it. */
4988 INSN_CODE (insn) = -1;
4990 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4992 fatal_insn ("invalid Z register replacement for insn", insn);
4994 insn = NEXT_INSN (info.last);
4997 /* Restore replacement register unless it was died. */
4998 if (insn && info.must_restore_reg && !info.must_push_reg)
5002 if (info.must_push_reg && 0)
5003 dst = gen_rtx_MEM (HImode,
5004 gen_rtx_POST_INC (HImode,
5005 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
5007 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
5009 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
5016 /* Scan all the insn and re-affects some registers
5017 - The Z register (if it was used), is affected to X or Y depending
5018 on the instruction. */
5021 m68hc11_reassign_regs (rtx first)
5025 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
5026 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
5027 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5028 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
5030 /* Scan all insns to replace Z by X or Y preserving the old value
5031 of X/Y and restoring it afterward. */
5033 for (insn = first; insn; insn = NEXT_INSN (insn))
5037 if (GET_CODE (insn) == CODE_LABEL
5038 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
5044 body = PATTERN (insn);
5045 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5048 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5049 || GET_CODE (body) == ASM_OPERANDS
5050 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5053 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5054 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5057 /* If Z appears in this insn, replace it in the current insn
5058 and the next ones until the flow changes or we have to
5059 restore back the replacement register. */
5061 if (reg_mentioned_p (z_reg, body))
5063 m68hc11_z_replacement (insn);
5068 printf ("insn not handled by Z replacement:\n");
5076 /* Machine-dependent reorg pass.
5077 Specific optimizations are defined here:
5078 - this pass changes the Z register into either X or Y
5079 (it preserves X/Y previous values in a memory slot in page0).
5081 When this pass is finished, the global variable
5082 'z_replacement_completed' is set to 2. */
5085 m68hc11_reorg (void)
5090 z_replacement_completed = 0;
5091 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5092 first = get_insns ();
5094 /* Some RTX are shared at this point. This breaks the Z register
5095 replacement, unshare everything. */
5096 unshare_all_rtl_again (first);
5098 /* Force a split of all splittable insn. This is necessary for the
5099 Z register replacement mechanism because we end up with basic insns. */
5100 split_all_insns_noflow ();
5103 z_replacement_completed = 1;
5104 m68hc11_reassign_regs (first);
5107 compute_bb_for_insn ();
5109 /* After some splitting, there are some opportunities for CSE pass.
5110 This happens quite often when 32-bit or above patterns are split. */
5111 if (optimize > 0 && split_done)
5113 reload_cse_regs (first);
5116 /* Re-create the REG_DEAD notes. These notes are used in the machine
5117 description to use the best assembly directives. */
5120 df_note_add_problem ();
5122 df_remove_problem (df_note);
5125 z_replacement_completed = 2;
5127 /* If optimizing, then go ahead and split insns that must be
5128 split after Z register replacement. This gives more opportunities
5129 for peephole (in particular for consecutives xgdx/xgdy). */
5131 split_all_insns_noflow ();
5133 /* Once insns are split after the z_replacement_completed == 2,
5134 we must not re-run the life_analysis. The xgdx/xgdy patterns
5135 are not recognized and the life_analysis pass removes some
5136 insns because it thinks some (SETs) are noops or made to dead
5137 stores (which is false due to the swap).
5139 Do a simple pass to eliminate the noop set that the final
5140 split could generate (because it was easier for split definition). */
5144 for (insn = first; insn; insn = NEXT_INSN (insn))
5148 if (INSN_DELETED_P (insn))
5153 /* Remove the (set (R) (R)) insns generated by some splits. */
5154 body = PATTERN (insn);
5155 if (GET_CODE (body) == SET
5156 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5158 SET_INSN_DELETED (insn);
5165 /* Override memcpy */
5168 m68hc11_init_libfuncs (void)
5170 memcpy_libfunc = init_one_libfunc ("__memcpy");
5171 memcmp_libfunc = init_one_libfunc ("__memcmp");
5172 memset_libfunc = init_one_libfunc ("__memset");
5177 /* Cost functions. */
5179 /* Cost of moving memory. */
5181 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
5182 int in ATTRIBUTE_UNUSED)
5184 if (rclass <= H_REGS && rclass > NO_REGS)
5186 if (GET_MODE_SIZE (mode) <= 2)
5187 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5189 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5193 if (GET_MODE_SIZE (mode) <= 2)
5194 return COSTS_N_INSNS (3);
5196 return COSTS_N_INSNS (4);
5201 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5202 Reload does not check the constraint of set insns when the two registers
5203 have a move cost of 2. Setting a higher cost will force reload to check
5206 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5209 /* All costs are symmetric, so reduce cases by putting the
5210 lower number class as the destination. */
5213 enum reg_class tmp = to;
5214 to = from, from = tmp;
5217 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5218 else if (from <= S_REGS)
5219 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5221 return COSTS_N_INSNS (2);
5225 /* Provide the costs of an addressing mode that contains ADDR.
5226 If ADDR is not a valid address, its cost is irrelevant. */
5229 m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
5233 switch (GET_CODE (addr))
5236 /* Make the cost of hard registers and specially SP, FP small. */
5237 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5254 register rtx plus0 = XEXP (addr, 0);
5255 register rtx plus1 = XEXP (addr, 1);
5257 if (GET_CODE (plus0) != REG)
5260 switch (GET_CODE (plus1))
5263 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5264 || INTVAL (plus1) < m68hc11_min_offset)
5266 else if (INTVAL (plus1) >= m68hc11_max_offset)
5270 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5292 if (SP_REG_P (XEXP (addr, 0)))
5301 printf ("Address cost: %d for :", cost);
5310 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5314 total = rtx_cost (x, SET, !optimize_size);
5316 total += m68hc11_cost->shiftQI_const[shift % 8];
5317 else if (mode == HImode)
5318 total += m68hc11_cost->shiftHI_const[shift % 16];
5319 else if (shift == 8 || shift == 16 || shift == 32)
5320 total += m68hc11_cost->shiftHI_const[8];
5321 else if (shift != 0 && shift != 16 && shift != 32)
5323 total += m68hc11_cost->shiftHI_const[1] * shift;
5326 /* For SI and others, the cost is higher. */
5327 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5328 total *= GET_MODE_SIZE (mode) / 2;
5330 /* When optimizing for size, make shift more costly so that
5331 multiplications are preferred. */
5332 if (optimize_size && (shift % 8) != 0)
5339 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5340 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5342 enum machine_mode mode = GET_MODE (x);
5353 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5355 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5358 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5359 total += m68hc11_cost->shift_var;
5365 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5366 total += m68hc11_cost->logical;
5368 /* Logical instructions are byte instructions only. */
5369 total *= GET_MODE_SIZE (mode);
5374 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5375 total += m68hc11_cost->add;
5376 if (GET_MODE_SIZE (mode) > 2)
5378 total *= GET_MODE_SIZE (mode) / 2;
5385 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5389 total += m68hc11_cost->divQI;
5393 total += m68hc11_cost->divHI;
5398 total += m68hc11_cost->divSI;
5404 /* mul instruction produces 16-bit result. */
5405 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5406 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5407 return m68hc11_cost->multQI
5408 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5409 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5411 /* emul instruction produces 32-bit result for 68HC12. */
5412 if (TARGET_M6812 && mode == SImode
5413 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5414 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5415 return m68hc11_cost->multHI
5416 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5417 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5419 total = rtx_cost (XEXP (x, 0), code, !optimize_size)
5420 + rtx_cost (XEXP (x, 1), code, !optimize_size);
5424 total += m68hc11_cost->multQI;
5428 total += m68hc11_cost->multHI;
5433 total += m68hc11_cost->multSI;
5440 extra_cost = COSTS_N_INSNS (2);
5448 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
5451 return total + COSTS_N_INSNS (1);
5455 return total + COSTS_N_INSNS (2);
5459 return total + COSTS_N_INSNS (4);
5461 return total + COSTS_N_INSNS (8);
5464 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5465 return COSTS_N_INSNS (1);
5467 return COSTS_N_INSNS (1);
5470 return COSTS_N_INSNS (4);
5475 m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
5476 bool speed ATTRIBUTE_UNUSED)
5478 enum rtx_code code = (enum rtx_code) codearg;
5479 enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
5483 /* Constants are cheap. Moving them in registers must be avoided
5484 because most instructions do not handle two register operands. */
5490 /* Logical and arithmetic operations with a constant operand are
5491 better because they are not supported with two registers. */
5493 if (outer_code == SET && x == const0_rtx)
5494 /* After reload, the reload_cse pass checks the cost to change
5495 a SET into a PLUS. Make const0 cheap then. */
5496 *total = 1 - reload_completed;
5502 if (outer_code != COMPARE)
5525 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5534 /* Worker function for TARGET_ASM_FILE_START. */
5537 m68hc11_file_start (void)
5539 default_file_start ();
5541 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5545 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5548 m68hc11_asm_out_constructor (rtx symbol, int priority)
5550 default_ctor_section_asm_out_constructor (symbol, priority);
5551 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5554 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5557 m68hc11_asm_out_destructor (rtx symbol, int priority)
5559 default_dtor_section_asm_out_destructor (symbol, priority);
5560 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5563 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5566 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5567 int incoming ATTRIBUTE_UNUSED)
5569 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5572 /* Return true if type TYPE should be returned in memory.
5573 Blocks and data types largers than 4 bytes cannot be returned
5574 in the register (D + X = 4). */
5577 m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
5579 if (TYPE_MODE (type) == BLKmode)
5581 HOST_WIDE_INT size = int_size_in_bytes (type);
5582 return (size == -1 || size > 4);
5585 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5588 #include "gt-m68hc11.h"