1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
3 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 2, 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 COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
24 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
25 on gcc 2.6.3. I have used it as a starting point for this port.
26 However, this new port is a complete re-write. Its internal
27 design is completely different. The generated code is not
28 compatible with the gcc 2.6.3 port.
30 The gcc 2.6.3 port is available at:
32 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
39 #include "coretypes.h"
45 #include "hard-reg-set.h"
47 #include "insn-config.h"
48 #include "conditions.h"
50 #include "insn-attr.h"
56 #include "basic-block.h"
61 #include "target-def.h"
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, int, rtx *);
66 static void m68hc11_reorg (void);
67 static int go_if_legitimate_address_internal (rtx, enum machine_mode, int);
68 static int register_indirect_p (rtx, enum machine_mode, int);
69 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
70 static int must_parenthesize (rtx);
71 static int m68hc11_address_cost (rtx);
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 *);
75 static int m68hc11_auto_inc_p (rtx);
76 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
77 const struct attribute_spec m68hc11_attribute_table[];
79 void create_regs_rtx (void);
81 static void asm_print_register (FILE *, int);
82 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
83 static void m68hc11_asm_out_constructor (rtx, int);
84 static void m68hc11_asm_out_destructor (rtx, int);
85 static void m68hc11_file_start (void);
86 static void m68hc11_encode_section_info (tree, rtx, int);
87 static const char *m68hc11_strip_name_encoding (const char* str);
88 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
89 static int autoinc_mode (rtx);
90 static int m68hc11_make_autoinc_notes (rtx *, void *);
91 static void m68hc11_init_libfuncs (void);
92 static rtx m68hc11_struct_value_rtx (tree, int);
93 static bool m68hc11_return_in_memory (tree, tree);
95 /* Must be set to 1 to produce debug messages. */
98 extern FILE *asm_out_file;
103 rtx m68hc11_soft_tmp_reg;
104 static GTY(()) rtx stack_push_word;
105 static GTY(()) rtx stack_pop_word;
106 static GTY(()) rtx z_reg;
107 static GTY(()) rtx z_reg_qi;
108 static int regs_inited = 0;
110 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
111 int current_function_interrupt;
113 /* Set to 1 by expand_prologue() when the function is a trap handler. */
114 int current_function_trap;
116 /* Set to 1 when the current function is placed in 68HC12 banked
117 memory and must return with rtc. */
118 int current_function_far;
120 /* Min offset that is valid for the indirect addressing mode. */
121 HOST_WIDE_INT m68hc11_min_offset = 0;
123 /* Max offset that is valid for the indirect addressing mode. */
124 HOST_WIDE_INT m68hc11_max_offset = 256;
126 /* The class value for base registers. */
127 enum reg_class m68hc11_base_reg_class = A_REGS;
129 /* The class value for index registers. This is NO_REGS for 68HC11. */
130 enum reg_class m68hc11_index_reg_class = NO_REGS;
132 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
134 /* Tables that tell whether a given hard register is valid for
135 a base or an index register. It is filled at init time depending
136 on the target processor. */
137 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
138 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
140 /* A correction offset which is applied to the stack pointer.
141 This is 1 for 68HC11 and 0 for 68HC12. */
142 int m68hc11_sp_correction;
144 #define ADDR_STRICT 0x01 /* Accept only registers in class A_REGS */
145 #define ADDR_INCDEC 0x02 /* Post/Pre inc/dec */
146 #define ADDR_INDEXED 0x04 /* D-reg index */
147 #define ADDR_OFFSET 0x08
148 #define ADDR_INDIRECT 0x10 /* Accept (mem (mem ...)) for [n,X] */
149 #define ADDR_CONST 0x20 /* Accept const and symbol_ref */
151 int m68hc11_addr_mode;
152 int m68hc11_mov_addr_mode;
154 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
155 rtx m68hc11_compare_op0;
156 rtx m68hc11_compare_op1;
159 const struct processor_costs *m68hc11_cost;
161 /* Costs for a 68HC11. */
162 static const struct processor_costs m6811_cost = {
167 /* non-constant shift */
170 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
171 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
172 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
175 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
176 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
177 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
178 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
179 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
180 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
185 COSTS_N_INSNS (20 * 4),
187 COSTS_N_INSNS (20 * 16),
196 /* Costs for a 68HC12. */
197 static const struct processor_costs m6812_cost = {
202 /* non-constant shift */
205 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
206 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
207 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
210 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
211 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
212 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
213 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
214 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
215 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
222 COSTS_N_INSNS (3 * 4),
231 /* Machine specific options */
233 const char *m68hc11_regparm_string;
234 const char *m68hc11_reg_alloc_order;
235 const char *m68hc11_soft_reg_count;
237 static int nb_soft_regs;
239 /* Initialize the GCC target structure. */
240 #undef TARGET_ATTRIBUTE_TABLE
241 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
243 #undef TARGET_ASM_ALIGNED_HI_OP
244 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
246 #undef TARGET_ASM_FUNCTION_EPILOGUE
247 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
249 #undef TARGET_ASM_FILE_START
250 #define TARGET_ASM_FILE_START m68hc11_file_start
251 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
252 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
254 #undef TARGET_ENCODE_SECTION_INFO
255 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
257 #undef TARGET_SECTION_TYPE_FLAGS
258 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
260 #undef TARGET_RTX_COSTS
261 #define TARGET_RTX_COSTS m68hc11_rtx_costs
262 #undef TARGET_ADDRESS_COST
263 #define TARGET_ADDRESS_COST m68hc11_address_cost
265 #undef TARGET_MACHINE_DEPENDENT_REORG
266 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
268 #undef TARGET_INIT_LIBFUNCS
269 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
271 #undef TARGET_STRUCT_VALUE_RTX
272 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
273 #undef TARGET_RETURN_IN_MEMORY
274 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
275 #undef TARGET_CALLEE_COPIES
276 #define TARGET_CALLEE_COPIES hook_callee_copies_named
278 #undef TARGET_STRIP_NAME_ENCODING
279 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
281 struct gcc_target targetm = TARGET_INITIALIZER;
284 m68hc11_override_options (void)
286 memset (m68hc11_reg_valid_for_index, 0,
287 sizeof (m68hc11_reg_valid_for_index));
288 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
290 /* Compilation with -fpic generates a wrong code. */
293 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
294 (flag_pic > 1) ? "PIC" : "pic");
298 /* Do not enable -fweb because it breaks the 32-bit shift patterns
299 by breaking the match_dup of those patterns. The shift patterns
300 will no longer be recognized after that. */
303 /* Configure for a 68hc11 processor. */
306 /* If gcc was built for a 68hc12, invalidate that because
307 a -m68hc11 option was specified on the command line. */
308 if (TARGET_DEFAULT != MASK_M6811)
309 target_flags &= ~TARGET_DEFAULT;
312 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
313 m68hc11_cost = &m6811_cost;
314 m68hc11_min_offset = 0;
315 m68hc11_max_offset = 256;
316 m68hc11_index_reg_class = NO_REGS;
317 m68hc11_base_reg_class = A_REGS;
318 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
319 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
320 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
321 m68hc11_sp_correction = 1;
322 m68hc11_tmp_regs_class = D_REGS;
323 m68hc11_addr_mode = ADDR_OFFSET;
324 m68hc11_mov_addr_mode = 0;
325 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
326 m68hc11_soft_reg_count = "4";
329 /* Configure for a 68hc12 processor. */
332 m68hc11_cost = &m6812_cost;
333 m68hc11_min_offset = -65536;
334 m68hc11_max_offset = 65536;
335 m68hc11_index_reg_class = D_REGS;
336 m68hc11_base_reg_class = A_OR_SP_REGS;
337 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
338 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
339 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
340 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
341 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
342 m68hc11_sp_correction = 0;
343 m68hc11_tmp_regs_class = TMP_REGS;
344 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
345 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
346 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
347 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
348 target_flags &= ~MASK_M6811;
349 target_flags |= MASK_NO_DIRECT_MODE;
350 if (m68hc11_soft_reg_count == 0)
351 m68hc11_soft_reg_count = "0";
353 if (TARGET_LONG_CALLS)
354 current_function_far = 1;
361 m68hc11_conditional_register_usage (void)
364 int cnt = atoi (m68hc11_soft_reg_count);
368 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
369 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
372 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
375 call_used_regs[i] = 1;
378 /* For 68HC12, the Z register emulation is not necessary when the
379 frame pointer is not used. The frame pointer is eliminated and
380 replaced by the stack register (which is a BASE_REG_CLASS). */
381 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
383 fixed_regs[HARD_Z_REGNUM] = 1;
388 /* Reload and register operations. */
390 static const char *const reg_class_names[] = REG_CLASS_NAMES;
394 create_regs_rtx (void)
396 /* regs_inited = 1; */
397 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
398 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
399 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
400 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
402 stack_push_word = gen_rtx_MEM (HImode,
403 gen_rtx_PRE_DEC (HImode,
404 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
405 stack_pop_word = gen_rtx_MEM (HImode,
406 gen_rtx_POST_INC (HImode,
407 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
411 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
412 - 8 bit values are stored anywhere (except the SP register).
413 - 16 bit values can be stored in any register whose mode is 16
414 - 32 bit values can be stored in D, X registers or in a soft register
415 (except the last one because we need 2 soft registers)
416 - Values whose size is > 32 bit are not stored in real hard
417 registers. They may be stored in soft registers if there are
420 hard_regno_mode_ok (int regno, enum machine_mode mode)
422 switch (GET_MODE_SIZE (mode))
425 return S_REGNO_P (regno) && nb_soft_regs >= 4;
428 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
431 return G_REGNO_P (regno);
434 /* We have to accept a QImode in X or Y registers. Otherwise, the
435 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
436 in the insns. Reload fails if the insn rejects the register class 'a'
437 as well as if it accepts it. Patterns that failed were
438 zero_extend_qihi2 and iorqi3. */
440 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
448 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
450 /* Don't accept renaming to Z register. We will replace it to
451 X,Y or D during machine reorg pass. */
452 if (reg2 == HARD_Z_REGNUM)
455 /* Don't accept renaming D,X to Y register as the code will be bigger. */
456 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
457 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
464 preferred_reload_class (rtx operand, enum reg_class class)
466 enum machine_mode mode;
468 mode = GET_MODE (operand);
472 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
475 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
476 return m68hc11_base_reg_class;
478 if (class >= S_REGS && (GET_CODE (operand) == MEM
479 || GET_CODE (operand) == CONST_INT))
481 /* S_REGS class must not be used. The movhi template does not
482 work to move a memory to a soft register.
483 Restrict to a hard reg. */
488 case D_OR_A_OR_S_REGS:
494 case D_OR_SP_OR_S_REGS:
495 class = D_OR_SP_REGS;
497 case D_OR_Y_OR_S_REGS:
500 case D_OR_X_OR_S_REGS:
516 else if (class == Y_REGS && GET_CODE (operand) == MEM)
520 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
524 else if (class >= S_REGS && S_REG_P (operand))
530 case D_OR_A_OR_S_REGS:
536 case D_OR_SP_OR_S_REGS:
537 class = D_OR_SP_REGS;
539 case D_OR_Y_OR_S_REGS:
542 case D_OR_X_OR_S_REGS:
558 else if (class >= S_REGS)
562 printf ("Class = %s for: ", reg_class_names[class]);
570 printf (" => class=%s\n", reg_class_names[class]);
578 /* Return 1 if the operand is a valid indexed addressing mode.
579 For 68hc11: n,r with n in [0..255] and r in A_REGS class
580 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
582 register_indirect_p (rtx operand, enum machine_mode mode, int addr_mode)
586 switch (GET_CODE (operand))
589 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
590 return register_indirect_p (XEXP (operand, 0), mode,
591 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
598 if (addr_mode & ADDR_INCDEC)
599 return register_indirect_p (XEXP (operand, 0), mode,
600 addr_mode & ADDR_STRICT);
604 base = XEXP (operand, 0);
605 if (GET_CODE (base) == MEM)
608 offset = XEXP (operand, 1);
609 if (GET_CODE (offset) == MEM)
612 /* Indexed addressing mode with 2 registers. */
613 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
615 if (!(addr_mode & ADDR_INDEXED))
618 addr_mode &= ADDR_STRICT;
619 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
620 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
623 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
624 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
630 if (!(addr_mode & ADDR_OFFSET))
633 if (GET_CODE (base) == REG)
635 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
638 if (!(addr_mode & ADDR_STRICT))
641 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
644 if (GET_CODE (offset) == REG)
646 if (!VALID_CONSTANT_OFFSET_P (base, mode))
649 if (!(addr_mode & ADDR_STRICT))
652 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
657 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
660 if (addr_mode & ADDR_CONST)
661 return VALID_CONSTANT_OFFSET_P (operand, mode);
669 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
670 a 68HC12 1-byte index addressing mode. */
672 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
677 if (GET_CODE (operand) == REG && reload_in_progress
678 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
679 && reg_equiv_memory_loc[REGNO (operand)])
681 operand = reg_equiv_memory_loc[REGNO (operand)];
682 operand = eliminate_regs (operand, 0, NULL_RTX);
685 if (GET_CODE (operand) != MEM)
688 operand = XEXP (operand, 0);
689 if (CONSTANT_ADDRESS_P (operand))
692 if (PUSH_POP_ADDRESS_P (operand))
695 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
696 if (!register_indirect_p (operand, mode, addr_mode))
699 if (TARGET_M6812 && GET_CODE (operand) == PLUS
700 && (reload_completed | reload_in_progress))
702 base = XEXP (operand, 0);
703 offset = XEXP (operand, 1);
705 /* The offset can be a symbol address and this is too big
706 for the operand constraint. */
707 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
710 if (GET_CODE (base) == CONST_INT)
713 switch (GET_MODE_SIZE (mode))
716 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
721 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
726 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
735 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
739 if (GET_CODE (operand) == REG && reload_in_progress
740 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
741 && reg_equiv_memory_loc[REGNO (operand)])
743 operand = reg_equiv_memory_loc[REGNO (operand)];
744 operand = eliminate_regs (operand, 0, NULL_RTX);
746 if (GET_CODE (operand) != MEM)
749 operand = XEXP (operand, 0);
750 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
751 return register_indirect_p (operand, mode, addr_mode);
755 go_if_legitimate_address_internal (rtx operand, enum machine_mode mode,
760 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
762 /* Reject the global variables if they are too wide. This forces
763 a load of their address in a register and generates smaller code. */
764 if (GET_MODE_SIZE (mode) == 8)
769 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
770 if (register_indirect_p (operand, mode, addr_mode))
774 if (PUSH_POP_ADDRESS_P (operand))
778 if (symbolic_memory_operand (operand, mode))
786 m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode,
793 printf ("Checking: ");
798 result = go_if_legitimate_address_internal (operand, mode, strict);
802 printf (" -> %s\n", result == 0 ? "NO" : "YES");
809 printf ("go_if_legitimate%s, ret 0: %d:",
810 (strict ? "_strict" : ""), mode);
819 m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED,
820 rtx old_operand ATTRIBUTE_UNUSED,
821 enum machine_mode mode ATTRIBUTE_UNUSED)
828 m68hc11_reload_operands (rtx operands[])
830 enum machine_mode mode;
832 if (regs_inited == 0)
835 mode = GET_MODE (operands[1]);
837 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
838 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
840 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
841 rtx base = XEXP (XEXP (operands[1], 0), 0);
843 if (GET_CODE (base) != REG)
850 /* If the offset is out of range, we have to compute the address
851 with a separate add instruction. We try to do with with an 8-bit
852 add on the A register. This is possible only if the lowest part
853 of the offset (ie, big_offset % 256) is a valid constant offset
854 with respect to the mode. If it's not, we have to generate a
855 16-bit add on the D register. From:
857 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
861 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
862 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
863 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
864 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
866 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
867 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
870 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
873 rtx reg = operands[0];
875 int val = INTVAL (big_offset);
878 /* We use the 'operands[0]' as a scratch register to compute the
879 address. Make sure 'base' is in that register. */
880 if (!rtx_equal_p (base, operands[0]))
882 emit_move_insn (reg, base);
892 vh = (val >> 8) & 0x0FF;
896 /* Create the lowest part offset that still remains to be added.
897 If it's not a valid offset, do a 16-bit add. */
898 offset = GEN_INT (vl);
899 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
901 emit_insn (gen_rtx_SET (VOIDmode, reg,
902 gen_rtx_PLUS (HImode, reg, big_offset)));
907 emit_insn (gen_rtx_SET (VOIDmode, reg,
908 gen_rtx_PLUS (HImode, reg,
909 GEN_INT (vh << 8))));
911 emit_move_insn (operands[0],
912 gen_rtx_MEM (GET_MODE (operands[1]),
913 gen_rtx_PLUS (Pmode, reg, offset)));
918 /* Use the normal gen_movhi pattern. */
923 m68hc11_emit_libcall (const char *name, enum rtx_code code,
924 enum machine_mode dmode, enum machine_mode smode,
925 int noperands, rtx *operands)
933 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
937 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
938 dmode, 1, operands[1], smode);
939 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
943 ret = emit_library_call_value (libcall, NULL_RTX,
945 operands[1], smode, operands[2],
947 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
954 insns = get_insns ();
956 emit_libcall_block (insns, operands[0], ret, equiv);
959 /* Returns true if X is a PRE/POST increment decrement
960 (same as auto_inc_p() in rtlanal.c but do not take into
961 account the stack). */
963 m68hc11_auto_inc_p (rtx x)
965 return GET_CODE (x) == PRE_DEC
966 || GET_CODE (x) == POST_INC
967 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
971 /* Predicates for machine description. */
974 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
976 return GET_CODE (operand) == MEM
977 && GET_CODE (XEXP (operand, 0)) == PLUS
978 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
979 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
980 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
981 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
985 tst_operand (rtx operand, enum machine_mode mode)
987 if (GET_CODE (operand) == MEM && reload_completed == 0)
989 rtx addr = XEXP (operand, 0);
990 if (m68hc11_auto_inc_p (addr))
993 return nonimmediate_operand (operand, mode);
997 cmp_operand (rtx operand, enum machine_mode mode)
999 if (GET_CODE (operand) == MEM)
1001 rtx addr = XEXP (operand, 0);
1002 if (m68hc11_auto_inc_p (addr))
1005 return general_operand (operand, mode);
1009 non_push_operand (rtx operand, enum machine_mode mode)
1011 if (general_operand (operand, mode) == 0)
1014 if (push_operand (operand, mode) == 1)
1020 splitable_operand (rtx operand, enum machine_mode mode)
1022 if (general_operand (operand, mode) == 0)
1025 if (push_operand (operand, mode) == 1)
1028 /* Reject a (MEM (MEM X)) because the patterns that use non_push_operand
1029 need to split such addresses to access the low and high part but it
1030 is not possible to express a valid address for the low part. */
1031 if (mode != QImode && GET_CODE (operand) == MEM
1032 && GET_CODE (XEXP (operand, 0)) == MEM)
1038 reg_or_some_mem_operand (rtx operand, enum machine_mode mode)
1040 if (GET_CODE (operand) == MEM)
1042 rtx op = XEXP (operand, 0);
1044 if (symbolic_memory_operand (op, mode))
1047 if (IS_STACK_PUSH (operand))
1050 if (m68hc11_register_indirect_p (operand, mode))
1056 return register_operand (operand, mode);
1060 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
1062 if (GET_CODE (operand) == MEM)
1064 rtx op = XEXP (operand, 0);
1066 if (symbolic_memory_operand (op, mode))
1073 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
1075 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
1077 rtx op = XEXP (operand, 0);
1080 if (m68hc11_page0_symbol_p (op))
1083 if (symbolic_memory_operand (op, mode))
1084 return TARGET_M6812;
1086 if (reload_in_progress)
1089 operand = XEXP (operand, 0);
1090 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1091 return register_indirect_p (operand, mode, addr_mode);
1097 stack_register_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1099 return SP_REG_P (operand);
1103 d_register_operand (rtx operand, enum machine_mode mode)
1105 if (GET_MODE (operand) != mode && mode != VOIDmode)
1108 if (GET_CODE (operand) == SUBREG)
1109 operand = XEXP (operand, 0);
1111 return GET_CODE (operand) == REG
1112 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1113 || REGNO (operand) == HARD_D_REGNUM
1114 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
1118 hard_addr_reg_operand (rtx operand, enum machine_mode mode)
1120 if (GET_MODE (operand) != mode && mode != VOIDmode)
1123 if (GET_CODE (operand) == SUBREG)
1124 operand = XEXP (operand, 0);
1126 return GET_CODE (operand) == REG
1127 && (REGNO (operand) == HARD_X_REGNUM
1128 || REGNO (operand) == HARD_Y_REGNUM
1129 || REGNO (operand) == HARD_Z_REGNUM);
1133 hard_reg_operand (rtx operand, enum machine_mode mode)
1135 if (GET_MODE (operand) != mode && mode != VOIDmode)
1138 if (GET_CODE (operand) == SUBREG)
1139 operand = XEXP (operand, 0);
1141 return GET_CODE (operand) == REG
1142 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1143 || H_REGNO_P (REGNO (operand)));
1147 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1149 if (GET_CODE (operand) != MEM)
1152 operand = XEXP (operand, 0);
1153 if (GET_CODE (operand) == PLUS)
1155 if (GET_CODE (XEXP (operand, 0)) == REG)
1156 operand = XEXP (operand, 0);
1157 else if (GET_CODE (XEXP (operand, 1)) == REG)
1158 operand = XEXP (operand, 1);
1160 return GET_CODE (operand) == REG
1161 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1162 || A_REGNO_P (REGNO (operand)));
1166 push_pop_operand_p (rtx operand)
1168 if (GET_CODE (operand) != MEM)
1172 operand = XEXP (operand, 0);
1173 return PUSH_POP_ADDRESS_P (operand);
1176 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1177 reference and a constant. */
1180 symbolic_memory_operand (rtx op, enum machine_mode mode)
1182 switch (GET_CODE (op))
1190 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1191 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1192 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1194 /* ??? This clause seems to be irrelevant. */
1196 return GET_MODE (op) == mode;
1199 return symbolic_memory_operand (XEXP (op, 0), mode)
1200 && symbolic_memory_operand (XEXP (op, 1), mode);
1208 m68hc11_eq_compare_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1210 return GET_CODE (op) == EQ || GET_CODE (op) == NE;
1214 m68hc11_logical_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1216 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1220 m68hc11_arith_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1222 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1223 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1224 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1225 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1226 || GET_CODE (op) == ROTATERT;
1230 m68hc11_non_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1232 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1233 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1236 /* Return true if op is a shift operator. */
1238 m68hc11_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1240 return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
1241 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
1242 || GET_CODE (op) == ASHIFTRT;
1246 m68hc11_unary_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1248 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1249 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1252 /* Emit the code to build the trampoline used to call a nested function.
1256 ldy #&CXT movw #&CXT,*_.d1
1257 sty *_.d1 jmp FNADDR
1262 m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1264 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1267 if (*static_chain_reg == '*')
1271 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1272 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1273 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1275 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1276 gen_rtx_CONST (QImode,
1277 gen_rtx_SYMBOL_REF (Pmode,
1278 static_chain_reg)));
1279 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1281 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1285 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1286 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1287 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1288 gen_rtx_CONST (HImode,
1289 gen_rtx_SYMBOL_REF (Pmode,
1290 static_chain_reg)));
1291 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1293 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1297 /* Declaration of types. */
1299 /* Handle an "tiny_data" attribute; arguments as in
1300 struct attribute_spec.handler. */
1302 m68hc11_handle_page0_attribute (tree *node, tree name,
1303 tree args ATTRIBUTE_UNUSED,
1304 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1308 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1310 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1314 warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
1315 *no_add_attrs = true;
1321 const struct attribute_spec m68hc11_attribute_table[] =
1323 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1324 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1325 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1326 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1327 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1328 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
1329 { NULL, 0, 0, false, false, false, NULL }
1332 /* Keep track of the symbol which has a `trap' attribute and which uses
1333 the `swi' calling convention. Since there is only one trap, we only
1334 record one such symbol. If there are several, a warning is reported. */
1335 static rtx trap_handler_symbol = 0;
1337 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1338 arguments as in struct attribute_spec.handler. */
1340 m68hc11_handle_fntype_attribute (tree *node, tree name,
1341 tree args ATTRIBUTE_UNUSED,
1342 int flags ATTRIBUTE_UNUSED,
1345 if (TREE_CODE (*node) != FUNCTION_TYPE
1346 && TREE_CODE (*node) != METHOD_TYPE
1347 && TREE_CODE (*node) != FIELD_DECL
1348 && TREE_CODE (*node) != TYPE_DECL)
1350 warning ("`%s' attribute only applies to functions",
1351 IDENTIFIER_POINTER (name));
1352 *no_add_attrs = true;
1357 /* Undo the effects of the above. */
1360 m68hc11_strip_name_encoding (const char *str)
1362 return str + (*str == '*' || *str == '@' || *str == '&');
1366 m68hc11_encode_label (tree decl)
1368 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1369 int len = strlen (str);
1370 char *newstr = alloca (len + 2);
1373 strcpy (&newstr[1], str);
1375 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1378 /* Return 1 if this is a symbol in page0 */
1380 m68hc11_page0_symbol_p (rtx x)
1382 switch (GET_CODE (x))
1385 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1388 return m68hc11_page0_symbol_p (XEXP (x, 0));
1391 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1394 return GET_CODE (XEXP (x, 1)) == CONST_INT
1395 && INTVAL (XEXP (x, 1)) < 256
1396 && INTVAL (XEXP (x, 1)) >= 0;
1403 /* We want to recognize trap handlers so that we handle calls to traps
1404 in a special manner (by issuing the trap). This information is stored
1405 in SYMBOL_REF_FLAG. */
1408 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1414 if (TREE_CODE (decl) == VAR_DECL)
1416 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1417 m68hc11_encode_label (decl);
1421 if (TREE_CODE (decl) != FUNCTION_DECL)
1424 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1427 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1429 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1430 is_far = TARGET_LONG_CALLS != 0;
1432 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1433 if (trap_handler && is_far)
1435 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1440 if (trap_handler_symbol != 0)
1441 warning ("`trap' attribute is already used");
1443 trap_handler_symbol = XEXP (rtl, 0);
1445 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1449 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1451 unsigned int flags = default_section_type_flags (decl, name, reloc);
1453 if (strncmp (name, ".eeprom", 7) == 0)
1455 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1462 m68hc11_is_far_symbol (rtx sym)
1464 if (GET_CODE (sym) == MEM)
1465 sym = XEXP (sym, 0);
1467 return SYMBOL_REF_FLAG (sym);
1471 m68hc11_is_trap_symbol (rtx sym)
1473 if (GET_CODE (sym) == MEM)
1474 sym = XEXP (sym, 0);
1476 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1480 /* Argument support functions. */
1482 /* Define the offset between two registers, one to be eliminated, and the
1483 other its replacement, at the start of a routine. */
1485 m68hc11_initial_elimination_offset (int from, int to)
1492 /* For a trap handler, we must take into account the registers which
1493 are pushed on the stack during the trap (except the PC). */
1494 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1495 current_function_interrupt = lookup_attribute ("interrupt",
1496 func_attr) != NULL_TREE;
1497 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1499 if (lookup_attribute ("far", func_attr) != 0)
1500 current_function_far = 1;
1501 else if (lookup_attribute ("near", func_attr) != 0)
1502 current_function_far = 0;
1504 current_function_far = (TARGET_LONG_CALLS != 0
1505 && !current_function_interrupt
1508 if (trap_handler && from == ARG_POINTER_REGNUM)
1511 /* For a function using 'call/rtc' we must take into account the
1512 page register which is pushed in the call. */
1513 else if (current_function_far && from == ARG_POINTER_REGNUM)
1518 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1520 /* 2 is for the saved frame.
1521 1 is for the 'sts' correction when creating the frame. */
1522 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1525 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1527 return m68hc11_sp_correction;
1530 /* Push any 2 byte pseudo hard registers that we need to save. */
1531 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1533 if (regs_ever_live[regno] && !call_used_regs[regno])
1539 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1541 return get_frame_size () + size;
1544 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1551 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1552 for a call to a function whose data type is FNTYPE.
1553 For a library call, FNTYPE is 0. */
1556 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1560 z_replacement_completed = 0;
1564 /* For a library call, we must find out the type of the return value.
1565 When the return value is bigger than 4 bytes, it is returned in
1566 memory. In that case, the first argument of the library call is a
1567 pointer to the memory location. Because the first argument is passed in
1568 register D, we have to identify this, so that the first function
1569 parameter is not passed in D either. */
1575 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1578 /* If the library ends in 'di' or in 'df', we assume it's
1579 returning some DImode or some DFmode which are 64-bit wide. */
1580 name = XSTR (libname, 0);
1581 len = strlen (name);
1583 && ((name[len - 2] == 'd'
1584 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1585 || (name[len - 3] == 'd'
1586 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1588 /* We are in. Mark the first parameter register as already used. */
1595 ret_type = TREE_TYPE (fntype);
1597 if (ret_type && aggregate_value_p (ret_type, fntype))
1604 /* Update the data in CUM to advance over an argument
1605 of mode MODE and data type TYPE.
1606 (TYPE is null for libcalls where that information may not be available.) */
1609 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1610 tree type, int named ATTRIBUTE_UNUSED)
1612 if (mode != BLKmode)
1614 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1617 cum->words = GET_MODE_SIZE (mode);
1621 cum->words += GET_MODE_SIZE (mode);
1622 if (cum->words <= HARD_REG_SIZE)
1628 cum->words += int_size_in_bytes (type);
1633 /* Define where to put the arguments to a function.
1634 Value is zero to push the argument on the stack,
1635 or a hard register in which to store the argument.
1637 MODE is the argument's machine mode.
1638 TYPE is the data type of the argument (as a tree).
1639 This is null for libcalls where that information may
1641 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1642 the preceding args and about the function being called.
1643 NAMED is nonzero if this argument is a named parameter
1644 (otherwise it is an extra parameter matching an ellipsis). */
1647 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1648 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1650 if (cum->words != 0)
1655 if (mode != BLKmode)
1657 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1658 return gen_rtx_REG (mode, HARD_X_REGNUM);
1660 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1664 return gen_rtx_REG (mode, HARD_D_REGNUM);
1669 /* If defined, a C expression which determines whether, and in which direction,
1670 to pad out an argument with extra space. The value should be of type
1671 `enum direction': either `upward' to pad above the argument,
1672 `downward' to pad below, or `none' to inhibit padding.
1674 Structures are stored left shifted in their argument slot. */
1676 m68hc11_function_arg_padding (enum machine_mode mode, tree type)
1678 if (type != 0 && AGGREGATE_TYPE_P (type))
1681 /* Fall back to the default. */
1682 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1686 /* Function prologue and epilogue. */
1688 /* Emit a move after the reload pass has completed. This is used to
1689 emit the prologue and epilogue. */
1691 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1695 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1697 insn = emit_move_insn (to, from);
1701 emit_move_insn (scratch, from);
1702 insn = emit_move_insn (to, scratch);
1705 /* Put a REG_INC note to tell the flow analysis that the instruction
1707 if (IS_STACK_PUSH (to))
1709 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1710 XEXP (XEXP (to, 0), 0),
1713 else if (IS_STACK_POP (from))
1715 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1716 XEXP (XEXP (from, 0), 0),
1720 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1721 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1722 The problem is that we are lying to gcc and use `txs' for x = sp
1723 (which is not really true because txs is really x = sp + 1). */
1724 else if (TARGET_M6811 && SP_REG_P (from))
1726 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1733 m68hc11_total_frame_size (void)
1738 size = get_frame_size ();
1739 if (current_function_interrupt)
1741 size += 3 * HARD_REG_SIZE;
1743 if (frame_pointer_needed)
1744 size += HARD_REG_SIZE;
1746 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1747 if (regs_ever_live[regno] && !call_used_regs[regno])
1748 size += HARD_REG_SIZE;
1754 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1755 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1757 /* We catch the function epilogue generation to have a chance
1758 to clear the z_replacement_completed flag. */
1759 z_replacement_completed = 0;
1763 expand_prologue (void)
1770 if (reload_completed != 1)
1773 size = get_frame_size ();
1777 /* Generate specific prologue for interrupt handlers. */
1778 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1779 current_function_interrupt = lookup_attribute ("interrupt",
1780 func_attr) != NULL_TREE;
1781 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1782 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1783 current_function_far = 1;
1784 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1785 current_function_far = 0;
1787 current_function_far = (TARGET_LONG_CALLS != 0
1788 && !current_function_interrupt
1789 && !current_function_trap);
1791 /* Get the scratch register to build the frame and push registers.
1792 If the first argument is a 32-bit quantity, the D+X registers
1793 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1794 For 68HC12, this scratch register is not used. */
1795 if (current_function_args_info.nregs == 2)
1800 /* Save current stack frame. */
1801 if (frame_pointer_needed)
1802 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1804 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1805 Other soft registers in page0 need not to be saved because they
1806 will be restored by C functions. For a trap handler, we don't
1807 need to preserve these registers because this is a synchronous call. */
1808 if (current_function_interrupt)
1810 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1811 emit_move_after_reload (stack_push_word,
1812 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1813 emit_move_after_reload (stack_push_word,
1814 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1818 /* Allocate local variables. */
1819 if (TARGET_M6812 && (size > 4 || size == 3))
1821 emit_insn (gen_addhi3 (stack_pointer_rtx,
1822 stack_pointer_rtx, GEN_INT (-size)));
1824 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1828 insn = gen_rtx_PARALLEL
1831 gen_rtx_SET (VOIDmode,
1833 gen_rtx_PLUS (HImode,
1836 gen_rtx_CLOBBER (VOIDmode, scratch)));
1843 /* Allocate by pushing scratch values. */
1844 for (i = 2; i <= size; i += 2)
1845 emit_move_after_reload (stack_push_word, ix_reg, 0);
1848 emit_insn (gen_addhi3 (stack_pointer_rtx,
1849 stack_pointer_rtx, constm1_rtx));
1852 /* Create the frame pointer. */
1853 if (frame_pointer_needed)
1854 emit_move_after_reload (hard_frame_pointer_rtx,
1855 stack_pointer_rtx, scratch);
1857 /* Push any 2 byte pseudo hard registers that we need to save. */
1858 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1860 if (regs_ever_live[regno] && !call_used_regs[regno])
1862 emit_move_after_reload (stack_push_word,
1863 gen_rtx_REG (HImode, regno), scratch);
1869 expand_epilogue (void)
1876 if (reload_completed != 1)
1879 size = get_frame_size ();
1881 /* If we are returning a value in two registers, we have to preserve the
1882 X register and use the Y register to restore the stack and the saved
1883 registers. Otherwise, use X because it's faster (and smaller). */
1884 if (current_function_return_rtx == 0)
1886 else if (GET_CODE (current_function_return_rtx) == MEM)
1887 return_size = HARD_REG_SIZE;
1889 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1891 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1896 /* Pop any 2 byte pseudo hard registers that we saved. */
1897 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1899 if (regs_ever_live[regno] && !call_used_regs[regno])
1901 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1902 stack_pop_word, scratch);
1906 /* de-allocate auto variables */
1907 if (TARGET_M6812 && (size > 4 || size == 3))
1909 emit_insn (gen_addhi3 (stack_pointer_rtx,
1910 stack_pointer_rtx, GEN_INT (size)));
1912 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1916 insn = gen_rtx_PARALLEL
1919 gen_rtx_SET (VOIDmode,
1921 gen_rtx_PLUS (HImode,
1924 gen_rtx_CLOBBER (VOIDmode, scratch)));
1931 for (i = 2; i <= size; i += 2)
1932 emit_move_after_reload (scratch, stack_pop_word, scratch);
1934 emit_insn (gen_addhi3 (stack_pointer_rtx,
1935 stack_pointer_rtx, const1_rtx));
1938 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1939 if (current_function_interrupt)
1941 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1942 stack_pop_word, scratch);
1943 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1944 stack_pop_word, scratch);
1945 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1948 /* Restore previous frame pointer. */
1949 if (frame_pointer_needed)
1950 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1952 /* If the trap handler returns some value, copy the value
1953 in D, X onto the stack so that the rti will pop the return value
1955 else if (current_function_trap && return_size != 0)
1957 rtx addr_reg = stack_pointer_rtx;
1961 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1964 emit_move_after_reload (gen_rtx_MEM (HImode,
1965 gen_rtx_PLUS (HImode, addr_reg,
1966 const1_rtx)), d_reg, 0);
1967 if (return_size > HARD_REG_SIZE)
1968 emit_move_after_reload (gen_rtx_MEM (HImode,
1969 gen_rtx_PLUS (HImode, addr_reg,
1970 GEN_INT (3))), ix_reg, 0);
1973 emit_jump_insn (gen_return ());
1977 /* Low and High part extraction for 68HC11. These routines are
1978 similar to gen_lowpart and gen_highpart but they have been
1979 fixed to work for constants and 68HC11 specific registers. */
1982 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1984 /* We assume that the low part of an auto-inc mode is the same with
1985 the mode changed and that the caller split the larger mode in the
1987 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1989 return gen_rtx_MEM (mode, XEXP (x, 0));
1992 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1993 floating-point constant. A CONST_DOUBLE is used whenever the
1994 constant requires more than one word in order to be adequately
1996 if (GET_CODE (x) == CONST_DOUBLE)
2000 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2004 if (GET_MODE (x) == SFmode)
2006 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
2007 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
2013 split_double (x, &first, &second);
2017 return GEN_INT (l[0]);
2019 return gen_int_mode (l[0], HImode);
2023 l[0] = CONST_DOUBLE_LOW (x);
2026 return GEN_INT (l[0]);
2027 else if (mode == HImode && GET_MODE (x) == SFmode)
2028 return gen_int_mode (l[0], HImode);
2033 if (mode == QImode && D_REG_P (x))
2034 return gen_rtx_REG (mode, HARD_B_REGNUM);
2036 /* gen_lowpart crashes when it is called with a SUBREG. */
2037 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
2040 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
2041 else if (mode == HImode)
2042 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
2046 x = gen_lowpart (mode, x);
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)
2057 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
2059 /* We assume that the high part of an auto-inc mode is the same with
2060 the mode changed and that the caller split the larger mode in the
2062 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
2064 return gen_rtx_MEM (mode, XEXP (x, 0));
2067 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
2068 floating-point constant. A CONST_DOUBLE is used whenever the
2069 constant requires more than one word in order to be adequately
2071 if (GET_CODE (x) == CONST_DOUBLE)
2075 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2079 if (GET_MODE (x) == SFmode)
2081 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
2082 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
2088 split_double (x, &first, &second);
2092 return GEN_INT (l[1]);
2094 return gen_int_mode ((l[1] >> 16), HImode);
2098 l[1] = CONST_DOUBLE_HIGH (x);
2102 return GEN_INT (l[1]);
2103 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2104 return gen_int_mode ((l[0] >> 16), HImode);
2108 if (GET_CODE (x) == CONST_INT)
2110 HOST_WIDE_INT val = INTVAL (x);
2114 return gen_int_mode (val >> 8, QImode);
2116 else if (mode == HImode)
2118 return gen_int_mode (val >> 16, HImode);
2121 if (mode == QImode && D_REG_P (x))
2122 return gen_rtx_REG (mode, HARD_A_REGNUM);
2124 /* There is no way in GCC to represent the upper part of a word register.
2125 To obtain the 8-bit upper part of a soft register, we change the
2126 reg into a mem rtx. This is possible because they are physically
2127 located in memory. There is no offset because we are big-endian. */
2128 if (mode == QImode && S_REG_P (x))
2132 /* Avoid the '*' for direct addressing mode when this
2133 addressing mode is disabled. */
2134 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
2135 return gen_rtx_MEM (QImode,
2136 gen_rtx_SYMBOL_REF (Pmode,
2137 ®_names[REGNO (x)][pos]));
2140 /* gen_highpart crashes when it is called with a SUBREG. */
2141 if (GET_CODE (x) == SUBREG)
2143 return gen_rtx_SUBREG (mode, XEXP (x, 0), XEXP (x, 1));
2145 if (GET_CODE (x) == REG)
2147 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
2148 return gen_rtx_REG (mode, REGNO (x));
2150 return gen_rtx_SUBREG (mode, x, 0);
2153 if (GET_CODE (x) == MEM)
2155 x = change_address (x, mode, 0);
2157 /* Return a different rtx to avoid to share it in several insns
2158 (when used by a split pattern). Sharing addresses within
2159 a MEM breaks the Z register replacement (and reloading). */
2160 if (GET_CODE (x) == MEM)
2168 /* Obscure register manipulation. */
2170 /* Finds backward in the instructions to see if register 'reg' is
2171 dead. This is used when generating code to see if we can use 'reg'
2172 as a scratch register. This allows us to choose a better generation
2173 of code when we know that some register dies or can be clobbered. */
2176 dead_register_here (rtx x, rtx reg)
2182 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2186 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2193 if (GET_CODE (body) == CALL_INSN)
2195 if (GET_CODE (body) == JUMP_INSN)
2198 if (GET_CODE (body) == SET)
2200 rtx dst = XEXP (body, 0);
2202 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2204 if (x_reg && rtx_equal_p (dst, x_reg))
2207 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2210 else if (reg_mentioned_p (reg, p)
2211 || (x_reg && reg_mentioned_p (x_reg, p)))
2215 /* Scan forward to see if the register is set in some insns and never
2217 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2221 if (GET_CODE (p) == CODE_LABEL
2222 || GET_CODE (p) == JUMP_INSN
2223 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2226 if (GET_CODE (p) != INSN)
2230 if (GET_CODE (body) == SET)
2232 rtx src = XEXP (body, 1);
2233 rtx dst = XEXP (body, 0);
2235 if (GET_CODE (dst) == REG
2236 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2240 /* Register is used (may be in source or in dest). */
2241 if (reg_mentioned_p (reg, p)
2242 || (x_reg != 0 && GET_MODE (p) == SImode
2243 && reg_mentioned_p (x_reg, p)))
2246 return p == 0 ? 1 : 0;
2250 /* Code generation operations called from machine description file. */
2252 /* Print the name of register 'regno' in the assembly file. */
2254 asm_print_register (FILE *file, int regno)
2256 const char *name = reg_names[regno];
2258 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2261 fprintf (file, "%s", name);
2264 /* A C compound statement to output to stdio stream STREAM the
2265 assembler syntax for an instruction operand X. X is an RTL
2268 CODE is a value that can be used to specify one of several ways
2269 of printing the operand. It is used when identical operands
2270 must be printed differently depending on the context. CODE
2271 comes from the `%' specification that was used to request
2272 printing of the operand. If the specification was just `%DIGIT'
2273 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2274 is the ASCII code for LTR.
2276 If X is a register, this macro should print the register's name.
2277 The names can be found in an array `reg_names' whose type is
2278 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2280 When the machine description has a specification `%PUNCT' (a `%'
2281 followed by a punctuation character), this macro is called with
2282 a null pointer for X and the punctuation character for CODE.
2284 The M68HC11 specific codes are:
2286 'b' for the low part of the operand.
2287 'h' for the high part of the operand
2288 The 'b' or 'h' modifiers have no effect if the operand has
2289 the QImode and is not a S_REG_P (soft register). If the
2290 operand is a hard register, these two modifiers have no effect.
2291 't' generate the temporary scratch register. The operand is
2293 'T' generate the low-part temporary scratch register. The operand is
2297 print_operand (FILE *file, rtx op, int letter)
2301 asm_print_register (file, SOFT_TMP_REGNUM);
2304 else if (letter == 'T')
2306 asm_print_register (file, SOFT_TMP_REGNUM);
2307 fprintf (file, "+1");
2310 else if (letter == '#')
2312 asm_fprintf (file, "%I");
2315 if (GET_CODE (op) == REG)
2317 if (letter == 'b' && S_REG_P (op))
2319 asm_print_register (file, REGNO (op));
2320 fprintf (file, "+1");
2322 else if (letter == 'b' && D_REG_P (op))
2324 asm_print_register (file, HARD_B_REGNUM);
2328 asm_print_register (file, REGNO (op));
2333 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2336 asm_fprintf (file, "%I%%lo(");
2338 asm_fprintf (file, "%I%%hi(");
2340 output_addr_const (file, op);
2341 fprintf (file, ")");
2345 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2346 are specified. If we already have a QImode, there is nothing to do. */
2347 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2351 op = m68hc11_gen_lowpart (QImode, op);
2353 else if (letter == 'h')
2355 op = m68hc11_gen_highpart (QImode, op);
2359 if (GET_CODE (op) == MEM)
2361 rtx base = XEXP (op, 0);
2362 switch (GET_CODE (base))
2367 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2368 asm_print_register (file, REGNO (XEXP (base, 0)));
2377 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2378 asm_print_register (file, REGNO (XEXP (base, 0)));
2379 fprintf (file, "-");
2388 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2389 asm_print_register (file, REGNO (XEXP (base, 0)));
2390 fprintf (file, "+");
2399 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2400 asm_print_register (file, REGNO (XEXP (base, 0)));
2409 fprintf (file, "[");
2410 print_operand_address (file, XEXP (base, 0));
2411 fprintf (file, "]");
2418 if (m68hc11_page0_symbol_p (base))
2419 fprintf (file, "*");
2421 output_address (base);
2425 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2430 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2431 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2432 asm_fprintf (file, "%I0x%lx", l);
2434 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2438 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2439 sizeof (dstr), 0, 1);
2440 asm_fprintf (file, "%I0r%s", dstr);
2444 int need_parenthesize = 0;
2447 asm_fprintf (file, "%I");
2449 need_parenthesize = must_parenthesize (op);
2451 if (need_parenthesize)
2452 fprintf (file, "(");
2454 output_addr_const (file, op);
2455 if (need_parenthesize)
2456 fprintf (file, ")");
2460 /* Returns true if the operand 'op' must be printed with parenthesis
2461 around it. This must be done only if there is a symbol whose name
2462 is a processor register. */
2464 must_parenthesize (rtx op)
2468 switch (GET_CODE (op))
2471 name = XSTR (op, 0);
2472 /* Avoid a conflict between symbol name and a possible
2474 return (strcasecmp (name, "a") == 0
2475 || strcasecmp (name, "b") == 0
2476 || strcasecmp (name, "d") == 0
2477 || strcasecmp (name, "x") == 0
2478 || strcasecmp (name, "y") == 0
2479 || strcasecmp (name, "ix") == 0
2480 || strcasecmp (name, "iy") == 0
2481 || strcasecmp (name, "pc") == 0
2482 || strcasecmp (name, "sp") == 0
2483 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2487 return must_parenthesize (XEXP (op, 0))
2488 || must_parenthesize (XEXP (op, 1));
2494 return must_parenthesize (XEXP (op, 0));
2505 /* A C compound statement to output to stdio stream STREAM the
2506 assembler syntax for an instruction operand that is a memory
2507 reference whose address is ADDR. ADDR is an RTL expression. */
2510 print_operand_address (FILE *file, rtx addr)
2514 int need_parenthesis = 0;
2516 switch (GET_CODE (addr))
2519 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2522 fprintf (file, "0,");
2523 asm_print_register (file, REGNO (addr));
2527 base = XEXP (addr, 0);
2528 switch (GET_CODE (base))
2533 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2534 asm_print_register (file, REGNO (XEXP (base, 0)));
2543 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2544 asm_print_register (file, REGNO (XEXP (base, 0)));
2545 fprintf (file, "-");
2554 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2555 asm_print_register (file, REGNO (XEXP (base, 0)));
2556 fprintf (file, "+");
2565 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2566 asm_print_register (file, REGNO (XEXP (base, 0)));
2573 need_parenthesis = must_parenthesize (base);
2574 if (need_parenthesis)
2575 fprintf (file, "(");
2577 output_addr_const (file, base);
2578 if (need_parenthesis)
2579 fprintf (file, ")");
2585 base = XEXP (addr, 0);
2586 offset = XEXP (addr, 1);
2587 if (!G_REG_P (base) && G_REG_P (offset))
2589 base = XEXP (addr, 1);
2590 offset = XEXP (addr, 0);
2592 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2594 need_parenthesis = must_parenthesize (addr);
2596 if (need_parenthesis)
2597 fprintf (file, "(");
2599 output_addr_const (file, base);
2600 fprintf (file, "+");
2601 output_addr_const (file, offset);
2602 if (need_parenthesis)
2603 fprintf (file, ")");
2605 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2611 asm_print_register (file, REGNO (offset));
2612 fprintf (file, ",");
2613 asm_print_register (file, REGNO (base));
2620 need_parenthesis = must_parenthesize (offset);
2621 if (need_parenthesis)
2622 fprintf (file, "(");
2624 output_addr_const (file, offset);
2625 if (need_parenthesis)
2626 fprintf (file, ")");
2627 fprintf (file, ",");
2628 asm_print_register (file, REGNO (base));
2638 if (GET_CODE (addr) == CONST_INT
2639 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2641 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2645 need_parenthesis = must_parenthesize (addr);
2646 if (need_parenthesis)
2647 fprintf (file, "(");
2649 output_addr_const (file, addr);
2650 if (need_parenthesis)
2651 fprintf (file, ")");
2658 /* Splitting of some instructions. */
2661 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2665 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2669 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2670 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2671 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2678 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2683 switch (GET_MODE (op0))
2687 tmp = m68hc11_expand_compare (code, op0, op1);
2688 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2689 gen_rtx_LABEL_REF (VOIDmode, label),
2691 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2695 /* SCz: from i386.c */
2698 /* Don't expand the comparison early, so that we get better code
2699 when jump or whoever decides to reverse the comparison. */
2704 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2705 &m68hc11_compare_op1);
2707 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2708 m68hc11_compare_op0, m68hc11_compare_op1);
2709 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2710 gen_rtx_LABEL_REF (VOIDmode, label),
2712 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2714 use_fcomi = ix86_use_fcomi_compare (code);
2715 vec = rtvec_alloc (3 + !use_fcomi);
2716 RTVEC_ELT (vec, 0) = tmp;
2718 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2720 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2723 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2725 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2731 /* Expand SImode branch into multiple compare+branch. */
2733 rtx lo[2], hi[2], label2;
2734 enum rtx_code code1, code2, code3;
2736 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2741 code = swap_condition (code);
2743 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2744 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2745 hi[0] = m68hc11_gen_highpart (HImode, op0);
2746 hi[1] = m68hc11_gen_highpart (HImode, op1);
2748 /* Otherwise, if we are doing less-than, op1 is a constant and the
2749 low word is zero, then we can just examine the high word. */
2751 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2752 && (code == LT || code == LTU))
2754 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2758 /* Otherwise, we need two or three jumps. */
2760 label2 = gen_label_rtx ();
2763 code2 = swap_condition (code);
2764 code3 = unsigned_condition (code);
2805 * if (hi(a) < hi(b)) goto true;
2806 * if (hi(a) > hi(b)) goto false;
2807 * if (lo(a) < lo(b)) goto true;
2810 if (code1 != UNKNOWN)
2811 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2812 if (code2 != UNKNOWN)
2813 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2815 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2817 if (code2 != UNKNOWN)
2818 emit_label (label2);
2828 /* Return the increment/decrement mode of a MEM if it is such.
2829 Return CONST if it is anything else. */
2831 autoinc_mode (rtx x)
2833 if (GET_CODE (x) != MEM)
2837 if (GET_CODE (x) == PRE_INC
2838 || GET_CODE (x) == PRE_DEC
2839 || GET_CODE (x) == POST_INC
2840 || GET_CODE (x) == POST_DEC)
2841 return GET_CODE (x);
2847 m68hc11_make_autoinc_notes (rtx *x, void *data)
2851 switch (GET_CODE (*x))
2858 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2867 /* Split a DI, SI or HI move into several smaller move operations.
2868 The scratch register 'scratch' is used as a temporary to load
2869 store intermediate values. It must be a hard register. */
2871 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2873 rtx low_to, low_from;
2874 rtx high_to, high_from;
2876 enum machine_mode mode;
2878 int autoinc_from = autoinc_mode (from);
2879 int autoinc_to = autoinc_mode (to);
2881 mode = GET_MODE (to);
2883 /* If the TO and FROM contain autoinc modes that are not compatible
2884 together (one pop and the other a push), we must change one to
2885 an offsetable operand and generate an appropriate add at the end. */
2886 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2891 /* The source uses an autoinc mode which is not compatible with
2892 a split (this would result in a word swap). */
2893 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2895 code = GET_CODE (XEXP (from, 0));
2896 reg = XEXP (XEXP (from, 0), 0);
2897 offset = GET_MODE_SIZE (GET_MODE (from));
2898 if (code == POST_DEC)
2901 if (code == PRE_INC)
2902 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2904 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2905 if (code == POST_DEC)
2906 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2910 /* Likewise for destination. */
2911 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2913 code = GET_CODE (XEXP (to, 0));
2914 reg = XEXP (XEXP (to, 0), 0);
2915 offset = GET_MODE_SIZE (GET_MODE (to));
2916 if (code == POST_DEC)
2919 if (code == PRE_INC)
2920 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2922 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2923 if (code == POST_DEC)
2924 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2928 /* The source and destination auto increment modes must be compatible
2929 with each other: same direction. */
2930 if ((autoinc_to != autoinc_from
2931 && autoinc_to != CONST && autoinc_from != CONST)
2932 /* The destination address register must not be used within
2933 the source operand because the source address would change
2934 while doing the copy. */
2935 || (autoinc_to != CONST
2936 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2937 && !IS_STACK_PUSH (to)))
2939 /* Must change the destination. */
2940 code = GET_CODE (XEXP (to, 0));
2941 reg = XEXP (XEXP (to, 0), 0);
2942 offset = GET_MODE_SIZE (GET_MODE (to));
2943 if (code == PRE_DEC || code == POST_DEC)
2946 if (code == PRE_DEC || code == PRE_INC)
2947 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2948 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2949 if (code == POST_DEC || code == POST_INC)
2950 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2955 /* Likewise, the source address register must not be used within
2956 the destination operand. */
2957 if (autoinc_from != CONST
2958 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2959 && !IS_STACK_PUSH (to))
2961 /* Must change the source. */
2962 code = GET_CODE (XEXP (from, 0));
2963 reg = XEXP (XEXP (from, 0), 0);
2964 offset = GET_MODE_SIZE (GET_MODE (from));
2965 if (code == PRE_DEC || code == POST_DEC)
2968 if (code == PRE_DEC || code == PRE_INC)
2969 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2970 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2971 if (code == POST_DEC || code == POST_INC)
2972 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2978 if (GET_MODE_SIZE (mode) == 8)
2980 else if (GET_MODE_SIZE (mode) == 4)
2986 && IS_STACK_PUSH (to)
2987 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2993 else if (mode == HImode)
3001 low_to = m68hc11_gen_lowpart (mode, to);
3002 high_to = m68hc11_gen_highpart (mode, to);
3004 low_from = m68hc11_gen_lowpart (mode, from);
3005 if (mode == SImode && GET_CODE (from) == CONST_INT)
3007 if (INTVAL (from) >= 0)
3008 high_from = const0_rtx;
3010 high_from = constm1_rtx;
3013 high_from = m68hc11_gen_highpart (mode, from);
3017 high_from = adjust_address (high_from, mode, offset);
3018 low_from = high_from;
3021 /* When copying with a POST_INC mode, we must copy the
3022 high part and then the low part to guarantee a correct
3025 && GET_MODE_SIZE (mode) >= 2
3026 && autoinc_from != autoinc_to
3027 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
3036 low_from = high_from;
3041 m68hc11_split_move (low_to, low_from, scratch);
3042 m68hc11_split_move (high_to, high_from, scratch);
3044 else if (H_REG_P (to) || H_REG_P (from)
3045 || (low_from == const0_rtx
3046 && high_from == const0_rtx
3047 && ! push_operand (to, GET_MODE (to))
3048 && ! H_REG_P (scratch))
3050 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
3051 || m68hc11_small_indexed_indirect_p (from,
3053 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
3054 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
3056 insn = emit_move_insn (low_to, low_from);
3057 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3059 insn = emit_move_insn (high_to, high_from);
3060 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3064 insn = emit_move_insn (scratch, low_from);
3065 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3066 insn = emit_move_insn (low_to, scratch);
3067 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3069 insn = emit_move_insn (scratch, high_from);
3070 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3071 insn = emit_move_insn (high_to, scratch);
3072 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3077 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
3083 if (GET_CODE (operand) != CONST_INT)
3091 val = INTVAL (operand);
3095 if ((val & mask) == 0)
3097 if ((val & mask) == mask)
3098 *result = constm1_rtx;
3102 if ((val & mask) == 0)
3103 *result = const0_rtx;
3104 if ((val & mask) == mask)
3109 if ((val & mask) == 0)
3117 m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
3122 need_copy = (rtx_equal_p (operands[0], operands[1])
3123 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
3125 operands[1] = simplify_logical (mode, code, operands[1], &result);
3126 operands[2] = simplify_logical (mode, code, operands[2], &result);
3128 if (result && GET_CODE (result) == CONST_INT)
3130 if (!H_REG_P (operands[0]) && operands[3]
3131 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
3133 emit_move_insn (operands[3], result);
3134 emit_move_insn (operands[0], operands[3]);
3138 emit_move_insn (operands[0], result);
3141 else if (operands[1] != 0 && operands[2] != 0)
3145 if (!H_REG_P (operands[0]) && operands[3])
3147 emit_move_insn (operands[3], operands[1]);
3148 emit_insn (gen_rtx_SET (mode,
3150 gen_rtx_fmt_ee (code, mode,
3151 operands[3], operands[2])));
3152 insn = emit_move_insn (operands[0], operands[3]);
3156 insn = emit_insn (gen_rtx_SET (mode,
3158 gen_rtx_fmt_ee (code, mode,
3164 /* The logical operation is similar to a copy. */
3169 if (GET_CODE (operands[1]) == CONST_INT)
3174 if (!H_REG_P (operands[0]) && !H_REG_P (src))
3176 emit_move_insn (operands[3], src);
3177 emit_move_insn (operands[0], operands[3]);
3181 emit_move_insn (operands[0], src);
3187 m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
3192 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3193 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3194 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3196 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3198 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3200 if (INTVAL (operands[1]) >= 0)
3201 high[1] = const0_rtx;
3203 high[1] = constm1_rtx;
3206 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3208 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3210 if (INTVAL (operands[2]) >= 0)
3211 high[2] = const0_rtx;
3213 high[2] = constm1_rtx;
3216 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3218 low[3] = operands[3];
3219 high[3] = operands[3];
3222 m68hc11_split_logical (HImode, code, low);
3223 m68hc11_split_logical (HImode, code, high);
3227 m68hc11_emit_logical (mode, code, low);
3228 m68hc11_emit_logical (mode, code, high);
3232 /* Code generation. */
3235 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3237 /* We have to be careful with the cc_status. An address register swap
3238 is generated for some comparison. The comparison is made with D
3239 but the branch really uses the address register. See the split
3240 pattern for compare. The xgdx/xgdy preserve the flags but after
3241 the exchange, the flags will reflect to the value of X and not D.
3242 Tell this by setting the cc_status according to the cc_prev_status. */
3243 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3245 if (cc_prev_status.value1 != 0
3246 && (D_REG_P (cc_prev_status.value1)
3247 || X_REG_P (cc_prev_status.value1)))
3249 cc_status = cc_prev_status;
3250 if (D_REG_P (cc_status.value1))
3251 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3254 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3260 output_asm_insn ("xgdx", operands);
3264 if (cc_prev_status.value1 != 0
3265 && (D_REG_P (cc_prev_status.value1)
3266 || Y_REG_P (cc_prev_status.value1)))
3268 cc_status = cc_prev_status;
3269 if (D_REG_P (cc_status.value1))
3270 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3273 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3279 output_asm_insn ("xgdy", operands);
3283 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3284 This is used to decide whether a move that set flags should be used
3287 next_insn_test_reg (rtx insn, rtx reg)
3291 insn = next_nonnote_insn (insn);
3292 if (GET_CODE (insn) != INSN)
3295 body = PATTERN (insn);
3296 if (sets_cc0_p (body) != 1)
3299 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3305 /* Generate the code to move a 16-bit operand into another one. */
3308 m68hc11_gen_movhi (rtx insn, rtx *operands)
3312 /* Move a register or memory to the same location.
3313 This is possible because such insn can appear
3314 in a non-optimizing mode. */
3315 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3317 cc_status = cc_prev_status;
3323 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3325 cc_status = cc_prev_status;
3326 switch (REGNO (operands[1]))
3331 output_asm_insn ("psh%1", operands);
3333 case HARD_SP_REGNUM:
3334 output_asm_insn ("sts\t2,-sp", operands);
3341 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3343 cc_status = cc_prev_status;
3344 switch (REGNO (operands[0]))
3349 output_asm_insn ("pul%0", operands);
3356 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3358 m68hc11_notice_keep_cc (operands[0]);
3359 output_asm_insn ("tfr\t%1,%0", operands);
3361 else if (H_REG_P (operands[0]))
3363 if (SP_REG_P (operands[0]))
3364 output_asm_insn ("lds\t%1", operands);
3366 output_asm_insn ("ld%0\t%1", operands);
3368 else if (H_REG_P (operands[1]))
3370 if (SP_REG_P (operands[1]))
3371 output_asm_insn ("sts\t%0", operands);
3373 output_asm_insn ("st%1\t%0", operands);
3377 rtx from = operands[1];
3378 rtx to = operands[0];
3380 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3381 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3382 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3383 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3389 ops[0] = operands[2];
3392 m68hc11_gen_movhi (insn, ops);
3394 ops[1] = operands[2];
3395 m68hc11_gen_movhi (insn, ops);
3399 /* !!!! SCz wrong here. */
3400 fatal_insn ("move insn not handled", insn);
3405 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3407 output_asm_insn ("clr\t%h0", operands);
3408 output_asm_insn ("clr\t%b0", operands);
3412 m68hc11_notice_keep_cc (operands[0]);
3413 output_asm_insn ("movw\t%1,%0", operands);
3420 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3422 cc_status = cc_prev_status;
3423 switch (REGNO (operands[0]))
3427 output_asm_insn ("pul%0", operands);
3430 output_asm_insn ("pula", operands);
3431 output_asm_insn ("pulb", operands);
3438 /* Some moves to a hard register are special. Not all of them
3439 are really supported and we have to use a temporary
3440 location to provide them (either the stack of a temp var). */
3441 if (H_REG_P (operands[0]))
3443 switch (REGNO (operands[0]))
3446 if (X_REG_P (operands[1]))
3448 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3450 m68hc11_output_swap (insn, operands);
3452 else if (next_insn_test_reg (insn, operands[0]))
3454 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3458 m68hc11_notice_keep_cc (operands[0]);
3459 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3462 else if (Y_REG_P (operands[1]))
3464 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3466 m68hc11_output_swap (insn, operands);
3470 /* %t means *ZTMP scratch register. */
3471 output_asm_insn ("sty\t%t1", operands);
3472 output_asm_insn ("ldd\t%t1", operands);
3475 else if (SP_REG_P (operands[1]))
3480 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3481 output_asm_insn ("xgdx", operands);
3482 output_asm_insn ("tsx", operands);
3483 output_asm_insn ("xgdx", operands);
3485 else if (IS_STACK_POP (operands[1]))
3487 output_asm_insn ("pula\n\tpulb", operands);
3489 else if (GET_CODE (operands[1]) == CONST_INT
3490 && INTVAL (operands[1]) == 0)
3492 output_asm_insn ("clra\n\tclrb", operands);
3496 output_asm_insn ("ldd\t%1", operands);
3501 if (D_REG_P (operands[1]))
3503 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3505 m68hc11_output_swap (insn, operands);
3507 else if (next_insn_test_reg (insn, operands[0]))
3509 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3513 m68hc11_notice_keep_cc (operands[0]);
3514 output_asm_insn ("pshb", operands);
3515 output_asm_insn ("psha", operands);
3516 output_asm_insn ("pulx", operands);
3519 else if (Y_REG_P (operands[1]))
3521 /* When both D and Y are dead, use the sequence xgdy, xgdx
3522 to move Y into X. The D and Y registers are modified. */
3523 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3524 && dead_register_here (insn, d_reg))
3526 output_asm_insn ("xgdy", operands);
3527 output_asm_insn ("xgdx", operands);
3530 else if (!optimize_size)
3532 output_asm_insn ("sty\t%t1", operands);
3533 output_asm_insn ("ldx\t%t1", operands);
3538 output_asm_insn ("pshy", operands);
3539 output_asm_insn ("pulx", operands);
3542 else if (SP_REG_P (operands[1]))
3544 /* tsx, tsy preserve the flags */
3545 cc_status = cc_prev_status;
3546 output_asm_insn ("tsx", operands);
3550 output_asm_insn ("ldx\t%1", operands);
3555 if (D_REG_P (operands[1]))
3557 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3559 m68hc11_output_swap (insn, operands);
3563 output_asm_insn ("std\t%t1", operands);
3564 output_asm_insn ("ldy\t%t1", operands);
3567 else if (X_REG_P (operands[1]))
3569 /* When both D and X are dead, use the sequence xgdx, xgdy
3570 to move X into Y. The D and X registers are modified. */
3571 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3572 && dead_register_here (insn, d_reg))
3574 output_asm_insn ("xgdx", operands);
3575 output_asm_insn ("xgdy", operands);
3578 else if (!optimize_size)
3580 output_asm_insn ("stx\t%t1", operands);
3581 output_asm_insn ("ldy\t%t1", operands);
3586 output_asm_insn ("pshx", operands);
3587 output_asm_insn ("puly", operands);
3590 else if (SP_REG_P (operands[1]))
3592 /* tsx, tsy preserve the flags */
3593 cc_status = cc_prev_status;
3594 output_asm_insn ("tsy", operands);
3598 output_asm_insn ("ldy\t%1", operands);
3602 case HARD_SP_REGNUM:
3603 if (D_REG_P (operands[1]))
3605 m68hc11_notice_keep_cc (operands[0]);
3606 output_asm_insn ("xgdx", operands);
3607 output_asm_insn ("txs", operands);
3608 output_asm_insn ("xgdx", operands);
3610 else if (X_REG_P (operands[1]))
3612 /* tys, txs preserve the flags */
3613 cc_status = cc_prev_status;
3614 output_asm_insn ("txs", operands);
3616 else if (Y_REG_P (operands[1]))
3618 /* tys, txs preserve the flags */
3619 cc_status = cc_prev_status;
3620 output_asm_insn ("tys", operands);
3624 /* lds sets the flags but the des does not. */
3626 output_asm_insn ("lds\t%1", operands);
3627 output_asm_insn ("des", operands);
3632 fatal_insn ("invalid register in the move instruction", insn);
3637 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3638 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3640 output_asm_insn ("sts\t%0", operands);
3644 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3646 cc_status = cc_prev_status;
3647 switch (REGNO (operands[1]))
3651 output_asm_insn ("psh%1", operands);
3654 output_asm_insn ("pshb", operands);
3655 output_asm_insn ("psha", operands);
3663 /* Operand 1 must be a hard register. */
3664 if (!H_REG_P (operands[1]))
3666 fatal_insn ("invalid operand in the instruction", insn);
3669 reg = REGNO (operands[1]);
3673 output_asm_insn ("std\t%0", operands);
3677 output_asm_insn ("stx\t%0", operands);
3681 output_asm_insn ("sty\t%0", operands);
3684 case HARD_SP_REGNUM:
3688 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3690 output_asm_insn ("pshx", operands);
3691 output_asm_insn ("tsx", operands);
3692 output_asm_insn ("inx", operands);
3693 output_asm_insn ("inx", operands);
3694 output_asm_insn ("stx\t%0", operands);
3695 output_asm_insn ("pulx", operands);
3698 else if (reg_mentioned_p (ix_reg, operands[0]))
3700 output_asm_insn ("sty\t%t0", operands);
3701 output_asm_insn ("tsy", operands);
3702 output_asm_insn ("sty\t%0", operands);
3703 output_asm_insn ("ldy\t%t0", operands);
3707 output_asm_insn ("stx\t%t0", operands);
3708 output_asm_insn ("tsx", operands);
3709 output_asm_insn ("stx\t%0", operands);
3710 output_asm_insn ("ldx\t%t0", operands);
3716 fatal_insn ("invalid register in the move instruction", insn);
3722 m68hc11_gen_movqi (rtx insn, rtx *operands)
3724 /* Move a register or memory to the same location.
3725 This is possible because such insn can appear
3726 in a non-optimizing mode. */
3727 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3729 cc_status = cc_prev_status;
3736 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3738 m68hc11_notice_keep_cc (operands[0]);
3739 output_asm_insn ("tfr\t%1,%0", operands);
3741 else if (H_REG_P (operands[0]))
3743 if (Q_REG_P (operands[0]))
3744 output_asm_insn ("lda%0\t%b1", operands);
3745 else if (D_REG_P (operands[0]))
3746 output_asm_insn ("ldab\t%b1", operands);
3750 else if (H_REG_P (operands[1]))
3752 if (Q_REG_P (operands[1]))
3753 output_asm_insn ("sta%1\t%b0", operands);
3754 else if (D_REG_P (operands[1]))
3755 output_asm_insn ("stab\t%b0", operands);
3761 rtx from = operands[1];
3762 rtx to = operands[0];
3764 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3765 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3766 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3767 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3773 ops[0] = operands[2];
3776 m68hc11_gen_movqi (insn, ops);
3778 ops[1] = operands[2];
3779 m68hc11_gen_movqi (insn, ops);
3783 /* !!!! SCz wrong here. */
3784 fatal_insn ("move insn not handled", insn);
3789 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3791 output_asm_insn ("clr\t%b0", operands);
3795 m68hc11_notice_keep_cc (operands[0]);
3796 output_asm_insn ("movb\t%b1,%b0", operands);
3804 if (H_REG_P (operands[0]))
3806 switch (REGNO (operands[0]))
3810 if (X_REG_P (operands[1]))
3812 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3814 m68hc11_output_swap (insn, operands);
3818 output_asm_insn ("stx\t%t1", operands);
3819 output_asm_insn ("ldab\t%T0", operands);
3822 else if (Y_REG_P (operands[1]))
3824 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3826 m68hc11_output_swap (insn, operands);
3830 output_asm_insn ("sty\t%t1", operands);
3831 output_asm_insn ("ldab\t%T0", operands);
3834 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3835 && !DA_REG_P (operands[1]))
3837 output_asm_insn ("ldab\t%b1", operands);
3839 else if (DA_REG_P (operands[1]))
3841 output_asm_insn ("tab", operands);
3845 cc_status = cc_prev_status;
3851 if (X_REG_P (operands[1]))
3853 output_asm_insn ("stx\t%t1", operands);
3854 output_asm_insn ("ldaa\t%T0", operands);
3856 else if (Y_REG_P (operands[1]))
3858 output_asm_insn ("sty\t%t1", operands);
3859 output_asm_insn ("ldaa\t%T0", operands);
3861 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3862 && !DA_REG_P (operands[1]))
3864 output_asm_insn ("ldaa\t%b1", operands);
3866 else if (!DA_REG_P (operands[1]))
3868 output_asm_insn ("tba", operands);
3872 cc_status = cc_prev_status;
3877 if (D_REG_P (operands[1]))
3879 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3881 m68hc11_output_swap (insn, operands);
3885 output_asm_insn ("stab\t%T1", operands);
3886 output_asm_insn ("ldx\t%t1", operands);
3890 else if (Y_REG_P (operands[1]))
3892 output_asm_insn ("sty\t%t0", operands);
3893 output_asm_insn ("ldx\t%t0", operands);
3895 else if (GET_CODE (operands[1]) == CONST_INT)
3897 output_asm_insn ("ldx\t%1", operands);
3899 else if (dead_register_here (insn, d_reg))
3901 output_asm_insn ("ldab\t%b1", operands);
3902 output_asm_insn ("xgdx", operands);
3904 else if (!reg_mentioned_p (operands[0], operands[1]))
3906 output_asm_insn ("xgdx", operands);
3907 output_asm_insn ("ldab\t%b1", operands);
3908 output_asm_insn ("xgdx", operands);
3912 output_asm_insn ("pshb", operands);
3913 output_asm_insn ("ldab\t%b1", operands);
3914 output_asm_insn ("stab\t%T1", operands);
3915 output_asm_insn ("ldx\t%t1", operands);
3916 output_asm_insn ("pulb", operands);
3922 if (D_REG_P (operands[1]))
3924 output_asm_insn ("stab\t%T1", operands);
3925 output_asm_insn ("ldy\t%t1", operands);
3928 else if (X_REG_P (operands[1]))
3930 output_asm_insn ("stx\t%t1", operands);
3931 output_asm_insn ("ldy\t%t1", operands);
3934 else if (GET_CODE (operands[1]) == CONST_INT)
3936 output_asm_insn ("ldy\t%1", operands);
3938 else if (dead_register_here (insn, d_reg))
3940 output_asm_insn ("ldab\t%b1", operands);
3941 output_asm_insn ("xgdy", operands);
3943 else if (!reg_mentioned_p (operands[0], operands[1]))
3945 output_asm_insn ("xgdy", operands);
3946 output_asm_insn ("ldab\t%b1", operands);
3947 output_asm_insn ("xgdy", operands);
3951 output_asm_insn ("pshb", operands);
3952 output_asm_insn ("ldab\t%b1", operands);
3953 output_asm_insn ("stab\t%T1", operands);
3954 output_asm_insn ("ldy\t%t1", operands);
3955 output_asm_insn ("pulb", operands);
3961 fatal_insn ("invalid register in the instruction", insn);
3965 else if (H_REG_P (operands[1]))
3967 switch (REGNO (operands[1]))
3971 output_asm_insn ("stab\t%b0", operands);
3975 output_asm_insn ("staa\t%b0", operands);
3979 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3983 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3987 fatal_insn ("invalid register in the move instruction", insn);
3994 fatal_insn ("operand 1 must be a hard register", insn);
3998 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3999 The source and destination must be D or A and the shift must
4002 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
4006 if (GET_CODE (operands[2]) != CONST_INT
4007 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
4008 fatal_insn ("invalid rotate insn", insn);
4010 val = INTVAL (operands[2]);
4011 if (code == ROTATERT)
4012 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
4014 if (GET_MODE (operands[0]) != QImode)
4017 /* Rotate by 8-bits if the shift is within [5..11]. */
4018 if (val >= 5 && val <= 11)
4021 output_asm_insn ("exg\ta,b", operands);
4024 output_asm_insn ("psha", operands);
4025 output_asm_insn ("tba", operands);
4026 output_asm_insn ("pulb", operands);
4031 /* If the shift is big, invert the rotation. */
4041 /* Set the carry to bit-15, but don't change D yet. */
4042 if (GET_MODE (operands[0]) != QImode)
4044 output_asm_insn ("asra", operands);
4045 output_asm_insn ("rola", operands);
4048 /* Rotate B first to move the carry to bit-0. */
4049 if (D_REG_P (operands[0]))
4050 output_asm_insn ("rolb", operands);
4052 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
4053 output_asm_insn ("rola", operands);
4060 /* Set the carry to bit-8 of D. */
4061 if (GET_MODE (operands[0]) != QImode)
4062 output_asm_insn ("tap", operands);
4064 /* Rotate B first to move the carry to bit-7. */
4065 if (D_REG_P (operands[0]))
4066 output_asm_insn ("rorb", operands);
4068 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
4069 output_asm_insn ("rora", operands);
4076 /* Store in cc_status the expressions that the condition codes will
4077 describe after execution of an instruction whose pattern is EXP.
4078 Do not alter them if the instruction would not alter the cc's. */
4081 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
4083 /* recognize SET insn's. */
4084 if (GET_CODE (exp) == SET)
4086 /* Jumps do not alter the cc's. */
4087 if (SET_DEST (exp) == pc_rtx)
4090 /* NOTE: most instructions don't affect the carry bit, but the
4091 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
4092 the conditions.h header. */
4094 /* Function calls clobber the cc's. */
4095 else if (GET_CODE (SET_SRC (exp)) == CALL)
4100 /* Tests and compares set the cc's in predictable ways. */
4101 else if (SET_DEST (exp) == cc0_rtx)
4103 cc_status.flags = 0;
4104 cc_status.value1 = XEXP (exp, 0);
4105 cc_status.value2 = XEXP (exp, 1);
4109 /* All other instructions affect the condition codes. */
4110 cc_status.flags = 0;
4111 cc_status.value1 = XEXP (exp, 0);
4112 cc_status.value2 = XEXP (exp, 1);
4117 /* Default action if we haven't recognized something
4118 and returned earlier. */
4122 if (cc_status.value2 != 0)
4123 switch (GET_CODE (cc_status.value2))
4125 /* These logical operations can generate several insns.
4126 The flags are setup according to what is generated. */
4132 /* The (not ...) generates several 'com' instructions for
4133 non QImode. We have to invalidate the flags. */
4135 if (GET_MODE (cc_status.value2) != QImode)
4147 if (GET_MODE (cc_status.value2) != VOIDmode)
4148 cc_status.flags |= CC_NO_OVERFLOW;
4151 /* The asl sets the overflow bit in such a way that this
4152 makes the flags unusable for a next compare insn. */
4156 if (GET_MODE (cc_status.value2) != VOIDmode)
4157 cc_status.flags |= CC_NO_OVERFLOW;
4160 /* A load/store instruction does not affect the carry. */
4165 cc_status.flags |= CC_NO_OVERFLOW;
4171 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
4173 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
4174 cc_status.value2 = 0;
4176 else if (cc_status.value1 && side_effects_p (cc_status.value1))
4177 cc_status.value1 = 0;
4179 else if (cc_status.value2 && side_effects_p (cc_status.value2))
4180 cc_status.value2 = 0;
4183 /* The current instruction does not affect the flags but changes
4184 the register 'reg'. See if the previous flags can be kept for the
4185 next instruction to avoid a comparison. */
4187 m68hc11_notice_keep_cc (rtx reg)
4190 || cc_prev_status.value1 == 0
4191 || rtx_equal_p (reg, cc_prev_status.value1)
4192 || (cc_prev_status.value2
4193 && reg_mentioned_p (reg, cc_prev_status.value2)))
4196 cc_status = cc_prev_status;
4201 /* Machine Specific Reorg. */
4203 /* Z register replacement:
4205 GCC treats the Z register as an index base address register like
4206 X or Y. In general, it uses it during reload to compute the address
4207 of some operand. This helps the reload pass to avoid to fall into the
4208 register spill failure.
4210 The Z register is in the A_REGS class. In the machine description,
4211 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4213 It can appear everywhere an X or Y register can appear, except for
4214 some templates in the clobber section (when a clobber of X or Y is asked).
4215 For a given instruction, the template must ensure that no more than
4216 2 'A' registers are used. Otherwise, the register replacement is not
4219 To replace the Z register, the algorithm is not terrific:
4220 1. Insns that do not use the Z register are not changed
4221 2. When a Z register is used, we scan forward the insns to see
4222 a potential register to use: either X or Y and sometimes D.
4223 We stop when a call, a label or a branch is seen, or when we
4224 detect that both X and Y are used (probably at different times, but it does
4226 3. The register that will be used for the replacement of Z is saved
4227 in a .page0 register or on the stack. If the first instruction that
4228 used Z, uses Z as an input, the value is loaded from another .page0
4229 register. The replacement register is pushed on the stack in the
4230 rare cases where a compare insn uses Z and we couldn't find if X/Y
4232 4. The Z register is replaced in all instructions until we reach
4233 the end of the Z-block, as detected by step 2.
4234 5. If we detect that Z is still alive, its value is saved.
4235 If the replacement register is alive, its old value is loaded.
4237 The Z register can be disabled with -ffixed-z.
4247 int must_restore_reg;
4258 int save_before_last;
4259 int z_loaded_with_sp;
4262 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4263 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4264 static void m68hc11_z_replacement (rtx);
4265 static void m68hc11_reassign_regs (rtx);
4267 int z_replacement_completed = 0;
4269 /* Analyze the insn to find out which replacement register to use and
4270 the boundaries of the replacement.
4271 Returns 0 if we reached the last insn to be replaced, 1 if we can
4272 continue replacement in next insns. */
4275 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4277 int this_insn_uses_ix;
4278 int this_insn_uses_iy;
4279 int this_insn_uses_z;
4280 int this_insn_uses_z_in_dst;
4281 int this_insn_uses_d;
4285 /* A call is said to clobber the Z register, we don't need
4286 to save the value of Z. We also don't need to restore
4287 the replacement register (unless it is used by the call). */
4288 if (GET_CODE (insn) == CALL_INSN)
4290 body = PATTERN (insn);
4292 info->can_use_d = 0;
4294 /* If the call is an indirect call with Z, we have to use the
4295 Y register because X can be used as an input (D+X).
4296 We also must not save Z nor restore Y. */
4297 if (reg_mentioned_p (z_reg, body))
4299 insn = NEXT_INSN (insn);
4302 info->found_call = 1;
4303 info->must_restore_reg = 0;
4304 info->last = NEXT_INSN (insn);
4306 info->need_save_z = 0;
4309 if (GET_CODE (insn) == CODE_LABEL
4310 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4313 if (GET_CODE (insn) == JUMP_INSN)
4315 if (reg_mentioned_p (z_reg, insn) == 0)
4318 info->can_use_d = 0;
4319 info->must_save_reg = 0;
4320 info->must_restore_reg = 0;
4321 info->need_save_z = 0;
4322 info->last = NEXT_INSN (insn);
4325 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4330 /* Z register dies here. */
4331 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4333 body = PATTERN (insn);
4334 if (GET_CODE (body) == SET)
4336 rtx src = XEXP (body, 1);
4337 rtx dst = XEXP (body, 0);
4339 /* Condition code is set here. We have to restore the X/Y and
4340 save into Z before any test/compare insn because once we save/restore
4341 we can change the condition codes. When the compare insn uses Z and
4342 we can't use X/Y, the comparison is made with the *ZREG soft register
4343 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4346 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4347 || (GET_CODE (src) == COMPARE &&
4348 ((rtx_equal_p (XEXP (src, 0), z_reg)
4349 && H_REG_P (XEXP (src, 1)))
4350 || (rtx_equal_p (XEXP (src, 1), z_reg)
4351 && H_REG_P (XEXP (src, 0))))))
4353 if (insn == info->first)
4355 info->must_load_z = 0;
4356 info->must_save_reg = 0;
4357 info->must_restore_reg = 0;
4358 info->need_save_z = 0;
4359 info->found_call = 1;
4360 info->regno = SOFT_Z_REGNUM;
4361 info->last = NEXT_INSN (insn);
4365 if (reg_mentioned_p (z_reg, src) == 0)
4367 info->can_use_d = 0;
4371 if (insn != info->first)
4374 /* Compare insn which uses Z. We have to save/restore the X/Y
4375 register without modifying the condition codes. For this
4376 we have to use a push/pop insn. */
4377 info->must_push_reg = 1;
4381 /* Z reg is set to something new. We don't need to load it. */
4384 if (!reg_mentioned_p (z_reg, src))
4386 /* Z reg is used before being set. Treat this as
4387 a new sequence of Z register replacement. */
4388 if (insn != info->first)
4392 info->must_load_z = 0;
4394 info->z_set_count++;
4395 info->z_value = src;
4397 info->z_loaded_with_sp = 1;
4399 else if (reg_mentioned_p (z_reg, dst))
4400 info->can_use_d = 0;
4402 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4403 | reg_mentioned_p (d_reg, dst);
4404 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4405 | reg_mentioned_p (ix_reg, dst);
4406 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4407 | reg_mentioned_p (iy_reg, dst);
4408 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4410 /* If z is used as an address operand (like (MEM (reg z))),
4411 we can't replace it with d. */
4412 if (this_insn_uses_z && !Z_REG_P (src)
4413 && !(m68hc11_arith_operator (src, GET_MODE (src))
4414 && Z_REG_P (XEXP (src, 0))
4415 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4416 && insn == info->first
4417 && dead_register_here (insn, d_reg)))
4418 info->can_use_d = 0;
4420 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4421 if (TARGET_M6812 && !z_dies_here
4422 && ((this_insn_uses_z && side_effects_p (src))
4423 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4425 info->need_save_z = 1;
4426 info->z_set_count++;
4428 this_insn_uses_z |= this_insn_uses_z_in_dst;
4430 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4432 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4435 if (this_insn_uses_d)
4436 info->can_use_d = 0;
4438 /* IX and IY are used at the same time, we have to restore
4439 the value of the scratch register before this insn. */
4440 if (this_insn_uses_ix && this_insn_uses_iy)
4445 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4446 info->can_use_d = 0;
4448 if (info->x_used == 0 && this_insn_uses_ix)
4452 /* We have a (set (REG:HI X) (REG:HI Z)).
4453 Since we use Z as the replacement register, this insn
4454 is no longer necessary. We turn it into a note. We must
4455 not reload the old value of X. */
4456 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4460 info->need_save_z = 0;
4463 info->must_save_reg = 0;
4464 info->must_restore_reg = 0;
4465 info->found_call = 1;
4466 info->can_use_d = 0;
4467 PUT_CODE (insn, NOTE);
4468 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4469 NOTE_SOURCE_FILE (insn) = 0;
4470 info->last = NEXT_INSN (insn);
4475 && (rtx_equal_p (src, z_reg)
4476 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4480 info->need_save_z = 0;
4483 info->last = NEXT_INSN (insn);
4484 info->must_save_reg = 0;
4485 info->must_restore_reg = 0;
4487 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4488 && !reg_mentioned_p (ix_reg, src))
4493 info->need_save_z = 0;
4495 else if (TARGET_M6812 && side_effects_p (src))
4498 info->must_restore_reg = 0;
4503 info->save_before_last = 1;
4505 info->must_restore_reg = 0;
4506 info->last = NEXT_INSN (insn);
4508 else if (info->can_use_d)
4510 info->last = NEXT_INSN (insn);
4516 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4517 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4519 info->need_save_z = 0;
4521 info->last = NEXT_INSN (insn);
4522 info->regno = HARD_X_REGNUM;
4523 info->must_save_reg = 0;
4524 info->must_restore_reg = 0;
4527 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4529 info->regno = HARD_X_REGNUM;
4530 info->must_restore_reg = 0;
4531 info->must_save_reg = 0;
4535 if (info->y_used == 0 && this_insn_uses_iy)
4539 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4543 info->need_save_z = 0;
4546 info->must_save_reg = 0;
4547 info->must_restore_reg = 0;
4548 info->found_call = 1;
4549 info->can_use_d = 0;
4550 PUT_CODE (insn, NOTE);
4551 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4552 NOTE_SOURCE_FILE (insn) = 0;
4553 info->last = NEXT_INSN (insn);
4558 && (rtx_equal_p (src, z_reg)
4559 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4564 info->need_save_z = 0;
4566 info->last = NEXT_INSN (insn);
4567 info->must_save_reg = 0;
4568 info->must_restore_reg = 0;
4570 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4571 && !reg_mentioned_p (iy_reg, src))
4576 info->need_save_z = 0;
4578 else if (TARGET_M6812 && side_effects_p (src))
4581 info->must_restore_reg = 0;
4586 info->save_before_last = 1;
4588 info->must_restore_reg = 0;
4589 info->last = NEXT_INSN (insn);
4591 else if (info->can_use_d)
4593 info->last = NEXT_INSN (insn);
4600 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4601 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4603 info->need_save_z = 0;
4605 info->last = NEXT_INSN (insn);
4606 info->regno = HARD_Y_REGNUM;
4607 info->must_save_reg = 0;
4608 info->must_restore_reg = 0;
4611 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4613 info->regno = HARD_Y_REGNUM;
4614 info->must_restore_reg = 0;
4615 info->must_save_reg = 0;
4621 info->need_save_z = 0;
4623 if (info->last == 0)
4624 info->last = NEXT_INSN (insn);
4627 return info->last != NULL_RTX ? 0 : 1;
4629 if (GET_CODE (body) == PARALLEL)
4632 char ix_clobber = 0;
4633 char iy_clobber = 0;
4635 this_insn_uses_iy = 0;
4636 this_insn_uses_ix = 0;
4637 this_insn_uses_z = 0;
4639 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4642 int uses_ix, uses_iy, uses_z;
4644 x = XVECEXP (body, 0, i);
4646 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4647 info->can_use_d = 0;
4649 uses_ix = reg_mentioned_p (ix_reg, x);
4650 uses_iy = reg_mentioned_p (iy_reg, x);
4651 uses_z = reg_mentioned_p (z_reg, x);
4652 if (GET_CODE (x) == CLOBBER)
4654 ix_clobber |= uses_ix;
4655 iy_clobber |= uses_iy;
4656 z_clobber |= uses_z;
4660 this_insn_uses_ix |= uses_ix;
4661 this_insn_uses_iy |= uses_iy;
4662 this_insn_uses_z |= uses_z;
4664 if (uses_z && GET_CODE (x) == SET)
4666 rtx dst = XEXP (x, 0);
4669 info->z_set_count++;
4671 if (TARGET_M6812 && uses_z && side_effects_p (x))
4672 info->need_save_z = 1;
4675 info->need_save_z = 0;
4679 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4680 this_insn_uses_ix, this_insn_uses_iy,
4681 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4684 if (this_insn_uses_z)
4685 info->can_use_d = 0;
4687 if (z_clobber && info->first != insn)
4689 info->need_save_z = 0;
4693 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4695 if (this_insn_uses_z == 0 && insn == info->first)
4697 info->must_load_z = 0;
4699 if (dead_register_here (insn, d_reg))
4701 info->regno = HARD_D_REGNUM;
4702 info->must_save_reg = 0;
4703 info->must_restore_reg = 0;
4705 else if (dead_register_here (insn, ix_reg))
4707 info->regno = HARD_X_REGNUM;
4708 info->must_save_reg = 0;
4709 info->must_restore_reg = 0;
4711 else if (dead_register_here (insn, iy_reg))
4713 info->regno = HARD_Y_REGNUM;
4714 info->must_save_reg = 0;
4715 info->must_restore_reg = 0;
4717 if (info->regno >= 0)
4719 info->last = NEXT_INSN (insn);
4722 if (this_insn_uses_ix == 0)
4724 info->regno = HARD_X_REGNUM;
4725 info->must_save_reg = 1;
4726 info->must_restore_reg = 1;
4728 else if (this_insn_uses_iy == 0)
4730 info->regno = HARD_Y_REGNUM;
4731 info->must_save_reg = 1;
4732 info->must_restore_reg = 1;
4736 info->regno = HARD_D_REGNUM;
4737 info->must_save_reg = 1;
4738 info->must_restore_reg = 1;
4740 info->last = NEXT_INSN (insn);
4744 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4745 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4747 if (this_insn_uses_z)
4749 if (info->y_used == 0 && iy_clobber)
4751 info->regno = HARD_Y_REGNUM;
4752 info->must_save_reg = 0;
4753 info->must_restore_reg = 0;
4755 if (info->first != insn
4756 && ((info->y_used && ix_clobber)
4757 || (info->x_used && iy_clobber)))
4760 info->last = NEXT_INSN (insn);
4761 info->save_before_last = 1;
4765 if (this_insn_uses_ix && this_insn_uses_iy)
4767 if (this_insn_uses_z)
4769 fatal_insn ("cannot do z-register replacement", insn);
4773 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4780 if (iy_clobber || z_clobber)
4782 info->last = NEXT_INSN (insn);
4783 info->save_before_last = 1;
4788 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4795 if (ix_clobber || z_clobber)
4797 info->last = NEXT_INSN (insn);
4798 info->save_before_last = 1;
4805 info->need_save_z = 0;
4809 if (GET_CODE (body) == CLOBBER)
4812 /* IX and IY are used at the same time, we have to restore
4813 the value of the scratch register before this insn. */
4814 if (this_insn_uses_ix && this_insn_uses_iy)
4818 if (info->x_used == 0 && this_insn_uses_ix)
4826 if (info->y_used == 0 && this_insn_uses_iy)
4840 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4844 info->replace_reg = NULL_RTX;
4845 info->must_load_z = 1;
4846 info->need_save_z = 1;
4847 info->must_save_reg = 1;
4848 info->must_restore_reg = 1;
4852 info->can_use_d = TARGET_M6811 ? 1 : 0;
4853 info->found_call = 0;
4857 info->z_set_count = 0;
4858 info->z_value = NULL_RTX;
4859 info->must_push_reg = 0;
4860 info->save_before_last = 0;
4861 info->z_loaded_with_sp = 0;
4863 /* Scan the insn forward to find an address register that is not used.
4865 - the flow of the program changes,
4866 - when we detect that both X and Y are necessary,
4867 - when the Z register dies,
4868 - when the condition codes are set. */
4870 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4872 if (m68hc11_check_z_replacement (insn, info) == 0)
4876 /* May be we can use Y or X if they contain the same value as Z.
4877 This happens very often after the reload. */
4878 if (info->z_set_count == 1)
4880 rtx p = info->first;
4885 v = find_last_value (iy_reg, &p, insn, 1);
4887 else if (info->y_used)
4889 v = find_last_value (ix_reg, &p, insn, 1);
4891 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4894 info->regno = HARD_Y_REGNUM;
4896 info->regno = HARD_X_REGNUM;
4897 info->must_load_z = 0;
4898 info->must_save_reg = 0;
4899 info->must_restore_reg = 0;
4900 info->found_call = 1;
4903 if (info->z_set_count == 0)
4904 info->need_save_z = 0;
4907 info->need_save_z = 0;
4909 if (info->last == 0)
4912 if (info->regno >= 0)
4915 info->replace_reg = gen_rtx_REG (HImode, reg);
4917 else if (info->can_use_d)
4919 reg = HARD_D_REGNUM;
4920 info->replace_reg = d_reg;
4922 else if (info->x_used)
4924 reg = HARD_Y_REGNUM;
4925 info->replace_reg = iy_reg;
4929 reg = HARD_X_REGNUM;
4930 info->replace_reg = ix_reg;
4934 if (info->must_save_reg && info->must_restore_reg)
4936 if (insn && dead_register_here (insn, info->replace_reg))
4938 info->must_save_reg = 0;
4939 info->must_restore_reg = 0;
4944 /* The insn uses the Z register. Find a replacement register for it
4945 (either X or Y) and replace it in the insn and the next ones until
4946 the flow changes or the replacement register is used. Instructions
4947 are emitted before and after the Z-block to preserve the value of
4948 Z and of the replacement register. */
4951 m68hc11_z_replacement (rtx insn)
4955 struct replace_info info;
4957 /* Find trivial case where we only need to replace z with the
4958 equivalent soft register. */
4959 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4961 rtx body = PATTERN (insn);
4962 rtx src = XEXP (body, 1);
4963 rtx dst = XEXP (body, 0);
4965 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4967 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4970 else if (Z_REG_P (src)
4971 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4973 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4976 else if (D_REG_P (dst)
4977 && m68hc11_arith_operator (src, GET_MODE (src))
4978 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4980 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4983 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4984 && INTVAL (src) == 0)
4986 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4987 /* Force it to be re-recognized. */
4988 INSN_CODE (insn) = -1;
4993 m68hc11_find_z_replacement (insn, &info);
4995 replace_reg = info.replace_reg;
4996 replace_reg_qi = NULL_RTX;
4998 /* Save the X register in a .page0 location. */
4999 if (info.must_save_reg && !info.must_push_reg)
5003 if (info.must_push_reg && 0)
5004 dst = gen_rtx_MEM (HImode,
5005 gen_rtx_PRE_DEC (HImode,
5006 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
5008 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
5010 emit_insn_before (gen_movhi (dst,
5011 gen_rtx_REG (HImode, info.regno)), insn);
5013 if (info.must_load_z && !info.must_push_reg)
5015 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
5016 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
5021 /* Replace all occurrence of Z by replace_reg.
5022 Stop when the last instruction to replace is reached.
5023 Also stop when we detect a change in the flow (but it's not
5024 necessary; just safeguard). */
5026 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
5030 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
5033 if (GET_CODE (insn) != INSN
5034 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
5037 body = PATTERN (insn);
5038 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5039 || GET_CODE (body) == ASM_OPERANDS
5040 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5044 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
5046 printf ("Reg mentioned here...:\n");
5051 /* Stack pointer was decremented by 2 due to the push.
5052 Correct that by adding 2 to the destination. */
5053 if (info.must_push_reg
5054 && info.z_loaded_with_sp && GET_CODE (body) == SET)
5058 src = SET_SRC (body);
5059 dst = SET_DEST (body);
5060 if (SP_REG_P (src) && Z_REG_P (dst))
5061 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
5064 /* Replace any (REG:HI Z) occurrence by either X or Y. */
5065 if (!validate_replace_rtx (z_reg, replace_reg, insn))
5067 INSN_CODE (insn) = -1;
5068 if (!validate_replace_rtx (z_reg, replace_reg, insn))
5069 fatal_insn ("cannot do z-register replacement", insn);
5072 /* Likewise for (REG:QI Z). */
5073 if (reg_mentioned_p (z_reg, insn))
5075 if (replace_reg_qi == NULL_RTX)
5076 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
5077 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
5080 /* If there is a REG_INC note on Z, replace it with a
5081 REG_INC note on the replacement register. This is necessary
5082 to make sure that the flow pass will identify the change
5083 and it will not remove a possible insn that saves Z. */
5084 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
5086 if (REG_NOTE_KIND (note) == REG_INC
5087 && GET_CODE (XEXP (note, 0)) == REG
5088 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
5090 XEXP (note, 0) = replace_reg;
5094 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5098 /* Save Z before restoring the old value. */
5099 if (insn && info.need_save_z && !info.must_push_reg)
5101 rtx save_pos_insn = insn;
5103 /* If Z is clobber by the last insn, we have to save its value
5104 before the last instruction. */
5105 if (info.save_before_last)
5106 save_pos_insn = PREV_INSN (save_pos_insn);
5108 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
5109 gen_rtx_REG (HImode, info.regno)),
5113 if (info.must_push_reg && info.last)
5117 body = PATTERN (info.last);
5118 new_body = gen_rtx_PARALLEL (VOIDmode,
5120 gen_rtx_USE (VOIDmode,
5122 gen_rtx_USE (VOIDmode,
5123 gen_rtx_REG (HImode,
5125 PATTERN (info.last) = new_body;
5127 /* Force recognition on insn since we changed it. */
5128 INSN_CODE (insn) = -1;
5130 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
5132 fatal_insn ("invalid Z register replacement for insn", insn);
5134 insn = NEXT_INSN (info.last);
5137 /* Restore replacement register unless it was died. */
5138 if (insn && info.must_restore_reg && !info.must_push_reg)
5142 if (info.must_push_reg && 0)
5143 dst = gen_rtx_MEM (HImode,
5144 gen_rtx_POST_INC (HImode,
5145 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
5147 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
5149 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
5156 /* Scan all the insn and re-affects some registers
5157 - The Z register (if it was used), is affected to X or Y depending
5158 on the instruction. */
5161 m68hc11_reassign_regs (rtx first)
5165 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
5166 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
5167 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5168 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
5170 /* Scan all insns to replace Z by X or Y preserving the old value
5171 of X/Y and restoring it afterward. */
5173 for (insn = first; insn; insn = NEXT_INSN (insn))
5177 if (GET_CODE (insn) == CODE_LABEL
5178 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
5184 body = PATTERN (insn);
5185 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5188 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5189 || GET_CODE (body) == ASM_OPERANDS
5190 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5193 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5194 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5197 /* If Z appears in this insn, replace it in the current insn
5198 and the next ones until the flow changes or we have to
5199 restore back the replacement register. */
5201 if (reg_mentioned_p (z_reg, body))
5203 m68hc11_z_replacement (insn);
5208 printf ("insn not handled by Z replacement:\n");
5216 /* Machine-dependent reorg pass.
5217 Specific optimizations are defined here:
5218 - this pass changes the Z register into either X or Y
5219 (it preserves X/Y previous values in a memory slot in page0).
5221 When this pass is finished, the global variable
5222 'z_replacement_completed' is set to 2. */
5225 m68hc11_reorg (void)
5230 z_replacement_completed = 0;
5231 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5232 first = get_insns ();
5234 /* Some RTX are shared at this point. This breaks the Z register
5235 replacement, unshare everything. */
5236 unshare_all_rtl_again (first);
5238 /* Force a split of all splitable insn. This is necessary for the
5239 Z register replacement mechanism because we end up with basic insns. */
5240 split_all_insns_noflow ();
5243 z_replacement_completed = 1;
5244 m68hc11_reassign_regs (first);
5247 compute_bb_for_insn ();
5249 /* After some splitting, there are some opportunities for CSE pass.
5250 This happens quite often when 32-bit or above patterns are split. */
5251 if (optimize > 0 && split_done)
5253 reload_cse_regs (first);
5256 /* Re-create the REG_DEAD notes. These notes are used in the machine
5257 description to use the best assembly directives. */
5260 /* Before recomputing the REG_DEAD notes, remove all of them.
5261 This is necessary because the reload_cse_regs() pass can
5262 have replaced some (MEM) with a register. In that case,
5263 the REG_DEAD that could exist for that register may become
5265 for (insn = first; insn; insn = NEXT_INSN (insn))
5271 pnote = ®_NOTES (insn);
5274 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5275 *pnote = XEXP (*pnote, 1);
5277 pnote = &XEXP (*pnote, 1);
5282 life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5285 z_replacement_completed = 2;
5287 /* If optimizing, then go ahead and split insns that must be
5288 split after Z register replacement. This gives more opportunities
5289 for peephole (in particular for consecutives xgdx/xgdy). */
5291 split_all_insns_noflow ();
5293 /* Once insns are split after the z_replacement_completed == 2,
5294 we must not re-run the life_analysis. The xgdx/xgdy patterns
5295 are not recognized and the life_analysis pass removes some
5296 insns because it thinks some (SETs) are noops or made to dead
5297 stores (which is false due to the swap).
5299 Do a simple pass to eliminate the noop set that the final
5300 split could generate (because it was easier for split definition). */
5304 for (insn = first; insn; insn = NEXT_INSN (insn))
5308 if (INSN_DELETED_P (insn))
5313 /* Remove the (set (R) (R)) insns generated by some splits. */
5314 body = PATTERN (insn);
5315 if (GET_CODE (body) == SET
5316 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5318 PUT_CODE (insn, NOTE);
5319 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5320 NOTE_SOURCE_FILE (insn) = 0;
5327 /* Override memcpy */
5330 m68hc11_init_libfuncs (void)
5332 memcpy_libfunc = init_one_libfunc ("__memcpy");
5333 memcmp_libfunc = init_one_libfunc ("__memcmp");
5334 memset_libfunc = init_one_libfunc ("__memset");
5339 /* Cost functions. */
5341 /* Cost of moving memory. */
5343 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class class,
5344 int in ATTRIBUTE_UNUSED)
5346 if (class <= H_REGS && class > NO_REGS)
5348 if (GET_MODE_SIZE (mode) <= 2)
5349 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5351 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5355 if (GET_MODE_SIZE (mode) <= 2)
5356 return COSTS_N_INSNS (3);
5358 return COSTS_N_INSNS (4);
5363 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5364 Reload does not check the constraint of set insns when the two registers
5365 have a move cost of 2. Setting a higher cost will force reload to check
5368 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5371 /* All costs are symmetric, so reduce cases by putting the
5372 lower number class as the destination. */
5375 enum reg_class tmp = to;
5376 to = from, from = tmp;
5379 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5380 else if (from <= S_REGS)
5381 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5383 return COSTS_N_INSNS (2);
5387 /* Provide the costs of an addressing mode that contains ADDR.
5388 If ADDR is not a valid address, its cost is irrelevant. */
5391 m68hc11_address_cost (rtx addr)
5395 switch (GET_CODE (addr))
5398 /* Make the cost of hard registers and specially SP, FP small. */
5399 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5416 register rtx plus0 = XEXP (addr, 0);
5417 register rtx plus1 = XEXP (addr, 1);
5419 if (GET_CODE (plus0) != REG)
5422 switch (GET_CODE (plus1))
5425 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5426 || INTVAL (plus1) < m68hc11_min_offset)
5428 else if (INTVAL (plus1) >= m68hc11_max_offset)
5432 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5454 if (SP_REG_P (XEXP (addr, 0)))
5463 printf ("Address cost: %d for :", cost);
5472 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5476 total = rtx_cost (x, SET);
5478 total += m68hc11_cost->shiftQI_const[shift % 8];
5479 else if (mode == HImode)
5480 total += m68hc11_cost->shiftHI_const[shift % 16];
5481 else if (shift == 8 || shift == 16 || shift == 32)
5482 total += m68hc11_cost->shiftHI_const[8];
5483 else if (shift != 0 && shift != 16 && shift != 32)
5485 total += m68hc11_cost->shiftHI_const[1] * shift;
5488 /* For SI and others, the cost is higher. */
5489 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5490 total *= GET_MODE_SIZE (mode) / 2;
5492 /* When optimizing for size, make shift more costly so that
5493 multiplications are preferred. */
5494 if (optimize_size && (shift % 8) != 0)
5501 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5502 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5504 enum machine_mode mode = GET_MODE (x);
5515 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5517 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5520 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5521 total += m68hc11_cost->shift_var;
5527 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5528 total += m68hc11_cost->logical;
5530 /* Logical instructions are byte instructions only. */
5531 total *= GET_MODE_SIZE (mode);
5536 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5537 total += m68hc11_cost->add;
5538 if (GET_MODE_SIZE (mode) > 2)
5540 total *= GET_MODE_SIZE (mode) / 2;
5547 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5551 total += m68hc11_cost->divQI;
5555 total += m68hc11_cost->divHI;
5560 total += m68hc11_cost->divSI;
5566 /* mul instruction produces 16-bit result. */
5567 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5568 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5569 return m68hc11_cost->multQI
5570 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5571 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5573 /* emul instruction produces 32-bit result for 68HC12. */
5574 if (TARGET_M6812 && mode == SImode
5575 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5576 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5577 return m68hc11_cost->multHI
5578 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5579 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5581 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5585 total += m68hc11_cost->multQI;
5589 total += m68hc11_cost->multHI;
5594 total += m68hc11_cost->multSI;
5601 extra_cost = COSTS_N_INSNS (2);
5608 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5611 return total + COSTS_N_INSNS (1);
5615 return total + COSTS_N_INSNS (2);
5619 return total + COSTS_N_INSNS (4);
5621 return total + COSTS_N_INSNS (8);
5624 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5625 return COSTS_N_INSNS (1);
5627 return COSTS_N_INSNS (1);
5630 return COSTS_N_INSNS (4);
5635 m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total)
5639 /* Constants are cheap. Moving them in registers must be avoided
5640 because most instructions do not handle two register operands. */
5646 /* Logical and arithmetic operations with a constant operand are
5647 better because they are not supported with two registers. */
5649 if (outer_code == SET && x == const0_rtx)
5650 /* After reload, the reload_cse pass checks the cost to change
5651 a SET into a PLUS. Make const0 cheap then. */
5652 *total = 1 - reload_completed;
5677 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5686 /* Worker function for TARGET_ASM_FILE_START. */
5689 m68hc11_file_start (void)
5691 default_file_start ();
5693 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5697 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5700 m68hc11_asm_out_constructor (rtx symbol, int priority)
5702 default_ctor_section_asm_out_constructor (symbol, priority);
5703 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5706 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5709 m68hc11_asm_out_destructor (rtx symbol, int priority)
5711 default_dtor_section_asm_out_destructor (symbol, priority);
5712 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5715 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5718 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5719 int incoming ATTRIBUTE_UNUSED)
5721 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5724 /* Return true if type TYPE should be returned in memory.
5725 Blocks and data types largers than 4 bytes cannot be returned
5726 in the register (D + X = 4). */
5729 m68hc11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
5731 if (TYPE_MODE (type) == BLKmode)
5733 HOST_WIDE_INT size = int_size_in_bytes (type);
5734 return (size == -1 || size > 4);
5737 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5740 #include "gt-m68hc11.h"