1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 2009, 2010 Free Software Foundation, Inc.
4 Contributed by Stephane Carrez (stcarrez@nerim.fr)
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 3, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>.
23 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24 on gcc 2.6.3. I have used it as a starting point for this port.
25 However, this new port is a complete re-write. Its internal
26 design is completely different. The generated code is not
27 compatible with the gcc 2.6.3 port.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
38 #include "coretypes.h"
45 #include "hard-reg-set.h"
46 #include "insn-config.h"
47 #include "conditions.h"
49 #include "insn-attr.h"
55 #include "basic-block.h"
60 #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
, enum rtx_code
, rtx
*);
66 static void m68hc11_reorg (void);
67 static bool m68hc11_legitimate_address_p_1 (enum machine_mode
, rtx
, bool);
68 static bool m68hc11_legitimate_address_p (enum machine_mode
, rtx
, bool);
69 static rtx
m68hc11_expand_compare (enum rtx_code
, rtx
, rtx
);
70 static int must_parenthesize (rtx
);
71 static int m68hc11_address_cost (rtx
, bool);
72 static int m68hc11_shift_cost (enum machine_mode
, rtx
, int);
73 static int m68hc11_rtx_costs_1 (rtx
, enum rtx_code
, enum rtx_code
);
74 static bool m68hc11_rtx_costs (rtx
, int, int, int *, bool);
75 static tree
m68hc11_handle_fntype_attribute (tree
*, tree
, tree
, int, bool *);
76 static tree
m68hc11_handle_page0_attribute (tree
*, tree
, tree
, int, bool *);
78 void create_regs_rtx (void);
80 static void asm_print_register (FILE *, int);
81 static void m68hc11_print_operand (FILE *, rtx
, int);
82 static void m68hc11_print_operand_address (FILE *, rtx
);
83 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT
);
84 static void m68hc11_asm_out_constructor (rtx
, int);
85 static void m68hc11_asm_out_destructor (rtx
, int);
86 static void m68hc11_file_start (void);
87 static void m68hc11_encode_section_info (tree
, rtx
, int);
88 static const char *m68hc11_strip_name_encoding (const char* str
);
89 static unsigned int m68hc11_section_type_flags (tree
, const char*, int);
90 static int autoinc_mode (rtx
);
91 static int m68hc11_make_autoinc_notes (rtx
*, void *);
92 static void m68hc11_init_libfuncs (void);
93 static rtx
m68hc11_struct_value_rtx (tree
, int);
94 static bool m68hc11_return_in_memory (const_tree
, const_tree
);
95 static bool m68hc11_can_eliminate (const int, const int);
96 static void m68hc11_trampoline_init (rtx
, tree
, rtx
);
98 /* Must be set to 1 to produce debug messages. */
101 extern FILE *asm_out_file
;
106 rtx m68hc11_soft_tmp_reg
;
107 static GTY(()) rtx stack_push_word
;
108 static GTY(()) rtx stack_pop_word
;
109 static GTY(()) rtx z_reg
;
110 static GTY(()) rtx z_reg_qi
;
111 static int regs_inited
= 0;
113 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
114 int current_function_interrupt
;
116 /* Set to 1 by expand_prologue() when the function is a trap handler. */
117 int current_function_trap
;
119 /* Set to 1 when the current function is placed in 68HC12 banked
120 memory and must return with rtc. */
121 int current_function_far
;
123 /* Min offset that is valid for the indirect addressing mode. */
124 HOST_WIDE_INT m68hc11_min_offset
= 0;
126 /* Max offset that is valid for the indirect addressing mode. */
127 HOST_WIDE_INT m68hc11_max_offset
= 256;
129 /* The class value for base registers. */
130 enum reg_class m68hc11_base_reg_class
= A_REGS
;
132 /* The class value for index registers. This is NO_REGS for 68HC11. */
133 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
135 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
137 /* Tables that tell whether a given hard register is valid for
138 a base or an index register. It is filled at init time depending
139 on the target processor. */
140 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
141 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
143 /* A correction offset which is applied to the stack pointer.
144 This is 1 for 68HC11 and 0 for 68HC12. */
145 int m68hc11_sp_correction
;
147 int m68hc11_addr_mode
;
148 int m68hc11_mov_addr_mode
;
151 const struct processor_costs
*m68hc11_cost
;
153 /* Costs for a 68HC11. */
154 static const struct processor_costs m6811_cost
= {
159 /* non-constant shift */
162 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
163 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
164 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
167 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
168 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
169 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
170 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
171 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
172 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
177 COSTS_N_INSNS (20 * 4),
179 COSTS_N_INSNS (20 * 16),
188 /* Costs for a 68HC12. */
189 static const struct processor_costs m6812_cost
= {
194 /* non-constant shift */
197 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
198 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
199 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
202 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
203 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
204 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
205 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
206 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
207 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
214 COSTS_N_INSNS (3 * 4),
223 /* M68HC11 specific attributes. */
225 static const struct attribute_spec m68hc11_attribute_table
[] =
227 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
228 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
229 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
230 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
231 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
232 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute
},
233 { NULL
, 0, 0, false, false, false, NULL
}
236 /* Initialize the GCC target structure. */
237 #undef TARGET_ATTRIBUTE_TABLE
238 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
240 #undef TARGET_ASM_ALIGNED_HI_OP
241 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
243 #undef TARGET_PRINT_OPERAND
244 #define TARGET_PRINT_OPERAND m68hc11_print_operand
245 #undef TARGET_PRINT_OPERAND_ADDRESS
246 #define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
248 #undef TARGET_ASM_FUNCTION_EPILOGUE
249 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
251 #undef TARGET_ASM_FILE_START
252 #define TARGET_ASM_FILE_START m68hc11_file_start
253 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
254 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
256 #undef TARGET_DEFAULT_TARGET_FLAGS
257 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
259 #undef TARGET_ENCODE_SECTION_INFO
260 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
262 #undef TARGET_SECTION_TYPE_FLAGS
263 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
265 #undef TARGET_RTX_COSTS
266 #define TARGET_RTX_COSTS m68hc11_rtx_costs
267 #undef TARGET_ADDRESS_COST
268 #define TARGET_ADDRESS_COST m68hc11_address_cost
270 #undef TARGET_MACHINE_DEPENDENT_REORG
271 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
273 #undef TARGET_INIT_LIBFUNCS
274 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
276 #undef TARGET_STRUCT_VALUE_RTX
277 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
278 #undef TARGET_RETURN_IN_MEMORY
279 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
280 #undef TARGET_CALLEE_COPIES
281 #define TARGET_CALLEE_COPIES hook_callee_copies_named
283 #undef TARGET_STRIP_NAME_ENCODING
284 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
286 #undef TARGET_LEGITIMATE_ADDRESS_P
287 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
289 #undef TARGET_CAN_ELIMINATE
290 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
292 #undef TARGET_TRAMPOLINE_INIT
293 #define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
295 struct gcc_target targetm
= TARGET_INITIALIZER
;
298 m68hc11_override_options (void)
300 memset (m68hc11_reg_valid_for_index
, 0,
301 sizeof (m68hc11_reg_valid_for_index
));
302 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
304 /* Compilation with -fpic generates a wrong code. */
307 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
308 (flag_pic
> 1) ? "PIC" : "pic");
312 /* Do not enable -fweb because it breaks the 32-bit shift patterns
313 by breaking the match_dup of those patterns. The shift patterns
314 will no longer be recognized after that. */
317 /* Configure for a 68hc11 processor. */
320 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
321 m68hc11_cost
= &m6811_cost
;
322 m68hc11_min_offset
= 0;
323 m68hc11_max_offset
= 256;
324 m68hc11_index_reg_class
= NO_REGS
;
325 m68hc11_base_reg_class
= A_REGS
;
326 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
327 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
328 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
329 m68hc11_sp_correction
= 1;
330 m68hc11_tmp_regs_class
= D_REGS
;
331 m68hc11_addr_mode
= ADDR_OFFSET
;
332 m68hc11_mov_addr_mode
= 0;
333 if (m68hc11_soft_reg_count
< 0)
334 m68hc11_soft_reg_count
= 4;
337 /* Configure for a 68hc12 processor. */
340 m68hc11_cost
= &m6812_cost
;
341 m68hc11_min_offset
= -65536;
342 m68hc11_max_offset
= 65536;
343 m68hc11_index_reg_class
= D_REGS
;
344 m68hc11_base_reg_class
= A_OR_SP_REGS
;
345 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
346 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
347 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
348 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
349 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
350 m68hc11_sp_correction
= 0;
351 m68hc11_tmp_regs_class
= TMP_REGS
;
352 m68hc11_addr_mode
= ADDR_INDIRECT
| ADDR_OFFSET
| ADDR_CONST
353 | (TARGET_AUTO_INC_DEC
? ADDR_INCDEC
: 0);
354 m68hc11_mov_addr_mode
= ADDR_OFFSET
| ADDR_CONST
355 | (TARGET_AUTO_INC_DEC
? ADDR_INCDEC
: 0);
356 target_flags
|= MASK_NO_DIRECT_MODE
;
357 if (m68hc11_soft_reg_count
< 0)
358 m68hc11_soft_reg_count
= 0;
360 if (TARGET_LONG_CALLS
)
361 current_function_far
= 1;
368 m68hc11_conditional_register_usage (void)
372 if (m68hc11_soft_reg_count
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
373 m68hc11_soft_reg_count
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
375 for (i
= SOFT_REG_FIRST
+ m68hc11_soft_reg_count
; i
< SOFT_REG_LAST
; i
++)
378 call_used_regs
[i
] = 1;
381 /* For 68HC12, the Z register emulation is not necessary when the
382 frame pointer is not used. The frame pointer is eliminated and
383 replaced by the stack register (which is a BASE_REG_CLASS). */
384 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
386 fixed_regs
[HARD_Z_REGNUM
] = 1;
391 /* Reload and register operations. */
395 create_regs_rtx (void)
397 /* regs_inited = 1; */
398 ix_reg
= gen_rtx_REG (HImode
, HARD_X_REGNUM
);
399 iy_reg
= gen_rtx_REG (HImode
, HARD_Y_REGNUM
);
400 d_reg
= gen_rtx_REG (HImode
, HARD_D_REGNUM
);
401 m68hc11_soft_tmp_reg
= gen_rtx_REG (HImode
, SOFT_TMP_REGNUM
);
403 stack_push_word
= gen_rtx_MEM (HImode
,
404 gen_rtx_PRE_DEC (HImode
,
405 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
406 stack_pop_word
= gen_rtx_MEM (HImode
,
407 gen_rtx_POST_INC (HImode
,
408 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
412 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
413 - 8-bit values are stored anywhere (except the SP register).
414 - 16-bit values can be stored in any register whose mode is 16
415 - 32-bit values can be stored in D, X registers or in a soft register
416 (except the last one because we need 2 soft registers)
417 - Values whose size is > 32 bit are not stored in real hard
418 registers. They may be stored in soft registers if there are
421 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
423 switch (GET_MODE_SIZE (mode
))
426 return S_REGNO_P (regno
) && m68hc11_soft_reg_count
>= 4;
429 return (X_REGNO_P (regno
)
430 || (S_REGNO_P (regno
) && m68hc11_soft_reg_count
>= 2));
433 return G_REGNO_P (regno
);
436 /* We have to accept a QImode in X or Y registers. Otherwise, the
437 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
438 in the insns. Reload fails if the insn rejects the register class 'a'
439 as well as if it accepts it. Patterns that failed were
440 zero_extend_qihi2 and iorqi3. */
442 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
450 m68hc11_hard_regno_rename_ok (int reg1
, int reg2
)
452 /* Don't accept renaming to Z register. We will replace it to
453 X,Y or D during machine reorg pass. */
454 if (reg2
== HARD_Z_REGNUM
)
457 /* Don't accept renaming D,X to Y register as the code will be bigger. */
458 if (TARGET_M6811
&& reg2
== HARD_Y_REGNUM
459 && (D_REGNO_P (reg1
) || X_REGNO_P (reg1
)))
466 preferred_reload_class (rtx operand
, enum reg_class rclass
)
468 enum machine_mode mode
;
470 mode
= GET_MODE (operand
);
474 printf ("Preferred reload: (class=%s): ", reg_class_names
[rclass
]);
477 if (rclass
== D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
478 return m68hc11_base_reg_class
;
480 if (rclass
>= S_REGS
&& (GET_CODE (operand
) == MEM
481 || GET_CODE (operand
) == CONST_INT
))
483 /* S_REGS class must not be used. The movhi template does not
484 work to move a memory to a soft register.
485 Restrict to a hard reg. */
490 case D_OR_A_OR_S_REGS
:
491 rclass
= A_OR_D_REGS
;
496 case D_OR_SP_OR_S_REGS
:
497 rclass
= D_OR_SP_REGS
;
499 case D_OR_Y_OR_S_REGS
:
500 rclass
= D_OR_Y_REGS
;
502 case D_OR_X_OR_S_REGS
:
503 rclass
= D_OR_X_REGS
;
518 else if (rclass
== Y_REGS
&& GET_CODE (operand
) == MEM
)
522 else if (rclass
== A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
524 rclass
= D_OR_X_REGS
;
526 else if (rclass
>= S_REGS
&& S_REG_P (operand
))
532 case D_OR_A_OR_S_REGS
:
533 rclass
= A_OR_D_REGS
;
538 case D_OR_SP_OR_S_REGS
:
539 rclass
= D_OR_SP_REGS
;
541 case D_OR_Y_OR_S_REGS
:
542 rclass
= D_OR_Y_REGS
;
544 case D_OR_X_OR_S_REGS
:
545 rclass
= D_OR_X_REGS
;
560 else if (rclass
>= S_REGS
)
564 printf ("Class = %s for: ", reg_class_names
[rclass
]);
572 printf (" => class=%s\n", reg_class_names
[rclass
]);
580 /* Return 1 if the operand is a valid indexed addressing mode.
581 For 68hc11: n,r with n in [0..255] and r in A_REGS class
582 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
584 m68hc11_valid_addressing_p (rtx operand
, enum machine_mode mode
, int addr_mode
)
588 switch (GET_CODE (operand
))
591 if ((addr_mode
& ADDR_INDIRECT
) && GET_MODE_SIZE (mode
) <= 2)
592 return m68hc11_valid_addressing_p (XEXP (operand
, 0), mode
,
593 addr_mode
& (ADDR_STRICT
| ADDR_OFFSET
));
600 if (addr_mode
& ADDR_INCDEC
)
601 return m68hc11_valid_addressing_p (XEXP (operand
, 0), mode
,
602 addr_mode
& ADDR_STRICT
);
606 base
= XEXP (operand
, 0);
607 if (GET_CODE (base
) == MEM
)
610 offset
= XEXP (operand
, 1);
611 if (GET_CODE (offset
) == MEM
)
614 /* Indexed addressing mode with 2 registers. */
615 if (GET_CODE (base
) == REG
&& GET_CODE (offset
) == REG
)
617 if (!(addr_mode
& ADDR_INDEXED
))
620 addr_mode
&= ADDR_STRICT
;
621 if (REGNO_OK_FOR_BASE_P2 (REGNO (base
), addr_mode
)
622 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset
), addr_mode
))
625 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset
), addr_mode
)
626 && REGNO_OK_FOR_INDEX_P2 (REGNO (base
), addr_mode
))
632 if (!(addr_mode
& ADDR_OFFSET
))
635 if (GET_CODE (base
) == REG
)
637 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
640 if (!(addr_mode
& ADDR_STRICT
))
643 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), 1);
646 if (GET_CODE (offset
) == REG
)
648 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
651 if (!(addr_mode
& ADDR_STRICT
))
654 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), 1);
659 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), addr_mode
& ADDR_STRICT
);
662 if (addr_mode
& ADDR_CONST
)
663 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
671 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
672 a 68HC12 1-byte index addressing mode. */
674 m68hc11_small_indexed_indirect_p (rtx operand
, enum machine_mode mode
)
679 if (GET_CODE (operand
) == REG
&& reload_in_progress
680 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
681 && reg_equiv_memory_loc
[REGNO (operand
)])
683 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
684 operand
= eliminate_regs (operand
, VOIDmode
, NULL_RTX
);
687 if (GET_CODE (operand
) != MEM
)
690 operand
= XEXP (operand
, 0);
691 if (CONSTANT_ADDRESS_P (operand
))
694 if (PUSH_POP_ADDRESS_P (operand
))
697 addr_mode
= m68hc11_mov_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
698 if (!m68hc11_valid_addressing_p (operand
, mode
, addr_mode
))
701 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
702 && (reload_completed
| reload_in_progress
))
704 base
= XEXP (operand
, 0);
705 offset
= XEXP (operand
, 1);
707 /* The offset can be a symbol address and this is too big
708 for the operand constraint. */
709 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
712 if (GET_CODE (base
) == CONST_INT
)
715 switch (GET_MODE_SIZE (mode
))
718 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
723 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
728 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
737 m68hc11_register_indirect_p (rtx operand
, enum machine_mode mode
)
741 if (GET_CODE (operand
) == REG
&& reload_in_progress
742 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
743 && reg_equiv_memory_loc
[REGNO (operand
)])
745 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
746 operand
= eliminate_regs (operand
, VOIDmode
, NULL_RTX
);
748 if (GET_CODE (operand
) != MEM
)
751 operand
= XEXP (operand
, 0);
752 addr_mode
= m68hc11_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
753 return m68hc11_valid_addressing_p (operand
, mode
, addr_mode
);
757 m68hc11_legitimate_address_p_1 (enum machine_mode mode
, rtx operand
,
762 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
764 /* Reject the global variables if they are too wide. This forces
765 a load of their address in a register and generates smaller code. */
766 if (GET_MODE_SIZE (mode
) == 8)
771 addr_mode
= m68hc11_addr_mode
| (strict
? ADDR_STRICT
: 0);
772 if (m68hc11_valid_addressing_p (operand
, mode
, addr_mode
))
776 if (PUSH_POP_ADDRESS_P (operand
))
780 if (symbolic_memory_operand (operand
, mode
))
788 m68hc11_legitimate_address_p (enum machine_mode mode
, rtx operand
,
795 printf ("Checking: ");
800 result
= m68hc11_legitimate_address_p_1 (mode
, operand
, strict
);
804 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
811 printf ("go_if_legitimate%s, ret 0: %d:",
812 (strict
? "_strict" : ""), mode
);
822 m68hc11_reload_operands (rtx operands
[])
824 enum machine_mode mode
;
826 if (regs_inited
== 0)
829 mode
= GET_MODE (operands
[1]);
831 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
832 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
834 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
835 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
837 if (GET_CODE (base
) != REG
)
844 /* If the offset is out of range, we have to compute the address
845 with a separate add instruction. We try to do this with an 8-bit
846 add on the A register. This is possible only if the lowest part
847 of the offset (i.e., big_offset % 256) is a valid constant offset
848 with respect to the mode. If it's not, we have to generate a
849 16-bit add on the D register. From:
851 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
855 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
856 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
857 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
858 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
860 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
861 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
864 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
867 rtx reg
= operands
[0];
869 int val
= INTVAL (big_offset
);
872 /* We use the 'operands[0]' as a scratch register to compute the
873 address. Make sure 'base' is in that register. */
874 if (!rtx_equal_p (base
, operands
[0]))
876 emit_move_insn (reg
, base
);
886 vh
= (val
>> 8) & 0x0FF;
890 /* Create the lowest part offset that still remains to be added.
891 If it's not a valid offset, do a 16-bit add. */
892 offset
= GEN_INT (vl
);
893 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
895 emit_insn (gen_rtx_SET (VOIDmode
, reg
,
896 gen_rtx_PLUS (HImode
, reg
, big_offset
)));
901 emit_insn (gen_rtx_SET (VOIDmode
, reg
,
902 gen_rtx_PLUS (HImode
, reg
,
903 GEN_INT (vh
<< 8))));
905 emit_move_insn (operands
[0],
906 gen_rtx_MEM (GET_MODE (operands
[1]),
907 gen_rtx_PLUS (Pmode
, reg
, offset
)));
912 /* Use the normal gen_movhi pattern. */
917 m68hc11_emit_libcall (const char *name
, enum rtx_code code
,
918 enum machine_mode dmode
, enum machine_mode smode
,
919 int noperands
, rtx
*operands
)
927 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
931 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
932 dmode
, 1, operands
[1], smode
);
933 equiv
= gen_rtx_fmt_e (code
, dmode
, operands
[1]);
937 ret
= emit_library_call_value (libcall
, NULL_RTX
,
939 operands
[1], smode
, operands
[2],
941 equiv
= gen_rtx_fmt_ee (code
, dmode
, operands
[1], operands
[2]);
948 insns
= get_insns ();
950 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
953 /* Returns true if X is a PRE/POST increment decrement
954 (same as auto_inc_p() in rtlanal.c but do not take into
955 account the stack). */
957 m68hc11_auto_inc_p (rtx x
)
959 return GET_CODE (x
) == PRE_DEC
960 || GET_CODE (x
) == POST_INC
961 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
965 /* Predicates for machine description. */
968 memory_reload_operand (rtx operand
, enum machine_mode mode ATTRIBUTE_UNUSED
)
970 return GET_CODE (operand
) == MEM
971 && GET_CODE (XEXP (operand
, 0)) == PLUS
972 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
973 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
974 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
975 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
979 m68hc11_symbolic_p (rtx operand
, enum machine_mode mode
)
981 if (GET_CODE (operand
) == MEM
)
983 rtx op
= XEXP (operand
, 0);
985 if (symbolic_memory_operand (op
, mode
))
992 m68hc11_indirect_p (rtx operand
, enum machine_mode mode
)
994 if (GET_CODE (operand
) == MEM
&& GET_MODE (operand
) == mode
)
996 rtx op
= XEXP (operand
, 0);
999 if (m68hc11_page0_symbol_p (op
))
1002 if (symbolic_memory_operand (op
, mode
))
1003 return TARGET_M6812
;
1005 if (reload_in_progress
)
1008 operand
= XEXP (operand
, 0);
1009 addr_mode
= m68hc11_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
1010 return m68hc11_valid_addressing_p (operand
, mode
, addr_mode
);
1016 memory_indexed_operand (rtx operand
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1018 if (GET_CODE (operand
) != MEM
)
1021 operand
= XEXP (operand
, 0);
1022 if (GET_CODE (operand
) == PLUS
)
1024 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1025 operand
= XEXP (operand
, 0);
1026 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1027 operand
= XEXP (operand
, 1);
1029 return GET_CODE (operand
) == REG
1030 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1031 || A_REGNO_P (REGNO (operand
)));
1035 push_pop_operand_p (rtx operand
)
1037 if (GET_CODE (operand
) != MEM
)
1041 operand
= XEXP (operand
, 0);
1042 return PUSH_POP_ADDRESS_P (operand
);
1045 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1046 reference and a constant. */
1049 symbolic_memory_operand (rtx op
, enum machine_mode mode
)
1051 switch (GET_CODE (op
))
1059 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1060 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1061 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1063 /* ??? This clause seems to be irrelevant. */
1065 return GET_MODE (op
) == mode
;
1068 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1069 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1076 /* Emit the code to build the trampoline used to call a nested function.
1080 ldy #&CXT movw #&CXT,*_.d1
1081 sty *_.d1 jmp FNADDR
1086 m68hc11_trampoline_init (rtx m_tramp
, tree fndecl
, rtx cxt
)
1088 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1089 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
1093 if (*static_chain_reg
== '*')
1097 mem
= adjust_address (m_tramp
, HImode
, 0);
1098 emit_move_insn (mem
, GEN_INT (0x18ce));
1099 mem
= adjust_address (m_tramp
, HImode
, 2);
1100 emit_move_insn (mem
, cxt
);
1101 mem
= adjust_address (m_tramp
, HImode
, 4);
1102 emit_move_insn (mem
, GEN_INT (0x18df));
1103 mem
= adjust_address (m_tramp
, QImode
, 6);
1104 emit_move_insn (mem
,
1105 gen_rtx_CONST (QImode
,
1106 gen_rtx_SYMBOL_REF (Pmode
,
1107 static_chain_reg
)));
1108 mem
= adjust_address (m_tramp
, QImode
, 7);
1109 emit_move_insn (mem
, GEN_INT (0x7e));
1110 mem
= adjust_address (m_tramp
, HImode
, 8);
1111 emit_move_insn (mem
, fnaddr
);
1115 mem
= adjust_address (m_tramp
, HImode
, 0);
1116 emit_move_insn (mem
, GEN_INT (0x1803));
1117 mem
= adjust_address (m_tramp
, HImode
, 2);
1118 emit_move_insn (mem
, cxt
);
1119 mem
= adjust_address (m_tramp
, HImode
, 4);
1120 emit_move_insn (mem
,
1121 gen_rtx_CONST (HImode
,
1122 gen_rtx_SYMBOL_REF (Pmode
,
1123 static_chain_reg
)));
1124 mem
= adjust_address (m_tramp
, QImode
, 6);
1125 emit_move_insn (mem
, GEN_INT (0x06));
1126 mem
= adjust_address (m_tramp
, HImode
, 7);
1127 emit_move_insn (mem
, fnaddr
);
1131 /* Declaration of types. */
1133 /* Handle an "tiny_data" attribute; arguments as in
1134 struct attribute_spec.handler. */
1136 m68hc11_handle_page0_attribute (tree
*node
, tree name
,
1137 tree args ATTRIBUTE_UNUSED
,
1138 int flags ATTRIBUTE_UNUSED
, bool *no_add_attrs
)
1142 if (TREE_STATIC (decl
) || DECL_EXTERNAL (decl
))
1144 DECL_SECTION_NAME (decl
) = build_string (6, ".page0");
1148 warning (OPT_Wattributes
, "%qE attribute ignored",
1150 *no_add_attrs
= true;
1156 /* Keep track of the symbol which has a `trap' attribute and which uses
1157 the `swi' calling convention. Since there is only one trap, we only
1158 record one such symbol. If there are several, a warning is reported. */
1159 static rtx trap_handler_symbol
= 0;
1161 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1162 arguments as in struct attribute_spec.handler. */
1164 m68hc11_handle_fntype_attribute (tree
*node
, tree name
,
1165 tree args ATTRIBUTE_UNUSED
,
1166 int flags ATTRIBUTE_UNUSED
,
1169 if (TREE_CODE (*node
) != FUNCTION_TYPE
1170 && TREE_CODE (*node
) != METHOD_TYPE
1171 && TREE_CODE (*node
) != FIELD_DECL
1172 && TREE_CODE (*node
) != TYPE_DECL
)
1174 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
1176 *no_add_attrs
= true;
1181 /* Undo the effects of the above. */
1184 m68hc11_strip_name_encoding (const char *str
)
1186 return str
+ (*str
== '*' || *str
== '@' || *str
== '&');
1190 m68hc11_encode_label (tree decl
)
1192 const char *str
= XSTR (XEXP (DECL_RTL (decl
), 0), 0);
1193 int len
= strlen (str
);
1194 char *newstr
= XALLOCAVEC (char, len
+ 2);
1197 strcpy (&newstr
[1], str
);
1199 XSTR (XEXP (DECL_RTL (decl
), 0), 0) = ggc_alloc_string (newstr
, len
+ 1);
1202 /* Return 1 if this is a symbol in page0 */
1204 m68hc11_page0_symbol_p (rtx x
)
1206 switch (GET_CODE (x
))
1209 return XSTR (x
, 0) != 0 && XSTR (x
, 0)[0] == '@';
1212 return m68hc11_page0_symbol_p (XEXP (x
, 0));
1215 if (!m68hc11_page0_symbol_p (XEXP (x
, 0)))
1218 return GET_CODE (XEXP (x
, 1)) == CONST_INT
1219 && INTVAL (XEXP (x
, 1)) < 256
1220 && INTVAL (XEXP (x
, 1)) >= 0;
1227 /* We want to recognize trap handlers so that we handle calls to traps
1228 in a special manner (by issuing the trap). This information is stored
1229 in SYMBOL_REF_FLAG. */
1232 m68hc11_encode_section_info (tree decl
, rtx rtl
, int first ATTRIBUTE_UNUSED
)
1238 if (TREE_CODE (decl
) == VAR_DECL
)
1240 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl
)) != 0)
1241 m68hc11_encode_label (decl
);
1245 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1248 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1251 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1253 else if (lookup_attribute ("near", func_attr
) == NULL_TREE
)
1254 is_far
= TARGET_LONG_CALLS
!= 0;
1256 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1257 if (trap_handler
&& is_far
)
1259 warning (OPT_Wattributes
, "%<trap%> and %<far%> attributes are "
1260 "not compatible, ignoring %<far%>");
1265 if (trap_handler_symbol
!= 0)
1266 warning (OPT_Wattributes
, "%<trap%> attribute is already used");
1268 trap_handler_symbol
= XEXP (rtl
, 0);
1270 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = is_far
;
1274 m68hc11_section_type_flags (tree decl
, const char *name
, int reloc
)
1276 unsigned int flags
= default_section_type_flags (decl
, name
, reloc
);
1278 if (strncmp (name
, ".eeprom", 7) == 0)
1280 flags
|= SECTION_WRITE
| SECTION_CODE
| SECTION_OVERRIDE
;
1287 m68hc11_is_far_symbol (rtx sym
)
1289 if (GET_CODE (sym
) == MEM
)
1290 sym
= XEXP (sym
, 0);
1292 return SYMBOL_REF_FLAG (sym
);
1296 m68hc11_is_trap_symbol (rtx sym
)
1298 if (GET_CODE (sym
) == MEM
)
1299 sym
= XEXP (sym
, 0);
1301 return trap_handler_symbol
!= 0 && rtx_equal_p (trap_handler_symbol
, sym
);
1305 /* Argument support functions. */
1307 /* Given FROM and TO register numbers, say whether this elimination is
1308 allowed. Frame pointer elimination is automatically handled.
1310 All other eliminations are valid. */
1313 m68hc11_can_eliminate (const int from
, const int to
)
1315 return (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
1316 ? ! frame_pointer_needed
1320 /* Define the offset between two registers, one to be eliminated, and the
1321 other its replacement, at the start of a routine. */
1323 m68hc11_initial_elimination_offset (int from
, int to
)
1330 /* For a trap handler, we must take into account the registers which
1331 are pushed on the stack during the trap (except the PC). */
1332 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1333 current_function_interrupt
= lookup_attribute ("interrupt",
1334 func_attr
) != NULL_TREE
;
1335 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1337 if (lookup_attribute ("far", func_attr
) != 0)
1338 current_function_far
= 1;
1339 else if (lookup_attribute ("near", func_attr
) != 0)
1340 current_function_far
= 0;
1342 current_function_far
= (TARGET_LONG_CALLS
!= 0
1343 && !current_function_interrupt
1346 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1349 /* For a function using 'call/rtc' we must take into account the
1350 page register which is pushed in the call. */
1351 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1356 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1358 /* 2 is for the saved frame.
1359 1 is for the 'sts' correction when creating the frame. */
1360 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1363 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1365 return m68hc11_sp_correction
;
1368 /* Push any 2 byte pseudo hard registers that we need to save. */
1369 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1371 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1377 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1379 return get_frame_size () + size
;
1382 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1389 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1390 for a call to a function whose data type is FNTYPE.
1391 For a library call, FNTYPE is 0. */
1394 m68hc11_init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
, rtx libname
)
1398 z_replacement_completed
= 0;
1402 /* For a library call, we must find out the type of the return value.
1403 When the return value is bigger than 4 bytes, it is returned in
1404 memory. In that case, the first argument of the library call is a
1405 pointer to the memory location. Because the first argument is passed in
1406 register D, we have to identify this, so that the first function
1407 parameter is not passed in D either. */
1413 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1416 /* If the library ends in 'di' or in 'df', we assume it's
1417 returning some DImode or some DFmode which are 64-bit wide. */
1418 name
= XSTR (libname
, 0);
1419 len
= strlen (name
);
1421 && ((name
[len
- 2] == 'd'
1422 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1423 || (name
[len
- 3] == 'd'
1424 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1426 /* We are in. Mark the first parameter register as already used. */
1433 ret_type
= TREE_TYPE (fntype
);
1435 if (ret_type
&& aggregate_value_p (ret_type
, fntype
))
1442 /* Update the data in CUM to advance over an argument
1443 of mode MODE and data type TYPE.
1444 (TYPE is null for libcalls where that information may not be available.) */
1447 m68hc11_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1448 tree type
, int named ATTRIBUTE_UNUSED
)
1450 if (mode
!= BLKmode
)
1452 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1455 cum
->words
= GET_MODE_SIZE (mode
);
1459 cum
->words
+= GET_MODE_SIZE (mode
);
1460 if (cum
->words
<= HARD_REG_SIZE
)
1466 cum
->words
+= int_size_in_bytes (type
);
1471 /* Define where to put the arguments to a function.
1472 Value is zero to push the argument on the stack,
1473 or a hard register in which to store the argument.
1475 MODE is the argument's machine mode.
1476 TYPE is the data type of the argument (as a tree).
1477 This is null for libcalls where that information may
1479 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1480 the preceding args and about the function being called.
1481 NAMED is nonzero if this argument is a named parameter
1482 (otherwise it is an extra parameter matching an ellipsis). */
1485 m68hc11_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1486 tree type ATTRIBUTE_UNUSED
, int named ATTRIBUTE_UNUSED
)
1488 if (cum
->words
!= 0)
1493 if (mode
!= BLKmode
)
1495 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1496 return gen_rtx_REG (mode
, HARD_X_REGNUM
);
1498 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1502 return gen_rtx_REG (mode
, HARD_D_REGNUM
);
1507 /* If defined, a C expression which determines whether, and in which direction,
1508 to pad out an argument with extra space. The value should be of type
1509 `enum direction': either `upward' to pad above the argument,
1510 `downward' to pad below, or `none' to inhibit padding.
1512 Structures are stored left shifted in their argument slot. */
1514 m68hc11_function_arg_padding (enum machine_mode mode
, const_tree type
)
1516 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1519 /* Fall back to the default. */
1520 return DEFAULT_FUNCTION_ARG_PADDING (mode
, type
);
1524 /* Function prologue and epilogue. */
1526 /* Emit a move after the reload pass has completed. This is used to
1527 emit the prologue and epilogue. */
1529 emit_move_after_reload (rtx to
, rtx from
, rtx scratch
)
1533 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1535 insn
= emit_move_insn (to
, from
);
1539 emit_move_insn (scratch
, from
);
1540 insn
= emit_move_insn (to
, scratch
);
1543 /* Put a REG_INC note to tell the flow analysis that the instruction
1545 if (IS_STACK_PUSH (to
))
1546 add_reg_note (insn
, REG_INC
, XEXP (XEXP (to
, 0), 0));
1547 else if (IS_STACK_POP (from
))
1548 add_reg_note (insn
, REG_INC
, XEXP (XEXP (from
, 0), 0));
1550 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1551 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1552 The problem is that we are lying to gcc and use `txs' for x = sp
1553 (which is not really true because txs is really x = sp + 1). */
1554 else if (TARGET_M6811
&& SP_REG_P (from
))
1555 add_reg_note (insn
, REG_INC
, from
);
1559 m68hc11_total_frame_size (void)
1564 size
= get_frame_size ();
1565 if (current_function_interrupt
)
1567 size
+= 3 * HARD_REG_SIZE
;
1569 if (frame_pointer_needed
)
1570 size
+= HARD_REG_SIZE
;
1572 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1573 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1574 size
+= HARD_REG_SIZE
;
1580 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED
,
1581 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
1583 /* We catch the function epilogue generation to have a chance
1584 to clear the z_replacement_completed flag. */
1585 z_replacement_completed
= 0;
1589 expand_prologue (void)
1596 gcc_assert (reload_completed
== 1);
1598 size
= get_frame_size ();
1602 /* Generate specific prologue for interrupt handlers. */
1603 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1604 current_function_interrupt
= lookup_attribute ("interrupt",
1605 func_attr
) != NULL_TREE
;
1606 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1607 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1608 current_function_far
= 1;
1609 else if (lookup_attribute ("near", func_attr
) != NULL_TREE
)
1610 current_function_far
= 0;
1612 current_function_far
= (TARGET_LONG_CALLS
!= 0
1613 && !current_function_interrupt
1614 && !current_function_trap
);
1616 /* Get the scratch register to build the frame and push registers.
1617 If the first argument is a 32-bit quantity, the D+X registers
1618 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1619 For 68HC12, this scratch register is not used. */
1620 if (crtl
->args
.info
.nregs
== 2)
1625 /* Save current stack frame. */
1626 if (frame_pointer_needed
)
1627 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1629 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1630 Other soft registers in page0 need not to be saved because they
1631 will be restored by C functions. For a trap handler, we don't
1632 need to preserve these registers because this is a synchronous call. */
1633 if (current_function_interrupt
)
1635 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1636 emit_move_after_reload (stack_push_word
,
1637 gen_rtx_REG (HImode
, SOFT_Z_REGNUM
), scratch
);
1638 emit_move_after_reload (stack_push_word
,
1639 gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
),
1643 /* Allocate local variables. */
1644 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1646 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1647 stack_pointer_rtx
, GEN_INT (-size
)));
1649 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1653 insn
= gen_rtx_PARALLEL
1656 gen_rtx_SET (VOIDmode
,
1658 gen_rtx_PLUS (HImode
,
1661 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1668 /* Allocate by pushing scratch values. */
1669 for (i
= 2; i
<= size
; i
+= 2)
1670 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1673 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1674 stack_pointer_rtx
, constm1_rtx
));
1677 /* Create the frame pointer. */
1678 if (frame_pointer_needed
)
1679 emit_move_after_reload (hard_frame_pointer_rtx
,
1680 stack_pointer_rtx
, scratch
);
1682 /* Push any 2 byte pseudo hard registers that we need to save. */
1683 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1685 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1687 emit_move_after_reload (stack_push_word
,
1688 gen_rtx_REG (HImode
, regno
), scratch
);
1694 expand_epilogue (void)
1701 gcc_assert (reload_completed
== 1);
1703 size
= get_frame_size ();
1705 /* If we are returning a value in two registers, we have to preserve the
1706 X register and use the Y register to restore the stack and the saved
1707 registers. Otherwise, use X because it's faster (and smaller). */
1708 if (crtl
->return_rtx
== 0)
1710 else if (GET_CODE (crtl
->return_rtx
) == MEM
)
1711 return_size
= HARD_REG_SIZE
;
1713 return_size
= GET_MODE_SIZE (GET_MODE (crtl
->return_rtx
));
1715 if (return_size
> HARD_REG_SIZE
&& return_size
<= 2 * HARD_REG_SIZE
)
1720 /* Pop any 2 byte pseudo hard registers that we saved. */
1721 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1723 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1725 emit_move_after_reload (gen_rtx_REG (HImode
, regno
),
1726 stack_pop_word
, scratch
);
1730 /* de-allocate auto variables */
1731 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1733 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1734 stack_pointer_rtx
, GEN_INT (size
)));
1736 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1740 insn
= gen_rtx_PARALLEL
1743 gen_rtx_SET (VOIDmode
,
1745 gen_rtx_PLUS (HImode
,
1748 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1755 for (i
= 2; i
<= size
; i
+= 2)
1756 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1758 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1759 stack_pointer_rtx
, const1_rtx
));
1762 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1763 if (current_function_interrupt
)
1765 emit_move_after_reload (gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
),
1766 stack_pop_word
, scratch
);
1767 emit_move_after_reload (gen_rtx_REG (HImode
, SOFT_Z_REGNUM
),
1768 stack_pop_word
, scratch
);
1769 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1772 /* Restore previous frame pointer. */
1773 if (frame_pointer_needed
)
1774 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1776 /* If the trap handler returns some value, copy the value
1777 in D, X onto the stack so that the rti will pop the return value
1779 else if (current_function_trap
&& return_size
!= 0)
1781 rtx addr_reg
= stack_pointer_rtx
;
1785 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1788 emit_move_after_reload (gen_rtx_MEM (HImode
,
1789 gen_rtx_PLUS (HImode
, addr_reg
,
1790 const1_rtx
)), d_reg
, 0);
1791 if (return_size
> HARD_REG_SIZE
)
1792 emit_move_after_reload (gen_rtx_MEM (HImode
,
1793 gen_rtx_PLUS (HImode
, addr_reg
,
1794 GEN_INT (3))), ix_reg
, 0);
1797 emit_jump_insn (gen_return ());
1801 /* Low and High part extraction for 68HC11. These routines are
1802 similar to gen_lowpart and gen_highpart but they have been
1803 fixed to work for constants and 68HC11 specific registers. */
1806 m68hc11_gen_lowpart (enum machine_mode mode
, rtx x
)
1808 /* We assume that the low part of an auto-inc mode is the same with
1809 the mode changed and that the caller split the larger mode in the
1811 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1813 return gen_rtx_MEM (mode
, XEXP (x
, 0));
1816 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1817 floating-point constant. A CONST_DOUBLE is used whenever the
1818 constant requires more than one word in order to be adequately
1820 if (GET_CODE (x
) == CONST_DOUBLE
)
1824 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1828 if (GET_MODE (x
) == SFmode
)
1830 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1831 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1837 split_double (x
, &first
, &second
);
1841 return GEN_INT (l
[0]);
1843 return gen_int_mode (l
[0], HImode
);
1847 l
[0] = CONST_DOUBLE_LOW (x
);
1852 return GEN_INT (l
[0]);
1854 gcc_assert (GET_MODE (x
) == SFmode
);
1855 return gen_int_mode (l
[0], HImode
);
1861 if (mode
== QImode
&& D_REG_P (x
))
1862 return gen_rtx_REG (mode
, HARD_B_REGNUM
);
1864 /* gen_lowpart crashes when it is called with a SUBREG. */
1865 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1870 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1872 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1877 x
= gen_lowpart (mode
, x
);
1879 /* Return a different rtx to avoid to share it in several insns
1880 (when used by a split pattern). Sharing addresses within
1881 a MEM breaks the Z register replacement (and reloading). */
1882 if (GET_CODE (x
) == MEM
)
1888 m68hc11_gen_highpart (enum machine_mode mode
, rtx x
)
1890 /* We assume that the high part of an auto-inc mode is the same with
1891 the mode changed and that the caller split the larger mode in the
1893 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1895 return gen_rtx_MEM (mode
, XEXP (x
, 0));
1898 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1899 floating-point constant. A CONST_DOUBLE is used whenever the
1900 constant requires more than one word in order to be adequately
1902 if (GET_CODE (x
) == CONST_DOUBLE
)
1906 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1910 if (GET_MODE (x
) == SFmode
)
1912 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1913 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1919 split_double (x
, &first
, &second
);
1923 return GEN_INT (l
[1]);
1925 return gen_int_mode ((l
[1] >> 16), HImode
);
1929 l
[1] = CONST_DOUBLE_HIGH (x
);
1935 return GEN_INT (l
[1]);
1937 gcc_assert (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
);
1938 return gen_int_mode ((l
[0] >> 16), HImode
);
1943 if (GET_CODE (x
) == CONST_INT
)
1945 HOST_WIDE_INT val
= INTVAL (x
);
1949 return gen_int_mode (val
>> 8, QImode
);
1951 else if (mode
== HImode
)
1953 return gen_int_mode (val
>> 16, HImode
);
1955 else if (mode
== SImode
)
1957 return gen_int_mode (val
>> 32, SImode
);
1960 if (mode
== QImode
&& D_REG_P (x
))
1961 return gen_rtx_REG (mode
, HARD_A_REGNUM
);
1963 /* There is no way in GCC to represent the upper part of a word register.
1964 To obtain the 8-bit upper part of a soft register, we change the
1965 reg into a mem rtx. This is possible because they are physically
1966 located in memory. There is no offset because we are big-endian. */
1967 if (mode
== QImode
&& S_REG_P (x
))
1971 /* Avoid the '*' for direct addressing mode when this
1972 addressing mode is disabled. */
1973 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1974 return gen_rtx_MEM (QImode
,
1975 gen_rtx_SYMBOL_REF (Pmode
,
1976 ®_names
[REGNO (x
)][pos
]));
1979 /* gen_highpart crashes when it is called with a SUBREG. */
1980 switch (GET_CODE (x
))
1983 return gen_rtx_SUBREG (mode
, XEXP (x
, 0), XINT (x
, 1));
1985 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
1986 return gen_rtx_REG (mode
, REGNO (x
));
1988 return gen_rtx_SUBREG (mode
, x
, 0);
1990 x
= change_address (x
, mode
, 0);
1992 /* Return a different rtx to avoid to share it in several insns
1993 (when used by a split pattern). Sharing addresses within
1994 a MEM breaks the Z register replacement (and reloading). */
1995 if (GET_CODE (x
) == MEM
)
2005 /* Obscure register manipulation. */
2007 /* Finds backward in the instructions to see if register 'reg' is
2008 dead. This is used when generating code to see if we can use 'reg'
2009 as a scratch register. This allows us to choose a better generation
2010 of code when we know that some register dies or can be clobbered. */
2013 dead_register_here (rtx x
, rtx reg
)
2019 x_reg
= gen_rtx_REG (SImode
, HARD_X_REGNUM
);
2023 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2030 if (GET_CODE (body
) == CALL_INSN
)
2032 if (GET_CODE (body
) == JUMP_INSN
)
2035 if (GET_CODE (body
) == SET
)
2037 rtx dst
= XEXP (body
, 0);
2039 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2041 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2044 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2047 else if (reg_mentioned_p (reg
, p
)
2048 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2052 /* Scan forward to see if the register is set in some insns and never
2054 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2058 if (GET_CODE (p
) == CODE_LABEL
2059 || GET_CODE (p
) == JUMP_INSN
2060 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2063 if (GET_CODE (p
) != INSN
)
2067 if (GET_CODE (body
) == SET
)
2069 rtx src
= XEXP (body
, 1);
2070 rtx dst
= XEXP (body
, 0);
2072 if (GET_CODE (dst
) == REG
2073 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2077 /* Register is used (may be in source or in dest). */
2078 if (reg_mentioned_p (reg
, p
)
2079 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2080 && reg_mentioned_p (x_reg
, p
)))
2083 return p
== 0 ? 1 : 0;
2087 /* Code generation operations called from machine description file. */
2089 /* Print the name of register 'regno' in the assembly file. */
2091 asm_print_register (FILE *file
, int regno
)
2093 const char *name
= reg_names
[regno
];
2095 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2098 fprintf (file
, "%s", name
);
2101 /* A C compound statement to output to stdio stream STREAM the
2102 assembler syntax for an instruction operand X. X is an RTL
2105 CODE is a value that can be used to specify one of several ways
2106 of printing the operand. It is used when identical operands
2107 must be printed differently depending on the context. CODE
2108 comes from the `%' specification that was used to request
2109 printing of the operand. If the specification was just `%DIGIT'
2110 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2111 is the ASCII code for LTR.
2113 If X is a register, this macro should print the register's name.
2114 The names can be found in an array `reg_names' whose type is
2115 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2117 When the machine description has a specification `%PUNCT' (a `%'
2118 followed by a punctuation character), this macro is called with
2119 a null pointer for X and the punctuation character for CODE.
2121 The M68HC11 specific codes are:
2123 'b' for the low part of the operand.
2124 'h' for the high part of the operand
2125 The 'b' or 'h' modifiers have no effect if the operand has
2126 the QImode and is not a S_REG_P (soft register). If the
2127 operand is a hard register, these two modifiers have no effect.
2128 't' generate the temporary scratch register. The operand is
2130 'T' generate the low-part temporary scratch register. The operand is
2134 m68hc11_print_operand (FILE *file
, rtx op
, int letter
)
2138 asm_print_register (file
, SOFT_TMP_REGNUM
);
2141 else if (letter
== 'T')
2143 asm_print_register (file
, SOFT_TMP_REGNUM
);
2144 fprintf (file
, "+1");
2147 else if (letter
== '#')
2149 asm_fprintf (file
, "%I");
2152 if (GET_CODE (op
) == REG
)
2154 if (letter
== 'b' && S_REG_P (op
))
2156 asm_print_register (file
, REGNO (op
));
2157 fprintf (file
, "+1");
2159 else if (letter
== 'b' && D_REG_P (op
))
2161 asm_print_register (file
, HARD_B_REGNUM
);
2165 asm_print_register (file
, REGNO (op
));
2170 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2173 asm_fprintf (file
, "%I%%lo(");
2175 asm_fprintf (file
, "%I%%hi(");
2177 output_addr_const (file
, op
);
2178 fprintf (file
, ")");
2182 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2183 are specified. If we already have a QImode, there is nothing to do. */
2184 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2188 op
= m68hc11_gen_lowpart (QImode
, op
);
2190 else if (letter
== 'h')
2192 op
= m68hc11_gen_highpart (QImode
, op
);
2196 if (GET_CODE (op
) == MEM
)
2198 rtx base
= XEXP (op
, 0);
2199 switch (GET_CODE (base
))
2202 gcc_assert (TARGET_M6812
);
2203 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2204 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2208 gcc_assert (TARGET_M6812
);
2209 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2210 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2211 fprintf (file
, "-");
2215 gcc_assert (TARGET_M6812
);
2216 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2217 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2218 fprintf (file
, "+");
2222 gcc_assert (TARGET_M6812
);
2223 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2224 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2228 gcc_assert (TARGET_M6812
);
2229 fprintf (file
, "[");
2230 print_operand_address (file
, XEXP (base
, 0));
2231 fprintf (file
, "]");
2235 if (m68hc11_page0_symbol_p (base
))
2236 fprintf (file
, "*");
2238 output_address (base
);
2242 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2247 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2248 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2249 asm_fprintf (file
, "%I0x%lx", l
);
2251 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == DFmode
)
2255 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2256 sizeof (dstr
), 0, 1);
2257 asm_fprintf (file
, "%I0r%s", dstr
);
2261 int need_parenthesize
= 0;
2264 asm_fprintf (file
, "%I");
2266 need_parenthesize
= must_parenthesize (op
);
2268 if (need_parenthesize
)
2269 fprintf (file
, "(");
2271 output_addr_const (file
, op
);
2272 if (need_parenthesize
)
2273 fprintf (file
, ")");
2277 /* Returns true if the operand 'op' must be printed with parenthesis
2278 around it. This must be done only if there is a symbol whose name
2279 is a processor register. */
2281 must_parenthesize (rtx op
)
2285 switch (GET_CODE (op
))
2288 name
= XSTR (op
, 0);
2289 /* Avoid a conflict between symbol name and a possible
2291 return (strcasecmp (name
, "a") == 0
2292 || strcasecmp (name
, "b") == 0
2293 || strcasecmp (name
, "d") == 0
2294 || strcasecmp (name
, "x") == 0
2295 || strcasecmp (name
, "y") == 0
2296 || strcasecmp (name
, "ix") == 0
2297 || strcasecmp (name
, "iy") == 0
2298 || strcasecmp (name
, "pc") == 0
2299 || strcasecmp (name
, "sp") == 0
2300 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2304 return must_parenthesize (XEXP (op
, 0))
2305 || must_parenthesize (XEXP (op
, 1));
2311 return must_parenthesize (XEXP (op
, 0));
2322 /* A C compound statement to output to stdio stream STREAM the
2323 assembler syntax for an instruction operand that is a memory
2324 reference whose address is ADDR. ADDR is an RTL expression. */
2327 m68hc11_print_operand_address (FILE *file
, rtx addr
)
2331 int need_parenthesis
= 0;
2333 switch (GET_CODE (addr
))
2336 gcc_assert (REG_P (addr
) && REG_OK_FOR_BASE_STRICT_P (addr
));
2338 fprintf (file
, "0,");
2339 asm_print_register (file
, REGNO (addr
));
2343 base
= XEXP (addr
, 0);
2344 switch (GET_CODE (base
))
2347 gcc_assert (TARGET_M6812
);
2348 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2349 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2353 gcc_assert (TARGET_M6812
);
2354 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2355 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2356 fprintf (file
, "-");
2360 gcc_assert (TARGET_M6812
);
2361 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2362 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2363 fprintf (file
, "+");
2367 gcc_assert (TARGET_M6812
);
2368 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2369 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2373 need_parenthesis
= must_parenthesize (base
);
2374 if (need_parenthesis
)
2375 fprintf (file
, "(");
2377 output_addr_const (file
, base
);
2378 if (need_parenthesis
)
2379 fprintf (file
, ")");
2385 base
= XEXP (addr
, 0);
2386 offset
= XEXP (addr
, 1);
2387 if (!G_REG_P (base
) && G_REG_P (offset
))
2389 base
= XEXP (addr
, 1);
2390 offset
= XEXP (addr
, 0);
2392 if (CONSTANT_ADDRESS_P (base
))
2394 need_parenthesis
= must_parenthesize (addr
);
2396 gcc_assert (CONSTANT_ADDRESS_P (offset
));
2397 if (need_parenthesis
)
2398 fprintf (file
, "(");
2400 output_addr_const (file
, base
);
2401 fprintf (file
, "+");
2402 output_addr_const (file
, offset
);
2403 if (need_parenthesis
)
2404 fprintf (file
, ")");
2408 gcc_assert (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
));
2411 gcc_assert (TARGET_M6812
);
2412 asm_print_register (file
, REGNO (offset
));
2413 fprintf (file
, ",");
2414 asm_print_register (file
, REGNO (base
));
2418 need_parenthesis
= must_parenthesize (offset
);
2419 if (need_parenthesis
)
2420 fprintf (file
, "(");
2422 output_addr_const (file
, offset
);
2423 if (need_parenthesis
)
2424 fprintf (file
, ")");
2425 fprintf (file
, ",");
2426 asm_print_register (file
, REGNO (base
));
2432 if (GET_CODE (addr
) == CONST_INT
2433 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2435 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2439 need_parenthesis
= must_parenthesize (addr
);
2440 if (need_parenthesis
)
2441 fprintf (file
, "(");
2443 output_addr_const (file
, addr
);
2444 if (need_parenthesis
)
2445 fprintf (file
, ")");
2452 /* Splitting of some instructions. */
2455 m68hc11_expand_compare (enum rtx_code code
, rtx op0
, rtx op1
)
2459 gcc_assert (GET_MODE_CLASS (GET_MODE (op0
)) != MODE_FLOAT
);
2460 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2461 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2462 ret
= gen_rtx_fmt_ee (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2468 m68hc11_expand_compare_and_branch (enum rtx_code code
, rtx op0
, rtx op1
,
2473 switch (GET_MODE (op0
))
2477 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2478 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2479 gen_rtx_LABEL_REF (VOIDmode
, label
),
2481 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2485 /* SCz: from i386.c */
2488 /* Don't expand the comparison early, so that we get better code
2489 when jump or whoever decides to reverse the comparison. */
2494 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2495 &m68hc11_compare_op1
);
2497 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2498 m68hc11_compare_op0
, m68hc11_compare_op1
);
2499 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2500 gen_rtx_LABEL_REF (VOIDmode
, label
),
2502 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2504 use_fcomi
= ix86_use_fcomi_compare (code
);
2505 vec
= rtvec_alloc (3 + !use_fcomi
);
2506 RTVEC_ELT (vec
, 0) = tmp
;
2508 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2510 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2513 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2515 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2521 /* Expand SImode branch into multiple compare+branch. */
2523 rtx lo
[2], hi
[2], label2
;
2524 enum rtx_code code1
, code2
, code3
;
2526 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2531 code
= swap_condition (code
);
2533 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2534 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2535 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2536 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2538 /* Otherwise, if we are doing less-than, op1 is a constant and the
2539 low word is zero, then we can just examine the high word. */
2541 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2542 && (code
== LT
|| code
== LTU
))
2544 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2548 /* Otherwise, we need two or three jumps. */
2550 label2
= gen_label_rtx ();
2553 code2
= swap_condition (code
);
2554 code3
= unsigned_condition (code
);
2595 * if (hi(a) < hi(b)) goto true;
2596 * if (hi(a) > hi(b)) goto false;
2597 * if (lo(a) < lo(b)) goto true;
2600 if (code1
!= UNKNOWN
)
2601 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2602 if (code2
!= UNKNOWN
)
2603 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2605 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2607 if (code2
!= UNKNOWN
)
2608 emit_label (label2
);
2618 /* Return the increment/decrement mode of a MEM if it is such.
2619 Return CONST if it is anything else. */
2621 autoinc_mode (rtx x
)
2623 if (GET_CODE (x
) != MEM
)
2627 if (GET_CODE (x
) == PRE_INC
2628 || GET_CODE (x
) == PRE_DEC
2629 || GET_CODE (x
) == POST_INC
2630 || GET_CODE (x
) == POST_DEC
)
2631 return GET_CODE (x
);
2637 m68hc11_make_autoinc_notes (rtx
*x
, void *data
)
2641 switch (GET_CODE (*x
))
2648 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2657 /* Split a DI, SI or HI move into several smaller move operations.
2658 The scratch register 'scratch' is used as a temporary to load
2659 store intermediate values. It must be a hard register. */
2661 m68hc11_split_move (rtx to
, rtx from
, rtx scratch
)
2663 rtx low_to
, low_from
;
2664 rtx high_to
, high_from
;
2666 enum machine_mode mode
;
2668 int autoinc_from
= autoinc_mode (from
);
2669 int autoinc_to
= autoinc_mode (to
);
2671 mode
= GET_MODE (to
);
2673 /* If the TO and FROM contain autoinc modes that are not compatible
2674 together (one pop and the other a push), we must change one to
2675 an offsetable operand and generate an appropriate add at the end. */
2676 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2681 /* The source uses an autoinc mode which is not compatible with
2682 a split (this would result in a word swap). */
2683 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2685 code
= GET_CODE (XEXP (from
, 0));
2686 reg
= XEXP (XEXP (from
, 0), 0);
2687 offset
= GET_MODE_SIZE (GET_MODE (from
));
2688 if (code
== POST_DEC
)
2691 if (code
== PRE_INC
)
2692 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2694 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2695 if (code
== POST_DEC
)
2696 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2700 /* Likewise for destination. */
2701 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2703 code
= GET_CODE (XEXP (to
, 0));
2704 reg
= XEXP (XEXP (to
, 0), 0);
2705 offset
= GET_MODE_SIZE (GET_MODE (to
));
2706 if (code
== POST_DEC
)
2709 if (code
== PRE_INC
)
2710 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2712 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2713 if (code
== POST_DEC
)
2714 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2718 /* The source and destination auto increment modes must be compatible
2719 with each other: same direction. */
2720 if ((autoinc_to
!= autoinc_from
2721 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2722 /* The destination address register must not be used within
2723 the source operand because the source address would change
2724 while doing the copy. */
2725 || (autoinc_to
!= CONST
2726 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2727 && !IS_STACK_PUSH (to
)))
2729 /* Must change the destination. */
2730 code
= GET_CODE (XEXP (to
, 0));
2731 reg
= XEXP (XEXP (to
, 0), 0);
2732 offset
= GET_MODE_SIZE (GET_MODE (to
));
2733 if (code
== PRE_DEC
|| code
== POST_DEC
)
2736 if (code
== PRE_DEC
|| code
== PRE_INC
)
2737 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2738 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2739 if (code
== POST_DEC
|| code
== POST_INC
)
2740 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2745 /* Likewise, the source address register must not be used within
2746 the destination operand. */
2747 if (autoinc_from
!= CONST
2748 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2749 && !IS_STACK_PUSH (to
))
2751 /* Must change the source. */
2752 code
= GET_CODE (XEXP (from
, 0));
2753 reg
= XEXP (XEXP (from
, 0), 0);
2754 offset
= GET_MODE_SIZE (GET_MODE (from
));
2755 if (code
== PRE_DEC
|| code
== POST_DEC
)
2758 if (code
== PRE_DEC
|| code
== PRE_INC
)
2759 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2760 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2761 if (code
== POST_DEC
|| code
== POST_INC
)
2762 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2768 if (GET_MODE_SIZE (mode
) == 8)
2770 else if (GET_MODE_SIZE (mode
) == 4)
2776 && IS_STACK_PUSH (to
)
2777 && reg_mentioned_p (gen_rtx_REG (HImode
, HARD_SP_REGNUM
), from
))
2783 else if (mode
== HImode
)
2791 low_to
= m68hc11_gen_lowpart (mode
, to
);
2792 high_to
= m68hc11_gen_highpart (mode
, to
);
2794 low_from
= m68hc11_gen_lowpart (mode
, from
);
2795 high_from
= m68hc11_gen_highpart (mode
, from
);
2799 high_from
= adjust_address (high_from
, mode
, offset
);
2800 low_from
= high_from
;
2803 /* When copying with a POST_INC mode, we must copy the
2804 high part and then the low part to guarantee a correct
2807 && GET_MODE_SIZE (mode
) >= 2
2808 && autoinc_from
!= autoinc_to
2809 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2818 low_from
= high_from
;
2823 m68hc11_split_move (low_to
, low_from
, scratch
);
2824 m68hc11_split_move (high_to
, high_from
, scratch
);
2826 else if (H_REG_P (to
) || H_REG_P (from
)
2827 || (low_from
== const0_rtx
2828 && high_from
== const0_rtx
2829 && ! push_operand (to
, GET_MODE (to
))
2830 && ! H_REG_P (scratch
))
2832 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2833 || m68hc11_small_indexed_indirect_p (from
,
2835 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2836 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2838 insn
= emit_move_insn (low_to
, low_from
);
2839 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2841 insn
= emit_move_insn (high_to
, high_from
);
2842 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2846 insn
= emit_move_insn (scratch
, low_from
);
2847 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2848 insn
= emit_move_insn (low_to
, scratch
);
2849 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2851 insn
= emit_move_insn (scratch
, high_from
);
2852 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2853 insn
= emit_move_insn (high_to
, scratch
);
2854 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2859 simplify_logical (enum machine_mode mode
, int code
, rtx operand
, rtx
*result
)
2865 if (GET_CODE (operand
) != CONST_INT
)
2873 val
= INTVAL (operand
);
2877 if ((val
& mask
) == 0)
2879 if ((val
& mask
) == mask
)
2880 *result
= constm1_rtx
;
2884 if ((val
& mask
) == 0)
2885 *result
= const0_rtx
;
2886 if ((val
& mask
) == mask
)
2891 if ((val
& mask
) == 0)
2899 m68hc11_emit_logical (enum machine_mode mode
, enum rtx_code code
, rtx
*operands
)
2904 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2905 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2907 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2908 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2910 if (result
&& GET_CODE (result
) == CONST_INT
)
2912 if (!H_REG_P (operands
[0]) && operands
[3]
2913 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2915 emit_move_insn (operands
[3], result
);
2916 emit_move_insn (operands
[0], operands
[3]);
2920 emit_move_insn (operands
[0], result
);
2923 else if (operands
[1] != 0 && operands
[2] != 0)
2927 if (!H_REG_P (operands
[0]) && operands
[3])
2929 emit_move_insn (operands
[3], operands
[1]);
2930 emit_insn (gen_rtx_SET (mode
,
2932 gen_rtx_fmt_ee (code
, mode
,
2933 operands
[3], operands
[2])));
2934 insn
= emit_move_insn (operands
[0], operands
[3]);
2938 insn
= emit_insn (gen_rtx_SET (mode
,
2940 gen_rtx_fmt_ee (code
, mode
,
2946 /* The logical operation is similar to a copy. */
2951 if (GET_CODE (operands
[1]) == CONST_INT
)
2956 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
2958 emit_move_insn (operands
[3], src
);
2959 emit_move_insn (operands
[0], operands
[3]);
2963 emit_move_insn (operands
[0], src
);
2969 m68hc11_split_logical (enum machine_mode mode
, enum rtx_code code
,
2975 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
2976 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
2977 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
2979 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
2980 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
2981 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
2983 low
[3] = operands
[3];
2984 high
[3] = operands
[3];
2987 m68hc11_split_logical (HImode
, code
, low
);
2988 m68hc11_split_logical (HImode
, code
, high
);
2992 m68hc11_emit_logical (mode
, code
, low
);
2993 m68hc11_emit_logical (mode
, code
, high
);
2997 /* Code generation. */
3000 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED
, rtx operands
[])
3002 /* We have to be careful with the cc_status. An address register swap
3003 is generated for some comparison. The comparison is made with D
3004 but the branch really uses the address register. See the split
3005 pattern for compare. The xgdx/xgdy preserve the flags but after
3006 the exchange, the flags will reflect to the value of X and not D.
3007 Tell this by setting the cc_status according to the cc_prev_status. */
3008 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3010 if (cc_prev_status
.value1
!= 0
3011 && (D_REG_P (cc_prev_status
.value1
)
3012 || X_REG_P (cc_prev_status
.value1
)))
3014 cc_status
= cc_prev_status
;
3015 if (D_REG_P (cc_status
.value1
))
3016 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3019 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3025 output_asm_insn ("xgdx", operands
);
3029 if (cc_prev_status
.value1
!= 0
3030 && (D_REG_P (cc_prev_status
.value1
)
3031 || Y_REG_P (cc_prev_status
.value1
)))
3033 cc_status
= cc_prev_status
;
3034 if (D_REG_P (cc_status
.value1
))
3035 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3038 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3044 output_asm_insn ("xgdy", operands
);
3048 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3049 This is used to decide whether a move that set flags should be used
3052 next_insn_test_reg (rtx insn
, rtx reg
)
3056 insn
= next_nonnote_insn (insn
);
3057 if (GET_CODE (insn
) != INSN
)
3060 body
= PATTERN (insn
);
3061 if (sets_cc0_p (body
) != 1)
3064 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3070 /* Generate the code to move a 16-bit operand into another one. */
3073 m68hc11_gen_movhi (rtx insn
, rtx
*operands
)
3077 /* Move a register or memory to the same location.
3078 This is possible because such insn can appear
3079 in a non-optimizing mode. */
3080 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3082 cc_status
= cc_prev_status
;
3088 rtx from
= operands
[1];
3089 rtx to
= operands
[0];
3091 if (IS_STACK_PUSH (to
) && H_REG_P (from
))
3093 cc_status
= cc_prev_status
;
3094 switch (REGNO (from
))
3099 output_asm_insn ("psh%1", operands
);
3101 case HARD_SP_REGNUM
:
3102 output_asm_insn ("sts\t2,-sp", operands
);
3109 if (IS_STACK_POP (from
) && H_REG_P (to
))
3111 cc_status
= cc_prev_status
;
3117 output_asm_insn ("pul%0", operands
);
3124 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3126 m68hc11_notice_keep_cc (operands
[0]);
3127 output_asm_insn ("tfr\t%1,%0", operands
);
3129 else if (H_REG_P (operands
[0]))
3131 if (SP_REG_P (operands
[0]))
3132 output_asm_insn ("lds\t%1", operands
);
3134 output_asm_insn ("ld%0\t%1", operands
);
3136 else if (H_REG_P (operands
[1]))
3138 if (SP_REG_P (operands
[1]))
3139 output_asm_insn ("sts\t%0", operands
);
3141 output_asm_insn ("st%1\t%0", operands
);
3144 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3145 instruction. We have to use a scratch register as temporary location.
3146 Trying to use a specific pattern or constrain failed. */
3147 else if (GET_CODE (to
) == MEM
&& GET_CODE (XEXP (to
, 0)) == MEM
)
3154 if (dead_register_here (insn
, d_reg
))
3156 else if (dead_register_here (insn
, ix_reg
))
3158 else if (dead_register_here (insn
, iy_reg
))
3164 output_asm_insn ("psh%3", ops
);
3169 output_asm_insn ("ld%1\t%2", ops
);
3170 output_asm_insn ("st%1\t%0", ops
);
3172 output_asm_insn ("pul%3", ops
);
3175 /* Use movw for non-null constants or when we are clearing
3176 a volatile memory reference. However, this is possible
3177 only if the memory reference has a small offset or is an
3178 absolute address. */
3179 else if (GET_CODE (from
) == CONST_INT
3180 && INTVAL (from
) == 0
3181 && (MEM_VOLATILE_P (to
) == 0
3182 || m68hc11_small_indexed_indirect_p (to
, HImode
) == 0))
3184 output_asm_insn ("clr\t%h0", operands
);
3185 output_asm_insn ("clr\t%b0", operands
);
3189 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3190 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3191 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3192 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3198 ops
[0] = operands
[2];
3201 m68hc11_gen_movhi (insn
, ops
);
3203 ops
[1] = operands
[2];
3204 m68hc11_gen_movhi (insn
, ops
);
3209 /* !!!! SCz wrong here. */
3210 fatal_insn ("move insn not handled", insn
);
3215 m68hc11_notice_keep_cc (operands
[0]);
3216 output_asm_insn ("movw\t%1,%0", operands
);
3222 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3224 cc_status
= cc_prev_status
;
3225 switch (REGNO (operands
[0]))
3229 output_asm_insn ("pul%0", operands
);
3232 output_asm_insn ("pula", operands
);
3233 output_asm_insn ("pulb", operands
);
3240 /* Some moves to a hard register are special. Not all of them
3241 are really supported and we have to use a temporary
3242 location to provide them (either the stack of a temp var). */
3243 if (H_REG_P (operands
[0]))
3245 switch (REGNO (operands
[0]))
3248 if (X_REG_P (operands
[1]))
3250 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3252 m68hc11_output_swap (insn
, operands
);
3254 else if (next_insn_test_reg (insn
, operands
[0]))
3256 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3260 m68hc11_notice_keep_cc (operands
[0]);
3261 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3264 else if (Y_REG_P (operands
[1]))
3266 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3268 m68hc11_output_swap (insn
, operands
);
3272 /* %t means *ZTMP scratch register. */
3273 output_asm_insn ("sty\t%t1", operands
);
3274 output_asm_insn ("ldd\t%t1", operands
);
3277 else if (SP_REG_P (operands
[1]))
3282 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3283 output_asm_insn ("xgdx", operands
);
3284 output_asm_insn ("tsx", operands
);
3285 output_asm_insn ("xgdx", operands
);
3287 else if (IS_STACK_POP (operands
[1]))
3289 output_asm_insn ("pula\n\tpulb", operands
);
3291 else if (GET_CODE (operands
[1]) == CONST_INT
3292 && INTVAL (operands
[1]) == 0)
3294 output_asm_insn ("clra\n\tclrb", operands
);
3298 output_asm_insn ("ldd\t%1", operands
);
3303 if (D_REG_P (operands
[1]))
3305 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3307 m68hc11_output_swap (insn
, operands
);
3309 else if (next_insn_test_reg (insn
, operands
[0]))
3311 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3315 m68hc11_notice_keep_cc (operands
[0]);
3316 output_asm_insn ("pshb", operands
);
3317 output_asm_insn ("psha", operands
);
3318 output_asm_insn ("pulx", operands
);
3321 else if (Y_REG_P (operands
[1]))
3323 /* When both D and Y are dead, use the sequence xgdy, xgdx
3324 to move Y into X. The D and Y registers are modified. */
3325 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3326 && dead_register_here (insn
, d_reg
))
3328 output_asm_insn ("xgdy", operands
);
3329 output_asm_insn ("xgdx", operands
);
3332 else if (!optimize_size
)
3334 output_asm_insn ("sty\t%t1", operands
);
3335 output_asm_insn ("ldx\t%t1", operands
);
3340 output_asm_insn ("pshy", operands
);
3341 output_asm_insn ("pulx", operands
);
3344 else if (SP_REG_P (operands
[1]))
3346 /* tsx, tsy preserve the flags */
3347 cc_status
= cc_prev_status
;
3348 output_asm_insn ("tsx", operands
);
3352 output_asm_insn ("ldx\t%1", operands
);
3357 if (D_REG_P (operands
[1]))
3359 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3361 m68hc11_output_swap (insn
, operands
);
3365 output_asm_insn ("std\t%t1", operands
);
3366 output_asm_insn ("ldy\t%t1", operands
);
3369 else if (X_REG_P (operands
[1]))
3371 /* When both D and X are dead, use the sequence xgdx, xgdy
3372 to move X into Y. The D and X registers are modified. */
3373 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3374 && dead_register_here (insn
, d_reg
))
3376 output_asm_insn ("xgdx", operands
);
3377 output_asm_insn ("xgdy", operands
);
3380 else if (!optimize_size
)
3382 output_asm_insn ("stx\t%t1", operands
);
3383 output_asm_insn ("ldy\t%t1", operands
);
3388 output_asm_insn ("pshx", operands
);
3389 output_asm_insn ("puly", operands
);
3392 else if (SP_REG_P (operands
[1]))
3394 /* tsx, tsy preserve the flags */
3395 cc_status
= cc_prev_status
;
3396 output_asm_insn ("tsy", operands
);
3400 output_asm_insn ("ldy\t%1", operands
);
3404 case HARD_SP_REGNUM
:
3405 if (D_REG_P (operands
[1]))
3407 m68hc11_notice_keep_cc (operands
[0]);
3408 output_asm_insn ("xgdx", operands
);
3409 output_asm_insn ("txs", operands
);
3410 output_asm_insn ("xgdx", operands
);
3412 else if (X_REG_P (operands
[1]))
3414 /* tys, txs preserve the flags */
3415 cc_status
= cc_prev_status
;
3416 output_asm_insn ("txs", operands
);
3418 else if (Y_REG_P (operands
[1]))
3420 /* tys, txs preserve the flags */
3421 cc_status
= cc_prev_status
;
3422 output_asm_insn ("tys", operands
);
3426 /* lds sets the flags but the des does not. */
3428 output_asm_insn ("lds\t%1", operands
);
3429 output_asm_insn ("des", operands
);
3434 fatal_insn ("invalid register in the move instruction", insn
);
3439 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3440 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3442 output_asm_insn ("sts\t%0", operands
);
3446 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3448 cc_status
= cc_prev_status
;
3449 switch (REGNO (operands
[1]))
3453 output_asm_insn ("psh%1", operands
);
3456 output_asm_insn ("pshb", operands
);
3457 output_asm_insn ("psha", operands
);
3465 /* Operand 1 must be a hard register. */
3466 if (!H_REG_P (operands
[1]))
3468 fatal_insn ("invalid operand in the instruction", insn
);
3471 reg
= REGNO (operands
[1]);
3475 output_asm_insn ("std\t%0", operands
);
3479 output_asm_insn ("stx\t%0", operands
);
3483 output_asm_insn ("sty\t%0", operands
);
3486 case HARD_SP_REGNUM
:
3490 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3492 output_asm_insn ("pshx", operands
);
3493 output_asm_insn ("tsx", operands
);
3494 output_asm_insn ("inx", operands
);
3495 output_asm_insn ("inx", operands
);
3496 output_asm_insn ("stx\t%0", operands
);
3497 output_asm_insn ("pulx", operands
);
3500 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3502 output_asm_insn ("sty\t%t0", operands
);
3503 output_asm_insn ("tsy", operands
);
3504 output_asm_insn ("sty\t%0", operands
);
3505 output_asm_insn ("ldy\t%t0", operands
);
3509 output_asm_insn ("stx\t%t0", operands
);
3510 output_asm_insn ("tsx", operands
);
3511 output_asm_insn ("stx\t%0", operands
);
3512 output_asm_insn ("ldx\t%t0", operands
);
3518 fatal_insn ("invalid register in the move instruction", insn
);
3524 m68hc11_gen_movqi (rtx insn
, rtx
*operands
)
3526 /* Move a register or memory to the same location.
3527 This is possible because such insn can appear
3528 in a non-optimizing mode. */
3529 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3531 cc_status
= cc_prev_status
;
3538 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3540 m68hc11_notice_keep_cc (operands
[0]);
3541 output_asm_insn ("tfr\t%1,%0", operands
);
3543 else if (H_REG_P (operands
[0]))
3545 if (IS_STACK_POP (operands
[1]))
3546 output_asm_insn ("pul%b0", operands
);
3547 else if (Q_REG_P (operands
[0]))
3548 output_asm_insn ("lda%0\t%b1", operands
);
3549 else if (D_REG_P (operands
[0]))
3550 output_asm_insn ("ldab\t%b1", operands
);
3554 else if (H_REG_P (operands
[1]))
3556 if (Q_REG_P (operands
[1]))
3557 output_asm_insn ("sta%1\t%b0", operands
);
3558 else if (D_REG_P (operands
[1]))
3559 output_asm_insn ("stab\t%b0", operands
);
3565 rtx from
= operands
[1];
3566 rtx to
= operands
[0];
3568 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3569 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3570 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3571 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3577 ops
[0] = operands
[2];
3580 m68hc11_gen_movqi (insn
, ops
);
3582 ops
[1] = operands
[2];
3583 m68hc11_gen_movqi (insn
, ops
);
3587 /* !!!! SCz wrong here. */
3588 fatal_insn ("move insn not handled", insn
);
3593 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3595 output_asm_insn ("clr\t%b0", operands
);
3599 m68hc11_notice_keep_cc (operands
[0]);
3600 output_asm_insn ("movb\t%b1,%b0", operands
);
3608 if (H_REG_P (operands
[0]))
3610 switch (REGNO (operands
[0]))
3614 if (X_REG_P (operands
[1]))
3616 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3618 m68hc11_output_swap (insn
, operands
);
3622 output_asm_insn ("stx\t%t1", operands
);
3623 output_asm_insn ("ldab\t%T0", operands
);
3626 else if (Y_REG_P (operands
[1]))
3628 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3630 m68hc11_output_swap (insn
, operands
);
3634 output_asm_insn ("sty\t%t1", operands
);
3635 output_asm_insn ("ldab\t%T0", operands
);
3638 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3639 && !DA_REG_P (operands
[1]))
3641 output_asm_insn ("ldab\t%b1", operands
);
3643 else if (DA_REG_P (operands
[1]))
3645 output_asm_insn ("tab", operands
);
3649 cc_status
= cc_prev_status
;
3655 if (X_REG_P (operands
[1]))
3657 output_asm_insn ("stx\t%t1", operands
);
3658 output_asm_insn ("ldaa\t%T0", operands
);
3660 else if (Y_REG_P (operands
[1]))
3662 output_asm_insn ("sty\t%t1", operands
);
3663 output_asm_insn ("ldaa\t%T0", operands
);
3665 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3666 && !DA_REG_P (operands
[1]))
3668 output_asm_insn ("ldaa\t%b1", operands
);
3670 else if (!DA_REG_P (operands
[1]))
3672 output_asm_insn ("tba", operands
);
3676 cc_status
= cc_prev_status
;
3681 if (D_REG_P (operands
[1]))
3683 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3685 m68hc11_output_swap (insn
, operands
);
3689 output_asm_insn ("stab\t%T1", operands
);
3690 output_asm_insn ("ldx\t%t1", operands
);
3694 else if (Y_REG_P (operands
[1]))
3696 output_asm_insn ("sty\t%t0", operands
);
3697 output_asm_insn ("ldx\t%t0", operands
);
3699 else if (GET_CODE (operands
[1]) == CONST_INT
)
3701 output_asm_insn ("ldx\t%1", operands
);
3703 else if (dead_register_here (insn
, d_reg
))
3705 output_asm_insn ("ldab\t%b1", operands
);
3706 output_asm_insn ("xgdx", operands
);
3708 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3710 output_asm_insn ("xgdx", operands
);
3711 output_asm_insn ("ldab\t%b1", operands
);
3712 output_asm_insn ("xgdx", operands
);
3716 output_asm_insn ("pshb", operands
);
3717 output_asm_insn ("ldab\t%b1", operands
);
3718 output_asm_insn ("stab\t%T1", operands
);
3719 output_asm_insn ("ldx\t%t1", operands
);
3720 output_asm_insn ("pulb", operands
);
3726 if (D_REG_P (operands
[1]))
3728 output_asm_insn ("stab\t%T1", operands
);
3729 output_asm_insn ("ldy\t%t1", operands
);
3732 else if (X_REG_P (operands
[1]))
3734 output_asm_insn ("stx\t%t1", operands
);
3735 output_asm_insn ("ldy\t%t1", operands
);
3738 else if (GET_CODE (operands
[1]) == CONST_INT
)
3740 output_asm_insn ("ldy\t%1", operands
);
3742 else if (dead_register_here (insn
, d_reg
))
3744 output_asm_insn ("ldab\t%b1", operands
);
3745 output_asm_insn ("xgdy", operands
);
3747 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3749 output_asm_insn ("xgdy", operands
);
3750 output_asm_insn ("ldab\t%b1", operands
);
3751 output_asm_insn ("xgdy", operands
);
3755 output_asm_insn ("pshb", operands
);
3756 output_asm_insn ("ldab\t%b1", operands
);
3757 output_asm_insn ("stab\t%T1", operands
);
3758 output_asm_insn ("ldy\t%t1", operands
);
3759 output_asm_insn ("pulb", operands
);
3765 fatal_insn ("invalid register in the instruction", insn
);
3769 else if (H_REG_P (operands
[1]))
3771 switch (REGNO (operands
[1]))
3775 output_asm_insn ("stab\t%b0", operands
);
3779 output_asm_insn ("staa\t%b0", operands
);
3783 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3787 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3791 fatal_insn ("invalid register in the move instruction", insn
);
3798 fatal_insn ("operand 1 must be a hard register", insn
);
3802 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3803 The source and destination must be D or A and the shift must
3806 m68hc11_gen_rotate (enum rtx_code code
, rtx insn
, rtx operands
[])
3810 if (GET_CODE (operands
[2]) != CONST_INT
3811 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3812 fatal_insn ("invalid rotate insn", insn
);
3814 val
= INTVAL (operands
[2]);
3815 if (code
== ROTATERT
)
3816 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3818 if (GET_MODE (operands
[0]) != QImode
)
3821 /* Rotate by 8-bits if the shift is within [5..11]. */
3822 if (val
>= 5 && val
<= 11)
3825 output_asm_insn ("exg\ta,b", operands
);
3828 output_asm_insn ("psha", operands
);
3829 output_asm_insn ("tba", operands
);
3830 output_asm_insn ("pulb", operands
);
3835 /* If the shift is big, invert the rotation. */
3845 /* Set the carry to bit-15, but don't change D yet. */
3846 if (GET_MODE (operands
[0]) != QImode
)
3848 output_asm_insn ("asra", operands
);
3849 output_asm_insn ("rola", operands
);
3852 /* Rotate B first to move the carry to bit-0. */
3853 if (D_REG_P (operands
[0]))
3854 output_asm_insn ("rolb", operands
);
3856 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3857 output_asm_insn ("rola", operands
);
3864 /* Set the carry to bit-8 of D. */
3865 if (GET_MODE (operands
[0]) != QImode
)
3866 output_asm_insn ("tap", operands
);
3868 /* Rotate B first to move the carry to bit-7. */
3869 if (D_REG_P (operands
[0]))
3870 output_asm_insn ("rorb", operands
);
3872 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3873 output_asm_insn ("rora", operands
);
3880 /* Store in cc_status the expressions that the condition codes will
3881 describe after execution of an instruction whose pattern is EXP.
3882 Do not alter them if the instruction would not alter the cc's. */
3885 m68hc11_notice_update_cc (rtx exp
, rtx insn ATTRIBUTE_UNUSED
)
3887 /* recognize SET insn's. */
3888 if (GET_CODE (exp
) == SET
)
3890 /* Jumps do not alter the cc's. */
3891 if (SET_DEST (exp
) == pc_rtx
)
3894 /* NOTE: most instructions don't affect the carry bit, but the
3895 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3896 the conditions.h header. */
3898 /* Function calls clobber the cc's. */
3899 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3904 /* Tests and compares set the cc's in predictable ways. */
3905 else if (SET_DEST (exp
) == cc0_rtx
)
3907 cc_status
.flags
= 0;
3908 cc_status
.value1
= XEXP (exp
, 0);
3909 if (GET_CODE (XEXP (exp
, 1)) == COMPARE
3910 && XEXP (XEXP (exp
, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp
, 1), 0))))
3911 cc_status
.value2
= XEXP (XEXP (exp
, 1), 0);
3913 cc_status
.value2
= XEXP (exp
, 1);
3917 /* All other instructions affect the condition codes. */
3918 cc_status
.flags
= 0;
3919 cc_status
.value1
= XEXP (exp
, 0);
3920 cc_status
.value2
= XEXP (exp
, 1);
3925 /* Default action if we haven't recognized something
3926 and returned earlier. */
3930 if (cc_status
.value2
!= 0)
3931 switch (GET_CODE (cc_status
.value2
))
3933 /* These logical operations can generate several insns.
3934 The flags are setup according to what is generated. */
3940 /* The (not ...) generates several 'com' instructions for
3941 non QImode. We have to invalidate the flags. */
3943 if (GET_MODE (cc_status
.value2
) != QImode
)
3955 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3956 cc_status
.flags
|= CC_NO_OVERFLOW
;
3959 /* The asl sets the overflow bit in such a way that this
3960 makes the flags unusable for a next compare insn. */
3964 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3965 cc_status
.flags
|= CC_NO_OVERFLOW
;
3968 /* A load/store instruction does not affect the carry. */
3973 cc_status
.flags
|= CC_NO_OVERFLOW
;
3979 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
3981 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
3982 cc_status
.value2
= 0;
3984 else if (cc_status
.value1
&& side_effects_p (cc_status
.value1
))
3985 cc_status
.value1
= 0;
3987 else if (cc_status
.value2
&& side_effects_p (cc_status
.value2
))
3988 cc_status
.value2
= 0;
3991 /* The current instruction does not affect the flags but changes
3992 the register 'reg'. See if the previous flags can be kept for the
3993 next instruction to avoid a comparison. */
3995 m68hc11_notice_keep_cc (rtx reg
)
3998 || cc_prev_status
.value1
== 0
3999 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4000 || (cc_prev_status
.value2
4001 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4004 cc_status
= cc_prev_status
;
4009 /* Machine Specific Reorg. */
4011 /* Z register replacement:
4013 GCC treats the Z register as an index base address register like
4014 X or Y. In general, it uses it during reload to compute the address
4015 of some operand. This helps the reload pass to avoid to fall into the
4016 register spill failure.
4018 The Z register is in the A_REGS class. In the machine description,
4019 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4021 It can appear everywhere an X or Y register can appear, except for
4022 some templates in the clobber section (when a clobber of X or Y is asked).
4023 For a given instruction, the template must ensure that no more than
4024 2 'A' registers are used. Otherwise, the register replacement is not
4027 To replace the Z register, the algorithm is not terrific:
4028 1. Insns that do not use the Z register are not changed
4029 2. When a Z register is used, we scan forward the insns to see
4030 a potential register to use: either X or Y and sometimes D.
4031 We stop when a call, a label or a branch is seen, or when we
4032 detect that both X and Y are used (probably at different times, but it does
4034 3. The register that will be used for the replacement of Z is saved
4035 in a .page0 register or on the stack. If the first instruction that
4036 used Z, uses Z as an input, the value is loaded from another .page0
4037 register. The replacement register is pushed on the stack in the
4038 rare cases where a compare insn uses Z and we couldn't find if X/Y
4040 4. The Z register is replaced in all instructions until we reach
4041 the end of the Z-block, as detected by step 2.
4042 5. If we detect that Z is still alive, its value is saved.
4043 If the replacement register is alive, its old value is loaded.
4045 The Z register can be disabled with -ffixed-z.
4055 int must_restore_reg
;
4066 int save_before_last
;
4067 int z_loaded_with_sp
;
4070 static int m68hc11_check_z_replacement (rtx
, struct replace_info
*);
4071 static void m68hc11_find_z_replacement (rtx
, struct replace_info
*);
4072 static void m68hc11_z_replacement (rtx
);
4073 static void m68hc11_reassign_regs (rtx
);
4075 int z_replacement_completed
= 0;
4077 /* Analyze the insn to find out which replacement register to use and
4078 the boundaries of the replacement.
4079 Returns 0 if we reached the last insn to be replaced, 1 if we can
4080 continue replacement in next insns. */
4083 m68hc11_check_z_replacement (rtx insn
, struct replace_info
*info
)
4085 int this_insn_uses_ix
;
4086 int this_insn_uses_iy
;
4087 int this_insn_uses_z
;
4088 int this_insn_uses_z_in_dst
;
4089 int this_insn_uses_d
;
4093 /* A call is said to clobber the Z register, we don't need
4094 to save the value of Z. We also don't need to restore
4095 the replacement register (unless it is used by the call). */
4096 if (GET_CODE (insn
) == CALL_INSN
)
4098 body
= PATTERN (insn
);
4100 info
->can_use_d
= 0;
4102 /* If the call is an indirect call with Z, we have to use the
4103 Y register because X can be used as an input (D+X).
4104 We also must not save Z nor restore Y. */
4105 if (reg_mentioned_p (z_reg
, body
))
4107 insn
= NEXT_INSN (insn
);
4110 info
->found_call
= 1;
4111 info
->must_restore_reg
= 0;
4112 info
->last
= NEXT_INSN (insn
);
4114 info
->need_save_z
= 0;
4117 if (GET_CODE (insn
) == CODE_LABEL
4118 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4121 if (GET_CODE (insn
) == JUMP_INSN
)
4123 if (reg_mentioned_p (z_reg
, insn
) == 0)
4126 info
->can_use_d
= 0;
4127 info
->must_save_reg
= 0;
4128 info
->must_restore_reg
= 0;
4129 info
->need_save_z
= 0;
4130 info
->last
= NEXT_INSN (insn
);
4133 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4138 /* Z register dies here. */
4139 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4141 body
= PATTERN (insn
);
4142 if (GET_CODE (body
) == SET
)
4144 rtx src
= XEXP (body
, 1);
4145 rtx dst
= XEXP (body
, 0);
4147 /* Condition code is set here. We have to restore the X/Y and
4148 save into Z before any test/compare insn because once we save/restore
4149 we can change the condition codes. When the compare insn uses Z and
4150 we can't use X/Y, the comparison is made with the *ZREG soft register
4151 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4154 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4155 || (GET_CODE (src
) == COMPARE
&&
4156 ((rtx_equal_p (XEXP (src
, 0), z_reg
)
4157 && H_REG_P (XEXP (src
, 1)))
4158 || (rtx_equal_p (XEXP (src
, 1), z_reg
)
4159 && H_REG_P (XEXP (src
, 0))))))
4161 if (insn
== info
->first
)
4163 info
->must_load_z
= 0;
4164 info
->must_save_reg
= 0;
4165 info
->must_restore_reg
= 0;
4166 info
->need_save_z
= 0;
4167 info
->found_call
= 1;
4168 info
->regno
= SOFT_Z_REGNUM
;
4169 info
->last
= NEXT_INSN (insn
);
4173 if (reg_mentioned_p (z_reg
, src
) == 0)
4175 info
->can_use_d
= 0;
4179 if (insn
!= info
->first
)
4182 /* Compare insn which uses Z. We have to save/restore the X/Y
4183 register without modifying the condition codes. For this
4184 we have to use a push/pop insn. */
4185 info
->must_push_reg
= 1;
4189 /* Z reg is set to something new. We don't need to load it. */
4192 if (!reg_mentioned_p (z_reg
, src
))
4194 /* Z reg is used before being set. Treat this as
4195 a new sequence of Z register replacement. */
4196 if (insn
!= info
->first
)
4200 info
->must_load_z
= 0;
4202 info
->z_set_count
++;
4203 info
->z_value
= src
;
4205 info
->z_loaded_with_sp
= 1;
4207 else if (reg_mentioned_p (z_reg
, dst
))
4208 info
->can_use_d
= 0;
4210 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4211 | reg_mentioned_p (d_reg
, dst
);
4212 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4213 | reg_mentioned_p (ix_reg
, dst
);
4214 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4215 | reg_mentioned_p (iy_reg
, dst
);
4216 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4218 /* If z is used as an address operand (like (MEM (reg z))),
4219 we can't replace it with d. */
4220 if (this_insn_uses_z
&& !Z_REG_P (src
)
4221 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4222 && Z_REG_P (XEXP (src
, 0))
4223 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4224 && insn
== info
->first
4225 && dead_register_here (insn
, d_reg
)))
4226 info
->can_use_d
= 0;
4228 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4229 if (TARGET_M6812
&& !z_dies_here
4230 && ((this_insn_uses_z
&& side_effects_p (src
))
4231 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4233 info
->need_save_z
= 1;
4234 info
->z_set_count
++;
4236 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4238 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4240 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4243 if (this_insn_uses_d
)
4244 info
->can_use_d
= 0;
4246 /* IX and IY are used at the same time, we have to restore
4247 the value of the scratch register before this insn. */
4248 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4253 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4254 info
->can_use_d
= 0;
4256 if (info
->x_used
== 0 && this_insn_uses_ix
)
4260 /* We have a (set (REG:HI X) (REG:HI Z)).
4261 Since we use Z as the replacement register, this insn
4262 is no longer necessary. We turn it into a note. We must
4263 not reload the old value of X. */
4264 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4268 info
->need_save_z
= 0;
4271 info
->must_save_reg
= 0;
4272 info
->must_restore_reg
= 0;
4273 info
->found_call
= 1;
4274 info
->can_use_d
= 0;
4275 SET_INSN_DELETED (insn
);
4276 info
->last
= NEXT_INSN (insn
);
4281 && (rtx_equal_p (src
, z_reg
)
4282 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4286 info
->need_save_z
= 0;
4289 info
->last
= NEXT_INSN (insn
);
4290 info
->must_save_reg
= 0;
4291 info
->must_restore_reg
= 0;
4293 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4294 && !reg_mentioned_p (ix_reg
, src
))
4299 info
->need_save_z
= 0;
4301 else if (TARGET_M6812
&& side_effects_p (src
))
4304 info
->must_restore_reg
= 0;
4309 info
->save_before_last
= 1;
4311 info
->must_restore_reg
= 0;
4312 info
->last
= NEXT_INSN (insn
);
4314 else if (info
->can_use_d
)
4316 info
->last
= NEXT_INSN (insn
);
4322 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4323 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4325 info
->need_save_z
= 0;
4327 info
->last
= NEXT_INSN (insn
);
4328 info
->regno
= HARD_X_REGNUM
;
4329 info
->must_save_reg
= 0;
4330 info
->must_restore_reg
= 0;
4333 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4335 info
->regno
= HARD_X_REGNUM
;
4336 info
->must_restore_reg
= 0;
4337 info
->must_save_reg
= 0;
4341 if (info
->y_used
== 0 && this_insn_uses_iy
)
4345 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4349 info
->need_save_z
= 0;
4352 info
->must_save_reg
= 0;
4353 info
->must_restore_reg
= 0;
4354 info
->found_call
= 1;
4355 info
->can_use_d
= 0;
4356 SET_INSN_DELETED (insn
);
4357 info
->last
= NEXT_INSN (insn
);
4362 && (rtx_equal_p (src
, z_reg
)
4363 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4368 info
->need_save_z
= 0;
4370 info
->last
= NEXT_INSN (insn
);
4371 info
->must_save_reg
= 0;
4372 info
->must_restore_reg
= 0;
4374 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4375 && !reg_mentioned_p (iy_reg
, src
))
4380 info
->need_save_z
= 0;
4382 else if (TARGET_M6812
&& side_effects_p (src
))
4385 info
->must_restore_reg
= 0;
4390 info
->save_before_last
= 1;
4392 info
->must_restore_reg
= 0;
4393 info
->last
= NEXT_INSN (insn
);
4395 else if (info
->can_use_d
)
4397 info
->last
= NEXT_INSN (insn
);
4404 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4405 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4407 info
->need_save_z
= 0;
4409 info
->last
= NEXT_INSN (insn
);
4410 info
->regno
= HARD_Y_REGNUM
;
4411 info
->must_save_reg
= 0;
4412 info
->must_restore_reg
= 0;
4415 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4417 info
->regno
= HARD_Y_REGNUM
;
4418 info
->must_restore_reg
= 0;
4419 info
->must_save_reg
= 0;
4425 info
->need_save_z
= 0;
4427 if (info
->last
== 0)
4428 info
->last
= NEXT_INSN (insn
);
4431 return info
->last
!= NULL_RTX
? 0 : 1;
4433 if (GET_CODE (body
) == PARALLEL
)
4436 char ix_clobber
= 0;
4437 char iy_clobber
= 0;
4439 this_insn_uses_iy
= 0;
4440 this_insn_uses_ix
= 0;
4441 this_insn_uses_z
= 0;
4443 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4446 int uses_ix
, uses_iy
, uses_z
;
4448 x
= XVECEXP (body
, 0, i
);
4450 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4451 info
->can_use_d
= 0;
4453 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4454 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4455 uses_z
= reg_mentioned_p (z_reg
, x
);
4456 if (GET_CODE (x
) == CLOBBER
)
4458 ix_clobber
|= uses_ix
;
4459 iy_clobber
|= uses_iy
;
4460 z_clobber
|= uses_z
;
4464 this_insn_uses_ix
|= uses_ix
;
4465 this_insn_uses_iy
|= uses_iy
;
4466 this_insn_uses_z
|= uses_z
;
4468 if (uses_z
&& GET_CODE (x
) == SET
)
4470 rtx dst
= XEXP (x
, 0);
4473 info
->z_set_count
++;
4475 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4476 info
->need_save_z
= 1;
4479 info
->need_save_z
= 0;
4483 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4484 this_insn_uses_ix
, this_insn_uses_iy
,
4485 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4488 if (this_insn_uses_z
)
4489 info
->can_use_d
= 0;
4491 if (z_clobber
&& info
->first
!= insn
)
4493 info
->need_save_z
= 0;
4497 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4499 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4501 info
->must_load_z
= 0;
4503 if (dead_register_here (insn
, d_reg
))
4505 info
->regno
= HARD_D_REGNUM
;
4506 info
->must_save_reg
= 0;
4507 info
->must_restore_reg
= 0;
4509 else if (dead_register_here (insn
, ix_reg
))
4511 info
->regno
= HARD_X_REGNUM
;
4512 info
->must_save_reg
= 0;
4513 info
->must_restore_reg
= 0;
4515 else if (dead_register_here (insn
, iy_reg
))
4517 info
->regno
= HARD_Y_REGNUM
;
4518 info
->must_save_reg
= 0;
4519 info
->must_restore_reg
= 0;
4521 if (info
->regno
>= 0)
4523 info
->last
= NEXT_INSN (insn
);
4526 if (this_insn_uses_ix
== 0)
4528 info
->regno
= HARD_X_REGNUM
;
4529 info
->must_save_reg
= 1;
4530 info
->must_restore_reg
= 1;
4532 else if (this_insn_uses_iy
== 0)
4534 info
->regno
= HARD_Y_REGNUM
;
4535 info
->must_save_reg
= 1;
4536 info
->must_restore_reg
= 1;
4540 info
->regno
= HARD_D_REGNUM
;
4541 info
->must_save_reg
= 1;
4542 info
->must_restore_reg
= 1;
4544 info
->last
= NEXT_INSN (insn
);
4548 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4549 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4551 if (this_insn_uses_z
)
4553 if (info
->y_used
== 0 && iy_clobber
)
4555 info
->regno
= HARD_Y_REGNUM
;
4556 info
->must_save_reg
= 0;
4557 info
->must_restore_reg
= 0;
4559 if (info
->first
!= insn
4560 && ((info
->y_used
&& ix_clobber
)
4561 || (info
->x_used
&& iy_clobber
)))
4564 info
->last
= NEXT_INSN (insn
);
4565 info
->save_before_last
= 1;
4569 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4571 if (this_insn_uses_z
)
4573 fatal_insn ("cannot do z-register replacement", insn
);
4577 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4584 if (iy_clobber
|| z_clobber
)
4586 info
->last
= NEXT_INSN (insn
);
4587 info
->save_before_last
= 1;
4592 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4599 if (ix_clobber
|| z_clobber
)
4601 info
->last
= NEXT_INSN (insn
);
4602 info
->save_before_last
= 1;
4609 info
->need_save_z
= 0;
4613 if (GET_CODE (body
) == CLOBBER
)
4616 /* IX and IY are used at the same time, we have to restore
4617 the value of the scratch register before this insn. */
4618 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4622 if (info
->x_used
== 0 && this_insn_uses_ix
)
4630 if (info
->y_used
== 0 && this_insn_uses_iy
)
4644 m68hc11_find_z_replacement (rtx insn
, struct replace_info
*info
)
4648 info
->replace_reg
= NULL_RTX
;
4649 info
->must_load_z
= 1;
4650 info
->need_save_z
= 1;
4651 info
->must_save_reg
= 1;
4652 info
->must_restore_reg
= 1;
4656 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4657 info
->found_call
= 0;
4661 info
->z_set_count
= 0;
4662 info
->z_value
= NULL_RTX
;
4663 info
->must_push_reg
= 0;
4664 info
->save_before_last
= 0;
4665 info
->z_loaded_with_sp
= 0;
4667 /* Scan the insn forward to find an address register that is not used.
4669 - the flow of the program changes,
4670 - when we detect that both X and Y are necessary,
4671 - when the Z register dies,
4672 - when the condition codes are set. */
4674 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4676 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4680 /* May be we can use Y or X if they contain the same value as Z.
4681 This happens very often after the reload. */
4682 if (info
->z_set_count
== 1)
4684 rtx p
= info
->first
;
4689 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4691 else if (info
->y_used
)
4693 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4695 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4698 info
->regno
= HARD_Y_REGNUM
;
4700 info
->regno
= HARD_X_REGNUM
;
4701 info
->must_load_z
= 0;
4702 info
->must_save_reg
= 0;
4703 info
->must_restore_reg
= 0;
4704 info
->found_call
= 1;
4707 if (info
->z_set_count
== 0)
4708 info
->need_save_z
= 0;
4711 info
->need_save_z
= 0;
4713 if (info
->last
== 0)
4716 if (info
->regno
>= 0)
4719 info
->replace_reg
= gen_rtx_REG (HImode
, reg
);
4721 else if (info
->can_use_d
)
4723 reg
= HARD_D_REGNUM
;
4724 info
->replace_reg
= d_reg
;
4726 else if (info
->x_used
)
4728 reg
= HARD_Y_REGNUM
;
4729 info
->replace_reg
= iy_reg
;
4733 reg
= HARD_X_REGNUM
;
4734 info
->replace_reg
= ix_reg
;
4738 if (info
->must_save_reg
&& info
->must_restore_reg
)
4740 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4742 info
->must_save_reg
= 0;
4743 info
->must_restore_reg
= 0;
4748 /* The insn uses the Z register. Find a replacement register for it
4749 (either X or Y) and replace it in the insn and the next ones until
4750 the flow changes or the replacement register is used. Instructions
4751 are emitted before and after the Z-block to preserve the value of
4752 Z and of the replacement register. */
4755 m68hc11_z_replacement (rtx insn
)
4759 struct replace_info info
;
4761 /* Find trivial case where we only need to replace z with the
4762 equivalent soft register. */
4763 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4765 rtx body
= PATTERN (insn
);
4766 rtx src
= XEXP (body
, 1);
4767 rtx dst
= XEXP (body
, 0);
4769 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4771 XEXP (body
, 0) = gen_rtx_REG (GET_MODE (dst
), SOFT_Z_REGNUM
);
4774 else if (Z_REG_P (src
)
4775 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4777 XEXP (body
, 1) = gen_rtx_REG (GET_MODE (src
), SOFT_Z_REGNUM
);
4780 else if (D_REG_P (dst
)
4781 && m68hc11_arith_operator (src
, GET_MODE (src
))
4782 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4784 XEXP (src
, 1) = gen_rtx_REG (GET_MODE (src
), SOFT_Z_REGNUM
);
4787 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4788 && INTVAL (src
) == 0)
4790 XEXP (body
, 0) = gen_rtx_REG (GET_MODE (dst
), SOFT_Z_REGNUM
);
4791 /* Force it to be re-recognized. */
4792 INSN_CODE (insn
) = -1;
4797 m68hc11_find_z_replacement (insn
, &info
);
4799 replace_reg
= info
.replace_reg
;
4800 replace_reg_qi
= NULL_RTX
;
4802 /* Save the X register in a .page0 location. */
4803 if (info
.must_save_reg
&& !info
.must_push_reg
)
4807 if (info
.must_push_reg
&& 0)
4808 dst
= gen_rtx_MEM (HImode
,
4809 gen_rtx_PRE_DEC (HImode
,
4810 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
4812 dst
= gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
);
4814 emit_insn_before (gen_movhi (dst
,
4815 gen_rtx_REG (HImode
, info
.regno
)), insn
);
4817 if (info
.must_load_z
&& !info
.must_push_reg
)
4819 emit_insn_before (gen_movhi (gen_rtx_REG (HImode
, info
.regno
),
4820 gen_rtx_REG (HImode
, SOFT_Z_REGNUM
)),
4825 /* Replace all occurrence of Z by replace_reg.
4826 Stop when the last instruction to replace is reached.
4827 Also stop when we detect a change in the flow (but it's not
4828 necessary; just safeguard). */
4830 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4834 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4837 if (GET_CODE (insn
) != INSN
4838 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4841 body
= PATTERN (insn
);
4842 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4843 || GET_CODE (body
) == ASM_OPERANDS
4844 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4848 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4850 printf ("Reg mentioned here...:\n");
4855 /* Stack pointer was decremented by 2 due to the push.
4856 Correct that by adding 2 to the destination. */
4857 if (info
.must_push_reg
4858 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4862 src
= SET_SRC (body
);
4863 dst
= SET_DEST (body
);
4864 if (SP_REG_P (src
) && Z_REG_P (dst
))
4865 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4868 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4869 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4871 INSN_CODE (insn
) = -1;
4872 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4873 fatal_insn ("cannot do z-register replacement", insn
);
4876 /* Likewise for (REG:QI Z). */
4877 if (reg_mentioned_p (z_reg
, insn
))
4879 if (replace_reg_qi
== NULL_RTX
)
4880 replace_reg_qi
= gen_rtx_REG (QImode
, REGNO (replace_reg
));
4881 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4884 /* If there is a REG_INC note on Z, replace it with a
4885 REG_INC note on the replacement register. This is necessary
4886 to make sure that the flow pass will identify the change
4887 and it will not remove a possible insn that saves Z. */
4888 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4890 if (REG_NOTE_KIND (note
) == REG_INC
4891 && GET_CODE (XEXP (note
, 0)) == REG
4892 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4894 XEXP (note
, 0) = replace_reg
;
4898 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4902 /* Save Z before restoring the old value. */
4903 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4905 rtx save_pos_insn
= insn
;
4907 /* If Z is clobber by the last insn, we have to save its value
4908 before the last instruction. */
4909 if (info
.save_before_last
)
4910 save_pos_insn
= PREV_INSN (save_pos_insn
);
4912 emit_insn_before (gen_movhi (gen_rtx_REG (HImode
, SOFT_Z_REGNUM
),
4913 gen_rtx_REG (HImode
, info
.regno
)),
4917 if (info
.must_push_reg
&& info
.last
)
4921 body
= PATTERN (info
.last
);
4922 new_body
= gen_rtx_PARALLEL (VOIDmode
,
4924 gen_rtx_USE (VOIDmode
,
4926 gen_rtx_USE (VOIDmode
,
4927 gen_rtx_REG (HImode
,
4929 PATTERN (info
.last
) = new_body
;
4931 /* Force recognition on insn since we changed it. */
4932 INSN_CODE (insn
) = -1;
4934 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4936 fatal_insn ("invalid Z register replacement for insn", insn
);
4938 insn
= NEXT_INSN (info
.last
);
4941 /* Restore replacement register unless it was died. */
4942 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4946 if (info
.must_push_reg
&& 0)
4947 dst
= gen_rtx_MEM (HImode
,
4948 gen_rtx_POST_INC (HImode
,
4949 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
4951 dst
= gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
);
4953 emit_insn_before (gen_movhi (gen_rtx_REG (HImode
, info
.regno
),
4960 /* Scan all the insn and re-affects some registers
4961 - The Z register (if it was used), is affected to X or Y depending
4962 on the instruction. */
4965 m68hc11_reassign_regs (rtx first
)
4969 ix_reg
= gen_rtx_REG (HImode
, HARD_X_REGNUM
);
4970 iy_reg
= gen_rtx_REG (HImode
, HARD_Y_REGNUM
);
4971 z_reg
= gen_rtx_REG (HImode
, HARD_Z_REGNUM
);
4972 z_reg_qi
= gen_rtx_REG (QImode
, HARD_Z_REGNUM
);
4974 /* Scan all insns to replace Z by X or Y preserving the old value
4975 of X/Y and restoring it afterward. */
4977 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
4981 if (GET_CODE (insn
) == CODE_LABEL
4982 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
4988 body
= PATTERN (insn
);
4989 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
4992 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
4993 || GET_CODE (body
) == ASM_OPERANDS
4994 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
4997 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4998 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5001 /* If Z appears in this insn, replace it in the current insn
5002 and the next ones until the flow changes or we have to
5003 restore back the replacement register. */
5005 if (reg_mentioned_p (z_reg
, body
))
5007 m68hc11_z_replacement (insn
);
5012 printf ("insn not handled by Z replacement:\n");
5020 /* Machine-dependent reorg pass.
5021 Specific optimizations are defined here:
5022 - this pass changes the Z register into either X or Y
5023 (it preserves X/Y previous values in a memory slot in page0).
5025 When this pass is finished, the global variable
5026 'z_replacement_completed' is set to 2. */
5029 m68hc11_reorg (void)
5034 z_replacement_completed
= 0;
5035 z_reg
= gen_rtx_REG (HImode
, HARD_Z_REGNUM
);
5036 first
= get_insns ();
5038 /* Some RTX are shared at this point. This breaks the Z register
5039 replacement, unshare everything. */
5040 unshare_all_rtl_again (first
);
5042 /* Force a split of all splittable insn. This is necessary for the
5043 Z register replacement mechanism because we end up with basic insns. */
5044 split_all_insns_noflow ();
5047 z_replacement_completed
= 1;
5048 m68hc11_reassign_regs (first
);
5051 compute_bb_for_insn ();
5053 /* After some splitting, there are some opportunities for CSE pass.
5054 This happens quite often when 32-bit or above patterns are split. */
5055 if (optimize
> 0 && split_done
)
5057 reload_cse_regs (first
);
5060 /* Re-create the REG_DEAD notes. These notes are used in the machine
5061 description to use the best assembly directives. */
5064 df_note_add_problem ();
5066 df_remove_problem (df_note
);
5069 z_replacement_completed
= 2;
5071 /* If optimizing, then go ahead and split insns that must be
5072 split after Z register replacement. This gives more opportunities
5073 for peephole (in particular for consecutives xgdx/xgdy). */
5075 split_all_insns_noflow ();
5077 /* Once insns are split after the z_replacement_completed == 2,
5078 we must not re-run the life_analysis. The xgdx/xgdy patterns
5079 are not recognized and the life_analysis pass removes some
5080 insns because it thinks some (SETs) are noops or made to dead
5081 stores (which is false due to the swap).
5083 Do a simple pass to eliminate the noop set that the final
5084 split could generate (because it was easier for split definition). */
5088 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5092 if (INSN_DELETED_P (insn
))
5097 /* Remove the (set (R) (R)) insns generated by some splits. */
5098 body
= PATTERN (insn
);
5099 if (GET_CODE (body
) == SET
5100 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5102 SET_INSN_DELETED (insn
);
5109 /* Override memcpy */
5112 m68hc11_init_libfuncs (void)
5114 memcpy_libfunc
= init_one_libfunc ("__memcpy");
5115 memcmp_libfunc
= init_one_libfunc ("__memcmp");
5116 memset_libfunc
= init_one_libfunc ("__memset");
5121 /* Cost functions. */
5123 /* Cost of moving memory. */
5125 m68hc11_memory_move_cost (enum machine_mode mode
, enum reg_class rclass
,
5126 int in ATTRIBUTE_UNUSED
)
5128 if (rclass
<= H_REGS
&& rclass
> NO_REGS
)
5130 if (GET_MODE_SIZE (mode
) <= 2)
5131 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5133 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5137 if (GET_MODE_SIZE (mode
) <= 2)
5138 return COSTS_N_INSNS (3);
5140 return COSTS_N_INSNS (4);
5145 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5146 Reload does not check the constraint of set insns when the two registers
5147 have a move cost of 2. Setting a higher cost will force reload to check
5150 m68hc11_register_move_cost (enum machine_mode mode
, enum reg_class from
,
5153 /* All costs are symmetric, so reduce cases by putting the
5154 lower number class as the destination. */
5157 enum reg_class tmp
= to
;
5158 to
= from
, from
= tmp
;
5161 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5162 else if (from
<= S_REGS
)
5163 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5165 return COSTS_N_INSNS (2);
5169 /* Provide the costs of an addressing mode that contains ADDR.
5170 If ADDR is not a valid address, its cost is irrelevant. */
5173 m68hc11_address_cost (rtx addr
, bool speed ATTRIBUTE_UNUSED
)
5177 switch (GET_CODE (addr
))
5180 /* Make the cost of hard registers and specially SP, FP small. */
5181 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5198 register rtx plus0
= XEXP (addr
, 0);
5199 register rtx plus1
= XEXP (addr
, 1);
5201 if (GET_CODE (plus0
) != REG
)
5204 switch (GET_CODE (plus1
))
5207 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5208 || INTVAL (plus1
) < m68hc11_min_offset
)
5210 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5214 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5236 if (SP_REG_P (XEXP (addr
, 0)))
5245 printf ("Address cost: %d for :", cost
);
5254 m68hc11_shift_cost (enum machine_mode mode
, rtx x
, int shift
)
5258 total
= rtx_cost (x
, SET
, !optimize_size
);
5260 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5261 else if (mode
== HImode
)
5262 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5263 else if (shift
== 8 || shift
== 16 || shift
== 32)
5264 total
+= m68hc11_cost
->shiftHI_const
[8];
5265 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5267 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5270 /* For SI and others, the cost is higher. */
5271 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5272 total
*= GET_MODE_SIZE (mode
) / 2;
5274 /* When optimizing for size, make shift more costly so that
5275 multiplications are preferred. */
5276 if (optimize_size
&& (shift
% 8) != 0)
5283 m68hc11_rtx_costs_1 (rtx x
, enum rtx_code code
,
5284 enum rtx_code outer_code ATTRIBUTE_UNUSED
)
5286 enum machine_mode mode
= GET_MODE (x
);
5297 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5299 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5302 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5303 total
+= m68hc11_cost
->shift_var
;
5309 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5310 total
+= m68hc11_cost
->logical
;
5312 /* Logical instructions are byte instructions only. */
5313 total
*= GET_MODE_SIZE (mode
);
5318 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5319 total
+= m68hc11_cost
->add
;
5320 if (GET_MODE_SIZE (mode
) > 2)
5322 total
*= GET_MODE_SIZE (mode
) / 2;
5329 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5333 total
+= m68hc11_cost
->divQI
;
5337 total
+= m68hc11_cost
->divHI
;
5342 total
+= m68hc11_cost
->divSI
;
5348 /* mul instruction produces 16-bit result. */
5349 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5350 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5351 return m68hc11_cost
->multQI
5352 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
, !optimize_size
)
5353 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
, !optimize_size
);
5355 /* emul instruction produces 32-bit result for 68HC12. */
5356 if (TARGET_M6812
&& mode
== SImode
5357 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5358 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5359 return m68hc11_cost
->multHI
5360 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
, !optimize_size
)
5361 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
, !optimize_size
);
5363 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
)
5364 + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5368 total
+= m68hc11_cost
->multQI
;
5372 total
+= m68hc11_cost
->multHI
;
5377 total
+= m68hc11_cost
->multSI
;
5384 extra_cost
= COSTS_N_INSNS (2);
5392 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
, !optimize_size
);
5395 return total
+ COSTS_N_INSNS (1);
5399 return total
+ COSTS_N_INSNS (2);
5403 return total
+ COSTS_N_INSNS (4);
5405 return total
+ COSTS_N_INSNS (8);
5408 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5409 return COSTS_N_INSNS (1);
5411 return COSTS_N_INSNS (1);
5414 return COSTS_N_INSNS (4);
5419 m68hc11_rtx_costs (rtx x
, int codearg
, int outer_code_arg
, int *total
,
5420 bool speed ATTRIBUTE_UNUSED
)
5422 enum rtx_code code
= (enum rtx_code
) codearg
;
5423 enum rtx_code outer_code
= (enum rtx_code
) outer_code_arg
;
5427 /* Constants are cheap. Moving them in registers must be avoided
5428 because most instructions do not handle two register operands. */
5434 /* Logical and arithmetic operations with a constant operand are
5435 better because they are not supported with two registers. */
5437 if (outer_code
== SET
&& x
== const0_rtx
)
5438 /* After reload, the reload_cse pass checks the cost to change
5439 a SET into a PLUS. Make const0 cheap then. */
5440 *total
= 1 - reload_completed
;
5446 if (outer_code
!= COMPARE
)
5469 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5478 /* Worker function for TARGET_ASM_FILE_START. */
5481 m68hc11_file_start (void)
5483 default_file_start ();
5485 fprintf (asm_out_file
, "\t.mode %s\n", TARGET_SHORT
? "mshort" : "mlong");
5489 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5492 m68hc11_asm_out_constructor (rtx symbol
, int priority
)
5494 default_ctor_section_asm_out_constructor (symbol
, priority
);
5495 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5498 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5501 m68hc11_asm_out_destructor (rtx symbol
, int priority
)
5503 default_dtor_section_asm_out_destructor (symbol
, priority
);
5504 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5507 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5510 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED
,
5511 int incoming ATTRIBUTE_UNUSED
)
5513 return gen_rtx_REG (Pmode
, HARD_D_REGNUM
);
5516 /* Return true if type TYPE should be returned in memory.
5517 Blocks and data types largers than 4 bytes cannot be returned
5518 in the register (D + X = 4). */
5521 m68hc11_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
5523 if (TYPE_MODE (type
) == BLKmode
)
5525 HOST_WIDE_INT size
= int_size_in_bytes (type
);
5526 return (size
== -1 || size
> 4);
5529 return GET_MODE_SIZE (TYPE_MODE (type
)) > 4;
5532 #include "gt-m68hc11.h"