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"
54 #include "diagnostic-core.h"
56 #include "basic-block.h"
61 #include "target-def.h"
64 static void emit_move_after_reload (rtx
, rtx
, rtx
);
65 static rtx
simplify_logical (enum machine_mode
, int, rtx
, rtx
*);
66 static void m68hc11_emit_logical (enum machine_mode
, enum rtx_code
, rtx
*);
67 static void m68hc11_reorg (void);
68 static bool m68hc11_legitimate_address_p_1 (enum machine_mode
, rtx
, bool);
69 static bool m68hc11_legitimate_address_p (enum machine_mode
, rtx
, bool);
70 static rtx
m68hc11_expand_compare (enum rtx_code
, rtx
, rtx
);
71 static int must_parenthesize (rtx
);
72 static int m68hc11_address_cost (rtx
, bool);
73 static int m68hc11_shift_cost (enum machine_mode
, rtx
, int);
74 static int m68hc11_rtx_costs_1 (rtx
, enum rtx_code
, enum rtx_code
);
75 static bool m68hc11_rtx_costs (rtx
, int, int, int *, bool);
76 static tree
m68hc11_handle_fntype_attribute (tree
*, tree
, tree
, int, bool *);
77 static tree
m68hc11_handle_page0_attribute (tree
*, tree
, tree
, int, bool *);
79 void create_regs_rtx (void);
81 static void asm_print_register (FILE *, int);
82 static void m68hc11_print_operand (FILE *, rtx
, int);
83 static void m68hc11_print_operand_address (FILE *, rtx
);
84 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT
);
85 static void m68hc11_asm_out_constructor (rtx
, int);
86 static void m68hc11_asm_out_destructor (rtx
, int);
87 static void m68hc11_file_start (void);
88 static void m68hc11_encode_section_info (tree
, rtx
, int);
89 static const char *m68hc11_strip_name_encoding (const char* str
);
90 static unsigned int m68hc11_section_type_flags (tree
, const char*, int);
91 static int autoinc_mode (rtx
);
92 static int m68hc11_make_autoinc_notes (rtx
*, void *);
93 static void m68hc11_init_libfuncs (void);
94 static rtx
m68hc11_struct_value_rtx (tree
, int);
95 static bool m68hc11_return_in_memory (const_tree
, const_tree
);
96 static bool m68hc11_can_eliminate (const int, const int);
97 static void m68hc11_trampoline_init (rtx
, tree
, rtx
);
99 /* Must be set to 1 to produce debug messages. */
102 extern FILE *asm_out_file
;
107 rtx m68hc11_soft_tmp_reg
;
108 static GTY(()) rtx stack_push_word
;
109 static GTY(()) rtx stack_pop_word
;
110 static GTY(()) rtx z_reg
;
111 static GTY(()) rtx z_reg_qi
;
112 static int regs_inited
= 0;
114 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
115 int current_function_interrupt
;
117 /* Set to 1 by expand_prologue() when the function is a trap handler. */
118 int current_function_trap
;
120 /* Set to 1 when the current function is placed in 68HC12 banked
121 memory and must return with rtc. */
122 int current_function_far
;
124 /* Min offset that is valid for the indirect addressing mode. */
125 HOST_WIDE_INT m68hc11_min_offset
= 0;
127 /* Max offset that is valid for the indirect addressing mode. */
128 HOST_WIDE_INT m68hc11_max_offset
= 256;
130 /* The class value for base registers. */
131 enum reg_class m68hc11_base_reg_class
= A_REGS
;
133 /* The class value for index registers. This is NO_REGS for 68HC11. */
134 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
136 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
138 /* Tables that tell whether a given hard register is valid for
139 a base or an index register. It is filled at init time depending
140 on the target processor. */
141 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
142 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
144 /* A correction offset which is applied to the stack pointer.
145 This is 1 for 68HC11 and 0 for 68HC12. */
146 int m68hc11_sp_correction
;
148 int m68hc11_addr_mode
;
149 int m68hc11_mov_addr_mode
;
152 const struct processor_costs
*m68hc11_cost
;
154 /* Costs for a 68HC11. */
155 static const struct processor_costs m6811_cost
= {
160 /* non-constant shift */
163 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
164 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
165 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
168 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
169 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
170 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
171 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
172 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
173 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
178 COSTS_N_INSNS (20 * 4),
180 COSTS_N_INSNS (20 * 16),
189 /* Costs for a 68HC12. */
190 static const struct processor_costs m6812_cost
= {
195 /* non-constant shift */
198 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
199 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
200 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
203 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
204 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
205 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
206 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
207 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
208 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
215 COSTS_N_INSNS (3 * 4),
224 /* M68HC11 specific attributes. */
226 static const struct attribute_spec m68hc11_attribute_table
[] =
228 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
229 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
230 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
231 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
232 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
233 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute
},
234 { NULL
, 0, 0, false, false, false, NULL
}
237 /* Initialize the GCC target structure. */
238 #undef TARGET_ATTRIBUTE_TABLE
239 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
241 #undef TARGET_ASM_ALIGNED_HI_OP
242 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
244 #undef TARGET_PRINT_OPERAND
245 #define TARGET_PRINT_OPERAND m68hc11_print_operand
246 #undef TARGET_PRINT_OPERAND_ADDRESS
247 #define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
249 #undef TARGET_ASM_FUNCTION_EPILOGUE
250 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
252 #undef TARGET_ASM_FILE_START
253 #define TARGET_ASM_FILE_START m68hc11_file_start
254 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
255 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
257 #undef TARGET_DEFAULT_TARGET_FLAGS
258 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
260 #undef TARGET_ENCODE_SECTION_INFO
261 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
263 #undef TARGET_SECTION_TYPE_FLAGS
264 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
266 #undef TARGET_RTX_COSTS
267 #define TARGET_RTX_COSTS m68hc11_rtx_costs
268 #undef TARGET_ADDRESS_COST
269 #define TARGET_ADDRESS_COST m68hc11_address_cost
271 #undef TARGET_MACHINE_DEPENDENT_REORG
272 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
274 #undef TARGET_INIT_LIBFUNCS
275 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
277 #undef TARGET_STRUCT_VALUE_RTX
278 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
279 #undef TARGET_RETURN_IN_MEMORY
280 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
281 #undef TARGET_CALLEE_COPIES
282 #define TARGET_CALLEE_COPIES hook_callee_copies_named
284 #undef TARGET_STRIP_NAME_ENCODING
285 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
287 #undef TARGET_LEGITIMATE_ADDRESS_P
288 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
290 #undef TARGET_CAN_ELIMINATE
291 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
293 #undef TARGET_TRAMPOLINE_INIT
294 #define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
296 struct gcc_target targetm
= TARGET_INITIALIZER
;
299 m68hc11_override_options (void)
301 memset (m68hc11_reg_valid_for_index
, 0,
302 sizeof (m68hc11_reg_valid_for_index
));
303 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
305 /* Compilation with -fpic generates a wrong code. */
308 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
309 (flag_pic
> 1) ? "PIC" : "pic");
313 /* Do not enable -fweb because it breaks the 32-bit shift patterns
314 by breaking the match_dup of those patterns. The shift patterns
315 will no longer be recognized after that. */
318 /* Configure for a 68hc11 processor. */
321 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
322 m68hc11_cost
= &m6811_cost
;
323 m68hc11_min_offset
= 0;
324 m68hc11_max_offset
= 256;
325 m68hc11_index_reg_class
= NO_REGS
;
326 m68hc11_base_reg_class
= A_REGS
;
327 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
328 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
329 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
330 m68hc11_sp_correction
= 1;
331 m68hc11_tmp_regs_class
= D_REGS
;
332 m68hc11_addr_mode
= ADDR_OFFSET
;
333 m68hc11_mov_addr_mode
= 0;
334 if (m68hc11_soft_reg_count
< 0)
335 m68hc11_soft_reg_count
= 4;
338 /* Configure for a 68hc12 processor. */
341 m68hc11_cost
= &m6812_cost
;
342 m68hc11_min_offset
= -65536;
343 m68hc11_max_offset
= 65536;
344 m68hc11_index_reg_class
= D_REGS
;
345 m68hc11_base_reg_class
= A_OR_SP_REGS
;
346 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
347 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
348 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
349 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
350 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
351 m68hc11_sp_correction
= 0;
352 m68hc11_tmp_regs_class
= TMP_REGS
;
353 m68hc11_addr_mode
= ADDR_INDIRECT
| ADDR_OFFSET
| ADDR_CONST
354 | (TARGET_AUTO_INC_DEC
? ADDR_INCDEC
: 0);
355 m68hc11_mov_addr_mode
= ADDR_OFFSET
| ADDR_CONST
356 | (TARGET_AUTO_INC_DEC
? ADDR_INCDEC
: 0);
357 target_flags
|= MASK_NO_DIRECT_MODE
;
358 if (m68hc11_soft_reg_count
< 0)
359 m68hc11_soft_reg_count
= 0;
361 if (TARGET_LONG_CALLS
)
362 current_function_far
= 1;
369 m68hc11_conditional_register_usage (void)
373 if (m68hc11_soft_reg_count
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
374 m68hc11_soft_reg_count
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
376 for (i
= SOFT_REG_FIRST
+ m68hc11_soft_reg_count
; i
< SOFT_REG_LAST
; i
++)
379 call_used_regs
[i
] = 1;
382 /* For 68HC12, the Z register emulation is not necessary when the
383 frame pointer is not used. The frame pointer is eliminated and
384 replaced by the stack register (which is a BASE_REG_CLASS). */
385 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
387 fixed_regs
[HARD_Z_REGNUM
] = 1;
392 /* Reload and register operations. */
396 create_regs_rtx (void)
398 /* regs_inited = 1; */
399 ix_reg
= gen_rtx_REG (HImode
, HARD_X_REGNUM
);
400 iy_reg
= gen_rtx_REG (HImode
, HARD_Y_REGNUM
);
401 d_reg
= gen_rtx_REG (HImode
, HARD_D_REGNUM
);
402 m68hc11_soft_tmp_reg
= gen_rtx_REG (HImode
, SOFT_TMP_REGNUM
);
404 stack_push_word
= gen_rtx_MEM (HImode
,
405 gen_rtx_PRE_DEC (HImode
,
406 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
407 stack_pop_word
= gen_rtx_MEM (HImode
,
408 gen_rtx_POST_INC (HImode
,
409 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
413 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
414 - 8-bit values are stored anywhere (except the SP register).
415 - 16-bit values can be stored in any register whose mode is 16
416 - 32-bit values can be stored in D, X registers or in a soft register
417 (except the last one because we need 2 soft registers)
418 - Values whose size is > 32 bit are not stored in real hard
419 registers. They may be stored in soft registers if there are
422 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
424 switch (GET_MODE_SIZE (mode
))
427 return S_REGNO_P (regno
) && m68hc11_soft_reg_count
>= 4;
430 return (X_REGNO_P (regno
)
431 || (S_REGNO_P (regno
) && m68hc11_soft_reg_count
>= 2));
434 return G_REGNO_P (regno
);
437 /* We have to accept a QImode in X or Y registers. Otherwise, the
438 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
439 in the insns. Reload fails if the insn rejects the register class 'a'
440 as well as if it accepts it. Patterns that failed were
441 zero_extend_qihi2 and iorqi3. */
443 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
451 m68hc11_hard_regno_rename_ok (int reg1
, int reg2
)
453 /* Don't accept renaming to Z register. We will replace it to
454 X,Y or D during machine reorg pass. */
455 if (reg2
== HARD_Z_REGNUM
)
458 /* Don't accept renaming D,X to Y register as the code will be bigger. */
459 if (TARGET_M6811
&& reg2
== HARD_Y_REGNUM
460 && (D_REGNO_P (reg1
) || X_REGNO_P (reg1
)))
467 preferred_reload_class (rtx operand
, enum reg_class rclass
)
469 enum machine_mode mode
;
471 mode
= GET_MODE (operand
);
475 printf ("Preferred reload: (class=%s): ", reg_class_names
[rclass
]);
478 if (rclass
== D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
479 return m68hc11_base_reg_class
;
481 if (rclass
>= S_REGS
&& (GET_CODE (operand
) == MEM
482 || GET_CODE (operand
) == CONST_INT
))
484 /* S_REGS class must not be used. The movhi template does not
485 work to move a memory to a soft register.
486 Restrict to a hard reg. */
491 case D_OR_A_OR_S_REGS
:
492 rclass
= A_OR_D_REGS
;
497 case D_OR_SP_OR_S_REGS
:
498 rclass
= D_OR_SP_REGS
;
500 case D_OR_Y_OR_S_REGS
:
501 rclass
= D_OR_Y_REGS
;
503 case D_OR_X_OR_S_REGS
:
504 rclass
= D_OR_X_REGS
;
519 else if (rclass
== Y_REGS
&& GET_CODE (operand
) == MEM
)
523 else if (rclass
== A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
525 rclass
= D_OR_X_REGS
;
527 else if (rclass
>= S_REGS
&& S_REG_P (operand
))
533 case D_OR_A_OR_S_REGS
:
534 rclass
= A_OR_D_REGS
;
539 case D_OR_SP_OR_S_REGS
:
540 rclass
= D_OR_SP_REGS
;
542 case D_OR_Y_OR_S_REGS
:
543 rclass
= D_OR_Y_REGS
;
545 case D_OR_X_OR_S_REGS
:
546 rclass
= D_OR_X_REGS
;
561 else if (rclass
>= S_REGS
)
565 printf ("Class = %s for: ", reg_class_names
[rclass
]);
573 printf (" => class=%s\n", reg_class_names
[rclass
]);
581 /* Return 1 if the operand is a valid indexed addressing mode.
582 For 68hc11: n,r with n in [0..255] and r in A_REGS class
583 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
585 m68hc11_valid_addressing_p (rtx operand
, enum machine_mode mode
, int addr_mode
)
589 switch (GET_CODE (operand
))
592 if ((addr_mode
& ADDR_INDIRECT
) && GET_MODE_SIZE (mode
) <= 2)
593 return m68hc11_valid_addressing_p (XEXP (operand
, 0), mode
,
594 addr_mode
& (ADDR_STRICT
| ADDR_OFFSET
));
601 if (addr_mode
& ADDR_INCDEC
)
602 return m68hc11_valid_addressing_p (XEXP (operand
, 0), mode
,
603 addr_mode
& ADDR_STRICT
);
607 base
= XEXP (operand
, 0);
608 if (GET_CODE (base
) == MEM
)
611 offset
= XEXP (operand
, 1);
612 if (GET_CODE (offset
) == MEM
)
615 /* Indexed addressing mode with 2 registers. */
616 if (GET_CODE (base
) == REG
&& GET_CODE (offset
) == REG
)
618 if (!(addr_mode
& ADDR_INDEXED
))
621 addr_mode
&= ADDR_STRICT
;
622 if (REGNO_OK_FOR_BASE_P2 (REGNO (base
), addr_mode
)
623 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset
), addr_mode
))
626 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset
), addr_mode
)
627 && REGNO_OK_FOR_INDEX_P2 (REGNO (base
), addr_mode
))
633 if (!(addr_mode
& ADDR_OFFSET
))
636 if (GET_CODE (base
) == REG
)
638 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
641 if (!(addr_mode
& ADDR_STRICT
))
644 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), 1);
647 if (GET_CODE (offset
) == REG
)
649 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
652 if (!(addr_mode
& ADDR_STRICT
))
655 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), 1);
660 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), addr_mode
& ADDR_STRICT
);
663 if (addr_mode
& ADDR_CONST
)
664 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
672 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
673 a 68HC12 1-byte index addressing mode. */
675 m68hc11_small_indexed_indirect_p (rtx operand
, enum machine_mode mode
)
680 if (GET_CODE (operand
) == REG
&& reload_in_progress
681 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
682 && reg_equiv_memory_loc
[REGNO (operand
)])
684 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
685 operand
= eliminate_regs (operand
, VOIDmode
, NULL_RTX
);
688 if (GET_CODE (operand
) != MEM
)
691 operand
= XEXP (operand
, 0);
692 if (CONSTANT_ADDRESS_P (operand
))
695 if (PUSH_POP_ADDRESS_P (operand
))
698 addr_mode
= m68hc11_mov_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
699 if (!m68hc11_valid_addressing_p (operand
, mode
, addr_mode
))
702 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
703 && (reload_completed
| reload_in_progress
))
705 base
= XEXP (operand
, 0);
706 offset
= XEXP (operand
, 1);
708 /* The offset can be a symbol address and this is too big
709 for the operand constraint. */
710 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
713 if (GET_CODE (base
) == CONST_INT
)
716 switch (GET_MODE_SIZE (mode
))
719 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
724 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
729 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
738 m68hc11_register_indirect_p (rtx operand
, enum machine_mode mode
)
742 if (GET_CODE (operand
) == REG
&& reload_in_progress
743 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
744 && reg_equiv_memory_loc
[REGNO (operand
)])
746 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
747 operand
= eliminate_regs (operand
, VOIDmode
, NULL_RTX
);
749 if (GET_CODE (operand
) != MEM
)
752 operand
= XEXP (operand
, 0);
753 addr_mode
= m68hc11_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
754 return m68hc11_valid_addressing_p (operand
, mode
, addr_mode
);
758 m68hc11_legitimate_address_p_1 (enum machine_mode mode
, rtx operand
,
763 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
765 /* Reject the global variables if they are too wide. This forces
766 a load of their address in a register and generates smaller code. */
767 if (GET_MODE_SIZE (mode
) == 8)
772 addr_mode
= m68hc11_addr_mode
| (strict
? ADDR_STRICT
: 0);
773 if (m68hc11_valid_addressing_p (operand
, mode
, addr_mode
))
777 if (PUSH_POP_ADDRESS_P (operand
))
781 if (symbolic_memory_operand (operand
, mode
))
789 m68hc11_legitimate_address_p (enum machine_mode mode
, rtx operand
,
796 printf ("Checking: ");
801 result
= m68hc11_legitimate_address_p_1 (mode
, operand
, strict
);
805 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
812 printf ("go_if_legitimate%s, ret 0: %d:",
813 (strict
? "_strict" : ""), mode
);
823 m68hc11_reload_operands (rtx operands
[])
825 enum machine_mode mode
;
827 if (regs_inited
== 0)
830 mode
= GET_MODE (operands
[1]);
832 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
833 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
835 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
836 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
838 if (GET_CODE (base
) != REG
)
845 /* If the offset is out of range, we have to compute the address
846 with a separate add instruction. We try to do this with an 8-bit
847 add on the A register. This is possible only if the lowest part
848 of the offset (i.e., big_offset % 256) is a valid constant offset
849 with respect to the mode. If it's not, we have to generate a
850 16-bit add on the D register. From:
852 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
856 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
857 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
858 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
859 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
861 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
862 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
865 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
868 rtx reg
= operands
[0];
870 int val
= INTVAL (big_offset
);
873 /* We use the 'operands[0]' as a scratch register to compute the
874 address. Make sure 'base' is in that register. */
875 if (!rtx_equal_p (base
, operands
[0]))
877 emit_move_insn (reg
, base
);
887 vh
= (val
>> 8) & 0x0FF;
891 /* Create the lowest part offset that still remains to be added.
892 If it's not a valid offset, do a 16-bit add. */
893 offset
= GEN_INT (vl
);
894 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
896 emit_insn (gen_rtx_SET (VOIDmode
, reg
,
897 gen_rtx_PLUS (HImode
, reg
, big_offset
)));
902 emit_insn (gen_rtx_SET (VOIDmode
, reg
,
903 gen_rtx_PLUS (HImode
, reg
,
904 GEN_INT (vh
<< 8))));
906 emit_move_insn (operands
[0],
907 gen_rtx_MEM (GET_MODE (operands
[1]),
908 gen_rtx_PLUS (Pmode
, reg
, offset
)));
913 /* Use the normal gen_movhi pattern. */
918 m68hc11_emit_libcall (const char *name
, enum rtx_code code
,
919 enum machine_mode dmode
, enum machine_mode smode
,
920 int noperands
, rtx
*operands
)
928 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
932 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
933 dmode
, 1, operands
[1], smode
);
934 equiv
= gen_rtx_fmt_e (code
, dmode
, operands
[1]);
938 ret
= emit_library_call_value (libcall
, NULL_RTX
,
940 operands
[1], smode
, operands
[2],
942 equiv
= gen_rtx_fmt_ee (code
, dmode
, operands
[1], operands
[2]);
949 insns
= get_insns ();
951 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
954 /* Returns true if X is a PRE/POST increment decrement
955 (same as auto_inc_p() in rtlanal.c but do not take into
956 account the stack). */
958 m68hc11_auto_inc_p (rtx x
)
960 return GET_CODE (x
) == PRE_DEC
961 || GET_CODE (x
) == POST_INC
962 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
966 /* Predicates for machine description. */
969 memory_reload_operand (rtx operand
, enum machine_mode mode ATTRIBUTE_UNUSED
)
971 return GET_CODE (operand
) == MEM
972 && GET_CODE (XEXP (operand
, 0)) == PLUS
973 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
974 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
975 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
976 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
980 m68hc11_symbolic_p (rtx operand
, enum machine_mode mode
)
982 if (GET_CODE (operand
) == MEM
)
984 rtx op
= XEXP (operand
, 0);
986 if (symbolic_memory_operand (op
, mode
))
993 m68hc11_indirect_p (rtx operand
, enum machine_mode mode
)
995 if (GET_CODE (operand
) == MEM
&& GET_MODE (operand
) == mode
)
997 rtx op
= XEXP (operand
, 0);
1000 if (m68hc11_page0_symbol_p (op
))
1003 if (symbolic_memory_operand (op
, mode
))
1004 return TARGET_M6812
;
1006 if (reload_in_progress
)
1009 operand
= XEXP (operand
, 0);
1010 addr_mode
= m68hc11_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
1011 return m68hc11_valid_addressing_p (operand
, mode
, addr_mode
);
1017 memory_indexed_operand (rtx operand
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1019 if (GET_CODE (operand
) != MEM
)
1022 operand
= XEXP (operand
, 0);
1023 if (GET_CODE (operand
) == PLUS
)
1025 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1026 operand
= XEXP (operand
, 0);
1027 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1028 operand
= XEXP (operand
, 1);
1030 return GET_CODE (operand
) == REG
1031 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1032 || A_REGNO_P (REGNO (operand
)));
1036 push_pop_operand_p (rtx operand
)
1038 if (GET_CODE (operand
) != MEM
)
1042 operand
= XEXP (operand
, 0);
1043 return PUSH_POP_ADDRESS_P (operand
);
1046 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1047 reference and a constant. */
1050 symbolic_memory_operand (rtx op
, enum machine_mode mode
)
1052 switch (GET_CODE (op
))
1060 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1061 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1062 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1064 /* ??? This clause seems to be irrelevant. */
1066 return GET_MODE (op
) == mode
;
1069 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1070 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1077 /* Emit the code to build the trampoline used to call a nested function.
1081 ldy #&CXT movw #&CXT,*_.d1
1082 sty *_.d1 jmp FNADDR
1087 m68hc11_trampoline_init (rtx m_tramp
, tree fndecl
, rtx cxt
)
1089 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1090 rtx fnaddr
= XEXP (DECL_RTL (fndecl
), 0);
1094 if (*static_chain_reg
== '*')
1098 mem
= adjust_address (m_tramp
, HImode
, 0);
1099 emit_move_insn (mem
, GEN_INT (0x18ce));
1100 mem
= adjust_address (m_tramp
, HImode
, 2);
1101 emit_move_insn (mem
, cxt
);
1102 mem
= adjust_address (m_tramp
, HImode
, 4);
1103 emit_move_insn (mem
, GEN_INT (0x18df));
1104 mem
= adjust_address (m_tramp
, QImode
, 6);
1105 emit_move_insn (mem
,
1106 gen_rtx_CONST (QImode
,
1107 gen_rtx_SYMBOL_REF (Pmode
,
1108 static_chain_reg
)));
1109 mem
= adjust_address (m_tramp
, QImode
, 7);
1110 emit_move_insn (mem
, GEN_INT (0x7e));
1111 mem
= adjust_address (m_tramp
, HImode
, 8);
1112 emit_move_insn (mem
, fnaddr
);
1116 mem
= adjust_address (m_tramp
, HImode
, 0);
1117 emit_move_insn (mem
, GEN_INT (0x1803));
1118 mem
= adjust_address (m_tramp
, HImode
, 2);
1119 emit_move_insn (mem
, cxt
);
1120 mem
= adjust_address (m_tramp
, HImode
, 4);
1121 emit_move_insn (mem
,
1122 gen_rtx_CONST (HImode
,
1123 gen_rtx_SYMBOL_REF (Pmode
,
1124 static_chain_reg
)));
1125 mem
= adjust_address (m_tramp
, QImode
, 6);
1126 emit_move_insn (mem
, GEN_INT (0x06));
1127 mem
= adjust_address (m_tramp
, HImode
, 7);
1128 emit_move_insn (mem
, fnaddr
);
1132 /* Declaration of types. */
1134 /* Handle an "tiny_data" attribute; arguments as in
1135 struct attribute_spec.handler. */
1137 m68hc11_handle_page0_attribute (tree
*node
, tree name
,
1138 tree args ATTRIBUTE_UNUSED
,
1139 int flags ATTRIBUTE_UNUSED
, bool *no_add_attrs
)
1143 if (TREE_STATIC (decl
) || DECL_EXTERNAL (decl
))
1145 DECL_SECTION_NAME (decl
) = build_string (6, ".page0");
1149 warning (OPT_Wattributes
, "%qE attribute ignored",
1151 *no_add_attrs
= true;
1157 /* Keep track of the symbol which has a `trap' attribute and which uses
1158 the `swi' calling convention. Since there is only one trap, we only
1159 record one such symbol. If there are several, a warning is reported. */
1160 static rtx trap_handler_symbol
= 0;
1162 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1163 arguments as in struct attribute_spec.handler. */
1165 m68hc11_handle_fntype_attribute (tree
*node
, tree name
,
1166 tree args ATTRIBUTE_UNUSED
,
1167 int flags ATTRIBUTE_UNUSED
,
1170 if (TREE_CODE (*node
) != FUNCTION_TYPE
1171 && TREE_CODE (*node
) != METHOD_TYPE
1172 && TREE_CODE (*node
) != FIELD_DECL
1173 && TREE_CODE (*node
) != TYPE_DECL
)
1175 warning (OPT_Wattributes
, "%qE attribute only applies to functions",
1177 *no_add_attrs
= true;
1182 /* Undo the effects of the above. */
1185 m68hc11_strip_name_encoding (const char *str
)
1187 return str
+ (*str
== '*' || *str
== '@' || *str
== '&');
1191 m68hc11_encode_label (tree decl
)
1193 const char *str
= XSTR (XEXP (DECL_RTL (decl
), 0), 0);
1194 int len
= strlen (str
);
1195 char *newstr
= XALLOCAVEC (char, len
+ 2);
1198 strcpy (&newstr
[1], str
);
1200 XSTR (XEXP (DECL_RTL (decl
), 0), 0) = ggc_alloc_string (newstr
, len
+ 1);
1203 /* Return 1 if this is a symbol in page0 */
1205 m68hc11_page0_symbol_p (rtx x
)
1207 switch (GET_CODE (x
))
1210 return XSTR (x
, 0) != 0 && XSTR (x
, 0)[0] == '@';
1213 return m68hc11_page0_symbol_p (XEXP (x
, 0));
1216 if (!m68hc11_page0_symbol_p (XEXP (x
, 0)))
1219 return GET_CODE (XEXP (x
, 1)) == CONST_INT
1220 && INTVAL (XEXP (x
, 1)) < 256
1221 && INTVAL (XEXP (x
, 1)) >= 0;
1228 /* We want to recognize trap handlers so that we handle calls to traps
1229 in a special manner (by issuing the trap). This information is stored
1230 in SYMBOL_REF_FLAG. */
1233 m68hc11_encode_section_info (tree decl
, rtx rtl
, int first ATTRIBUTE_UNUSED
)
1239 if (TREE_CODE (decl
) == VAR_DECL
)
1241 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl
)) != 0)
1242 m68hc11_encode_label (decl
);
1246 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1249 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1252 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1254 else if (lookup_attribute ("near", func_attr
) == NULL_TREE
)
1255 is_far
= TARGET_LONG_CALLS
!= 0;
1257 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1258 if (trap_handler
&& is_far
)
1260 warning (OPT_Wattributes
, "%<trap%> and %<far%> attributes are "
1261 "not compatible, ignoring %<far%>");
1266 if (trap_handler_symbol
!= 0)
1267 warning (OPT_Wattributes
, "%<trap%> attribute is already used");
1269 trap_handler_symbol
= XEXP (rtl
, 0);
1271 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = is_far
;
1275 m68hc11_section_type_flags (tree decl
, const char *name
, int reloc
)
1277 unsigned int flags
= default_section_type_flags (decl
, name
, reloc
);
1279 if (strncmp (name
, ".eeprom", 7) == 0)
1281 flags
|= SECTION_WRITE
| SECTION_CODE
| SECTION_OVERRIDE
;
1288 m68hc11_is_far_symbol (rtx sym
)
1290 if (GET_CODE (sym
) == MEM
)
1291 sym
= XEXP (sym
, 0);
1293 return SYMBOL_REF_FLAG (sym
);
1297 m68hc11_is_trap_symbol (rtx sym
)
1299 if (GET_CODE (sym
) == MEM
)
1300 sym
= XEXP (sym
, 0);
1302 return trap_handler_symbol
!= 0 && rtx_equal_p (trap_handler_symbol
, sym
);
1306 /* Argument support functions. */
1308 /* Given FROM and TO register numbers, say whether this elimination is
1309 allowed. Frame pointer elimination is automatically handled.
1311 All other eliminations are valid. */
1314 m68hc11_can_eliminate (const int from
, const int to
)
1316 return (from
== ARG_POINTER_REGNUM
&& to
== STACK_POINTER_REGNUM
1317 ? ! frame_pointer_needed
1321 /* Define the offset between two registers, one to be eliminated, and the
1322 other its replacement, at the start of a routine. */
1324 m68hc11_initial_elimination_offset (int from
, int to
)
1331 /* For a trap handler, we must take into account the registers which
1332 are pushed on the stack during the trap (except the PC). */
1333 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1334 current_function_interrupt
= lookup_attribute ("interrupt",
1335 func_attr
) != NULL_TREE
;
1336 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1338 if (lookup_attribute ("far", func_attr
) != 0)
1339 current_function_far
= 1;
1340 else if (lookup_attribute ("near", func_attr
) != 0)
1341 current_function_far
= 0;
1343 current_function_far
= (TARGET_LONG_CALLS
!= 0
1344 && !current_function_interrupt
1347 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1350 /* For a function using 'call/rtc' we must take into account the
1351 page register which is pushed in the call. */
1352 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1357 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1359 /* 2 is for the saved frame.
1360 1 is for the 'sts' correction when creating the frame. */
1361 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1364 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1366 return m68hc11_sp_correction
;
1369 /* Push any 2 byte pseudo hard registers that we need to save. */
1370 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1372 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1378 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1380 return get_frame_size () + size
;
1383 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1390 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1391 for a call to a function whose data type is FNTYPE.
1392 For a library call, FNTYPE is 0. */
1395 m68hc11_init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
, rtx libname
)
1399 z_replacement_completed
= 0;
1403 /* For a library call, we must find out the type of the return value.
1404 When the return value is bigger than 4 bytes, it is returned in
1405 memory. In that case, the first argument of the library call is a
1406 pointer to the memory location. Because the first argument is passed in
1407 register D, we have to identify this, so that the first function
1408 parameter is not passed in D either. */
1414 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1417 /* If the library ends in 'di' or in 'df', we assume it's
1418 returning some DImode or some DFmode which are 64-bit wide. */
1419 name
= XSTR (libname
, 0);
1420 len
= strlen (name
);
1422 && ((name
[len
- 2] == 'd'
1423 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1424 || (name
[len
- 3] == 'd'
1425 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1427 /* We are in. Mark the first parameter register as already used. */
1434 ret_type
= TREE_TYPE (fntype
);
1436 if (ret_type
&& aggregate_value_p (ret_type
, fntype
))
1443 /* Update the data in CUM to advance over an argument
1444 of mode MODE and data type TYPE.
1445 (TYPE is null for libcalls where that information may not be available.) */
1448 m68hc11_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1449 tree type
, int named ATTRIBUTE_UNUSED
)
1451 if (mode
!= BLKmode
)
1453 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1456 cum
->words
= GET_MODE_SIZE (mode
);
1460 cum
->words
+= GET_MODE_SIZE (mode
);
1461 if (cum
->words
<= HARD_REG_SIZE
)
1467 cum
->words
+= int_size_in_bytes (type
);
1472 /* Define where to put the arguments to a function.
1473 Value is zero to push the argument on the stack,
1474 or a hard register in which to store the argument.
1476 MODE is the argument's machine mode.
1477 TYPE is the data type of the argument (as a tree).
1478 This is null for libcalls where that information may
1480 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1481 the preceding args and about the function being called.
1482 NAMED is nonzero if this argument is a named parameter
1483 (otherwise it is an extra parameter matching an ellipsis). */
1486 m68hc11_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1487 tree type ATTRIBUTE_UNUSED
, int named ATTRIBUTE_UNUSED
)
1489 if (cum
->words
!= 0)
1494 if (mode
!= BLKmode
)
1496 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1497 return gen_rtx_REG (mode
, HARD_X_REGNUM
);
1499 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1503 return gen_rtx_REG (mode
, HARD_D_REGNUM
);
1508 /* If defined, a C expression which determines whether, and in which direction,
1509 to pad out an argument with extra space. The value should be of type
1510 `enum direction': either `upward' to pad above the argument,
1511 `downward' to pad below, or `none' to inhibit padding.
1513 Structures are stored left shifted in their argument slot. */
1515 m68hc11_function_arg_padding (enum machine_mode mode
, const_tree type
)
1517 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1520 /* Fall back to the default. */
1521 return DEFAULT_FUNCTION_ARG_PADDING (mode
, type
);
1525 /* Function prologue and epilogue. */
1527 /* Emit a move after the reload pass has completed. This is used to
1528 emit the prologue and epilogue. */
1530 emit_move_after_reload (rtx to
, rtx from
, rtx scratch
)
1534 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1536 insn
= emit_move_insn (to
, from
);
1540 emit_move_insn (scratch
, from
);
1541 insn
= emit_move_insn (to
, scratch
);
1544 /* Put a REG_INC note to tell the flow analysis that the instruction
1546 if (IS_STACK_PUSH (to
))
1547 add_reg_note (insn
, REG_INC
, XEXP (XEXP (to
, 0), 0));
1548 else if (IS_STACK_POP (from
))
1549 add_reg_note (insn
, REG_INC
, XEXP (XEXP (from
, 0), 0));
1551 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1552 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1553 The problem is that we are lying to gcc and use `txs' for x = sp
1554 (which is not really true because txs is really x = sp + 1). */
1555 else if (TARGET_M6811
&& SP_REG_P (from
))
1556 add_reg_note (insn
, REG_INC
, from
);
1560 m68hc11_total_frame_size (void)
1565 size
= get_frame_size ();
1566 if (current_function_interrupt
)
1568 size
+= 3 * HARD_REG_SIZE
;
1570 if (frame_pointer_needed
)
1571 size
+= HARD_REG_SIZE
;
1573 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1574 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1575 size
+= HARD_REG_SIZE
;
1581 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED
,
1582 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
1584 /* We catch the function epilogue generation to have a chance
1585 to clear the z_replacement_completed flag. */
1586 z_replacement_completed
= 0;
1590 expand_prologue (void)
1597 gcc_assert (reload_completed
== 1);
1599 size
= get_frame_size ();
1603 /* Generate specific prologue for interrupt handlers. */
1604 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1605 current_function_interrupt
= lookup_attribute ("interrupt",
1606 func_attr
) != NULL_TREE
;
1607 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1608 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1609 current_function_far
= 1;
1610 else if (lookup_attribute ("near", func_attr
) != NULL_TREE
)
1611 current_function_far
= 0;
1613 current_function_far
= (TARGET_LONG_CALLS
!= 0
1614 && !current_function_interrupt
1615 && !current_function_trap
);
1617 /* Get the scratch register to build the frame and push registers.
1618 If the first argument is a 32-bit quantity, the D+X registers
1619 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1620 For 68HC12, this scratch register is not used. */
1621 if (crtl
->args
.info
.nregs
== 2)
1626 /* Save current stack frame. */
1627 if (frame_pointer_needed
)
1628 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1630 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1631 Other soft registers in page0 need not to be saved because they
1632 will be restored by C functions. For a trap handler, we don't
1633 need to preserve these registers because this is a synchronous call. */
1634 if (current_function_interrupt
)
1636 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1637 emit_move_after_reload (stack_push_word
,
1638 gen_rtx_REG (HImode
, SOFT_Z_REGNUM
), scratch
);
1639 emit_move_after_reload (stack_push_word
,
1640 gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
),
1644 /* Allocate local variables. */
1645 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1647 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1648 stack_pointer_rtx
, GEN_INT (-size
)));
1650 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1654 insn
= gen_rtx_PARALLEL
1657 gen_rtx_SET (VOIDmode
,
1659 gen_rtx_PLUS (HImode
,
1662 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1669 /* Allocate by pushing scratch values. */
1670 for (i
= 2; i
<= size
; i
+= 2)
1671 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1674 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1675 stack_pointer_rtx
, constm1_rtx
));
1678 /* Create the frame pointer. */
1679 if (frame_pointer_needed
)
1680 emit_move_after_reload (hard_frame_pointer_rtx
,
1681 stack_pointer_rtx
, scratch
);
1683 /* Push any 2 byte pseudo hard registers that we need to save. */
1684 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1686 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1688 emit_move_after_reload (stack_push_word
,
1689 gen_rtx_REG (HImode
, regno
), scratch
);
1695 expand_epilogue (void)
1702 gcc_assert (reload_completed
== 1);
1704 size
= get_frame_size ();
1706 /* If we are returning a value in two registers, we have to preserve the
1707 X register and use the Y register to restore the stack and the saved
1708 registers. Otherwise, use X because it's faster (and smaller). */
1709 if (crtl
->return_rtx
== 0)
1711 else if (GET_CODE (crtl
->return_rtx
) == MEM
)
1712 return_size
= HARD_REG_SIZE
;
1714 return_size
= GET_MODE_SIZE (GET_MODE (crtl
->return_rtx
));
1716 if (return_size
> HARD_REG_SIZE
&& return_size
<= 2 * HARD_REG_SIZE
)
1721 /* Pop any 2 byte pseudo hard registers that we saved. */
1722 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1724 if (df_regs_ever_live_p (regno
) && !call_used_regs
[regno
])
1726 emit_move_after_reload (gen_rtx_REG (HImode
, regno
),
1727 stack_pop_word
, scratch
);
1731 /* de-allocate auto variables */
1732 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1734 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1735 stack_pointer_rtx
, GEN_INT (size
)));
1737 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1741 insn
= gen_rtx_PARALLEL
1744 gen_rtx_SET (VOIDmode
,
1746 gen_rtx_PLUS (HImode
,
1749 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1756 for (i
= 2; i
<= size
; i
+= 2)
1757 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1759 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1760 stack_pointer_rtx
, const1_rtx
));
1763 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1764 if (current_function_interrupt
)
1766 emit_move_after_reload (gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
),
1767 stack_pop_word
, scratch
);
1768 emit_move_after_reload (gen_rtx_REG (HImode
, SOFT_Z_REGNUM
),
1769 stack_pop_word
, scratch
);
1770 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1773 /* Restore previous frame pointer. */
1774 if (frame_pointer_needed
)
1775 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1777 /* If the trap handler returns some value, copy the value
1778 in D, X onto the stack so that the rti will pop the return value
1780 else if (current_function_trap
&& return_size
!= 0)
1782 rtx addr_reg
= stack_pointer_rtx
;
1786 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1789 emit_move_after_reload (gen_rtx_MEM (HImode
,
1790 gen_rtx_PLUS (HImode
, addr_reg
,
1791 const1_rtx
)), d_reg
, 0);
1792 if (return_size
> HARD_REG_SIZE
)
1793 emit_move_after_reload (gen_rtx_MEM (HImode
,
1794 gen_rtx_PLUS (HImode
, addr_reg
,
1795 GEN_INT (3))), ix_reg
, 0);
1798 emit_jump_insn (gen_return ());
1802 /* Low and High part extraction for 68HC11. These routines are
1803 similar to gen_lowpart and gen_highpart but they have been
1804 fixed to work for constants and 68HC11 specific registers. */
1807 m68hc11_gen_lowpart (enum machine_mode mode
, rtx x
)
1809 /* We assume that the low part of an auto-inc mode is the same with
1810 the mode changed and that the caller split the larger mode in the
1812 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1814 return gen_rtx_MEM (mode
, XEXP (x
, 0));
1817 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1818 floating-point constant. A CONST_DOUBLE is used whenever the
1819 constant requires more than one word in order to be adequately
1821 if (GET_CODE (x
) == CONST_DOUBLE
)
1825 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1829 if (GET_MODE (x
) == SFmode
)
1831 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1832 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1838 split_double (x
, &first
, &second
);
1842 return GEN_INT (l
[0]);
1844 return gen_int_mode (l
[0], HImode
);
1848 l
[0] = CONST_DOUBLE_LOW (x
);
1853 return GEN_INT (l
[0]);
1855 gcc_assert (GET_MODE (x
) == SFmode
);
1856 return gen_int_mode (l
[0], HImode
);
1862 if (mode
== QImode
&& D_REG_P (x
))
1863 return gen_rtx_REG (mode
, HARD_B_REGNUM
);
1865 /* gen_lowpart crashes when it is called with a SUBREG. */
1866 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1871 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1873 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1878 x
= gen_lowpart (mode
, x
);
1880 /* Return a different rtx to avoid to share it in several insns
1881 (when used by a split pattern). Sharing addresses within
1882 a MEM breaks the Z register replacement (and reloading). */
1883 if (GET_CODE (x
) == MEM
)
1889 m68hc11_gen_highpart (enum machine_mode mode
, rtx x
)
1891 /* We assume that the high part of an auto-inc mode is the same with
1892 the mode changed and that the caller split the larger mode in the
1894 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1896 return gen_rtx_MEM (mode
, XEXP (x
, 0));
1899 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1900 floating-point constant. A CONST_DOUBLE is used whenever the
1901 constant requires more than one word in order to be adequately
1903 if (GET_CODE (x
) == CONST_DOUBLE
)
1907 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1911 if (GET_MODE (x
) == SFmode
)
1913 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1914 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1920 split_double (x
, &first
, &second
);
1924 return GEN_INT (l
[1]);
1926 return gen_int_mode ((l
[1] >> 16), HImode
);
1930 l
[1] = CONST_DOUBLE_HIGH (x
);
1936 return GEN_INT (l
[1]);
1938 gcc_assert (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
);
1939 return gen_int_mode ((l
[0] >> 16), HImode
);
1944 if (GET_CODE (x
) == CONST_INT
)
1946 HOST_WIDE_INT val
= INTVAL (x
);
1950 return gen_int_mode (val
>> 8, QImode
);
1952 else if (mode
== HImode
)
1954 return gen_int_mode (val
>> 16, HImode
);
1956 else if (mode
== SImode
)
1958 return gen_int_mode (val
>> 32, SImode
);
1961 if (mode
== QImode
&& D_REG_P (x
))
1962 return gen_rtx_REG (mode
, HARD_A_REGNUM
);
1964 /* There is no way in GCC to represent the upper part of a word register.
1965 To obtain the 8-bit upper part of a soft register, we change the
1966 reg into a mem rtx. This is possible because they are physically
1967 located in memory. There is no offset because we are big-endian. */
1968 if (mode
== QImode
&& S_REG_P (x
))
1972 /* Avoid the '*' for direct addressing mode when this
1973 addressing mode is disabled. */
1974 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1975 return gen_rtx_MEM (QImode
,
1976 gen_rtx_SYMBOL_REF (Pmode
,
1977 ®_names
[REGNO (x
)][pos
]));
1980 /* gen_highpart crashes when it is called with a SUBREG. */
1981 switch (GET_CODE (x
))
1984 return gen_rtx_SUBREG (mode
, XEXP (x
, 0), XINT (x
, 1));
1986 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
1987 return gen_rtx_REG (mode
, REGNO (x
));
1989 return gen_rtx_SUBREG (mode
, x
, 0);
1991 x
= change_address (x
, mode
, 0);
1993 /* Return a different rtx to avoid to share it in several insns
1994 (when used by a split pattern). Sharing addresses within
1995 a MEM breaks the Z register replacement (and reloading). */
1996 if (GET_CODE (x
) == MEM
)
2006 /* Obscure register manipulation. */
2008 /* Finds backward in the instructions to see if register 'reg' is
2009 dead. This is used when generating code to see if we can use 'reg'
2010 as a scratch register. This allows us to choose a better generation
2011 of code when we know that some register dies or can be clobbered. */
2014 dead_register_here (rtx x
, rtx reg
)
2020 x_reg
= gen_rtx_REG (SImode
, HARD_X_REGNUM
);
2024 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2031 if (GET_CODE (body
) == CALL_INSN
)
2033 if (GET_CODE (body
) == JUMP_INSN
)
2036 if (GET_CODE (body
) == SET
)
2038 rtx dst
= XEXP (body
, 0);
2040 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2042 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2045 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2048 else if (reg_mentioned_p (reg
, p
)
2049 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2053 /* Scan forward to see if the register is set in some insns and never
2055 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2059 if (GET_CODE (p
) == CODE_LABEL
2060 || GET_CODE (p
) == JUMP_INSN
2061 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2064 if (GET_CODE (p
) != INSN
)
2068 if (GET_CODE (body
) == SET
)
2070 rtx src
= XEXP (body
, 1);
2071 rtx dst
= XEXP (body
, 0);
2073 if (GET_CODE (dst
) == REG
2074 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2078 /* Register is used (may be in source or in dest). */
2079 if (reg_mentioned_p (reg
, p
)
2080 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2081 && reg_mentioned_p (x_reg
, p
)))
2084 return p
== 0 ? 1 : 0;
2088 /* Code generation operations called from machine description file. */
2090 /* Print the name of register 'regno' in the assembly file. */
2092 asm_print_register (FILE *file
, int regno
)
2094 const char *name
= reg_names
[regno
];
2096 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2099 fprintf (file
, "%s", name
);
2102 /* A C compound statement to output to stdio stream STREAM the
2103 assembler syntax for an instruction operand X. X is an RTL
2106 CODE is a value that can be used to specify one of several ways
2107 of printing the operand. It is used when identical operands
2108 must be printed differently depending on the context. CODE
2109 comes from the `%' specification that was used to request
2110 printing of the operand. If the specification was just `%DIGIT'
2111 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2112 is the ASCII code for LTR.
2114 If X is a register, this macro should print the register's name.
2115 The names can be found in an array `reg_names' whose type is
2116 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2118 When the machine description has a specification `%PUNCT' (a `%'
2119 followed by a punctuation character), this macro is called with
2120 a null pointer for X and the punctuation character for CODE.
2122 The M68HC11 specific codes are:
2124 'b' for the low part of the operand.
2125 'h' for the high part of the operand
2126 The 'b' or 'h' modifiers have no effect if the operand has
2127 the QImode and is not a S_REG_P (soft register). If the
2128 operand is a hard register, these two modifiers have no effect.
2129 't' generate the temporary scratch register. The operand is
2131 'T' generate the low-part temporary scratch register. The operand is
2135 m68hc11_print_operand (FILE *file
, rtx op
, int letter
)
2139 asm_print_register (file
, SOFT_TMP_REGNUM
);
2142 else if (letter
== 'T')
2144 asm_print_register (file
, SOFT_TMP_REGNUM
);
2145 fprintf (file
, "+1");
2148 else if (letter
== '#')
2150 asm_fprintf (file
, "%I");
2153 if (GET_CODE (op
) == REG
)
2155 if (letter
== 'b' && S_REG_P (op
))
2157 asm_print_register (file
, REGNO (op
));
2158 fprintf (file
, "+1");
2160 else if (letter
== 'b' && D_REG_P (op
))
2162 asm_print_register (file
, HARD_B_REGNUM
);
2166 asm_print_register (file
, REGNO (op
));
2171 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2174 asm_fprintf (file
, "%I%%lo(");
2176 asm_fprintf (file
, "%I%%hi(");
2178 output_addr_const (file
, op
);
2179 fprintf (file
, ")");
2183 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2184 are specified. If we already have a QImode, there is nothing to do. */
2185 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2189 op
= m68hc11_gen_lowpart (QImode
, op
);
2191 else if (letter
== 'h')
2193 op
= m68hc11_gen_highpart (QImode
, op
);
2197 if (GET_CODE (op
) == MEM
)
2199 rtx base
= XEXP (op
, 0);
2200 switch (GET_CODE (base
))
2203 gcc_assert (TARGET_M6812
);
2204 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2205 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2209 gcc_assert (TARGET_M6812
);
2210 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2211 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2212 fprintf (file
, "-");
2216 gcc_assert (TARGET_M6812
);
2217 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2218 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2219 fprintf (file
, "+");
2223 gcc_assert (TARGET_M6812
);
2224 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2225 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2229 gcc_assert (TARGET_M6812
);
2230 fprintf (file
, "[");
2231 print_operand_address (file
, XEXP (base
, 0));
2232 fprintf (file
, "]");
2236 if (m68hc11_page0_symbol_p (base
))
2237 fprintf (file
, "*");
2239 output_address (base
);
2243 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2248 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2249 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2250 asm_fprintf (file
, "%I0x%lx", l
);
2252 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == DFmode
)
2256 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2257 sizeof (dstr
), 0, 1);
2258 asm_fprintf (file
, "%I0r%s", dstr
);
2262 int need_parenthesize
= 0;
2265 asm_fprintf (file
, "%I");
2267 need_parenthesize
= must_parenthesize (op
);
2269 if (need_parenthesize
)
2270 fprintf (file
, "(");
2272 output_addr_const (file
, op
);
2273 if (need_parenthesize
)
2274 fprintf (file
, ")");
2278 /* Returns true if the operand 'op' must be printed with parenthesis
2279 around it. This must be done only if there is a symbol whose name
2280 is a processor register. */
2282 must_parenthesize (rtx op
)
2286 switch (GET_CODE (op
))
2289 name
= XSTR (op
, 0);
2290 /* Avoid a conflict between symbol name and a possible
2292 return (strcasecmp (name
, "a") == 0
2293 || strcasecmp (name
, "b") == 0
2294 || strcasecmp (name
, "d") == 0
2295 || strcasecmp (name
, "x") == 0
2296 || strcasecmp (name
, "y") == 0
2297 || strcasecmp (name
, "ix") == 0
2298 || strcasecmp (name
, "iy") == 0
2299 || strcasecmp (name
, "pc") == 0
2300 || strcasecmp (name
, "sp") == 0
2301 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2305 return must_parenthesize (XEXP (op
, 0))
2306 || must_parenthesize (XEXP (op
, 1));
2312 return must_parenthesize (XEXP (op
, 0));
2323 /* A C compound statement to output to stdio stream STREAM the
2324 assembler syntax for an instruction operand that is a memory
2325 reference whose address is ADDR. ADDR is an RTL expression. */
2328 m68hc11_print_operand_address (FILE *file
, rtx addr
)
2332 int need_parenthesis
= 0;
2334 switch (GET_CODE (addr
))
2337 gcc_assert (REG_P (addr
) && REG_OK_FOR_BASE_STRICT_P (addr
));
2339 fprintf (file
, "0,");
2340 asm_print_register (file
, REGNO (addr
));
2344 base
= XEXP (addr
, 0);
2345 switch (GET_CODE (base
))
2348 gcc_assert (TARGET_M6812
);
2349 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2350 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2354 gcc_assert (TARGET_M6812
);
2355 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2356 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2357 fprintf (file
, "-");
2361 gcc_assert (TARGET_M6812
);
2362 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2363 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2364 fprintf (file
, "+");
2368 gcc_assert (TARGET_M6812
);
2369 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2370 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2374 need_parenthesis
= must_parenthesize (base
);
2375 if (need_parenthesis
)
2376 fprintf (file
, "(");
2378 output_addr_const (file
, base
);
2379 if (need_parenthesis
)
2380 fprintf (file
, ")");
2386 base
= XEXP (addr
, 0);
2387 offset
= XEXP (addr
, 1);
2388 if (!G_REG_P (base
) && G_REG_P (offset
))
2390 base
= XEXP (addr
, 1);
2391 offset
= XEXP (addr
, 0);
2393 if (CONSTANT_ADDRESS_P (base
))
2395 need_parenthesis
= must_parenthesize (addr
);
2397 gcc_assert (CONSTANT_ADDRESS_P (offset
));
2398 if (need_parenthesis
)
2399 fprintf (file
, "(");
2401 output_addr_const (file
, base
);
2402 fprintf (file
, "+");
2403 output_addr_const (file
, offset
);
2404 if (need_parenthesis
)
2405 fprintf (file
, ")");
2409 gcc_assert (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
));
2412 gcc_assert (TARGET_M6812
);
2413 asm_print_register (file
, REGNO (offset
));
2414 fprintf (file
, ",");
2415 asm_print_register (file
, REGNO (base
));
2419 need_parenthesis
= must_parenthesize (offset
);
2420 if (need_parenthesis
)
2421 fprintf (file
, "(");
2423 output_addr_const (file
, offset
);
2424 if (need_parenthesis
)
2425 fprintf (file
, ")");
2426 fprintf (file
, ",");
2427 asm_print_register (file
, REGNO (base
));
2433 if (GET_CODE (addr
) == CONST_INT
2434 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2436 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2440 need_parenthesis
= must_parenthesize (addr
);
2441 if (need_parenthesis
)
2442 fprintf (file
, "(");
2444 output_addr_const (file
, addr
);
2445 if (need_parenthesis
)
2446 fprintf (file
, ")");
2453 /* Splitting of some instructions. */
2456 m68hc11_expand_compare (enum rtx_code code
, rtx op0
, rtx op1
)
2460 gcc_assert (GET_MODE_CLASS (GET_MODE (op0
)) != MODE_FLOAT
);
2461 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2462 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2463 ret
= gen_rtx_fmt_ee (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2469 m68hc11_expand_compare_and_branch (enum rtx_code code
, rtx op0
, rtx op1
,
2474 switch (GET_MODE (op0
))
2478 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2479 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2480 gen_rtx_LABEL_REF (VOIDmode
, label
),
2482 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2486 /* SCz: from i386.c */
2489 /* Don't expand the comparison early, so that we get better code
2490 when jump or whoever decides to reverse the comparison. */
2495 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2496 &m68hc11_compare_op1
);
2498 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2499 m68hc11_compare_op0
, m68hc11_compare_op1
);
2500 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2501 gen_rtx_LABEL_REF (VOIDmode
, label
),
2503 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2505 use_fcomi
= ix86_use_fcomi_compare (code
);
2506 vec
= rtvec_alloc (3 + !use_fcomi
);
2507 RTVEC_ELT (vec
, 0) = tmp
;
2509 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2511 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2514 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2516 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2522 /* Expand SImode branch into multiple compare+branch. */
2524 rtx lo
[2], hi
[2], label2
;
2525 enum rtx_code code1
, code2
, code3
;
2527 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2532 code
= swap_condition (code
);
2534 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2535 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2536 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2537 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2539 /* Otherwise, if we are doing less-than, op1 is a constant and the
2540 low word is zero, then we can just examine the high word. */
2542 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2543 && (code
== LT
|| code
== LTU
))
2545 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2549 /* Otherwise, we need two or three jumps. */
2551 label2
= gen_label_rtx ();
2554 code2
= swap_condition (code
);
2555 code3
= unsigned_condition (code
);
2596 * if (hi(a) < hi(b)) goto true;
2597 * if (hi(a) > hi(b)) goto false;
2598 * if (lo(a) < lo(b)) goto true;
2601 if (code1
!= UNKNOWN
)
2602 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2603 if (code2
!= UNKNOWN
)
2604 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2606 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2608 if (code2
!= UNKNOWN
)
2609 emit_label (label2
);
2619 /* Return the increment/decrement mode of a MEM if it is such.
2620 Return CONST if it is anything else. */
2622 autoinc_mode (rtx x
)
2624 if (GET_CODE (x
) != MEM
)
2628 if (GET_CODE (x
) == PRE_INC
2629 || GET_CODE (x
) == PRE_DEC
2630 || GET_CODE (x
) == POST_INC
2631 || GET_CODE (x
) == POST_DEC
)
2632 return GET_CODE (x
);
2638 m68hc11_make_autoinc_notes (rtx
*x
, void *data
)
2642 switch (GET_CODE (*x
))
2649 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2658 /* Split a DI, SI or HI move into several smaller move operations.
2659 The scratch register 'scratch' is used as a temporary to load
2660 store intermediate values. It must be a hard register. */
2662 m68hc11_split_move (rtx to
, rtx from
, rtx scratch
)
2664 rtx low_to
, low_from
;
2665 rtx high_to
, high_from
;
2667 enum machine_mode mode
;
2669 int autoinc_from
= autoinc_mode (from
);
2670 int autoinc_to
= autoinc_mode (to
);
2672 mode
= GET_MODE (to
);
2674 /* If the TO and FROM contain autoinc modes that are not compatible
2675 together (one pop and the other a push), we must change one to
2676 an offsetable operand and generate an appropriate add at the end. */
2677 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2682 /* The source uses an autoinc mode which is not compatible with
2683 a split (this would result in a word swap). */
2684 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2686 code
= GET_CODE (XEXP (from
, 0));
2687 reg
= XEXP (XEXP (from
, 0), 0);
2688 offset
= GET_MODE_SIZE (GET_MODE (from
));
2689 if (code
== POST_DEC
)
2692 if (code
== PRE_INC
)
2693 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2695 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2696 if (code
== POST_DEC
)
2697 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2701 /* Likewise for destination. */
2702 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2704 code
= GET_CODE (XEXP (to
, 0));
2705 reg
= XEXP (XEXP (to
, 0), 0);
2706 offset
= GET_MODE_SIZE (GET_MODE (to
));
2707 if (code
== POST_DEC
)
2710 if (code
== PRE_INC
)
2711 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2713 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2714 if (code
== POST_DEC
)
2715 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2719 /* The source and destination auto increment modes must be compatible
2720 with each other: same direction. */
2721 if ((autoinc_to
!= autoinc_from
2722 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2723 /* The destination address register must not be used within
2724 the source operand because the source address would change
2725 while doing the copy. */
2726 || (autoinc_to
!= CONST
2727 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2728 && !IS_STACK_PUSH (to
)))
2730 /* Must change the destination. */
2731 code
= GET_CODE (XEXP (to
, 0));
2732 reg
= XEXP (XEXP (to
, 0), 0);
2733 offset
= GET_MODE_SIZE (GET_MODE (to
));
2734 if (code
== PRE_DEC
|| code
== POST_DEC
)
2737 if (code
== PRE_DEC
|| code
== PRE_INC
)
2738 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2739 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2740 if (code
== POST_DEC
|| code
== POST_INC
)
2741 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2746 /* Likewise, the source address register must not be used within
2747 the destination operand. */
2748 if (autoinc_from
!= CONST
2749 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2750 && !IS_STACK_PUSH (to
))
2752 /* Must change the source. */
2753 code
= GET_CODE (XEXP (from
, 0));
2754 reg
= XEXP (XEXP (from
, 0), 0);
2755 offset
= GET_MODE_SIZE (GET_MODE (from
));
2756 if (code
== PRE_DEC
|| code
== POST_DEC
)
2759 if (code
== PRE_DEC
|| code
== PRE_INC
)
2760 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2761 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2762 if (code
== POST_DEC
|| code
== POST_INC
)
2763 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2769 if (GET_MODE_SIZE (mode
) == 8)
2771 else if (GET_MODE_SIZE (mode
) == 4)
2777 && IS_STACK_PUSH (to
)
2778 && reg_mentioned_p (gen_rtx_REG (HImode
, HARD_SP_REGNUM
), from
))
2784 else if (mode
== HImode
)
2792 low_to
= m68hc11_gen_lowpart (mode
, to
);
2793 high_to
= m68hc11_gen_highpart (mode
, to
);
2795 low_from
= m68hc11_gen_lowpart (mode
, from
);
2796 high_from
= m68hc11_gen_highpart (mode
, from
);
2800 high_from
= adjust_address (high_from
, mode
, offset
);
2801 low_from
= high_from
;
2804 /* When copying with a POST_INC mode, we must copy the
2805 high part and then the low part to guarantee a correct
2808 && GET_MODE_SIZE (mode
) >= 2
2809 && autoinc_from
!= autoinc_to
2810 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2819 low_from
= high_from
;
2824 m68hc11_split_move (low_to
, low_from
, scratch
);
2825 m68hc11_split_move (high_to
, high_from
, scratch
);
2827 else if (H_REG_P (to
) || H_REG_P (from
)
2828 || (low_from
== const0_rtx
2829 && high_from
== const0_rtx
2830 && ! push_operand (to
, GET_MODE (to
))
2831 && ! H_REG_P (scratch
))
2833 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2834 || m68hc11_small_indexed_indirect_p (from
,
2836 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2837 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2839 insn
= emit_move_insn (low_to
, low_from
);
2840 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2842 insn
= emit_move_insn (high_to
, high_from
);
2843 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2847 insn
= emit_move_insn (scratch
, low_from
);
2848 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2849 insn
= emit_move_insn (low_to
, scratch
);
2850 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2852 insn
= emit_move_insn (scratch
, high_from
);
2853 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2854 insn
= emit_move_insn (high_to
, scratch
);
2855 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2860 simplify_logical (enum machine_mode mode
, int code
, rtx operand
, rtx
*result
)
2866 if (GET_CODE (operand
) != CONST_INT
)
2874 val
= INTVAL (operand
);
2878 if ((val
& mask
) == 0)
2880 if ((val
& mask
) == mask
)
2881 *result
= constm1_rtx
;
2885 if ((val
& mask
) == 0)
2886 *result
= const0_rtx
;
2887 if ((val
& mask
) == mask
)
2892 if ((val
& mask
) == 0)
2900 m68hc11_emit_logical (enum machine_mode mode
, enum rtx_code code
, rtx
*operands
)
2905 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2906 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2908 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2909 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2911 if (result
&& GET_CODE (result
) == CONST_INT
)
2913 if (!H_REG_P (operands
[0]) && operands
[3]
2914 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2916 emit_move_insn (operands
[3], result
);
2917 emit_move_insn (operands
[0], operands
[3]);
2921 emit_move_insn (operands
[0], result
);
2924 else if (operands
[1] != 0 && operands
[2] != 0)
2928 if (!H_REG_P (operands
[0]) && operands
[3])
2930 emit_move_insn (operands
[3], operands
[1]);
2931 emit_insn (gen_rtx_SET (mode
,
2933 gen_rtx_fmt_ee (code
, mode
,
2934 operands
[3], operands
[2])));
2935 insn
= emit_move_insn (operands
[0], operands
[3]);
2939 insn
= emit_insn (gen_rtx_SET (mode
,
2941 gen_rtx_fmt_ee (code
, mode
,
2947 /* The logical operation is similar to a copy. */
2952 if (GET_CODE (operands
[1]) == CONST_INT
)
2957 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
2959 emit_move_insn (operands
[3], src
);
2960 emit_move_insn (operands
[0], operands
[3]);
2964 emit_move_insn (operands
[0], src
);
2970 m68hc11_split_logical (enum machine_mode mode
, enum rtx_code code
,
2976 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
2977 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
2978 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
2980 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
2981 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
2982 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
2984 low
[3] = operands
[3];
2985 high
[3] = operands
[3];
2988 m68hc11_split_logical (HImode
, code
, low
);
2989 m68hc11_split_logical (HImode
, code
, high
);
2993 m68hc11_emit_logical (mode
, code
, low
);
2994 m68hc11_emit_logical (mode
, code
, high
);
2998 /* Code generation. */
3001 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED
, rtx operands
[])
3003 /* We have to be careful with the cc_status. An address register swap
3004 is generated for some comparison. The comparison is made with D
3005 but the branch really uses the address register. See the split
3006 pattern for compare. The xgdx/xgdy preserve the flags but after
3007 the exchange, the flags will reflect to the value of X and not D.
3008 Tell this by setting the cc_status according to the cc_prev_status. */
3009 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3011 if (cc_prev_status
.value1
!= 0
3012 && (D_REG_P (cc_prev_status
.value1
)
3013 || X_REG_P (cc_prev_status
.value1
)))
3015 cc_status
= cc_prev_status
;
3016 if (D_REG_P (cc_status
.value1
))
3017 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3020 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3026 output_asm_insn ("xgdx", operands
);
3030 if (cc_prev_status
.value1
!= 0
3031 && (D_REG_P (cc_prev_status
.value1
)
3032 || Y_REG_P (cc_prev_status
.value1
)))
3034 cc_status
= cc_prev_status
;
3035 if (D_REG_P (cc_status
.value1
))
3036 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3039 cc_status
.value1
= gen_rtx_REG (GET_MODE (cc_status
.value1
),
3045 output_asm_insn ("xgdy", operands
);
3049 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3050 This is used to decide whether a move that set flags should be used
3053 next_insn_test_reg (rtx insn
, rtx reg
)
3057 insn
= next_nonnote_insn (insn
);
3058 if (GET_CODE (insn
) != INSN
)
3061 body
= PATTERN (insn
);
3062 if (sets_cc0_p (body
) != 1)
3065 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3071 /* Generate the code to move a 16-bit operand into another one. */
3074 m68hc11_gen_movhi (rtx insn
, rtx
*operands
)
3078 /* Move a register or memory to the same location.
3079 This is possible because such insn can appear
3080 in a non-optimizing mode. */
3081 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3083 cc_status
= cc_prev_status
;
3089 rtx from
= operands
[1];
3090 rtx to
= operands
[0];
3092 if (IS_STACK_PUSH (to
) && H_REG_P (from
))
3094 cc_status
= cc_prev_status
;
3095 switch (REGNO (from
))
3100 output_asm_insn ("psh%1", operands
);
3102 case HARD_SP_REGNUM
:
3103 output_asm_insn ("sts\t2,-sp", operands
);
3110 if (IS_STACK_POP (from
) && H_REG_P (to
))
3112 cc_status
= cc_prev_status
;
3118 output_asm_insn ("pul%0", operands
);
3125 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3127 m68hc11_notice_keep_cc (operands
[0]);
3128 output_asm_insn ("tfr\t%1,%0", operands
);
3130 else if (H_REG_P (operands
[0]))
3132 if (SP_REG_P (operands
[0]))
3133 output_asm_insn ("lds\t%1", operands
);
3135 output_asm_insn ("ld%0\t%1", operands
);
3137 else if (H_REG_P (operands
[1]))
3139 if (SP_REG_P (operands
[1]))
3140 output_asm_insn ("sts\t%0", operands
);
3142 output_asm_insn ("st%1\t%0", operands
);
3145 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3146 instruction. We have to use a scratch register as temporary location.
3147 Trying to use a specific pattern or constrain failed. */
3148 else if (GET_CODE (to
) == MEM
&& GET_CODE (XEXP (to
, 0)) == MEM
)
3155 if (dead_register_here (insn
, d_reg
))
3157 else if (dead_register_here (insn
, ix_reg
))
3159 else if (dead_register_here (insn
, iy_reg
))
3165 output_asm_insn ("psh%3", ops
);
3170 output_asm_insn ("ld%1\t%2", ops
);
3171 output_asm_insn ("st%1\t%0", ops
);
3173 output_asm_insn ("pul%3", ops
);
3176 /* Use movw for non-null constants or when we are clearing
3177 a volatile memory reference. However, this is possible
3178 only if the memory reference has a small offset or is an
3179 absolute address. */
3180 else if (GET_CODE (from
) == CONST_INT
3181 && INTVAL (from
) == 0
3182 && (MEM_VOLATILE_P (to
) == 0
3183 || m68hc11_small_indexed_indirect_p (to
, HImode
) == 0))
3185 output_asm_insn ("clr\t%h0", operands
);
3186 output_asm_insn ("clr\t%b0", operands
);
3190 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3191 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3192 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3193 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3199 ops
[0] = operands
[2];
3202 m68hc11_gen_movhi (insn
, ops
);
3204 ops
[1] = operands
[2];
3205 m68hc11_gen_movhi (insn
, ops
);
3210 /* !!!! SCz wrong here. */
3211 fatal_insn ("move insn not handled", insn
);
3216 m68hc11_notice_keep_cc (operands
[0]);
3217 output_asm_insn ("movw\t%1,%0", operands
);
3223 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3225 cc_status
= cc_prev_status
;
3226 switch (REGNO (operands
[0]))
3230 output_asm_insn ("pul%0", operands
);
3233 output_asm_insn ("pula", operands
);
3234 output_asm_insn ("pulb", operands
);
3241 /* Some moves to a hard register are special. Not all of them
3242 are really supported and we have to use a temporary
3243 location to provide them (either the stack of a temp var). */
3244 if (H_REG_P (operands
[0]))
3246 switch (REGNO (operands
[0]))
3249 if (X_REG_P (operands
[1]))
3251 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3253 m68hc11_output_swap (insn
, operands
);
3255 else if (next_insn_test_reg (insn
, operands
[0]))
3257 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3261 m68hc11_notice_keep_cc (operands
[0]);
3262 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3265 else if (Y_REG_P (operands
[1]))
3267 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3269 m68hc11_output_swap (insn
, operands
);
3273 /* %t means *ZTMP scratch register. */
3274 output_asm_insn ("sty\t%t1", operands
);
3275 output_asm_insn ("ldd\t%t1", operands
);
3278 else if (SP_REG_P (operands
[1]))
3283 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3284 output_asm_insn ("xgdx", operands
);
3285 output_asm_insn ("tsx", operands
);
3286 output_asm_insn ("xgdx", operands
);
3288 else if (IS_STACK_POP (operands
[1]))
3290 output_asm_insn ("pula\n\tpulb", operands
);
3292 else if (GET_CODE (operands
[1]) == CONST_INT
3293 && INTVAL (operands
[1]) == 0)
3295 output_asm_insn ("clra\n\tclrb", operands
);
3299 output_asm_insn ("ldd\t%1", operands
);
3304 if (D_REG_P (operands
[1]))
3306 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3308 m68hc11_output_swap (insn
, operands
);
3310 else if (next_insn_test_reg (insn
, operands
[0]))
3312 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3316 m68hc11_notice_keep_cc (operands
[0]);
3317 output_asm_insn ("pshb", operands
);
3318 output_asm_insn ("psha", operands
);
3319 output_asm_insn ("pulx", operands
);
3322 else if (Y_REG_P (operands
[1]))
3324 /* When both D and Y are dead, use the sequence xgdy, xgdx
3325 to move Y into X. The D and Y registers are modified. */
3326 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3327 && dead_register_here (insn
, d_reg
))
3329 output_asm_insn ("xgdy", operands
);
3330 output_asm_insn ("xgdx", operands
);
3333 else if (!optimize_size
)
3335 output_asm_insn ("sty\t%t1", operands
);
3336 output_asm_insn ("ldx\t%t1", operands
);
3341 output_asm_insn ("pshy", operands
);
3342 output_asm_insn ("pulx", operands
);
3345 else if (SP_REG_P (operands
[1]))
3347 /* tsx, tsy preserve the flags */
3348 cc_status
= cc_prev_status
;
3349 output_asm_insn ("tsx", operands
);
3353 output_asm_insn ("ldx\t%1", operands
);
3358 if (D_REG_P (operands
[1]))
3360 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3362 m68hc11_output_swap (insn
, operands
);
3366 output_asm_insn ("std\t%t1", operands
);
3367 output_asm_insn ("ldy\t%t1", operands
);
3370 else if (X_REG_P (operands
[1]))
3372 /* When both D and X are dead, use the sequence xgdx, xgdy
3373 to move X into Y. The D and X registers are modified. */
3374 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3375 && dead_register_here (insn
, d_reg
))
3377 output_asm_insn ("xgdx", operands
);
3378 output_asm_insn ("xgdy", operands
);
3381 else if (!optimize_size
)
3383 output_asm_insn ("stx\t%t1", operands
);
3384 output_asm_insn ("ldy\t%t1", operands
);
3389 output_asm_insn ("pshx", operands
);
3390 output_asm_insn ("puly", operands
);
3393 else if (SP_REG_P (operands
[1]))
3395 /* tsx, tsy preserve the flags */
3396 cc_status
= cc_prev_status
;
3397 output_asm_insn ("tsy", operands
);
3401 output_asm_insn ("ldy\t%1", operands
);
3405 case HARD_SP_REGNUM
:
3406 if (D_REG_P (operands
[1]))
3408 m68hc11_notice_keep_cc (operands
[0]);
3409 output_asm_insn ("xgdx", operands
);
3410 output_asm_insn ("txs", operands
);
3411 output_asm_insn ("xgdx", operands
);
3413 else if (X_REG_P (operands
[1]))
3415 /* tys, txs preserve the flags */
3416 cc_status
= cc_prev_status
;
3417 output_asm_insn ("txs", operands
);
3419 else if (Y_REG_P (operands
[1]))
3421 /* tys, txs preserve the flags */
3422 cc_status
= cc_prev_status
;
3423 output_asm_insn ("tys", operands
);
3427 /* lds sets the flags but the des does not. */
3429 output_asm_insn ("lds\t%1", operands
);
3430 output_asm_insn ("des", operands
);
3435 fatal_insn ("invalid register in the move instruction", insn
);
3440 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3441 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3443 output_asm_insn ("sts\t%0", operands
);
3447 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3449 cc_status
= cc_prev_status
;
3450 switch (REGNO (operands
[1]))
3454 output_asm_insn ("psh%1", operands
);
3457 output_asm_insn ("pshb", operands
);
3458 output_asm_insn ("psha", operands
);
3466 /* Operand 1 must be a hard register. */
3467 if (!H_REG_P (operands
[1]))
3469 fatal_insn ("invalid operand in the instruction", insn
);
3472 reg
= REGNO (operands
[1]);
3476 output_asm_insn ("std\t%0", operands
);
3480 output_asm_insn ("stx\t%0", operands
);
3484 output_asm_insn ("sty\t%0", operands
);
3487 case HARD_SP_REGNUM
:
3491 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3493 output_asm_insn ("pshx", operands
);
3494 output_asm_insn ("tsx", operands
);
3495 output_asm_insn ("inx", operands
);
3496 output_asm_insn ("inx", operands
);
3497 output_asm_insn ("stx\t%0", operands
);
3498 output_asm_insn ("pulx", operands
);
3501 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3503 output_asm_insn ("sty\t%t0", operands
);
3504 output_asm_insn ("tsy", operands
);
3505 output_asm_insn ("sty\t%0", operands
);
3506 output_asm_insn ("ldy\t%t0", operands
);
3510 output_asm_insn ("stx\t%t0", operands
);
3511 output_asm_insn ("tsx", operands
);
3512 output_asm_insn ("stx\t%0", operands
);
3513 output_asm_insn ("ldx\t%t0", operands
);
3519 fatal_insn ("invalid register in the move instruction", insn
);
3525 m68hc11_gen_movqi (rtx insn
, rtx
*operands
)
3527 /* Move a register or memory to the same location.
3528 This is possible because such insn can appear
3529 in a non-optimizing mode. */
3530 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3532 cc_status
= cc_prev_status
;
3539 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3541 m68hc11_notice_keep_cc (operands
[0]);
3542 output_asm_insn ("tfr\t%1,%0", operands
);
3544 else if (H_REG_P (operands
[0]))
3546 if (IS_STACK_POP (operands
[1]))
3547 output_asm_insn ("pul%b0", operands
);
3548 else if (Q_REG_P (operands
[0]))
3549 output_asm_insn ("lda%0\t%b1", operands
);
3550 else if (D_REG_P (operands
[0]))
3551 output_asm_insn ("ldab\t%b1", operands
);
3555 else if (H_REG_P (operands
[1]))
3557 if (Q_REG_P (operands
[1]))
3558 output_asm_insn ("sta%1\t%b0", operands
);
3559 else if (D_REG_P (operands
[1]))
3560 output_asm_insn ("stab\t%b0", operands
);
3566 rtx from
= operands
[1];
3567 rtx to
= operands
[0];
3569 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3570 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3571 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3572 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3578 ops
[0] = operands
[2];
3581 m68hc11_gen_movqi (insn
, ops
);
3583 ops
[1] = operands
[2];
3584 m68hc11_gen_movqi (insn
, ops
);
3588 /* !!!! SCz wrong here. */
3589 fatal_insn ("move insn not handled", insn
);
3594 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3596 output_asm_insn ("clr\t%b0", operands
);
3600 m68hc11_notice_keep_cc (operands
[0]);
3601 output_asm_insn ("movb\t%b1,%b0", operands
);
3609 if (H_REG_P (operands
[0]))
3611 switch (REGNO (operands
[0]))
3615 if (X_REG_P (operands
[1]))
3617 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3619 m68hc11_output_swap (insn
, operands
);
3623 output_asm_insn ("stx\t%t1", operands
);
3624 output_asm_insn ("ldab\t%T0", operands
);
3627 else if (Y_REG_P (operands
[1]))
3629 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3631 m68hc11_output_swap (insn
, operands
);
3635 output_asm_insn ("sty\t%t1", operands
);
3636 output_asm_insn ("ldab\t%T0", operands
);
3639 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3640 && !DA_REG_P (operands
[1]))
3642 output_asm_insn ("ldab\t%b1", operands
);
3644 else if (DA_REG_P (operands
[1]))
3646 output_asm_insn ("tab", operands
);
3650 cc_status
= cc_prev_status
;
3656 if (X_REG_P (operands
[1]))
3658 output_asm_insn ("stx\t%t1", operands
);
3659 output_asm_insn ("ldaa\t%T0", operands
);
3661 else if (Y_REG_P (operands
[1]))
3663 output_asm_insn ("sty\t%t1", operands
);
3664 output_asm_insn ("ldaa\t%T0", operands
);
3666 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3667 && !DA_REG_P (operands
[1]))
3669 output_asm_insn ("ldaa\t%b1", operands
);
3671 else if (!DA_REG_P (operands
[1]))
3673 output_asm_insn ("tba", operands
);
3677 cc_status
= cc_prev_status
;
3682 if (D_REG_P (operands
[1]))
3684 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3686 m68hc11_output_swap (insn
, operands
);
3690 output_asm_insn ("stab\t%T1", operands
);
3691 output_asm_insn ("ldx\t%t1", operands
);
3695 else if (Y_REG_P (operands
[1]))
3697 output_asm_insn ("sty\t%t0", operands
);
3698 output_asm_insn ("ldx\t%t0", operands
);
3700 else if (GET_CODE (operands
[1]) == CONST_INT
)
3702 output_asm_insn ("ldx\t%1", operands
);
3704 else if (dead_register_here (insn
, d_reg
))
3706 output_asm_insn ("ldab\t%b1", operands
);
3707 output_asm_insn ("xgdx", operands
);
3709 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3711 output_asm_insn ("xgdx", operands
);
3712 output_asm_insn ("ldab\t%b1", operands
);
3713 output_asm_insn ("xgdx", operands
);
3717 output_asm_insn ("pshb", operands
);
3718 output_asm_insn ("ldab\t%b1", operands
);
3719 output_asm_insn ("stab\t%T1", operands
);
3720 output_asm_insn ("ldx\t%t1", operands
);
3721 output_asm_insn ("pulb", operands
);
3727 if (D_REG_P (operands
[1]))
3729 output_asm_insn ("stab\t%T1", operands
);
3730 output_asm_insn ("ldy\t%t1", operands
);
3733 else if (X_REG_P (operands
[1]))
3735 output_asm_insn ("stx\t%t1", operands
);
3736 output_asm_insn ("ldy\t%t1", operands
);
3739 else if (GET_CODE (operands
[1]) == CONST_INT
)
3741 output_asm_insn ("ldy\t%1", operands
);
3743 else if (dead_register_here (insn
, d_reg
))
3745 output_asm_insn ("ldab\t%b1", operands
);
3746 output_asm_insn ("xgdy", operands
);
3748 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3750 output_asm_insn ("xgdy", operands
);
3751 output_asm_insn ("ldab\t%b1", operands
);
3752 output_asm_insn ("xgdy", operands
);
3756 output_asm_insn ("pshb", operands
);
3757 output_asm_insn ("ldab\t%b1", operands
);
3758 output_asm_insn ("stab\t%T1", operands
);
3759 output_asm_insn ("ldy\t%t1", operands
);
3760 output_asm_insn ("pulb", operands
);
3766 fatal_insn ("invalid register in the instruction", insn
);
3770 else if (H_REG_P (operands
[1]))
3772 switch (REGNO (operands
[1]))
3776 output_asm_insn ("stab\t%b0", operands
);
3780 output_asm_insn ("staa\t%b0", operands
);
3784 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3788 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3792 fatal_insn ("invalid register in the move instruction", insn
);
3799 fatal_insn ("operand 1 must be a hard register", insn
);
3803 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3804 The source and destination must be D or A and the shift must
3807 m68hc11_gen_rotate (enum rtx_code code
, rtx insn
, rtx operands
[])
3811 if (GET_CODE (operands
[2]) != CONST_INT
3812 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3813 fatal_insn ("invalid rotate insn", insn
);
3815 val
= INTVAL (operands
[2]);
3816 if (code
== ROTATERT
)
3817 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3819 if (GET_MODE (operands
[0]) != QImode
)
3822 /* Rotate by 8-bits if the shift is within [5..11]. */
3823 if (val
>= 5 && val
<= 11)
3826 output_asm_insn ("exg\ta,b", operands
);
3829 output_asm_insn ("psha", operands
);
3830 output_asm_insn ("tba", operands
);
3831 output_asm_insn ("pulb", operands
);
3836 /* If the shift is big, invert the rotation. */
3846 /* Set the carry to bit-15, but don't change D yet. */
3847 if (GET_MODE (operands
[0]) != QImode
)
3849 output_asm_insn ("asra", operands
);
3850 output_asm_insn ("rola", operands
);
3853 /* Rotate B first to move the carry to bit-0. */
3854 if (D_REG_P (operands
[0]))
3855 output_asm_insn ("rolb", operands
);
3857 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3858 output_asm_insn ("rola", operands
);
3865 /* Set the carry to bit-8 of D. */
3866 if (GET_MODE (operands
[0]) != QImode
)
3867 output_asm_insn ("tap", operands
);
3869 /* Rotate B first to move the carry to bit-7. */
3870 if (D_REG_P (operands
[0]))
3871 output_asm_insn ("rorb", operands
);
3873 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3874 output_asm_insn ("rora", operands
);
3881 /* Store in cc_status the expressions that the condition codes will
3882 describe after execution of an instruction whose pattern is EXP.
3883 Do not alter them if the instruction would not alter the cc's. */
3886 m68hc11_notice_update_cc (rtx exp
, rtx insn ATTRIBUTE_UNUSED
)
3888 /* recognize SET insn's. */
3889 if (GET_CODE (exp
) == SET
)
3891 /* Jumps do not alter the cc's. */
3892 if (SET_DEST (exp
) == pc_rtx
)
3895 /* NOTE: most instructions don't affect the carry bit, but the
3896 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3897 the conditions.h header. */
3899 /* Function calls clobber the cc's. */
3900 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3905 /* Tests and compares set the cc's in predictable ways. */
3906 else if (SET_DEST (exp
) == cc0_rtx
)
3908 cc_status
.flags
= 0;
3909 cc_status
.value1
= XEXP (exp
, 0);
3910 if (GET_CODE (XEXP (exp
, 1)) == COMPARE
3911 && XEXP (XEXP (exp
, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp
, 1), 0))))
3912 cc_status
.value2
= XEXP (XEXP (exp
, 1), 0);
3914 cc_status
.value2
= XEXP (exp
, 1);
3918 /* All other instructions affect the condition codes. */
3919 cc_status
.flags
= 0;
3920 cc_status
.value1
= XEXP (exp
, 0);
3921 cc_status
.value2
= XEXP (exp
, 1);
3926 /* Default action if we haven't recognized something
3927 and returned earlier. */
3931 if (cc_status
.value2
!= 0)
3932 switch (GET_CODE (cc_status
.value2
))
3934 /* These logical operations can generate several insns.
3935 The flags are setup according to what is generated. */
3941 /* The (not ...) generates several 'com' instructions for
3942 non QImode. We have to invalidate the flags. */
3944 if (GET_MODE (cc_status
.value2
) != QImode
)
3956 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3957 cc_status
.flags
|= CC_NO_OVERFLOW
;
3960 /* The asl sets the overflow bit in such a way that this
3961 makes the flags unusable for a next compare insn. */
3965 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3966 cc_status
.flags
|= CC_NO_OVERFLOW
;
3969 /* A load/store instruction does not affect the carry. */
3974 cc_status
.flags
|= CC_NO_OVERFLOW
;
3980 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
3982 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
3983 cc_status
.value2
= 0;
3985 else if (cc_status
.value1
&& side_effects_p (cc_status
.value1
))
3986 cc_status
.value1
= 0;
3988 else if (cc_status
.value2
&& side_effects_p (cc_status
.value2
))
3989 cc_status
.value2
= 0;
3992 /* The current instruction does not affect the flags but changes
3993 the register 'reg'. See if the previous flags can be kept for the
3994 next instruction to avoid a comparison. */
3996 m68hc11_notice_keep_cc (rtx reg
)
3999 || cc_prev_status
.value1
== 0
4000 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4001 || (cc_prev_status
.value2
4002 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4005 cc_status
= cc_prev_status
;
4010 /* Machine Specific Reorg. */
4012 /* Z register replacement:
4014 GCC treats the Z register as an index base address register like
4015 X or Y. In general, it uses it during reload to compute the address
4016 of some operand. This helps the reload pass to avoid to fall into the
4017 register spill failure.
4019 The Z register is in the A_REGS class. In the machine description,
4020 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4022 It can appear everywhere an X or Y register can appear, except for
4023 some templates in the clobber section (when a clobber of X or Y is asked).
4024 For a given instruction, the template must ensure that no more than
4025 2 'A' registers are used. Otherwise, the register replacement is not
4028 To replace the Z register, the algorithm is not terrific:
4029 1. Insns that do not use the Z register are not changed
4030 2. When a Z register is used, we scan forward the insns to see
4031 a potential register to use: either X or Y and sometimes D.
4032 We stop when a call, a label or a branch is seen, or when we
4033 detect that both X and Y are used (probably at different times, but it does
4035 3. The register that will be used for the replacement of Z is saved
4036 in a .page0 register or on the stack. If the first instruction that
4037 used Z, uses Z as an input, the value is loaded from another .page0
4038 register. The replacement register is pushed on the stack in the
4039 rare cases where a compare insn uses Z and we couldn't find if X/Y
4041 4. The Z register is replaced in all instructions until we reach
4042 the end of the Z-block, as detected by step 2.
4043 5. If we detect that Z is still alive, its value is saved.
4044 If the replacement register is alive, its old value is loaded.
4046 The Z register can be disabled with -ffixed-z.
4056 int must_restore_reg
;
4067 int save_before_last
;
4068 int z_loaded_with_sp
;
4071 static int m68hc11_check_z_replacement (rtx
, struct replace_info
*);
4072 static void m68hc11_find_z_replacement (rtx
, struct replace_info
*);
4073 static void m68hc11_z_replacement (rtx
);
4074 static void m68hc11_reassign_regs (rtx
);
4076 int z_replacement_completed
= 0;
4078 /* Analyze the insn to find out which replacement register to use and
4079 the boundaries of the replacement.
4080 Returns 0 if we reached the last insn to be replaced, 1 if we can
4081 continue replacement in next insns. */
4084 m68hc11_check_z_replacement (rtx insn
, struct replace_info
*info
)
4086 int this_insn_uses_ix
;
4087 int this_insn_uses_iy
;
4088 int this_insn_uses_z
;
4089 int this_insn_uses_z_in_dst
;
4090 int this_insn_uses_d
;
4094 /* A call is said to clobber the Z register, we don't need
4095 to save the value of Z. We also don't need to restore
4096 the replacement register (unless it is used by the call). */
4097 if (GET_CODE (insn
) == CALL_INSN
)
4099 body
= PATTERN (insn
);
4101 info
->can_use_d
= 0;
4103 /* If the call is an indirect call with Z, we have to use the
4104 Y register because X can be used as an input (D+X).
4105 We also must not save Z nor restore Y. */
4106 if (reg_mentioned_p (z_reg
, body
))
4108 insn
= NEXT_INSN (insn
);
4111 info
->found_call
= 1;
4112 info
->must_restore_reg
= 0;
4113 info
->last
= NEXT_INSN (insn
);
4115 info
->need_save_z
= 0;
4118 if (GET_CODE (insn
) == CODE_LABEL
4119 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4122 if (GET_CODE (insn
) == JUMP_INSN
)
4124 if (reg_mentioned_p (z_reg
, insn
) == 0)
4127 info
->can_use_d
= 0;
4128 info
->must_save_reg
= 0;
4129 info
->must_restore_reg
= 0;
4130 info
->need_save_z
= 0;
4131 info
->last
= NEXT_INSN (insn
);
4134 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4139 /* Z register dies here. */
4140 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4142 body
= PATTERN (insn
);
4143 if (GET_CODE (body
) == SET
)
4145 rtx src
= XEXP (body
, 1);
4146 rtx dst
= XEXP (body
, 0);
4148 /* Condition code is set here. We have to restore the X/Y and
4149 save into Z before any test/compare insn because once we save/restore
4150 we can change the condition codes. When the compare insn uses Z and
4151 we can't use X/Y, the comparison is made with the *ZREG soft register
4152 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4155 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4156 || (GET_CODE (src
) == COMPARE
&&
4157 ((rtx_equal_p (XEXP (src
, 0), z_reg
)
4158 && H_REG_P (XEXP (src
, 1)))
4159 || (rtx_equal_p (XEXP (src
, 1), z_reg
)
4160 && H_REG_P (XEXP (src
, 0))))))
4162 if (insn
== info
->first
)
4164 info
->must_load_z
= 0;
4165 info
->must_save_reg
= 0;
4166 info
->must_restore_reg
= 0;
4167 info
->need_save_z
= 0;
4168 info
->found_call
= 1;
4169 info
->regno
= SOFT_Z_REGNUM
;
4170 info
->last
= NEXT_INSN (insn
);
4174 if (reg_mentioned_p (z_reg
, src
) == 0)
4176 info
->can_use_d
= 0;
4180 if (insn
!= info
->first
)
4183 /* Compare insn which uses Z. We have to save/restore the X/Y
4184 register without modifying the condition codes. For this
4185 we have to use a push/pop insn. */
4186 info
->must_push_reg
= 1;
4190 /* Z reg is set to something new. We don't need to load it. */
4193 if (!reg_mentioned_p (z_reg
, src
))
4195 /* Z reg is used before being set. Treat this as
4196 a new sequence of Z register replacement. */
4197 if (insn
!= info
->first
)
4201 info
->must_load_z
= 0;
4203 info
->z_set_count
++;
4204 info
->z_value
= src
;
4206 info
->z_loaded_with_sp
= 1;
4208 else if (reg_mentioned_p (z_reg
, dst
))
4209 info
->can_use_d
= 0;
4211 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4212 | reg_mentioned_p (d_reg
, dst
);
4213 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4214 | reg_mentioned_p (ix_reg
, dst
);
4215 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4216 | reg_mentioned_p (iy_reg
, dst
);
4217 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4219 /* If z is used as an address operand (like (MEM (reg z))),
4220 we can't replace it with d. */
4221 if (this_insn_uses_z
&& !Z_REG_P (src
)
4222 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4223 && Z_REG_P (XEXP (src
, 0))
4224 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4225 && insn
== info
->first
4226 && dead_register_here (insn
, d_reg
)))
4227 info
->can_use_d
= 0;
4229 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4230 if (TARGET_M6812
&& !z_dies_here
4231 && ((this_insn_uses_z
&& side_effects_p (src
))
4232 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4234 info
->need_save_z
= 1;
4235 info
->z_set_count
++;
4237 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4239 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4241 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4244 if (this_insn_uses_d
)
4245 info
->can_use_d
= 0;
4247 /* IX and IY are used at the same time, we have to restore
4248 the value of the scratch register before this insn. */
4249 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4254 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4255 info
->can_use_d
= 0;
4257 if (info
->x_used
== 0 && this_insn_uses_ix
)
4261 /* We have a (set (REG:HI X) (REG:HI Z)).
4262 Since we use Z as the replacement register, this insn
4263 is no longer necessary. We turn it into a note. We must
4264 not reload the old value of X. */
4265 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4269 info
->need_save_z
= 0;
4272 info
->must_save_reg
= 0;
4273 info
->must_restore_reg
= 0;
4274 info
->found_call
= 1;
4275 info
->can_use_d
= 0;
4276 SET_INSN_DELETED (insn
);
4277 info
->last
= NEXT_INSN (insn
);
4282 && (rtx_equal_p (src
, z_reg
)
4283 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4287 info
->need_save_z
= 0;
4290 info
->last
= NEXT_INSN (insn
);
4291 info
->must_save_reg
= 0;
4292 info
->must_restore_reg
= 0;
4294 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4295 && !reg_mentioned_p (ix_reg
, src
))
4300 info
->need_save_z
= 0;
4302 else if (TARGET_M6812
&& side_effects_p (src
))
4305 info
->must_restore_reg
= 0;
4310 info
->save_before_last
= 1;
4312 info
->must_restore_reg
= 0;
4313 info
->last
= NEXT_INSN (insn
);
4315 else if (info
->can_use_d
)
4317 info
->last
= NEXT_INSN (insn
);
4323 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4324 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4326 info
->need_save_z
= 0;
4328 info
->last
= NEXT_INSN (insn
);
4329 info
->regno
= HARD_X_REGNUM
;
4330 info
->must_save_reg
= 0;
4331 info
->must_restore_reg
= 0;
4334 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4336 info
->regno
= HARD_X_REGNUM
;
4337 info
->must_restore_reg
= 0;
4338 info
->must_save_reg
= 0;
4342 if (info
->y_used
== 0 && this_insn_uses_iy
)
4346 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4350 info
->need_save_z
= 0;
4353 info
->must_save_reg
= 0;
4354 info
->must_restore_reg
= 0;
4355 info
->found_call
= 1;
4356 info
->can_use_d
= 0;
4357 SET_INSN_DELETED (insn
);
4358 info
->last
= NEXT_INSN (insn
);
4363 && (rtx_equal_p (src
, z_reg
)
4364 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4369 info
->need_save_z
= 0;
4371 info
->last
= NEXT_INSN (insn
);
4372 info
->must_save_reg
= 0;
4373 info
->must_restore_reg
= 0;
4375 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4376 && !reg_mentioned_p (iy_reg
, src
))
4381 info
->need_save_z
= 0;
4383 else if (TARGET_M6812
&& side_effects_p (src
))
4386 info
->must_restore_reg
= 0;
4391 info
->save_before_last
= 1;
4393 info
->must_restore_reg
= 0;
4394 info
->last
= NEXT_INSN (insn
);
4396 else if (info
->can_use_d
)
4398 info
->last
= NEXT_INSN (insn
);
4405 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4406 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4408 info
->need_save_z
= 0;
4410 info
->last
= NEXT_INSN (insn
);
4411 info
->regno
= HARD_Y_REGNUM
;
4412 info
->must_save_reg
= 0;
4413 info
->must_restore_reg
= 0;
4416 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4418 info
->regno
= HARD_Y_REGNUM
;
4419 info
->must_restore_reg
= 0;
4420 info
->must_save_reg
= 0;
4426 info
->need_save_z
= 0;
4428 if (info
->last
== 0)
4429 info
->last
= NEXT_INSN (insn
);
4432 return info
->last
!= NULL_RTX
? 0 : 1;
4434 if (GET_CODE (body
) == PARALLEL
)
4437 char ix_clobber
= 0;
4438 char iy_clobber
= 0;
4440 this_insn_uses_iy
= 0;
4441 this_insn_uses_ix
= 0;
4442 this_insn_uses_z
= 0;
4444 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4447 int uses_ix
, uses_iy
, uses_z
;
4449 x
= XVECEXP (body
, 0, i
);
4451 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4452 info
->can_use_d
= 0;
4454 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4455 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4456 uses_z
= reg_mentioned_p (z_reg
, x
);
4457 if (GET_CODE (x
) == CLOBBER
)
4459 ix_clobber
|= uses_ix
;
4460 iy_clobber
|= uses_iy
;
4461 z_clobber
|= uses_z
;
4465 this_insn_uses_ix
|= uses_ix
;
4466 this_insn_uses_iy
|= uses_iy
;
4467 this_insn_uses_z
|= uses_z
;
4469 if (uses_z
&& GET_CODE (x
) == SET
)
4471 rtx dst
= XEXP (x
, 0);
4474 info
->z_set_count
++;
4476 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4477 info
->need_save_z
= 1;
4480 info
->need_save_z
= 0;
4484 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4485 this_insn_uses_ix
, this_insn_uses_iy
,
4486 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4489 if (this_insn_uses_z
)
4490 info
->can_use_d
= 0;
4492 if (z_clobber
&& info
->first
!= insn
)
4494 info
->need_save_z
= 0;
4498 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4500 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4502 info
->must_load_z
= 0;
4504 if (dead_register_here (insn
, d_reg
))
4506 info
->regno
= HARD_D_REGNUM
;
4507 info
->must_save_reg
= 0;
4508 info
->must_restore_reg
= 0;
4510 else if (dead_register_here (insn
, ix_reg
))
4512 info
->regno
= HARD_X_REGNUM
;
4513 info
->must_save_reg
= 0;
4514 info
->must_restore_reg
= 0;
4516 else if (dead_register_here (insn
, iy_reg
))
4518 info
->regno
= HARD_Y_REGNUM
;
4519 info
->must_save_reg
= 0;
4520 info
->must_restore_reg
= 0;
4522 if (info
->regno
>= 0)
4524 info
->last
= NEXT_INSN (insn
);
4527 if (this_insn_uses_ix
== 0)
4529 info
->regno
= HARD_X_REGNUM
;
4530 info
->must_save_reg
= 1;
4531 info
->must_restore_reg
= 1;
4533 else if (this_insn_uses_iy
== 0)
4535 info
->regno
= HARD_Y_REGNUM
;
4536 info
->must_save_reg
= 1;
4537 info
->must_restore_reg
= 1;
4541 info
->regno
= HARD_D_REGNUM
;
4542 info
->must_save_reg
= 1;
4543 info
->must_restore_reg
= 1;
4545 info
->last
= NEXT_INSN (insn
);
4549 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4550 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4552 if (this_insn_uses_z
)
4554 if (info
->y_used
== 0 && iy_clobber
)
4556 info
->regno
= HARD_Y_REGNUM
;
4557 info
->must_save_reg
= 0;
4558 info
->must_restore_reg
= 0;
4560 if (info
->first
!= insn
4561 && ((info
->y_used
&& ix_clobber
)
4562 || (info
->x_used
&& iy_clobber
)))
4565 info
->last
= NEXT_INSN (insn
);
4566 info
->save_before_last
= 1;
4570 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4572 if (this_insn_uses_z
)
4574 fatal_insn ("cannot do z-register replacement", insn
);
4578 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4585 if (iy_clobber
|| z_clobber
)
4587 info
->last
= NEXT_INSN (insn
);
4588 info
->save_before_last
= 1;
4593 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4600 if (ix_clobber
|| z_clobber
)
4602 info
->last
= NEXT_INSN (insn
);
4603 info
->save_before_last
= 1;
4610 info
->need_save_z
= 0;
4614 if (GET_CODE (body
) == CLOBBER
)
4617 /* IX and IY are used at the same time, we have to restore
4618 the value of the scratch register before this insn. */
4619 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4623 if (info
->x_used
== 0 && this_insn_uses_ix
)
4631 if (info
->y_used
== 0 && this_insn_uses_iy
)
4645 m68hc11_find_z_replacement (rtx insn
, struct replace_info
*info
)
4649 info
->replace_reg
= NULL_RTX
;
4650 info
->must_load_z
= 1;
4651 info
->need_save_z
= 1;
4652 info
->must_save_reg
= 1;
4653 info
->must_restore_reg
= 1;
4657 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4658 info
->found_call
= 0;
4662 info
->z_set_count
= 0;
4663 info
->z_value
= NULL_RTX
;
4664 info
->must_push_reg
= 0;
4665 info
->save_before_last
= 0;
4666 info
->z_loaded_with_sp
= 0;
4668 /* Scan the insn forward to find an address register that is not used.
4670 - the flow of the program changes,
4671 - when we detect that both X and Y are necessary,
4672 - when the Z register dies,
4673 - when the condition codes are set. */
4675 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4677 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4681 /* May be we can use Y or X if they contain the same value as Z.
4682 This happens very often after the reload. */
4683 if (info
->z_set_count
== 1)
4685 rtx p
= info
->first
;
4690 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4692 else if (info
->y_used
)
4694 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4696 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4699 info
->regno
= HARD_Y_REGNUM
;
4701 info
->regno
= HARD_X_REGNUM
;
4702 info
->must_load_z
= 0;
4703 info
->must_save_reg
= 0;
4704 info
->must_restore_reg
= 0;
4705 info
->found_call
= 1;
4708 if (info
->z_set_count
== 0)
4709 info
->need_save_z
= 0;
4712 info
->need_save_z
= 0;
4714 if (info
->last
== 0)
4717 if (info
->regno
>= 0)
4720 info
->replace_reg
= gen_rtx_REG (HImode
, reg
);
4722 else if (info
->can_use_d
)
4724 reg
= HARD_D_REGNUM
;
4725 info
->replace_reg
= d_reg
;
4727 else if (info
->x_used
)
4729 reg
= HARD_Y_REGNUM
;
4730 info
->replace_reg
= iy_reg
;
4734 reg
= HARD_X_REGNUM
;
4735 info
->replace_reg
= ix_reg
;
4739 if (info
->must_save_reg
&& info
->must_restore_reg
)
4741 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4743 info
->must_save_reg
= 0;
4744 info
->must_restore_reg
= 0;
4749 /* The insn uses the Z register. Find a replacement register for it
4750 (either X or Y) and replace it in the insn and the next ones until
4751 the flow changes or the replacement register is used. Instructions
4752 are emitted before and after the Z-block to preserve the value of
4753 Z and of the replacement register. */
4756 m68hc11_z_replacement (rtx insn
)
4760 struct replace_info info
;
4762 /* Find trivial case where we only need to replace z with the
4763 equivalent soft register. */
4764 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4766 rtx body
= PATTERN (insn
);
4767 rtx src
= XEXP (body
, 1);
4768 rtx dst
= XEXP (body
, 0);
4770 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4772 XEXP (body
, 0) = gen_rtx_REG (GET_MODE (dst
), SOFT_Z_REGNUM
);
4775 else if (Z_REG_P (src
)
4776 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4778 XEXP (body
, 1) = gen_rtx_REG (GET_MODE (src
), SOFT_Z_REGNUM
);
4781 else if (D_REG_P (dst
)
4782 && m68hc11_arith_operator (src
, GET_MODE (src
))
4783 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4785 XEXP (src
, 1) = gen_rtx_REG (GET_MODE (src
), SOFT_Z_REGNUM
);
4788 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4789 && INTVAL (src
) == 0)
4791 XEXP (body
, 0) = gen_rtx_REG (GET_MODE (dst
), SOFT_Z_REGNUM
);
4792 /* Force it to be re-recognized. */
4793 INSN_CODE (insn
) = -1;
4798 m68hc11_find_z_replacement (insn
, &info
);
4800 replace_reg
= info
.replace_reg
;
4801 replace_reg_qi
= NULL_RTX
;
4803 /* Save the X register in a .page0 location. */
4804 if (info
.must_save_reg
&& !info
.must_push_reg
)
4808 if (info
.must_push_reg
&& 0)
4809 dst
= gen_rtx_MEM (HImode
,
4810 gen_rtx_PRE_DEC (HImode
,
4811 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
4813 dst
= gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
);
4815 emit_insn_before (gen_movhi (dst
,
4816 gen_rtx_REG (HImode
, info
.regno
)), insn
);
4818 if (info
.must_load_z
&& !info
.must_push_reg
)
4820 emit_insn_before (gen_movhi (gen_rtx_REG (HImode
, info
.regno
),
4821 gen_rtx_REG (HImode
, SOFT_Z_REGNUM
)),
4826 /* Replace all occurrence of Z by replace_reg.
4827 Stop when the last instruction to replace is reached.
4828 Also stop when we detect a change in the flow (but it's not
4829 necessary; just safeguard). */
4831 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4835 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4838 if (GET_CODE (insn
) != INSN
4839 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4842 body
= PATTERN (insn
);
4843 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4844 || GET_CODE (body
) == ASM_OPERANDS
4845 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4849 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4851 printf ("Reg mentioned here...:\n");
4856 /* Stack pointer was decremented by 2 due to the push.
4857 Correct that by adding 2 to the destination. */
4858 if (info
.must_push_reg
4859 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4863 src
= SET_SRC (body
);
4864 dst
= SET_DEST (body
);
4865 if (SP_REG_P (src
) && Z_REG_P (dst
))
4866 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4869 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4870 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4872 INSN_CODE (insn
) = -1;
4873 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4874 fatal_insn ("cannot do z-register replacement", insn
);
4877 /* Likewise for (REG:QI Z). */
4878 if (reg_mentioned_p (z_reg
, insn
))
4880 if (replace_reg_qi
== NULL_RTX
)
4881 replace_reg_qi
= gen_rtx_REG (QImode
, REGNO (replace_reg
));
4882 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4885 /* If there is a REG_INC note on Z, replace it with a
4886 REG_INC note on the replacement register. This is necessary
4887 to make sure that the flow pass will identify the change
4888 and it will not remove a possible insn that saves Z. */
4889 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4891 if (REG_NOTE_KIND (note
) == REG_INC
4892 && GET_CODE (XEXP (note
, 0)) == REG
4893 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4895 XEXP (note
, 0) = replace_reg
;
4899 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4903 /* Save Z before restoring the old value. */
4904 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4906 rtx save_pos_insn
= insn
;
4908 /* If Z is clobber by the last insn, we have to save its value
4909 before the last instruction. */
4910 if (info
.save_before_last
)
4911 save_pos_insn
= PREV_INSN (save_pos_insn
);
4913 emit_insn_before (gen_movhi (gen_rtx_REG (HImode
, SOFT_Z_REGNUM
),
4914 gen_rtx_REG (HImode
, info
.regno
)),
4918 if (info
.must_push_reg
&& info
.last
)
4922 body
= PATTERN (info
.last
);
4923 new_body
= gen_rtx_PARALLEL (VOIDmode
,
4925 gen_rtx_USE (VOIDmode
,
4927 gen_rtx_USE (VOIDmode
,
4928 gen_rtx_REG (HImode
,
4930 PATTERN (info
.last
) = new_body
;
4932 /* Force recognition on insn since we changed it. */
4933 INSN_CODE (insn
) = -1;
4935 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4937 fatal_insn ("invalid Z register replacement for insn", insn
);
4939 insn
= NEXT_INSN (info
.last
);
4942 /* Restore replacement register unless it was died. */
4943 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4947 if (info
.must_push_reg
&& 0)
4948 dst
= gen_rtx_MEM (HImode
,
4949 gen_rtx_POST_INC (HImode
,
4950 gen_rtx_REG (HImode
, HARD_SP_REGNUM
)));
4952 dst
= gen_rtx_REG (HImode
, SOFT_SAVED_XY_REGNUM
);
4954 emit_insn_before (gen_movhi (gen_rtx_REG (HImode
, info
.regno
),
4961 /* Scan all the insn and re-affects some registers
4962 - The Z register (if it was used), is affected to X or Y depending
4963 on the instruction. */
4966 m68hc11_reassign_regs (rtx first
)
4970 ix_reg
= gen_rtx_REG (HImode
, HARD_X_REGNUM
);
4971 iy_reg
= gen_rtx_REG (HImode
, HARD_Y_REGNUM
);
4972 z_reg
= gen_rtx_REG (HImode
, HARD_Z_REGNUM
);
4973 z_reg_qi
= gen_rtx_REG (QImode
, HARD_Z_REGNUM
);
4975 /* Scan all insns to replace Z by X or Y preserving the old value
4976 of X/Y and restoring it afterward. */
4978 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
4982 if (GET_CODE (insn
) == CODE_LABEL
4983 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
4989 body
= PATTERN (insn
);
4990 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
4993 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
4994 || GET_CODE (body
) == ASM_OPERANDS
4995 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
4998 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4999 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5002 /* If Z appears in this insn, replace it in the current insn
5003 and the next ones until the flow changes or we have to
5004 restore back the replacement register. */
5006 if (reg_mentioned_p (z_reg
, body
))
5008 m68hc11_z_replacement (insn
);
5013 printf ("insn not handled by Z replacement:\n");
5021 /* Machine-dependent reorg pass.
5022 Specific optimizations are defined here:
5023 - this pass changes the Z register into either X or Y
5024 (it preserves X/Y previous values in a memory slot in page0).
5026 When this pass is finished, the global variable
5027 'z_replacement_completed' is set to 2. */
5030 m68hc11_reorg (void)
5035 z_replacement_completed
= 0;
5036 z_reg
= gen_rtx_REG (HImode
, HARD_Z_REGNUM
);
5037 first
= get_insns ();
5039 /* Some RTX are shared at this point. This breaks the Z register
5040 replacement, unshare everything. */
5041 unshare_all_rtl_again (first
);
5043 /* Force a split of all splittable insn. This is necessary for the
5044 Z register replacement mechanism because we end up with basic insns. */
5045 split_all_insns_noflow ();
5048 z_replacement_completed
= 1;
5049 m68hc11_reassign_regs (first
);
5052 compute_bb_for_insn ();
5054 /* After some splitting, there are some opportunities for CSE pass.
5055 This happens quite often when 32-bit or above patterns are split. */
5056 if (optimize
> 0 && split_done
)
5058 reload_cse_regs (first
);
5061 /* Re-create the REG_DEAD notes. These notes are used in the machine
5062 description to use the best assembly directives. */
5065 df_note_add_problem ();
5067 df_remove_problem (df_note
);
5070 z_replacement_completed
= 2;
5072 /* If optimizing, then go ahead and split insns that must be
5073 split after Z register replacement. This gives more opportunities
5074 for peephole (in particular for consecutives xgdx/xgdy). */
5076 split_all_insns_noflow ();
5078 /* Once insns are split after the z_replacement_completed == 2,
5079 we must not re-run the life_analysis. The xgdx/xgdy patterns
5080 are not recognized and the life_analysis pass removes some
5081 insns because it thinks some (SETs) are noops or made to dead
5082 stores (which is false due to the swap).
5084 Do a simple pass to eliminate the noop set that the final
5085 split could generate (because it was easier for split definition). */
5089 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5093 if (INSN_DELETED_P (insn
))
5098 /* Remove the (set (R) (R)) insns generated by some splits. */
5099 body
= PATTERN (insn
);
5100 if (GET_CODE (body
) == SET
5101 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5103 SET_INSN_DELETED (insn
);
5110 /* Override memcpy */
5113 m68hc11_init_libfuncs (void)
5115 memcpy_libfunc
= init_one_libfunc ("__memcpy");
5116 memcmp_libfunc
= init_one_libfunc ("__memcmp");
5117 memset_libfunc
= init_one_libfunc ("__memset");
5122 /* Cost functions. */
5124 /* Cost of moving memory. */
5126 m68hc11_memory_move_cost (enum machine_mode mode
, enum reg_class rclass
,
5127 int in ATTRIBUTE_UNUSED
)
5129 if (rclass
<= H_REGS
&& rclass
> NO_REGS
)
5131 if (GET_MODE_SIZE (mode
) <= 2)
5132 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5134 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5138 if (GET_MODE_SIZE (mode
) <= 2)
5139 return COSTS_N_INSNS (3);
5141 return COSTS_N_INSNS (4);
5146 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5147 Reload does not check the constraint of set insns when the two registers
5148 have a move cost of 2. Setting a higher cost will force reload to check
5151 m68hc11_register_move_cost (enum machine_mode mode
, enum reg_class from
,
5154 /* All costs are symmetric, so reduce cases by putting the
5155 lower number class as the destination. */
5158 enum reg_class tmp
= to
;
5159 to
= from
, from
= tmp
;
5162 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5163 else if (from
<= S_REGS
)
5164 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5166 return COSTS_N_INSNS (2);
5170 /* Provide the costs of an addressing mode that contains ADDR.
5171 If ADDR is not a valid address, its cost is irrelevant. */
5174 m68hc11_address_cost (rtx addr
, bool speed ATTRIBUTE_UNUSED
)
5178 switch (GET_CODE (addr
))
5181 /* Make the cost of hard registers and specially SP, FP small. */
5182 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5199 register rtx plus0
= XEXP (addr
, 0);
5200 register rtx plus1
= XEXP (addr
, 1);
5202 if (GET_CODE (plus0
) != REG
)
5205 switch (GET_CODE (plus1
))
5208 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5209 || INTVAL (plus1
) < m68hc11_min_offset
)
5211 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5215 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5237 if (SP_REG_P (XEXP (addr
, 0)))
5246 printf ("Address cost: %d for :", cost
);
5255 m68hc11_shift_cost (enum machine_mode mode
, rtx x
, int shift
)
5259 total
= rtx_cost (x
, SET
, !optimize_size
);
5261 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5262 else if (mode
== HImode
)
5263 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5264 else if (shift
== 8 || shift
== 16 || shift
== 32)
5265 total
+= m68hc11_cost
->shiftHI_const
[8];
5266 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5268 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5271 /* For SI and others, the cost is higher. */
5272 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5273 total
*= GET_MODE_SIZE (mode
) / 2;
5275 /* When optimizing for size, make shift more costly so that
5276 multiplications are preferred. */
5277 if (optimize_size
&& (shift
% 8) != 0)
5284 m68hc11_rtx_costs_1 (rtx x
, enum rtx_code code
,
5285 enum rtx_code outer_code ATTRIBUTE_UNUSED
)
5287 enum machine_mode mode
= GET_MODE (x
);
5298 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5300 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5303 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5304 total
+= m68hc11_cost
->shift_var
;
5310 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5311 total
+= m68hc11_cost
->logical
;
5313 /* Logical instructions are byte instructions only. */
5314 total
*= GET_MODE_SIZE (mode
);
5319 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5320 total
+= m68hc11_cost
->add
;
5321 if (GET_MODE_SIZE (mode
) > 2)
5323 total
*= GET_MODE_SIZE (mode
) / 2;
5330 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
) + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5334 total
+= m68hc11_cost
->divQI
;
5338 total
+= m68hc11_cost
->divHI
;
5343 total
+= m68hc11_cost
->divSI
;
5349 /* mul instruction produces 16-bit result. */
5350 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5351 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5352 return m68hc11_cost
->multQI
5353 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
, !optimize_size
)
5354 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
, !optimize_size
);
5356 /* emul instruction produces 32-bit result for 68HC12. */
5357 if (TARGET_M6812
&& mode
== SImode
5358 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5359 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5360 return m68hc11_cost
->multHI
5361 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
, !optimize_size
)
5362 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
, !optimize_size
);
5364 total
= rtx_cost (XEXP (x
, 0), code
, !optimize_size
)
5365 + rtx_cost (XEXP (x
, 1), code
, !optimize_size
);
5369 total
+= m68hc11_cost
->multQI
;
5373 total
+= m68hc11_cost
->multHI
;
5378 total
+= m68hc11_cost
->multSI
;
5385 extra_cost
= COSTS_N_INSNS (2);
5393 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
, !optimize_size
);
5396 return total
+ COSTS_N_INSNS (1);
5400 return total
+ COSTS_N_INSNS (2);
5404 return total
+ COSTS_N_INSNS (4);
5406 return total
+ COSTS_N_INSNS (8);
5409 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5410 return COSTS_N_INSNS (1);
5412 return COSTS_N_INSNS (1);
5415 return COSTS_N_INSNS (4);
5420 m68hc11_rtx_costs (rtx x
, int codearg
, int outer_code_arg
, int *total
,
5421 bool speed ATTRIBUTE_UNUSED
)
5423 enum rtx_code code
= (enum rtx_code
) codearg
;
5424 enum rtx_code outer_code
= (enum rtx_code
) outer_code_arg
;
5428 /* Constants are cheap. Moving them in registers must be avoided
5429 because most instructions do not handle two register operands. */
5435 /* Logical and arithmetic operations with a constant operand are
5436 better because they are not supported with two registers. */
5438 if (outer_code
== SET
&& x
== const0_rtx
)
5439 /* After reload, the reload_cse pass checks the cost to change
5440 a SET into a PLUS. Make const0 cheap then. */
5441 *total
= 1 - reload_completed
;
5447 if (outer_code
!= COMPARE
)
5470 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5479 /* Worker function for TARGET_ASM_FILE_START. */
5482 m68hc11_file_start (void)
5484 default_file_start ();
5486 fprintf (asm_out_file
, "\t.mode %s\n", TARGET_SHORT
? "mshort" : "mlong");
5490 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5493 m68hc11_asm_out_constructor (rtx symbol
, int priority
)
5495 default_ctor_section_asm_out_constructor (symbol
, priority
);
5496 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5499 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5502 m68hc11_asm_out_destructor (rtx symbol
, int priority
)
5504 default_dtor_section_asm_out_destructor (symbol
, priority
);
5505 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5508 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5511 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED
,
5512 int incoming ATTRIBUTE_UNUSED
)
5514 return gen_rtx_REG (Pmode
, HARD_D_REGNUM
);
5517 /* Return true if type TYPE should be returned in memory.
5518 Blocks and data types largers than 4 bytes cannot be returned
5519 in the register (D + X = 4). */
5522 m68hc11_return_in_memory (const_tree type
, const_tree fntype ATTRIBUTE_UNUSED
)
5524 if (TYPE_MODE (type
) == BLKmode
)
5526 HOST_WIDE_INT size
= int_size_in_bytes (type
);
5527 return (size
== -1 || size
> 4);
5530 return GET_MODE_SIZE (TYPE_MODE (type
)) > 4;
5533 #include "gt-m68hc11.h"