1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@nerim.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
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"
44 #include "hard-reg-set.h"
46 #include "insn-config.h"
47 #include "conditions.h"
49 #include "insn-attr.h"
54 #include "basic-block.h"
59 #include "target-def.h"
61 static void print_options
PARAMS ((FILE *));
62 static void emit_move_after_reload
PARAMS ((rtx
, rtx
, rtx
));
63 static rtx simplify_logical
PARAMS ((enum machine_mode
, int, rtx
, rtx
*));
64 static void m68hc11_emit_logical
PARAMS ((enum machine_mode
, int, rtx
*));
65 static void m68hc11_reorg
PARAMS ((void));
66 static int go_if_legitimate_address_internal
PARAMS((rtx
, enum machine_mode
,
68 static int register_indirect_p
PARAMS((rtx
, enum machine_mode
, int));
69 static rtx m68hc11_expand_compare
PARAMS((enum rtx_code
, rtx
, rtx
));
70 static int must_parenthesize
PARAMS ((rtx
));
71 static int m68hc11_address_cost
PARAMS ((rtx
));
72 static int m68hc11_shift_cost
PARAMS ((enum machine_mode
, rtx
, int));
73 static int m68hc11_rtx_costs_1
PARAMS ((rtx
, enum rtx_code
, enum rtx_code
));
74 static bool m68hc11_rtx_costs
PARAMS ((rtx
, int, int, int *));
75 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
76 static tree m68hc11_handle_fntype_attribute
PARAMS ((tree
*, tree
, tree
, int, bool *));
77 const struct attribute_spec m68hc11_attribute_table
[];
79 void create_regs_rtx
PARAMS ((void));
81 static void asm_print_register
PARAMS ((FILE *, int));
82 static void m68hc11_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
83 static void m68hc11_asm_out_constructor
PARAMS ((rtx
, int));
84 static void m68hc11_asm_out_destructor
PARAMS ((rtx
, int));
85 static void m68hc11_encode_section_info
PARAMS((tree
, rtx
, int));
86 static int autoinc_mode
PARAMS((rtx
));
87 static int m68hc11_make_autoinc_notes
PARAMS((rtx
*, void *));
89 /* Must be set to 1 to produce debug messages. */
92 extern FILE *asm_out_file
;
97 rtx m68hc11_soft_tmp_reg
;
98 static GTY(()) rtx stack_push_word
;
99 static GTY(()) rtx stack_pop_word
;
100 static GTY(()) rtx z_reg
;
101 static GTY(()) rtx z_reg_qi
;
102 static int regs_inited
= 0;
104 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
105 int current_function_interrupt
;
107 /* Set to 1 by expand_prologue() when the function is a trap handler. */
108 int current_function_trap
;
110 /* Set to 1 when the current function is placed in 68HC12 banked
111 memory and must return with rtc. */
112 int current_function_far
;
114 /* Min offset that is valid for the indirect addressing mode. */
115 HOST_WIDE_INT m68hc11_min_offset
= 0;
117 /* Max offset that is valid for the indirect addressing mode. */
118 HOST_WIDE_INT m68hc11_max_offset
= 256;
120 /* The class value for base registers. */
121 enum reg_class m68hc11_base_reg_class
= A_REGS
;
123 /* The class value for index registers. This is NO_REGS for 68HC11. */
124 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
126 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
128 /* Tables that tell whether a given hard register is valid for
129 a base or an index register. It is filled at init time depending
130 on the target processor. */
131 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
132 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
134 /* A correction offset which is applied to the stack pointer.
135 This is 1 for 68HC11 and 0 for 68HC12. */
136 int m68hc11_sp_correction
;
138 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
139 rtx m68hc11_compare_op0
;
140 rtx m68hc11_compare_op1
;
143 const struct processor_costs
*m68hc11_cost
;
145 /* Costs for a 68HC11. */
146 static const struct processor_costs m6811_cost
= {
151 /* non-constant shift */
154 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
155 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
156 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
159 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
160 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
161 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
162 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
163 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
164 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
169 COSTS_N_INSNS (20 * 4),
171 COSTS_N_INSNS (20 * 16),
180 /* Costs for a 68HC12. */
181 static const struct processor_costs m6812_cost
= {
186 /* non-constant shift */
189 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
190 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
191 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
194 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
195 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
196 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
197 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
198 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
199 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
206 COSTS_N_INSNS (3 * 4),
215 /* Machine specific options */
217 const char *m68hc11_regparm_string
;
218 const char *m68hc11_reg_alloc_order
;
219 const char *m68hc11_soft_reg_count
;
221 static int nb_soft_regs
;
223 /* Initialize the GCC target structure. */
224 #undef TARGET_ATTRIBUTE_TABLE
225 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
227 #undef TARGET_ASM_ALIGNED_HI_OP
228 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
230 #undef TARGET_ASM_FUNCTION_EPILOGUE
231 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
233 #undef TARGET_ENCODE_SECTION_INFO
234 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
236 #undef TARGET_RTX_COSTS
237 #define TARGET_RTX_COSTS m68hc11_rtx_costs
238 #undef TARGET_ADDRESS_COST
239 #define TARGET_ADDRESS_COST m68hc11_address_cost
241 #undef TARGET_MACHINE_DEPENDENT_REORG
242 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
244 struct gcc_target targetm
= TARGET_INITIALIZER
;
247 m68hc11_override_options ()
249 memset (m68hc11_reg_valid_for_index
, 0,
250 sizeof (m68hc11_reg_valid_for_index
));
251 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
253 /* Compilation with -fpic generates a wrong code. */
256 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
257 (flag_pic
> 1) ? "PIC" : "pic");
261 /* Configure for a 68hc11 processor. */
264 /* If gcc was built for a 68hc12, invalidate that because
265 a -m68hc11 option was specified on the command line. */
266 if (TARGET_DEFAULT
!= MASK_M6811
)
267 target_flags
&= ~TARGET_DEFAULT
;
270 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
271 m68hc11_cost
= &m6811_cost
;
272 m68hc11_min_offset
= 0;
273 m68hc11_max_offset
= 256;
274 m68hc11_index_reg_class
= NO_REGS
;
275 m68hc11_base_reg_class
= A_REGS
;
276 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
277 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
278 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
279 m68hc11_sp_correction
= 1;
280 m68hc11_tmp_regs_class
= D_REGS
;
281 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
282 m68hc11_soft_reg_count
= "4";
285 /* Configure for a 68hc12 processor. */
288 m68hc11_cost
= &m6812_cost
;
289 m68hc11_min_offset
= -65536;
290 m68hc11_max_offset
= 65536;
291 m68hc11_index_reg_class
= D_REGS
;
292 m68hc11_base_reg_class
= A_OR_SP_REGS
;
293 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
294 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
295 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
296 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
297 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
298 m68hc11_sp_correction
= 0;
299 m68hc11_tmp_regs_class
= TMP_REGS
;
300 target_flags
&= ~MASK_M6811
;
301 target_flags
|= MASK_NO_DIRECT_MODE
;
302 if (m68hc11_soft_reg_count
== 0)
303 m68hc11_soft_reg_count
= "0";
305 if (TARGET_LONG_CALLS
)
306 current_function_far
= 1;
313 m68hc11_conditional_register_usage ()
316 int cnt
= atoi (m68hc11_soft_reg_count
);
320 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
321 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
324 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
327 call_used_regs
[i
] = 1;
330 /* For 68HC12, the Z register emulation is not necessary when the
331 frame pointer is not used. The frame pointer is eliminated and
332 replaced by the stack register (which is a BASE_REG_CLASS). */
333 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
335 fixed_regs
[HARD_Z_REGNUM
] = 1;
340 /* Reload and register operations. */
342 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
348 /* regs_inited = 1; */
349 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
350 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
351 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
352 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
354 stack_push_word
= gen_rtx (MEM
, HImode
,
355 gen_rtx (PRE_DEC
, HImode
,
356 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
357 stack_pop_word
= gen_rtx (MEM
, HImode
,
358 gen_rtx (POST_INC
, HImode
,
359 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
363 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
364 - 8 bit values are stored anywhere (except the SP register).
365 - 16 bit values can be stored in any register whose mode is 16
366 - 32 bit values can be stored in D, X registers or in a soft register
367 (except the last one because we need 2 soft registers)
368 - Values whose size is > 32 bit are not stored in real hard
369 registers. They may be stored in soft registers if there are
372 hard_regno_mode_ok (regno
, mode
)
374 enum machine_mode mode
;
376 switch (GET_MODE_SIZE (mode
))
379 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
382 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
385 return G_REGNO_P (regno
);
388 /* We have to accept a QImode in X or Y registers. Otherwise, the
389 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
390 in the insns. Reload fails if the insn rejects the register class 'a'
391 as well as if it accepts it. Patterns that failed were
392 zero_extend_qihi2 and iorqi3. */
394 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
402 m68hc11_hard_regno_rename_ok (reg1
, reg2
)
405 /* Don't accept renaming to Z register. We will replace it to
406 X,Y or D during machine reorg pass. */
407 if (reg2
== HARD_Z_REGNUM
)
410 /* Don't accept renaming D,X to Y register as the code will be bigger. */
411 if (TARGET_M6811
&& reg2
== HARD_Y_REGNUM
412 && (D_REGNO_P (reg1
) || X_REGNO_P (reg1
)))
419 preferred_reload_class (operand
, class)
421 enum reg_class
class;
423 enum machine_mode mode
;
425 mode
= GET_MODE (operand
);
429 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
432 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
433 return m68hc11_base_reg_class
;
435 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
436 || GET_CODE (operand
) == CONST_INT
))
438 /* S_REGS class must not be used. The movhi template does not
439 work to move a memory to a soft register.
440 Restrict to a hard reg. */
445 case D_OR_A_OR_S_REGS
:
451 case D_OR_SP_OR_S_REGS
:
452 class = D_OR_SP_REGS
;
454 case D_OR_Y_OR_S_REGS
:
457 case D_OR_X_OR_S_REGS
:
473 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
477 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
481 else if (class >= S_REGS
&& S_REG_P (operand
))
487 case D_OR_A_OR_S_REGS
:
493 case D_OR_SP_OR_S_REGS
:
494 class = D_OR_SP_REGS
;
496 case D_OR_Y_OR_S_REGS
:
499 case D_OR_X_OR_S_REGS
:
515 else if (class >= S_REGS
)
519 printf ("Class = %s for: ", reg_class_names
[class]);
527 printf (" => class=%s\n", reg_class_names
[class]);
535 /* Return 1 if the operand is a valid indexed addressing mode.
536 For 68hc11: n,r with n in [0..255] and r in A_REGS class
537 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
539 register_indirect_p (operand
, mode
, strict
)
541 enum machine_mode mode
;
546 switch (GET_CODE (operand
))
552 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
553 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
557 base
= XEXP (operand
, 0);
558 if (GET_CODE (base
) == MEM
)
561 offset
= XEXP (operand
, 1);
562 if (GET_CODE (offset
) == MEM
)
565 if (GET_CODE (base
) == REG
)
567 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
573 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
575 if (GET_CODE (offset
) == REG
)
577 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
583 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
588 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
594 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
601 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
602 a 68HC12 1-byte index addressing mode. */
604 m68hc11_small_indexed_indirect_p (operand
, mode
)
606 enum machine_mode mode
;
610 if (GET_CODE (operand
) == REG
&& reload_in_progress
611 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
612 && reg_equiv_memory_loc
[REGNO (operand
)])
614 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
615 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
618 if (GET_CODE (operand
) != MEM
)
621 operand
= XEXP (operand
, 0);
622 if (CONSTANT_ADDRESS_P (operand
))
625 if (PUSH_POP_ADDRESS_P (operand
))
628 if (!register_indirect_p (operand
, mode
, reload_completed
))
631 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
632 && (reload_completed
| reload_in_progress
))
634 base
= XEXP (operand
, 0);
635 offset
= XEXP (operand
, 1);
637 /* The offset can be a symbol address and this is too big
638 for the operand constraint. */
639 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
642 if (GET_CODE (base
) == CONST_INT
)
645 switch (GET_MODE_SIZE (mode
))
648 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
653 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
658 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
667 m68hc11_register_indirect_p (operand
, mode
)
669 enum machine_mode mode
;
671 if (GET_CODE (operand
) != MEM
)
674 operand
= XEXP (operand
, 0);
675 return register_indirect_p (operand
, mode
,
676 (reload_completed
| reload_in_progress
));
680 go_if_legitimate_address_internal (operand
, mode
, strict
)
682 enum machine_mode mode
;
685 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
687 /* Reject the global variables if they are too wide. This forces
688 a load of their address in a register and generates smaller code. */
689 if (GET_MODE_SIZE (mode
) == 8)
694 if (register_indirect_p (operand
, mode
, strict
))
698 if (PUSH_POP_ADDRESS_P (operand
))
702 if (symbolic_memory_operand (operand
, mode
))
710 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
712 enum machine_mode mode
;
719 printf ("Checking: ");
724 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
728 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
735 printf ("go_if_legitimate%s, ret 0: %d:",
736 (strict
? "_strict" : ""), mode
);
745 m68hc11_legitimize_address (operand
, old_operand
, mode
)
746 rtx
*operand ATTRIBUTE_UNUSED
;
747 rtx old_operand ATTRIBUTE_UNUSED
;
748 enum machine_mode mode ATTRIBUTE_UNUSED
;
755 m68hc11_reload_operands (operands
)
758 enum machine_mode mode
;
760 if (regs_inited
== 0)
763 mode
= GET_MODE (operands
[1]);
765 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
766 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
768 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
769 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
771 if (GET_CODE (base
) != REG
)
778 /* If the offset is out of range, we have to compute the address
779 with a separate add instruction. We try to do with with an 8-bit
780 add on the A register. This is possible only if the lowest part
781 of the offset (ie, big_offset % 256) is a valid constant offset
782 with respect to the mode. If it's not, we have to generate a
783 16-bit add on the D register. From:
785 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
789 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
790 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
791 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
792 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
794 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
795 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
798 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
801 rtx reg
= operands
[0];
803 int val
= INTVAL (big_offset
);
806 /* We use the 'operands[0]' as a scratch register to compute the
807 address. Make sure 'base' is in that register. */
808 if (!rtx_equal_p (base
, operands
[0]))
810 emit_move_insn (reg
, base
);
820 vh
= (val
>> 8) & 0x0FF;
824 /* Create the lowest part offset that still remains to be added.
825 If it's not a valid offset, do a 16-bit add. */
826 offset
= GEN_INT (vl
);
827 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
829 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
830 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
835 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
836 gen_rtx (PLUS
, HImode
, reg
,
837 GEN_INT (vh
<< 8))));
839 emit_move_insn (operands
[0],
840 gen_rtx (MEM
, GET_MODE (operands
[1]),
841 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
846 /* Use the normal gen_movhi pattern. */
851 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
854 enum machine_mode dmode
;
855 enum machine_mode smode
;
865 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
869 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
870 dmode
, 1, operands
[1], smode
);
871 equiv
= gen_rtx (code
, dmode
, operands
[1]);
875 ret
= emit_library_call_value (libcall
, NULL_RTX
,
877 operands
[1], smode
, operands
[2],
879 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
886 insns
= get_insns ();
888 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
891 /* Returns true if X is a PRE/POST increment decrement
892 (same as auto_inc_p() in rtlanal.c but do not take into
893 account the stack). */
895 m68hc11_auto_inc_p (x
)
898 return GET_CODE (x
) == PRE_DEC
899 || GET_CODE (x
) == POST_INC
900 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
904 /* Predicates for machine description. */
907 memory_reload_operand (operand
, mode
)
909 enum machine_mode mode ATTRIBUTE_UNUSED
;
911 return GET_CODE (operand
) == MEM
912 && GET_CODE (XEXP (operand
, 0)) == PLUS
913 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
914 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
915 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
916 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
920 tst_operand (operand
, mode
)
922 enum machine_mode mode
;
924 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
926 rtx addr
= XEXP (operand
, 0);
927 if (m68hc11_auto_inc_p (addr
))
930 return nonimmediate_operand (operand
, mode
);
934 cmp_operand (operand
, mode
)
936 enum machine_mode mode
;
938 if (GET_CODE (operand
) == MEM
)
940 rtx addr
= XEXP (operand
, 0);
941 if (m68hc11_auto_inc_p (addr
))
944 return general_operand (operand
, mode
);
948 non_push_operand (operand
, mode
)
950 enum machine_mode mode
;
952 if (general_operand (operand
, mode
) == 0)
955 if (push_operand (operand
, mode
) == 1)
961 reg_or_some_mem_operand (operand
, mode
)
963 enum machine_mode mode
;
965 if (GET_CODE (operand
) == MEM
)
967 rtx op
= XEXP (operand
, 0);
969 if (symbolic_memory_operand (op
, mode
))
972 if (IS_STACK_PUSH (operand
))
975 if (m68hc11_register_indirect_p (operand
, mode
))
981 return register_operand (operand
, mode
);
985 m68hc11_symbolic_p (operand
, mode
)
987 enum machine_mode mode
;
989 if (GET_CODE (operand
) == MEM
)
991 rtx op
= XEXP (operand
, 0);
993 if (symbolic_memory_operand (op
, mode
))
1000 m68hc11_indirect_p (operand
, mode
)
1002 enum machine_mode mode
;
1004 if (GET_CODE (operand
) == MEM
)
1006 rtx op
= XEXP (operand
, 0);
1008 if (symbolic_memory_operand (op
, mode
))
1011 if (reload_in_progress
)
1014 operand
= XEXP (operand
, 0);
1015 return register_indirect_p (operand
, mode
, reload_completed
);
1021 stack_register_operand (operand
, mode
)
1023 enum machine_mode mode ATTRIBUTE_UNUSED
;
1025 return SP_REG_P (operand
);
1029 d_register_operand (operand
, mode
)
1031 enum machine_mode mode ATTRIBUTE_UNUSED
;
1033 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1036 if (GET_CODE (operand
) == SUBREG
)
1037 operand
= XEXP (operand
, 0);
1039 return GET_CODE (operand
) == REG
1040 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1041 || REGNO (operand
) == HARD_D_REGNUM
1042 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1046 hard_addr_reg_operand (operand
, mode
)
1048 enum machine_mode mode ATTRIBUTE_UNUSED
;
1050 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1053 if (GET_CODE (operand
) == SUBREG
)
1054 operand
= XEXP (operand
, 0);
1056 return GET_CODE (operand
) == REG
1057 && (REGNO (operand
) == HARD_X_REGNUM
1058 || REGNO (operand
) == HARD_Y_REGNUM
1059 || REGNO (operand
) == HARD_Z_REGNUM
);
1063 hard_reg_operand (operand
, mode
)
1065 enum machine_mode mode
;
1067 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1070 if (GET_CODE (operand
) == SUBREG
)
1071 operand
= XEXP (operand
, 0);
1073 return GET_CODE (operand
) == REG
1074 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1075 || H_REGNO_P (REGNO (operand
)));
1079 memory_indexed_operand (operand
, mode
)
1081 enum machine_mode mode ATTRIBUTE_UNUSED
;
1083 if (GET_CODE (operand
) != MEM
)
1086 operand
= XEXP (operand
, 0);
1087 if (GET_CODE (operand
) == PLUS
)
1089 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1090 operand
= XEXP (operand
, 0);
1091 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1092 operand
= XEXP (operand
, 1);
1094 return GET_CODE (operand
) == REG
1095 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1096 || A_REGNO_P (REGNO (operand
)));
1100 push_pop_operand_p (operand
)
1103 if (GET_CODE (operand
) != MEM
)
1107 operand
= XEXP (operand
, 0);
1108 return PUSH_POP_ADDRESS_P (operand
);
1111 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1112 reference and a constant. */
1115 symbolic_memory_operand (op
, mode
)
1117 enum machine_mode mode
;
1119 switch (GET_CODE (op
))
1127 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1128 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1129 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1131 /* ??? This clause seems to be irrelevant. */
1133 return GET_MODE (op
) == mode
;
1136 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1137 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1145 m68hc11_eq_compare_operator (op
, mode
)
1147 enum machine_mode mode ATTRIBUTE_UNUSED
;
1149 return GET_CODE (op
) == EQ
|| GET_CODE (op
) == NE
;
1153 m68hc11_logical_operator (op
, mode
)
1155 enum machine_mode mode ATTRIBUTE_UNUSED
;
1157 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1161 m68hc11_arith_operator (op
, mode
)
1163 enum machine_mode mode ATTRIBUTE_UNUSED
;
1165 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1166 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1167 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1168 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1169 || GET_CODE (op
) == ROTATERT
;
1173 m68hc11_non_shift_operator (op
, mode
)
1175 enum machine_mode mode ATTRIBUTE_UNUSED
;
1177 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1178 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1181 /* Return true if op is a shift operator. */
1183 m68hc11_shift_operator (op
, mode
)
1185 enum machine_mode mode ATTRIBUTE_UNUSED
;
1187 return GET_CODE (op
) == ROTATE
|| GET_CODE (op
) == ROTATERT
1188 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ASHIFT
1189 || GET_CODE (op
) == ASHIFTRT
;
1193 m68hc11_unary_operator (op
, mode
)
1195 enum machine_mode mode ATTRIBUTE_UNUSED
;
1197 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1198 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1201 /* Emit the code to build the trampoline used to call a nested function.
1205 ldy #&CXT movw #&CXT,*_.d1
1206 sty *_.d1 jmp FNADDR
1211 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1216 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1219 if (*static_chain_reg
== '*')
1223 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1224 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1225 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1227 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1228 gen_rtx_CONST (QImode
,
1229 gen_rtx_SYMBOL_REF (Pmode
,
1230 static_chain_reg
)));
1231 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1233 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1237 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1238 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1239 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1240 gen_rtx_CONST (HImode
,
1241 gen_rtx_SYMBOL_REF (Pmode
,
1242 static_chain_reg
)));
1243 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1245 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1249 /* Declaration of types. */
1251 const struct attribute_spec m68hc11_attribute_table
[] =
1253 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1254 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1255 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1256 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1257 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1258 { NULL
, 0, 0, false, false, false, NULL
}
1261 /* Keep track of the symbol which has a `trap' attribute and which uses
1262 the `swi' calling convention. Since there is only one trap, we only
1263 record one such symbol. If there are several, a warning is reported. */
1264 static rtx trap_handler_symbol
= 0;
1266 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1267 arguments as in struct attribute_spec.handler. */
1269 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1272 tree args ATTRIBUTE_UNUSED
;
1273 int flags ATTRIBUTE_UNUSED
;
1276 if (TREE_CODE (*node
) != FUNCTION_TYPE
1277 && TREE_CODE (*node
) != METHOD_TYPE
1278 && TREE_CODE (*node
) != FIELD_DECL
1279 && TREE_CODE (*node
) != TYPE_DECL
)
1281 warning ("`%s' attribute only applies to functions",
1282 IDENTIFIER_POINTER (name
));
1283 *no_add_attrs
= true;
1289 /* We want to recognize trap handlers so that we handle calls to traps
1290 in a special manner (by issuing the trap). This information is stored
1291 in SYMBOL_REF_FLAG. */
1294 m68hc11_encode_section_info (decl
, rtl
, first
)
1297 int first ATTRIBUTE_UNUSED
;
1303 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1306 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1309 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1311 else if (lookup_attribute ("near", func_attr
) == NULL_TREE
)
1312 is_far
= TARGET_LONG_CALLS
!= 0;
1314 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1315 if (trap_handler
&& is_far
)
1317 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1322 if (trap_handler_symbol
!= 0)
1323 warning ("`trap' attribute is already used");
1325 trap_handler_symbol
= XEXP (rtl
, 0);
1327 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = is_far
;
1331 m68hc11_is_far_symbol (sym
)
1334 if (GET_CODE (sym
) == MEM
)
1335 sym
= XEXP (sym
, 0);
1337 return SYMBOL_REF_FLAG (sym
);
1341 m68hc11_is_trap_symbol (sym
)
1344 if (GET_CODE (sym
) == MEM
)
1345 sym
= XEXP (sym
, 0);
1347 return trap_handler_symbol
!= 0 && rtx_equal_p (trap_handler_symbol
, sym
);
1351 /* Argument support functions. */
1353 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1354 Arrays are passed by references and other types by value.
1356 SCz: I tried to pass DImode by reference but it seems that this
1357 does not work very well. */
1359 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1360 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1361 enum machine_mode mode ATTRIBUTE_UNUSED
;
1363 int named ATTRIBUTE_UNUSED
;
1365 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1366 /* Consider complex values as aggregates, so care for TCmode. */
1367 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1368 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1372 /* Define the offset between two registers, one to be eliminated, and the
1373 other its replacement, at the start of a routine. */
1375 m68hc11_initial_elimination_offset (from
, to
)
1384 /* For a trap handler, we must take into account the registers which
1385 are pushed on the stack during the trap (except the PC). */
1386 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1388 if (lookup_attribute ("far", func_attr
) != 0)
1389 current_function_far
= 1;
1390 else if (lookup_attribute ("near", func_attr
) != 0)
1391 current_function_far
= 0;
1393 current_function_far
= TARGET_LONG_CALLS
!= 0;
1395 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1396 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1399 /* For a function using 'call/rtc' we must take into account the
1400 page register which is pushed in the call. */
1401 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1406 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1408 /* 2 is for the saved frame.
1409 1 is for the 'sts' correction when creating the frame. */
1410 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1413 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1415 return m68hc11_sp_correction
;
1418 /* Push any 2 byte pseudo hard registers that we need to save. */
1419 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1421 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1427 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1429 return get_frame_size () + size
;
1432 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1439 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1440 for a call to a function whose data type is FNTYPE.
1441 For a library call, FNTYPE is 0. */
1444 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1445 CUMULATIVE_ARGS
*cum
;
1451 z_replacement_completed
= 0;
1455 /* For a library call, we must find out the type of the return value.
1456 When the return value is bigger than 4 bytes, it is returned in
1457 memory. In that case, the first argument of the library call is a
1458 pointer to the memory location. Because the first argument is passed in
1459 register D, we have to identify this, so that the first function
1460 parameter is not passed in D either. */
1466 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1469 /* If the library ends in 'di' or in 'df', we assume it's
1470 returning some DImode or some DFmode which are 64-bit wide. */
1471 name
= XSTR (libname
, 0);
1472 len
= strlen (name
);
1474 && ((name
[len
- 2] == 'd'
1475 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1476 || (name
[len
- 3] == 'd'
1477 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1479 /* We are in. Mark the first parameter register as already used. */
1486 ret_type
= TREE_TYPE (fntype
);
1488 if (ret_type
&& aggregate_value_p (ret_type
))
1495 /* Update the data in CUM to advance over an argument
1496 of mode MODE and data type TYPE.
1497 (TYPE is null for libcalls where that information may not be available.) */
1500 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1501 CUMULATIVE_ARGS
*cum
;
1502 enum machine_mode mode
;
1504 int named ATTRIBUTE_UNUSED
;
1506 if (mode
!= BLKmode
)
1508 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1511 cum
->words
= GET_MODE_SIZE (mode
);
1515 cum
->words
+= GET_MODE_SIZE (mode
);
1516 if (cum
->words
<= HARD_REG_SIZE
)
1522 cum
->words
+= int_size_in_bytes (type
);
1527 /* Define where to put the arguments to a function.
1528 Value is zero to push the argument on the stack,
1529 or a hard register in which to store the argument.
1531 MODE is the argument's machine mode.
1532 TYPE is the data type of the argument (as a tree).
1533 This is null for libcalls where that information may
1535 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1536 the preceding args and about the function being called.
1537 NAMED is nonzero if this argument is a named parameter
1538 (otherwise it is an extra parameter matching an ellipsis). */
1541 m68hc11_function_arg (cum
, mode
, type
, named
)
1542 const CUMULATIVE_ARGS
*cum
;
1543 enum machine_mode mode
;
1544 tree type ATTRIBUTE_UNUSED
;
1545 int named ATTRIBUTE_UNUSED
;
1547 if (cum
->words
!= 0)
1552 if (mode
!= BLKmode
)
1554 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1555 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1557 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1561 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1566 /* If defined, a C expression which determines whether, and in which direction,
1567 to pad out an argument with extra space. The value should be of type
1568 `enum direction': either `upward' to pad above the argument,
1569 `downward' to pad below, or `none' to inhibit padding.
1571 Structures are stored left shifted in their argument slot. */
1573 m68hc11_function_arg_padding (mode
, type
)
1574 enum machine_mode mode
;
1577 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1580 /* This is the default definition. */
1581 return (!BYTES_BIG_ENDIAN
1584 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1585 && int_size_in_bytes (type
) <
1586 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1587 PARM_BOUNDARY
) ? downward
: upward
));
1591 /* Function prologue and epilogue. */
1593 /* Emit a move after the reload pass has completed. This is used to
1594 emit the prologue and epilogue. */
1596 emit_move_after_reload (to
, from
, scratch
)
1597 rtx to
, from
, scratch
;
1601 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1603 insn
= emit_move_insn (to
, from
);
1607 emit_move_insn (scratch
, from
);
1608 insn
= emit_move_insn (to
, scratch
);
1611 /* Put a REG_INC note to tell the flow analysis that the instruction
1613 if (IS_STACK_PUSH (to
))
1615 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1616 XEXP (XEXP (to
, 0), 0),
1619 else if (IS_STACK_POP (from
))
1621 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1622 XEXP (XEXP (from
, 0), 0),
1626 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1627 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1628 The problem is that we are lying to gcc and use `txs' for x = sp
1629 (which is not really true because txs is really x = sp + 1). */
1630 else if (TARGET_M6811
&& SP_REG_P (from
))
1632 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1639 m68hc11_total_frame_size ()
1644 size
= get_frame_size ();
1645 if (current_function_interrupt
)
1647 size
+= 3 * HARD_REG_SIZE
;
1649 if (frame_pointer_needed
)
1650 size
+= HARD_REG_SIZE
;
1652 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1653 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1654 size
+= HARD_REG_SIZE
;
1660 m68hc11_output_function_epilogue (out
, size
)
1661 FILE *out ATTRIBUTE_UNUSED
;
1662 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1664 /* We catch the function epilogue generation to have a chance
1665 to clear the z_replacement_completed flag. */
1666 z_replacement_completed
= 0;
1677 if (reload_completed
!= 1)
1680 size
= get_frame_size ();
1684 /* Generate specific prologue for interrupt handlers. */
1685 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1686 current_function_interrupt
= lookup_attribute ("interrupt",
1687 func_attr
) != NULL_TREE
;
1688 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1689 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1690 current_function_far
= 1;
1691 else if (lookup_attribute ("near", func_attr
) != NULL_TREE
)
1692 current_function_far
= 0;
1694 current_function_far
= TARGET_LONG_CALLS
!= 0;
1696 /* Get the scratch register to build the frame and push registers.
1697 If the first argument is a 32-bit quantity, the D+X registers
1698 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1699 For 68HC12, this scratch register is not used. */
1700 if (current_function_args_info
.nregs
== 2)
1705 /* Save current stack frame. */
1706 if (frame_pointer_needed
)
1707 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1709 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1710 Other soft registers in page0 need not to be saved because they
1711 will be restored by C functions. For a trap handler, we don't
1712 need to preserve these registers because this is a synchronous call. */
1713 if (current_function_interrupt
)
1715 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1716 emit_move_after_reload (stack_push_word
,
1717 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1718 emit_move_after_reload (stack_push_word
,
1719 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1723 /* Allocate local variables. */
1724 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1726 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1727 stack_pointer_rtx
, GEN_INT (-size
)));
1729 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1733 insn
= gen_rtx_PARALLEL
1736 gen_rtx_SET (VOIDmode
,
1738 gen_rtx_PLUS (HImode
,
1741 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1748 /* Allocate by pushing scratch values. */
1749 for (i
= 2; i
<= size
; i
+= 2)
1750 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1753 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1754 stack_pointer_rtx
, GEN_INT (-1)));
1757 /* Create the frame pointer. */
1758 if (frame_pointer_needed
)
1759 emit_move_after_reload (hard_frame_pointer_rtx
,
1760 stack_pointer_rtx
, scratch
);
1762 /* Push any 2 byte pseudo hard registers that we need to save. */
1763 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1765 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1767 emit_move_after_reload (stack_push_word
,
1768 gen_rtx (REG
, HImode
, regno
), scratch
);
1781 if (reload_completed
!= 1)
1784 size
= get_frame_size ();
1786 /* If we are returning a value in two registers, we have to preserve the
1787 X register and use the Y register to restore the stack and the saved
1788 registers. Otherwise, use X because it's faster (and smaller). */
1789 if (current_function_return_rtx
== 0)
1791 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1792 return_size
= HARD_REG_SIZE
;
1794 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1796 if (return_size
> HARD_REG_SIZE
&& return_size
<= 2 * HARD_REG_SIZE
)
1801 /* Pop any 2 byte pseudo hard registers that we saved. */
1802 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1804 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1806 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1807 stack_pop_word
, scratch
);
1811 /* de-allocate auto variables */
1812 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1814 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1815 stack_pointer_rtx
, GEN_INT (size
)));
1817 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1821 insn
= gen_rtx_PARALLEL
1824 gen_rtx_SET (VOIDmode
,
1826 gen_rtx_PLUS (HImode
,
1829 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1836 for (i
= 2; i
<= size
; i
+= 2)
1837 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1839 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1840 stack_pointer_rtx
, GEN_INT (1)));
1843 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1844 if (current_function_interrupt
)
1846 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1847 stack_pop_word
, scratch
);
1848 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1849 stack_pop_word
, scratch
);
1850 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1853 /* Restore previous frame pointer. */
1854 if (frame_pointer_needed
)
1855 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1857 /* If the trap handler returns some value, copy the value
1858 in D, X onto the stack so that the rti will pop the return value
1860 else if (current_function_trap
&& return_size
!= 0)
1862 rtx addr_reg
= stack_pointer_rtx
;
1866 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1869 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1870 gen_rtx (PLUS
, HImode
, addr_reg
,
1871 GEN_INT (1))), d_reg
, 0);
1872 if (return_size
> HARD_REG_SIZE
)
1873 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1874 gen_rtx (PLUS
, HImode
, addr_reg
,
1875 GEN_INT (3))), ix_reg
, 0);
1878 emit_jump_insn (gen_return ());
1882 /* Low and High part extraction for 68HC11. These routines are
1883 similar to gen_lowpart and gen_highpart but they have been
1884 fixed to work for constants and 68HC11 specific registers. */
1887 m68hc11_gen_lowpart (mode
, x
)
1888 enum machine_mode mode
;
1891 /* We assume that the low 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
[0]);
1920 split_double (x
, &first
, &second
);
1924 return GEN_INT (l
[0]);
1926 return gen_int_mode (l
[0], HImode
);
1930 l
[0] = CONST_DOUBLE_LOW (x
);
1933 return GEN_INT (l
[0]);
1934 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1935 return gen_int_mode (l
[0], HImode
);
1940 if (mode
== QImode
&& D_REG_P (x
))
1941 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1943 /* gen_lowpart crashes when it is called with a SUBREG. */
1944 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1947 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1948 else if (mode
== HImode
)
1949 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1953 x
= gen_lowpart (mode
, x
);
1955 /* Return a different rtx to avoid to share it in several insns
1956 (when used by a split pattern). Sharing addresses within
1957 a MEM breaks the Z register replacement (and reloading). */
1958 if (GET_CODE (x
) == MEM
)
1964 m68hc11_gen_highpart (mode
, x
)
1965 enum machine_mode mode
;
1968 /* We assume that the high part of an auto-inc mode is the same with
1969 the mode changed and that the caller split the larger mode in the
1971 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1973 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1976 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1977 floating-point constant. A CONST_DOUBLE is used whenever the
1978 constant requires more than one word in order to be adequately
1980 if (GET_CODE (x
) == CONST_DOUBLE
)
1984 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1988 if (GET_MODE (x
) == SFmode
)
1990 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1991 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1997 split_double (x
, &first
, &second
);
2001 return GEN_INT (l
[1]);
2003 return gen_int_mode ((l
[1] >> 16), HImode
);
2007 l
[1] = CONST_DOUBLE_HIGH (x
);
2011 return GEN_INT (l
[1]);
2012 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
2013 return gen_int_mode ((l
[0] >> 16), HImode
);
2017 if (GET_CODE (x
) == CONST_INT
)
2019 HOST_WIDE_INT val
= INTVAL (x
);
2023 return gen_int_mode (val
>> 8, QImode
);
2025 else if (mode
== HImode
)
2027 return gen_int_mode (val
>> 16, HImode
);
2030 if (mode
== QImode
&& D_REG_P (x
))
2031 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
2033 /* There is no way in GCC to represent the upper part of a word register.
2034 To obtain the 8-bit upper part of a soft register, we change the
2035 reg into a mem rtx. This is possible because they are physically
2036 located in memory. There is no offset because we are big-endian. */
2037 if (mode
== QImode
&& S_REG_P (x
))
2041 /* Avoid the '*' for direct addressing mode when this
2042 addressing mode is disabled. */
2043 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
2044 return gen_rtx (MEM
, QImode
,
2045 gen_rtx (SYMBOL_REF
, Pmode
,
2046 ®_names
[REGNO (x
)][pos
]));
2049 /* gen_highpart crashes when it is called with a SUBREG. */
2050 if (GET_CODE (x
) == SUBREG
)
2052 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
2054 if (GET_CODE (x
) == REG
)
2056 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
2057 return gen_rtx (REG
, mode
, REGNO (x
));
2059 return gen_rtx_SUBREG (mode
, x
, 0);
2062 if (GET_CODE (x
) == MEM
)
2064 x
= change_address (x
, mode
, 0);
2066 /* Return a different rtx to avoid to share it in several insns
2067 (when used by a split pattern). Sharing addresses within
2068 a MEM breaks the Z register replacement (and reloading). */
2069 if (GET_CODE (x
) == MEM
)
2077 /* Obscure register manipulation. */
2079 /* Finds backward in the instructions to see if register 'reg' is
2080 dead. This is used when generating code to see if we can use 'reg'
2081 as a scratch register. This allows us to choose a better generation
2082 of code when we know that some register dies or can be clobbered. */
2085 dead_register_here (x
, reg
)
2093 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2097 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2098 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2104 if (GET_CODE (body
) == CALL_INSN
)
2106 if (GET_CODE (body
) == JUMP_INSN
)
2109 if (GET_CODE (body
) == SET
)
2111 rtx dst
= XEXP (body
, 0);
2113 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2115 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2118 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2121 else if (reg_mentioned_p (reg
, p
)
2122 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2126 /* Scan forward to see if the register is set in some insns and never
2128 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2132 if (GET_CODE (p
) == CODE_LABEL
2133 || GET_CODE (p
) == JUMP_INSN
2134 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2137 if (GET_CODE (p
) != INSN
)
2141 if (GET_CODE (body
) == SET
)
2143 rtx src
= XEXP (body
, 1);
2144 rtx dst
= XEXP (body
, 0);
2146 if (GET_CODE (dst
) == REG
2147 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2151 /* Register is used (may be in source or in dest). */
2152 if (reg_mentioned_p (reg
, p
)
2153 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2154 && reg_mentioned_p (x_reg
, p
)))
2157 return p
== 0 ? 1 : 0;
2161 /* Code generation operations called from machine description file. */
2163 /* Print the name of register 'regno' in the assembly file. */
2165 asm_print_register (file
, regno
)
2169 const char *name
= reg_names
[regno
];
2171 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2174 fprintf (file
, "%s", name
);
2177 /* A C compound statement to output to stdio stream STREAM the
2178 assembler syntax for an instruction operand X. X is an RTL
2181 CODE is a value that can be used to specify one of several ways
2182 of printing the operand. It is used when identical operands
2183 must be printed differently depending on the context. CODE
2184 comes from the `%' specification that was used to request
2185 printing of the operand. If the specification was just `%DIGIT'
2186 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2187 is the ASCII code for LTR.
2189 If X is a register, this macro should print the register's name.
2190 The names can be found in an array `reg_names' whose type is
2191 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2193 When the machine description has a specification `%PUNCT' (a `%'
2194 followed by a punctuation character), this macro is called with
2195 a null pointer for X and the punctuation character for CODE.
2197 The M68HC11 specific codes are:
2199 'b' for the low part of the operand.
2200 'h' for the high part of the operand
2201 The 'b' or 'h' modifiers have no effect if the operand has
2202 the QImode and is not a S_REG_P (soft register). If the
2203 operand is a hard register, these two modifiers have no effect.
2204 't' generate the temporary scratch register. The operand is
2206 'T' generate the low-part temporary scratch register. The operand is
2210 print_operand (file
, op
, letter
)
2217 asm_print_register (file
, SOFT_TMP_REGNUM
);
2220 else if (letter
== 'T')
2222 asm_print_register (file
, SOFT_TMP_REGNUM
);
2223 fprintf (file
, "+1");
2226 else if (letter
== '#')
2228 asm_fprintf (file
, "%I");
2231 if (GET_CODE (op
) == REG
)
2233 if (letter
== 'b' && S_REG_P (op
))
2235 asm_print_register (file
, REGNO (op
));
2236 fprintf (file
, "+1");
2238 else if (letter
== 'b' && D_REG_P (op
))
2240 asm_print_register (file
, HARD_B_REGNUM
);
2244 asm_print_register (file
, REGNO (op
));
2249 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2252 asm_fprintf (file
, "%I%%lo(");
2254 asm_fprintf (file
, "%I%%hi(");
2256 output_addr_const (file
, op
);
2257 fprintf (file
, ")");
2261 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2262 are specified. If we already have a QImode, there is nothing to do. */
2263 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2267 op
= m68hc11_gen_lowpart (QImode
, op
);
2269 else if (letter
== 'h')
2271 op
= m68hc11_gen_highpart (QImode
, op
);
2275 if (GET_CODE (op
) == MEM
)
2277 rtx base
= XEXP (op
, 0);
2278 switch (GET_CODE (base
))
2283 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2284 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2293 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2294 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2295 fprintf (file
, "-");
2304 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2305 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2306 fprintf (file
, "+");
2315 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2316 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2323 output_address (base
);
2327 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2332 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2333 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2334 asm_fprintf (file
, "%I0x%lx", l
);
2336 else if (GET_CODE (op
) == CONST_DOUBLE
2337 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2341 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2342 sizeof (dstr
), 0, 1);
2343 asm_fprintf (file
, "%I0r%s", dstr
);
2347 int need_parenthesize
= 0;
2350 asm_fprintf (file
, "%I");
2352 need_parenthesize
= must_parenthesize (op
);
2354 if (need_parenthesize
)
2355 fprintf (file
, "(");
2357 output_addr_const (file
, op
);
2358 if (need_parenthesize
)
2359 fprintf (file
, ")");
2363 /* Returns true if the operand 'op' must be printed with parenthesis
2364 arround it. This must be done only if there is a symbol whose name
2365 is a processor register. */
2367 must_parenthesize (op
)
2372 switch (GET_CODE (op
))
2375 name
= XSTR (op
, 0);
2376 /* Avoid a conflict between symbol name and a possible
2378 return (strcasecmp (name
, "a") == 0
2379 || strcasecmp (name
, "b") == 0
2380 || strcasecmp (name
, "d") == 0
2381 || strcasecmp (name
, "x") == 0
2382 || strcasecmp (name
, "y") == 0
2383 || strcasecmp (name
, "ix") == 0
2384 || strcasecmp (name
, "iy") == 0
2385 || strcasecmp (name
, "pc") == 0
2386 || strcasecmp (name
, "sp") == 0
2387 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2391 return must_parenthesize (XEXP (op
, 0))
2392 || must_parenthesize (XEXP (op
, 1));
2398 return must_parenthesize (XEXP (op
, 0));
2409 /* A C compound statement to output to stdio stream STREAM the
2410 assembler syntax for an instruction operand that is a memory
2411 reference whose address is ADDR. ADDR is an RTL expression. */
2414 print_operand_address (file
, addr
)
2420 int need_parenthesis
= 0;
2422 switch (GET_CODE (addr
))
2425 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2428 fprintf (file
, "0,");
2429 asm_print_register (file
, REGNO (addr
));
2433 base
= XEXP (addr
, 0);
2434 switch (GET_CODE (base
))
2439 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2440 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2449 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2450 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2451 fprintf (file
, "-");
2460 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2461 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2462 fprintf (file
, "+");
2471 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2472 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2479 need_parenthesis
= must_parenthesize (base
);
2480 if (need_parenthesis
)
2481 fprintf (file
, "(");
2483 output_addr_const (file
, base
);
2484 if (need_parenthesis
)
2485 fprintf (file
, ")");
2491 base
= XEXP (addr
, 0);
2492 offset
= XEXP (addr
, 1);
2493 if (!G_REG_P (base
) && G_REG_P (offset
))
2495 base
= XEXP (addr
, 1);
2496 offset
= XEXP (addr
, 0);
2498 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2500 need_parenthesis
= must_parenthesize (addr
);
2502 if (need_parenthesis
)
2503 fprintf (file
, "(");
2505 output_addr_const (file
, base
);
2506 fprintf (file
, "+");
2507 output_addr_const (file
, offset
);
2508 if (need_parenthesis
)
2509 fprintf (file
, ")");
2511 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2517 asm_print_register (file
, REGNO (offset
));
2518 fprintf (file
, ",");
2519 asm_print_register (file
, REGNO (base
));
2526 need_parenthesis
= must_parenthesize (offset
);
2527 if (need_parenthesis
)
2528 fprintf (file
, "(");
2530 output_addr_const (file
, offset
);
2531 if (need_parenthesis
)
2532 fprintf (file
, ")");
2533 fprintf (file
, ",");
2534 asm_print_register (file
, REGNO (base
));
2544 if (GET_CODE (addr
) == CONST_INT
2545 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2547 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2551 need_parenthesis
= must_parenthesize (addr
);
2552 if (need_parenthesis
)
2553 fprintf (file
, "(");
2555 output_addr_const (file
, addr
);
2556 if (need_parenthesis
)
2557 fprintf (file
, ")");
2564 /* Splitting of some instructions. */
2567 m68hc11_expand_compare (code
, op0
, op1
)
2573 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2577 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2578 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2579 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2586 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2588 rtx op0
, op1
, label
;
2592 switch (GET_MODE (op0
))
2596 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2597 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2598 gen_rtx_LABEL_REF (VOIDmode
, label
),
2600 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2604 /* SCz: from i386.c */
2607 /* Don't expand the comparison early, so that we get better code
2608 when jump or whoever decides to reverse the comparison. */
2613 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2614 &m68hc11_compare_op1
);
2616 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2617 m68hc11_compare_op0
, m68hc11_compare_op1
);
2618 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2619 gen_rtx_LABEL_REF (VOIDmode
, label
),
2621 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2623 use_fcomi
= ix86_use_fcomi_compare (code
);
2624 vec
= rtvec_alloc (3 + !use_fcomi
);
2625 RTVEC_ELT (vec
, 0) = tmp
;
2627 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2629 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2632 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2634 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2640 /* Expand SImode branch into multiple compare+branch. */
2642 rtx lo
[2], hi
[2], label2
;
2643 enum rtx_code code1
, code2
, code3
;
2645 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2650 code
= swap_condition (code
);
2652 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2653 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2654 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2655 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2657 /* Otherwise, if we are doing less-than, op1 is a constant and the
2658 low word is zero, then we can just examine the high word. */
2660 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2661 && (code
== LT
|| code
== LTU
))
2663 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2667 /* Otherwise, we need two or three jumps. */
2669 label2
= gen_label_rtx ();
2672 code2
= swap_condition (code
);
2673 code3
= unsigned_condition (code
);
2714 * if (hi(a) < hi(b)) goto true;
2715 * if (hi(a) > hi(b)) goto false;
2716 * if (lo(a) < lo(b)) goto true;
2720 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2722 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2724 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2727 emit_label (label2
);
2737 /* Return the increment/decrement mode of a MEM if it is such.
2738 Return CONST if it is anything else. */
2743 if (GET_CODE (x
) != MEM
)
2747 if (GET_CODE (x
) == PRE_INC
2748 || GET_CODE (x
) == PRE_DEC
2749 || GET_CODE (x
) == POST_INC
2750 || GET_CODE (x
) == POST_DEC
)
2751 return GET_CODE (x
);
2757 m68hc11_make_autoinc_notes (x
, data
)
2763 switch (GET_CODE (*x
))
2770 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2779 /* Split a DI, SI or HI move into several smaller move operations.
2780 The scratch register 'scratch' is used as a temporary to load
2781 store intermediate values. It must be a hard register. */
2783 m68hc11_split_move (to
, from
, scratch
)
2784 rtx to
, from
, scratch
;
2786 rtx low_to
, low_from
;
2787 rtx high_to
, high_from
;
2789 enum machine_mode mode
;
2791 int autoinc_from
= autoinc_mode (from
);
2792 int autoinc_to
= autoinc_mode (to
);
2794 mode
= GET_MODE (to
);
2796 /* If the TO and FROM contain autoinc modes that are not compatible
2797 together (one pop and the other a push), we must change one to
2798 an offsetable operand and generate an appropriate add at the end. */
2799 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2804 /* The source uses an autoinc mode which is not compatible with
2805 a split (this would result in a word swap). */
2806 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2808 code
= GET_CODE (XEXP (from
, 0));
2809 reg
= XEXP (XEXP (from
, 0), 0);
2810 offset
= GET_MODE_SIZE (GET_MODE (from
));
2811 if (code
== POST_DEC
)
2814 if (code
== PRE_INC
)
2815 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2817 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2818 if (code
== POST_DEC
)
2819 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2823 /* Likewise for destination. */
2824 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2826 code
= GET_CODE (XEXP (to
, 0));
2827 reg
= XEXP (XEXP (to
, 0), 0);
2828 offset
= GET_MODE_SIZE (GET_MODE (to
));
2829 if (code
== POST_DEC
)
2832 if (code
== PRE_INC
)
2833 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2835 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2836 if (code
== POST_DEC
)
2837 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2841 /* The source and destination auto increment modes must be compatible
2842 with each other: same direction. */
2843 if ((autoinc_to
!= autoinc_from
2844 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2845 /* The destination address register must not be used within
2846 the source operand because the source address would change
2847 while doing the copy. */
2848 || (autoinc_to
!= CONST
2849 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2850 && !IS_STACK_PUSH (to
)))
2852 /* Must change the destination. */
2853 code
= GET_CODE (XEXP (to
, 0));
2854 reg
= XEXP (XEXP (to
, 0), 0);
2855 offset
= GET_MODE_SIZE (GET_MODE (to
));
2856 if (code
== PRE_DEC
|| code
== POST_DEC
)
2859 if (code
== PRE_DEC
|| code
== PRE_INC
)
2860 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2861 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2862 if (code
== POST_DEC
|| code
== POST_INC
)
2863 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2868 /* Likewise, the source address register must not be used within
2869 the destination operand. */
2870 if (autoinc_from
!= CONST
2871 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2872 && !IS_STACK_PUSH (to
))
2874 /* Must change the source. */
2875 code
= GET_CODE (XEXP (from
, 0));
2876 reg
= XEXP (XEXP (from
, 0), 0);
2877 offset
= GET_MODE_SIZE (GET_MODE (from
));
2878 if (code
== PRE_DEC
|| code
== POST_DEC
)
2881 if (code
== PRE_DEC
|| code
== PRE_INC
)
2882 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2883 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2884 if (code
== POST_DEC
|| code
== POST_INC
)
2885 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2891 if (GET_MODE_SIZE (mode
) == 8)
2893 else if (GET_MODE_SIZE (mode
) == 4)
2899 && IS_STACK_PUSH (to
)
2900 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2906 else if (mode
== HImode
)
2914 low_to
= m68hc11_gen_lowpart (mode
, to
);
2915 high_to
= m68hc11_gen_highpart (mode
, to
);
2917 low_from
= m68hc11_gen_lowpart (mode
, from
);
2918 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2920 if (INTVAL (from
) >= 0)
2921 high_from
= const0_rtx
;
2923 high_from
= constm1_rtx
;
2926 high_from
= m68hc11_gen_highpart (mode
, from
);
2930 high_from
= adjust_address (high_from
, mode
, offset
);
2931 low_from
= high_from
;
2934 /* When copying with a POST_INC mode, we must copy the
2935 high part and then the low part to guarantee a correct
2938 && GET_MODE_SIZE (mode
) >= 2
2939 && autoinc_from
!= autoinc_to
2940 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2949 low_from
= high_from
;
2954 m68hc11_split_move (low_to
, low_from
, scratch
);
2955 m68hc11_split_move (high_to
, high_from
, scratch
);
2957 else if (H_REG_P (to
) || H_REG_P (from
)
2958 || (low_from
== const0_rtx
2959 && high_from
== const0_rtx
2960 && ! push_operand (to
, GET_MODE (to
))
2961 && ! H_REG_P (scratch
))
2963 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2964 || m68hc11_small_indexed_indirect_p (from
,
2966 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2967 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2969 insn
= emit_move_insn (low_to
, low_from
);
2970 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2972 insn
= emit_move_insn (high_to
, high_from
);
2973 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2977 insn
= emit_move_insn (scratch
, low_from
);
2978 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2979 insn
= emit_move_insn (low_to
, scratch
);
2980 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2982 insn
= emit_move_insn (scratch
, high_from
);
2983 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2984 insn
= emit_move_insn (high_to
, scratch
);
2985 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2990 simplify_logical (mode
, code
, operand
, result
)
2991 enum machine_mode mode
;
3000 if (GET_CODE (operand
) != CONST_INT
)
3008 val
= INTVAL (operand
);
3012 if ((val
& mask
) == 0)
3014 if ((val
& mask
) == mask
)
3015 *result
= constm1_rtx
;
3019 if ((val
& mask
) == 0)
3020 *result
= const0_rtx
;
3021 if ((val
& mask
) == mask
)
3026 if ((val
& mask
) == 0)
3034 m68hc11_emit_logical (mode
, code
, operands
)
3035 enum machine_mode mode
;
3042 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
3043 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
3045 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
3046 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
3048 if (result
&& GET_CODE (result
) == CONST_INT
)
3050 if (!H_REG_P (operands
[0]) && operands
[3]
3051 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
3053 emit_move_insn (operands
[3], result
);
3054 emit_move_insn (operands
[0], operands
[3]);
3058 emit_move_insn (operands
[0], result
);
3061 else if (operands
[1] != 0 && operands
[2] != 0)
3065 if (!H_REG_P (operands
[0]) && operands
[3])
3067 emit_move_insn (operands
[3], operands
[1]);
3068 emit_insn (gen_rtx (SET
, mode
,
3070 gen_rtx (code
, mode
,
3071 operands
[3], operands
[2])));
3072 insn
= emit_move_insn (operands
[0], operands
[3]);
3076 insn
= emit_insn (gen_rtx (SET
, mode
,
3078 gen_rtx (code
, mode
,
3079 operands
[0], operands
[2])));
3083 /* The logical operation is similar to a copy. */
3088 if (GET_CODE (operands
[1]) == CONST_INT
)
3093 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3095 emit_move_insn (operands
[3], src
);
3096 emit_move_insn (operands
[0], operands
[3]);
3100 emit_move_insn (operands
[0], src
);
3106 m68hc11_split_logical (mode
, code
, operands
)
3107 enum machine_mode mode
;
3114 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3115 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3116 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3118 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3120 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3122 if (INTVAL (operands
[1]) >= 0)
3123 high
[1] = const0_rtx
;
3125 high
[1] = constm1_rtx
;
3128 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3130 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3132 if (INTVAL (operands
[2]) >= 0)
3133 high
[2] = const0_rtx
;
3135 high
[2] = constm1_rtx
;
3138 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3140 low
[3] = operands
[3];
3141 high
[3] = operands
[3];
3144 m68hc11_split_logical (HImode
, code
, low
);
3145 m68hc11_split_logical (HImode
, code
, high
);
3149 m68hc11_emit_logical (mode
, code
, low
);
3150 m68hc11_emit_logical (mode
, code
, high
);
3154 /* Code generation. */
3157 m68hc11_output_swap (insn
, operands
)
3158 rtx insn ATTRIBUTE_UNUSED
;
3161 /* We have to be careful with the cc_status. An address register swap
3162 is generated for some comparison. The comparison is made with D
3163 but the branch really uses the address register. See the split
3164 pattern for compare. The xgdx/xgdy preserve the flags but after
3165 the exchange, the flags will reflect to the value of X and not D.
3166 Tell this by setting the cc_status according to the cc_prev_status. */
3167 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3169 if (cc_prev_status
.value1
!= 0
3170 && (D_REG_P (cc_prev_status
.value1
)
3171 || X_REG_P (cc_prev_status
.value1
)))
3173 cc_status
= cc_prev_status
;
3174 if (D_REG_P (cc_status
.value1
))
3175 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3178 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3184 output_asm_insn ("xgdx", operands
);
3188 if (cc_prev_status
.value1
!= 0
3189 && (D_REG_P (cc_prev_status
.value1
)
3190 || Y_REG_P (cc_prev_status
.value1
)))
3192 cc_status
= cc_prev_status
;
3193 if (D_REG_P (cc_status
.value1
))
3194 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3197 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3203 output_asm_insn ("xgdy", operands
);
3207 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3208 This is used to decide whether a move that set flags should be used
3211 next_insn_test_reg (insn
, reg
)
3217 insn
= next_nonnote_insn (insn
);
3218 if (GET_CODE (insn
) != INSN
)
3221 body
= PATTERN (insn
);
3222 if (sets_cc0_p (body
) != 1)
3225 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3231 /* Generate the code to move a 16-bit operand into another one. */
3234 m68hc11_gen_movhi (insn
, operands
)
3240 /* Move a register or memory to the same location.
3241 This is possible because such insn can appear
3242 in a non-optimizing mode. */
3243 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3245 cc_status
= cc_prev_status
;
3251 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3253 cc_status
= cc_prev_status
;
3254 switch (REGNO (operands
[1]))
3259 output_asm_insn ("psh%1", operands
);
3261 case HARD_SP_REGNUM
:
3262 output_asm_insn ("sts\t-2,sp", operands
);
3269 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3271 cc_status
= cc_prev_status
;
3272 switch (REGNO (operands
[0]))
3277 output_asm_insn ("pul%0", operands
);
3284 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3286 m68hc11_notice_keep_cc (operands
[0]);
3287 output_asm_insn ("tfr\t%1,%0", operands
);
3289 else if (H_REG_P (operands
[0]))
3291 if (SP_REG_P (operands
[0]))
3292 output_asm_insn ("lds\t%1", operands
);
3293 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3294 && !D_REG_P (operands
[0])
3295 && GET_CODE (operands
[1]) == CONST_INT
3296 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3297 && find_reg_note (insn
, REG_WAS_0
, 0))
3299 if (INTVAL (operands
[1]) == 1)
3300 output_asm_insn ("in%0", operands
);
3302 output_asm_insn ("de%0", operands
);
3305 output_asm_insn ("ld%0\t%1", operands
);
3307 else if (H_REG_P (operands
[1]))
3309 if (SP_REG_P (operands
[1]))
3310 output_asm_insn ("sts\t%0", operands
);
3312 output_asm_insn ("st%1\t%0", operands
);
3316 rtx from
= operands
[1];
3317 rtx to
= operands
[0];
3319 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3320 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3321 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3322 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3328 ops
[0] = operands
[2];
3331 m68hc11_gen_movhi (insn
, ops
);
3333 ops
[1] = operands
[2];
3334 m68hc11_gen_movhi (insn
, ops
);
3338 /* !!!! SCz wrong here. */
3339 fatal_insn ("move insn not handled", insn
);
3344 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3346 output_asm_insn ("clr\t%h0", operands
);
3347 output_asm_insn ("clr\t%b0", operands
);
3351 m68hc11_notice_keep_cc (operands
[0]);
3352 output_asm_insn ("movw\t%1,%0", operands
);
3359 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3361 cc_status
= cc_prev_status
;
3362 switch (REGNO (operands
[0]))
3366 output_asm_insn ("pul%0", operands
);
3369 output_asm_insn ("pula", operands
);
3370 output_asm_insn ("pulb", operands
);
3377 /* Some moves to a hard register are special. Not all of them
3378 are really supported and we have to use a temporary
3379 location to provide them (either the stack of a temp var). */
3380 if (H_REG_P (operands
[0]))
3382 switch (REGNO (operands
[0]))
3385 if (X_REG_P (operands
[1]))
3387 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3389 m68hc11_output_swap (insn
, operands
);
3391 else if (next_insn_test_reg (insn
, operands
[0]))
3393 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3397 m68hc11_notice_keep_cc (operands
[0]);
3398 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3401 else if (Y_REG_P (operands
[1]))
3403 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3405 m68hc11_output_swap (insn
, operands
);
3409 /* %t means *ZTMP scratch register. */
3410 output_asm_insn ("sty\t%t1", operands
);
3411 output_asm_insn ("ldd\t%t1", operands
);
3414 else if (SP_REG_P (operands
[1]))
3419 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3420 output_asm_insn ("xgdx", operands
);
3421 output_asm_insn ("tsx", operands
);
3422 output_asm_insn ("xgdx", operands
);
3424 else if (IS_STACK_POP (operands
[1]))
3426 output_asm_insn ("pula\n\tpulb", operands
);
3428 else if (GET_CODE (operands
[1]) == CONST_INT
3429 && INTVAL (operands
[1]) == 0)
3431 output_asm_insn ("clra\n\tclrb", operands
);
3435 output_asm_insn ("ldd\t%1", operands
);
3440 if (D_REG_P (operands
[1]))
3442 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3444 m68hc11_output_swap (insn
, operands
);
3446 else if (next_insn_test_reg (insn
, operands
[0]))
3448 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3452 m68hc11_notice_keep_cc (operands
[0]);
3453 output_asm_insn ("pshb", operands
);
3454 output_asm_insn ("psha", operands
);
3455 output_asm_insn ("pulx", operands
);
3458 else if (Y_REG_P (operands
[1]))
3460 /* When both D and Y are dead, use the sequence xgdy, xgdx
3461 to move Y into X. The D and Y registers are modified. */
3462 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3463 && dead_register_here (insn
, d_reg
))
3465 output_asm_insn ("xgdy", operands
);
3466 output_asm_insn ("xgdx", operands
);
3469 else if (!optimize_size
)
3471 output_asm_insn ("sty\t%t1", operands
);
3472 output_asm_insn ("ldx\t%t1", operands
);
3477 output_asm_insn ("pshy", operands
);
3478 output_asm_insn ("pulx", operands
);
3481 else if (SP_REG_P (operands
[1]))
3483 /* tsx, tsy preserve the flags */
3484 cc_status
= cc_prev_status
;
3485 output_asm_insn ("tsx", operands
);
3487 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3488 && GET_CODE (operands
[1]) == CONST_INT
3489 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3490 && find_reg_note (insn
, REG_WAS_0
, 0))
3492 if (INTVAL (operands
[1]) == 1)
3493 output_asm_insn ("in%0", operands
);
3495 output_asm_insn ("de%0", operands
);
3499 output_asm_insn ("ldx\t%1", operands
);
3504 if (D_REG_P (operands
[1]))
3506 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3508 m68hc11_output_swap (insn
, operands
);
3512 output_asm_insn ("std\t%t1", operands
);
3513 output_asm_insn ("ldy\t%t1", operands
);
3516 else if (X_REG_P (operands
[1]))
3518 /* When both D and X are dead, use the sequence xgdx, xgdy
3519 to move X into Y. The D and X registers are modified. */
3520 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3521 && dead_register_here (insn
, d_reg
))
3523 output_asm_insn ("xgdx", operands
);
3524 output_asm_insn ("xgdy", operands
);
3527 else if (!optimize_size
)
3529 output_asm_insn ("stx\t%t1", operands
);
3530 output_asm_insn ("ldy\t%t1", operands
);
3535 output_asm_insn ("pshx", operands
);
3536 output_asm_insn ("puly", operands
);
3539 else if (SP_REG_P (operands
[1]))
3541 /* tsx, tsy preserve the flags */
3542 cc_status
= cc_prev_status
;
3543 output_asm_insn ("tsy", operands
);
3545 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3546 && GET_CODE (operands
[1]) == CONST_INT
3547 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3548 && find_reg_note (insn
, REG_WAS_0
, 0))
3550 if (INTVAL (operands
[1]) == 1)
3551 output_asm_insn ("in%0", operands
);
3553 output_asm_insn ("de%0", operands
);
3557 output_asm_insn ("ldy\t%1", operands
);
3561 case HARD_SP_REGNUM
:
3562 if (D_REG_P (operands
[1]))
3564 m68hc11_notice_keep_cc (operands
[0]);
3565 output_asm_insn ("xgdx", operands
);
3566 output_asm_insn ("txs", operands
);
3567 output_asm_insn ("xgdx", operands
);
3569 else if (X_REG_P (operands
[1]))
3571 /* tys, txs preserve the flags */
3572 cc_status
= cc_prev_status
;
3573 output_asm_insn ("txs", operands
);
3575 else if (Y_REG_P (operands
[1]))
3577 /* tys, txs preserve the flags */
3578 cc_status
= cc_prev_status
;
3579 output_asm_insn ("tys", operands
);
3583 /* lds sets the flags but the des does not. */
3585 output_asm_insn ("lds\t%1", operands
);
3586 output_asm_insn ("des", operands
);
3591 fatal_insn ("invalid register in the move instruction", insn
);
3596 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3597 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3599 output_asm_insn ("sts\t%0", operands
);
3603 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3605 cc_status
= cc_prev_status
;
3606 switch (REGNO (operands
[1]))
3610 output_asm_insn ("psh%1", operands
);
3613 output_asm_insn ("pshb", operands
);
3614 output_asm_insn ("psha", operands
);
3622 /* Operand 1 must be a hard register. */
3623 if (!H_REG_P (operands
[1]))
3625 fatal_insn ("invalid operand in the instruction", insn
);
3628 reg
= REGNO (operands
[1]);
3632 output_asm_insn ("std\t%0", operands
);
3636 output_asm_insn ("stx\t%0", operands
);
3640 output_asm_insn ("sty\t%0", operands
);
3643 case HARD_SP_REGNUM
:
3647 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3649 output_asm_insn ("pshx", operands
);
3650 output_asm_insn ("tsx", operands
);
3651 output_asm_insn ("inx", operands
);
3652 output_asm_insn ("inx", operands
);
3653 output_asm_insn ("stx\t%0", operands
);
3654 output_asm_insn ("pulx", operands
);
3657 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3659 output_asm_insn ("sty\t%t0", operands
);
3660 output_asm_insn ("tsy", operands
);
3661 output_asm_insn ("sty\t%0", operands
);
3662 output_asm_insn ("ldy\t%t0", operands
);
3666 output_asm_insn ("stx\t%t0", operands
);
3667 output_asm_insn ("tsx", operands
);
3668 output_asm_insn ("stx\t%0", operands
);
3669 output_asm_insn ("ldx\t%t0", operands
);
3675 fatal_insn ("invalid register in the move instruction", insn
);
3681 m68hc11_gen_movqi (insn
, operands
)
3685 /* Move a register or memory to the same location.
3686 This is possible because such insn can appear
3687 in a non-optimizing mode. */
3688 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3690 cc_status
= cc_prev_status
;
3697 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3699 m68hc11_notice_keep_cc (operands
[0]);
3700 output_asm_insn ("tfr\t%1,%0", operands
);
3702 else if (H_REG_P (operands
[0]))
3704 if (Q_REG_P (operands
[0]))
3705 output_asm_insn ("lda%0\t%b1", operands
);
3706 else if (D_REG_P (operands
[0]))
3707 output_asm_insn ("ldab\t%b1", operands
);
3711 else if (H_REG_P (operands
[1]))
3713 if (Q_REG_P (operands
[1]))
3714 output_asm_insn ("sta%1\t%b0", operands
);
3715 else if (D_REG_P (operands
[1]))
3716 output_asm_insn ("stab\t%b0", operands
);
3722 rtx from
= operands
[1];
3723 rtx to
= operands
[0];
3725 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3726 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3727 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3728 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3734 ops
[0] = operands
[2];
3737 m68hc11_gen_movqi (insn
, ops
);
3739 ops
[1] = operands
[2];
3740 m68hc11_gen_movqi (insn
, ops
);
3744 /* !!!! SCz wrong here. */
3745 fatal_insn ("move insn not handled", insn
);
3750 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3752 output_asm_insn ("clr\t%b0", operands
);
3756 m68hc11_notice_keep_cc (operands
[0]);
3757 output_asm_insn ("movb\t%b1,%b0", operands
);
3765 if (H_REG_P (operands
[0]))
3767 switch (REGNO (operands
[0]))
3771 if (X_REG_P (operands
[1]))
3773 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3775 m68hc11_output_swap (insn
, operands
);
3779 output_asm_insn ("stx\t%t1", operands
);
3780 output_asm_insn ("ldab\t%T0", operands
);
3783 else if (Y_REG_P (operands
[1]))
3785 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3787 m68hc11_output_swap (insn
, operands
);
3791 output_asm_insn ("sty\t%t1", operands
);
3792 output_asm_insn ("ldab\t%T0", operands
);
3795 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3796 && GET_CODE (operands
[1]) == CONST_INT
3797 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3798 && find_reg_note (insn
, REG_WAS_0
, 0))
3800 if (INTVAL (operands
[1]) == 1)
3801 output_asm_insn ("inc%b0", operands
);
3803 output_asm_insn ("dec%b0", operands
);
3805 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3806 && !DA_REG_P (operands
[1]))
3808 output_asm_insn ("ldab\t%b1", operands
);
3810 else if (DA_REG_P (operands
[1]))
3812 output_asm_insn ("tab", operands
);
3816 cc_status
= cc_prev_status
;
3822 if (X_REG_P (operands
[1]))
3824 output_asm_insn ("stx\t%t1", operands
);
3825 output_asm_insn ("ldaa\t%T0", operands
);
3827 else if (Y_REG_P (operands
[1]))
3829 output_asm_insn ("sty\t%t1", operands
);
3830 output_asm_insn ("ldaa\t%T0", operands
);
3832 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3833 && !DA_REG_P (operands
[1]))
3835 output_asm_insn ("ldaa\t%b1", operands
);
3837 else if (!DA_REG_P (operands
[1]))
3839 output_asm_insn ("tba", operands
);
3843 cc_status
= cc_prev_status
;
3848 if (D_REG_P (operands
[1]))
3850 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3852 m68hc11_output_swap (insn
, operands
);
3856 output_asm_insn ("stab\t%T1", operands
);
3857 output_asm_insn ("ldx\t%t1", operands
);
3861 else if (Y_REG_P (operands
[1]))
3863 output_asm_insn ("sty\t%t0", operands
);
3864 output_asm_insn ("ldx\t%t0", operands
);
3866 else if (GET_CODE (operands
[1]) == CONST_INT
)
3868 output_asm_insn ("ldx\t%1", operands
);
3870 else if (dead_register_here (insn
, d_reg
))
3872 output_asm_insn ("ldab\t%b1", operands
);
3873 output_asm_insn ("xgdx", operands
);
3875 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3877 output_asm_insn ("xgdx", operands
);
3878 output_asm_insn ("ldab\t%b1", operands
);
3879 output_asm_insn ("xgdx", operands
);
3883 output_asm_insn ("pshb", operands
);
3884 output_asm_insn ("ldab\t%b1", operands
);
3885 output_asm_insn ("stab\t%T1", operands
);
3886 output_asm_insn ("ldx\t%t1", operands
);
3887 output_asm_insn ("pulb", operands
);
3893 if (D_REG_P (operands
[1]))
3895 output_asm_insn ("stab\t%T1", operands
);
3896 output_asm_insn ("ldy\t%t1", operands
);
3899 else if (X_REG_P (operands
[1]))
3901 output_asm_insn ("stx\t%t1", operands
);
3902 output_asm_insn ("ldy\t%t1", operands
);
3905 else if (GET_CODE (operands
[1]) == CONST_INT
)
3907 output_asm_insn ("ldy\t%1", operands
);
3909 else if (dead_register_here (insn
, d_reg
))
3911 output_asm_insn ("ldab\t%b1", operands
);
3912 output_asm_insn ("xgdy", operands
);
3914 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3916 output_asm_insn ("xgdy", operands
);
3917 output_asm_insn ("ldab\t%b1", operands
);
3918 output_asm_insn ("xgdy", operands
);
3922 output_asm_insn ("pshb", operands
);
3923 output_asm_insn ("ldab\t%b1", operands
);
3924 output_asm_insn ("stab\t%T1", operands
);
3925 output_asm_insn ("ldy\t%t1", operands
);
3926 output_asm_insn ("pulb", operands
);
3932 fatal_insn ("invalid register in the instruction", insn
);
3936 else if (H_REG_P (operands
[1]))
3938 switch (REGNO (operands
[1]))
3942 output_asm_insn ("stab\t%b0", operands
);
3946 output_asm_insn ("staa\t%b0", operands
);
3950 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3954 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3958 fatal_insn ("invalid register in the move instruction", insn
);
3965 fatal_insn ("operand 1 must be a hard register", insn
);
3969 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3970 The source and destination must be D or A and the shift must
3973 m68hc11_gen_rotate (code
, insn
, operands
)
3980 if (GET_CODE (operands
[2]) != CONST_INT
3981 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3982 fatal_insn ("invalid rotate insn", insn
);
3984 val
= INTVAL (operands
[2]);
3985 if (code
== ROTATERT
)
3986 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3988 if (GET_MODE (operands
[0]) != QImode
)
3991 /* Rotate by 8-bits if the shift is within [5..11]. */
3992 if (val
>= 5 && val
<= 11)
3995 output_asm_insn ("exg\ta,b", operands
);
3998 output_asm_insn ("psha", operands
);
3999 output_asm_insn ("tba", operands
);
4000 output_asm_insn ("pulb", operands
);
4005 /* If the shift is big, invert the rotation. */
4015 /* Set the carry to bit-15, but don't change D yet. */
4016 if (GET_MODE (operands
[0]) != QImode
)
4018 output_asm_insn ("asra", operands
);
4019 output_asm_insn ("rola", operands
);
4022 /* Rotate B first to move the carry to bit-0. */
4023 if (D_REG_P (operands
[0]))
4024 output_asm_insn ("rolb", operands
);
4026 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
4027 output_asm_insn ("rola", operands
);
4034 /* Set the carry to bit-8 of D. */
4035 if (GET_MODE (operands
[0]) != QImode
)
4036 output_asm_insn ("tap", operands
);
4038 /* Rotate B first to move the carry to bit-7. */
4039 if (D_REG_P (operands
[0]))
4040 output_asm_insn ("rorb", operands
);
4042 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
4043 output_asm_insn ("rora", operands
);
4050 /* Store in cc_status the expressions that the condition codes will
4051 describe after execution of an instruction whose pattern is EXP.
4052 Do not alter them if the instruction would not alter the cc's. */
4055 m68hc11_notice_update_cc (exp
, insn
)
4057 rtx insn ATTRIBUTE_UNUSED
;
4059 /* recognize SET insn's. */
4060 if (GET_CODE (exp
) == SET
)
4062 /* Jumps do not alter the cc's. */
4063 if (SET_DEST (exp
) == pc_rtx
)
4066 /* NOTE: most instructions don't affect the carry bit, but the
4067 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
4068 the conditions.h header. */
4070 /* Function calls clobber the cc's. */
4071 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
4076 /* Tests and compares set the cc's in predictable ways. */
4077 else if (SET_DEST (exp
) == cc0_rtx
)
4079 cc_status
.flags
= 0;
4080 cc_status
.value1
= XEXP (exp
, 0);
4081 cc_status
.value2
= XEXP (exp
, 1);
4085 /* All other instructions affect the condition codes. */
4086 cc_status
.flags
= 0;
4087 cc_status
.value1
= XEXP (exp
, 0);
4088 cc_status
.value2
= XEXP (exp
, 1);
4093 /* Default action if we haven't recognized something
4094 and returned earlier. */
4098 if (cc_status
.value2
!= 0)
4099 switch (GET_CODE (cc_status
.value2
))
4101 /* These logical operations can generate several insns.
4102 The flags are setup according to what is generated. */
4108 /* The (not ...) generates several 'com' instructions for
4109 non QImode. We have to invalidate the flags. */
4111 if (GET_MODE (cc_status
.value2
) != QImode
)
4123 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4124 cc_status
.flags
|= CC_NO_OVERFLOW
;
4127 /* The asl sets the overflow bit in such a way that this
4128 makes the flags unusable for a next compare insn. */
4132 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4133 cc_status
.flags
|= CC_NO_OVERFLOW
;
4136 /* A load/store instruction does not affect the carry. */
4141 cc_status
.flags
|= CC_NO_OVERFLOW
;
4147 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4149 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4150 cc_status
.value2
= 0;
4153 /* The current instruction does not affect the flags but changes
4154 the register 'reg'. See if the previous flags can be kept for the
4155 next instruction to avoid a comparison. */
4157 m68hc11_notice_keep_cc (reg
)
4161 || cc_prev_status
.value1
== 0
4162 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4163 || (cc_prev_status
.value2
4164 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4167 cc_status
= cc_prev_status
;
4172 /* Machine Specific Reorg. */
4174 /* Z register replacement:
4176 GCC treats the Z register as an index base address register like
4177 X or Y. In general, it uses it during reload to compute the address
4178 of some operand. This helps the reload pass to avoid to fall into the
4179 register spill failure.
4181 The Z register is in the A_REGS class. In the machine description,
4182 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4184 It can appear everywhere an X or Y register can appear, except for
4185 some templates in the clobber section (when a clobber of X or Y is asked).
4186 For a given instruction, the template must ensure that no more than
4187 2 'A' registers are used. Otherwise, the register replacement is not
4190 To replace the Z register, the algorithm is not terrific:
4191 1. Insns that do not use the Z register are not changed
4192 2. When a Z register is used, we scan forward the insns to see
4193 a potential register to use: either X or Y and sometimes D.
4194 We stop when a call, a label or a branch is seen, or when we
4195 detect that both X and Y are used (probably at different times, but it does
4197 3. The register that will be used for the replacement of Z is saved
4198 in a .page0 register or on the stack. If the first instruction that
4199 used Z, uses Z as an input, the value is loaded from another .page0
4200 register. The replacement register is pushed on the stack in the
4201 rare cases where a compare insn uses Z and we couldn't find if X/Y
4203 4. The Z register is replaced in all instructions until we reach
4204 the end of the Z-block, as detected by step 2.
4205 5. If we detect that Z is still alive, its value is saved.
4206 If the replacement register is alive, its old value is loaded.
4208 The Z register can be disabled with -ffixed-z.
4218 int must_restore_reg
;
4229 int save_before_last
;
4230 int z_loaded_with_sp
;
4233 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4234 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4235 static void m68hc11_z_replacement
PARAMS ((rtx
));
4236 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4238 int z_replacement_completed
= 0;
4240 /* Analyze the insn to find out which replacement register to use and
4241 the boundaries of the replacement.
4242 Returns 0 if we reached the last insn to be replaced, 1 if we can
4243 continue replacement in next insns. */
4246 m68hc11_check_z_replacement (insn
, info
)
4248 struct replace_info
*info
;
4250 int this_insn_uses_ix
;
4251 int this_insn_uses_iy
;
4252 int this_insn_uses_z
;
4253 int this_insn_uses_z_in_dst
;
4254 int this_insn_uses_d
;
4258 /* A call is said to clobber the Z register, we don't need
4259 to save the value of Z. We also don't need to restore
4260 the replacement register (unless it is used by the call). */
4261 if (GET_CODE (insn
) == CALL_INSN
)
4263 body
= PATTERN (insn
);
4265 info
->can_use_d
= 0;
4267 /* If the call is an indirect call with Z, we have to use the
4268 Y register because X can be used as an input (D+X).
4269 We also must not save Z nor restore Y. */
4270 if (reg_mentioned_p (z_reg
, body
))
4272 insn
= NEXT_INSN (insn
);
4275 info
->found_call
= 1;
4276 info
->must_restore_reg
= 0;
4277 info
->last
= NEXT_INSN (insn
);
4279 info
->need_save_z
= 0;
4282 if (GET_CODE (insn
) == CODE_LABEL
4283 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4286 if (GET_CODE (insn
) == JUMP_INSN
)
4288 if (reg_mentioned_p (z_reg
, insn
) == 0)
4291 info
->can_use_d
= 0;
4292 info
->must_save_reg
= 0;
4293 info
->must_restore_reg
= 0;
4294 info
->need_save_z
= 0;
4295 info
->last
= NEXT_INSN (insn
);
4298 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4303 /* Z register dies here. */
4304 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4306 body
= PATTERN (insn
);
4307 if (GET_CODE (body
) == SET
)
4309 rtx src
= XEXP (body
, 1);
4310 rtx dst
= XEXP (body
, 0);
4312 /* Condition code is set here. We have to restore the X/Y and
4313 save into Z before any test/compare insn because once we save/restore
4314 we can change the condition codes. When the compare insn uses Z and
4315 we can't use X/Y, the comparison is made with the *ZREG soft register
4316 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4319 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4320 || (GET_CODE (src
) == COMPARE
&&
4321 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4322 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4324 if (insn
== info
->first
)
4326 info
->must_load_z
= 0;
4327 info
->must_save_reg
= 0;
4328 info
->must_restore_reg
= 0;
4329 info
->need_save_z
= 0;
4330 info
->found_call
= 1;
4331 info
->regno
= SOFT_Z_REGNUM
;
4332 info
->last
= NEXT_INSN (insn
);
4336 if (reg_mentioned_p (z_reg
, src
) == 0)
4338 info
->can_use_d
= 0;
4342 if (insn
!= info
->first
)
4345 /* Compare insn which uses Z. We have to save/restore the X/Y
4346 register without modifying the condition codes. For this
4347 we have to use a push/pop insn. */
4348 info
->must_push_reg
= 1;
4352 /* Z reg is set to something new. We don't need to load it. */
4355 if (!reg_mentioned_p (z_reg
, src
))
4357 /* Z reg is used before being set. Treat this as
4358 a new sequence of Z register replacement. */
4359 if (insn
!= info
->first
)
4363 info
->must_load_z
= 0;
4365 info
->z_set_count
++;
4366 info
->z_value
= src
;
4368 info
->z_loaded_with_sp
= 1;
4370 else if (reg_mentioned_p (z_reg
, dst
))
4371 info
->can_use_d
= 0;
4373 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4374 | reg_mentioned_p (d_reg
, dst
);
4375 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4376 | reg_mentioned_p (ix_reg
, dst
);
4377 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4378 | reg_mentioned_p (iy_reg
, dst
);
4379 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4381 /* If z is used as an address operand (like (MEM (reg z))),
4382 we can't replace it with d. */
4383 if (this_insn_uses_z
&& !Z_REG_P (src
)
4384 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4385 && Z_REG_P (XEXP (src
, 0))
4386 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4387 && insn
== info
->first
4388 && dead_register_here (insn
, d_reg
)))
4389 info
->can_use_d
= 0;
4391 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4392 if (TARGET_M6812
&& !z_dies_here
4393 && ((this_insn_uses_z
&& side_effects_p (src
))
4394 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4396 info
->need_save_z
= 1;
4397 info
->z_set_count
++;
4399 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4401 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4403 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4406 if (this_insn_uses_d
)
4407 info
->can_use_d
= 0;
4409 /* IX and IY are used at the same time, we have to restore
4410 the value of the scratch register before this insn. */
4411 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4416 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4417 info
->can_use_d
= 0;
4419 if (info
->x_used
== 0 && this_insn_uses_ix
)
4423 /* We have a (set (REG:HI X) (REG:HI Z)).
4424 Since we use Z as the replacement register, this insn
4425 is no longer necessary. We turn it into a note. We must
4426 not reload the old value of X. */
4427 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4431 info
->need_save_z
= 0;
4434 info
->must_save_reg
= 0;
4435 info
->must_restore_reg
= 0;
4436 info
->found_call
= 1;
4437 info
->can_use_d
= 0;
4438 PUT_CODE (insn
, NOTE
);
4439 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4440 NOTE_SOURCE_FILE (insn
) = 0;
4441 info
->last
= NEXT_INSN (insn
);
4446 && (rtx_equal_p (src
, z_reg
)
4447 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4451 info
->need_save_z
= 0;
4454 info
->last
= NEXT_INSN (insn
);
4455 info
->must_save_reg
= 0;
4456 info
->must_restore_reg
= 0;
4458 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4459 && !reg_mentioned_p (ix_reg
, src
))
4464 info
->need_save_z
= 0;
4466 else if (TARGET_M6812
&& side_effects_p (src
))
4469 info
->must_restore_reg
= 0;
4474 info
->save_before_last
= 1;
4476 info
->must_restore_reg
= 0;
4477 info
->last
= NEXT_INSN (insn
);
4479 else if (info
->can_use_d
)
4481 info
->last
= NEXT_INSN (insn
);
4487 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4488 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4490 info
->need_save_z
= 0;
4492 info
->last
= NEXT_INSN (insn
);
4493 info
->regno
= HARD_X_REGNUM
;
4494 info
->must_save_reg
= 0;
4495 info
->must_restore_reg
= 0;
4498 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4500 info
->regno
= HARD_X_REGNUM
;
4501 info
->must_restore_reg
= 0;
4502 info
->must_save_reg
= 0;
4506 if (info
->y_used
== 0 && this_insn_uses_iy
)
4510 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4514 info
->need_save_z
= 0;
4517 info
->must_save_reg
= 0;
4518 info
->must_restore_reg
= 0;
4519 info
->found_call
= 1;
4520 info
->can_use_d
= 0;
4521 PUT_CODE (insn
, NOTE
);
4522 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4523 NOTE_SOURCE_FILE (insn
) = 0;
4524 info
->last
= NEXT_INSN (insn
);
4529 && (rtx_equal_p (src
, z_reg
)
4530 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4535 info
->need_save_z
= 0;
4537 info
->last
= NEXT_INSN (insn
);
4538 info
->must_save_reg
= 0;
4539 info
->must_restore_reg
= 0;
4541 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4542 && !reg_mentioned_p (iy_reg
, src
))
4547 info
->need_save_z
= 0;
4549 else if (TARGET_M6812
&& side_effects_p (src
))
4552 info
->must_restore_reg
= 0;
4557 info
->save_before_last
= 1;
4559 info
->must_restore_reg
= 0;
4560 info
->last
= NEXT_INSN (insn
);
4562 else if (info
->can_use_d
)
4564 info
->last
= NEXT_INSN (insn
);
4571 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4572 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4574 info
->need_save_z
= 0;
4576 info
->last
= NEXT_INSN (insn
);
4577 info
->regno
= HARD_Y_REGNUM
;
4578 info
->must_save_reg
= 0;
4579 info
->must_restore_reg
= 0;
4582 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4584 info
->regno
= HARD_Y_REGNUM
;
4585 info
->must_restore_reg
= 0;
4586 info
->must_save_reg
= 0;
4592 info
->need_save_z
= 0;
4594 if (info
->last
== 0)
4595 info
->last
= NEXT_INSN (insn
);
4598 return info
->last
!= NULL_RTX
? 0 : 1;
4600 if (GET_CODE (body
) == PARALLEL
)
4603 char ix_clobber
= 0;
4604 char iy_clobber
= 0;
4606 this_insn_uses_iy
= 0;
4607 this_insn_uses_ix
= 0;
4608 this_insn_uses_z
= 0;
4610 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4613 int uses_ix
, uses_iy
, uses_z
;
4615 x
= XVECEXP (body
, 0, i
);
4617 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4618 info
->can_use_d
= 0;
4620 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4621 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4622 uses_z
= reg_mentioned_p (z_reg
, x
);
4623 if (GET_CODE (x
) == CLOBBER
)
4625 ix_clobber
|= uses_ix
;
4626 iy_clobber
|= uses_iy
;
4627 z_clobber
|= uses_z
;
4631 this_insn_uses_ix
|= uses_ix
;
4632 this_insn_uses_iy
|= uses_iy
;
4633 this_insn_uses_z
|= uses_z
;
4635 if (uses_z
&& GET_CODE (x
) == SET
)
4637 rtx dst
= XEXP (x
, 0);
4640 info
->z_set_count
++;
4642 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4643 info
->need_save_z
= 1;
4646 info
->need_save_z
= 0;
4650 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4651 this_insn_uses_ix
, this_insn_uses_iy
,
4652 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4655 if (this_insn_uses_z
)
4656 info
->can_use_d
= 0;
4658 if (z_clobber
&& info
->first
!= insn
)
4660 info
->need_save_z
= 0;
4664 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4666 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4668 info
->must_load_z
= 0;
4670 if (dead_register_here (insn
, d_reg
))
4672 info
->regno
= HARD_D_REGNUM
;
4673 info
->must_save_reg
= 0;
4674 info
->must_restore_reg
= 0;
4676 else if (dead_register_here (insn
, ix_reg
))
4678 info
->regno
= HARD_X_REGNUM
;
4679 info
->must_save_reg
= 0;
4680 info
->must_restore_reg
= 0;
4682 else if (dead_register_here (insn
, iy_reg
))
4684 info
->regno
= HARD_Y_REGNUM
;
4685 info
->must_save_reg
= 0;
4686 info
->must_restore_reg
= 0;
4688 if (info
->regno
>= 0)
4690 info
->last
= NEXT_INSN (insn
);
4693 if (this_insn_uses_ix
== 0)
4695 info
->regno
= HARD_X_REGNUM
;
4696 info
->must_save_reg
= 1;
4697 info
->must_restore_reg
= 1;
4699 else if (this_insn_uses_iy
== 0)
4701 info
->regno
= HARD_Y_REGNUM
;
4702 info
->must_save_reg
= 1;
4703 info
->must_restore_reg
= 1;
4707 info
->regno
= HARD_D_REGNUM
;
4708 info
->must_save_reg
= 1;
4709 info
->must_restore_reg
= 1;
4711 info
->last
= NEXT_INSN (insn
);
4715 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4716 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4718 if (this_insn_uses_z
)
4720 if (info
->y_used
== 0 && iy_clobber
)
4722 info
->regno
= HARD_Y_REGNUM
;
4723 info
->must_save_reg
= 0;
4724 info
->must_restore_reg
= 0;
4726 if (info
->first
!= insn
4727 && ((info
->y_used
&& ix_clobber
)
4728 || (info
->x_used
&& iy_clobber
)))
4731 info
->last
= NEXT_INSN (insn
);
4732 info
->save_before_last
= 1;
4736 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4738 if (this_insn_uses_z
)
4740 fatal_insn ("cannot do z-register replacement", insn
);
4744 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4751 if (iy_clobber
|| z_clobber
)
4753 info
->last
= NEXT_INSN (insn
);
4754 info
->save_before_last
= 1;
4759 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4766 if (ix_clobber
|| z_clobber
)
4768 info
->last
= NEXT_INSN (insn
);
4769 info
->save_before_last
= 1;
4776 info
->need_save_z
= 0;
4780 if (GET_CODE (body
) == CLOBBER
)
4783 /* IX and IY are used at the same time, we have to restore
4784 the value of the scratch register before this insn. */
4785 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4789 if (info
->x_used
== 0 && this_insn_uses_ix
)
4797 if (info
->y_used
== 0 && this_insn_uses_iy
)
4811 m68hc11_find_z_replacement (insn
, info
)
4813 struct replace_info
*info
;
4817 info
->replace_reg
= NULL_RTX
;
4818 info
->must_load_z
= 1;
4819 info
->need_save_z
= 1;
4820 info
->must_save_reg
= 1;
4821 info
->must_restore_reg
= 1;
4825 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4826 info
->found_call
= 0;
4830 info
->z_set_count
= 0;
4831 info
->z_value
= NULL_RTX
;
4832 info
->must_push_reg
= 0;
4833 info
->save_before_last
= 0;
4834 info
->z_loaded_with_sp
= 0;
4836 /* Scan the insn forward to find an address register that is not used.
4838 - the flow of the program changes,
4839 - when we detect that both X and Y are necessary,
4840 - when the Z register dies,
4841 - when the condition codes are set. */
4843 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4845 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4849 /* May be we can use Y or X if they contain the same value as Z.
4850 This happens very often after the reload. */
4851 if (info
->z_set_count
== 1)
4853 rtx p
= info
->first
;
4858 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4860 else if (info
->y_used
)
4862 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4864 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4867 info
->regno
= HARD_Y_REGNUM
;
4869 info
->regno
= HARD_X_REGNUM
;
4870 info
->must_load_z
= 0;
4871 info
->must_save_reg
= 0;
4872 info
->must_restore_reg
= 0;
4873 info
->found_call
= 1;
4876 if (info
->z_set_count
== 0)
4877 info
->need_save_z
= 0;
4880 info
->need_save_z
= 0;
4882 if (info
->last
== 0)
4885 if (info
->regno
>= 0)
4888 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4890 else if (info
->can_use_d
)
4892 reg
= HARD_D_REGNUM
;
4893 info
->replace_reg
= d_reg
;
4895 else if (info
->x_used
)
4897 reg
= HARD_Y_REGNUM
;
4898 info
->replace_reg
= iy_reg
;
4902 reg
= HARD_X_REGNUM
;
4903 info
->replace_reg
= ix_reg
;
4907 if (info
->must_save_reg
&& info
->must_restore_reg
)
4909 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4911 info
->must_save_reg
= 0;
4912 info
->must_restore_reg
= 0;
4917 /* The insn uses the Z register. Find a replacement register for it
4918 (either X or Y) and replace it in the insn and the next ones until
4919 the flow changes or the replacement register is used. Instructions
4920 are emited before and after the Z-block to preserve the value of
4921 Z and of the replacement register. */
4924 m68hc11_z_replacement (insn
)
4929 struct replace_info info
;
4931 /* Find trivial case where we only need to replace z with the
4932 equivalent soft register. */
4933 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4935 rtx body
= PATTERN (insn
);
4936 rtx src
= XEXP (body
, 1);
4937 rtx dst
= XEXP (body
, 0);
4939 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4941 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4944 else if (Z_REG_P (src
)
4945 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4947 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4950 else if (D_REG_P (dst
)
4951 && m68hc11_arith_operator (src
, GET_MODE (src
))
4952 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4954 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4957 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4958 && INTVAL (src
) == 0)
4960 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4961 /* Force it to be re-recognized. */
4962 INSN_CODE (insn
) = -1;
4967 m68hc11_find_z_replacement (insn
, &info
);
4969 replace_reg
= info
.replace_reg
;
4970 replace_reg_qi
= NULL_RTX
;
4972 /* Save the X register in a .page0 location. */
4973 if (info
.must_save_reg
&& !info
.must_push_reg
)
4977 if (info
.must_push_reg
&& 0)
4978 dst
= gen_rtx (MEM
, HImode
,
4979 gen_rtx (PRE_DEC
, HImode
,
4980 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4982 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4984 emit_insn_before (gen_movhi (dst
,
4985 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4987 if (info
.must_load_z
&& !info
.must_push_reg
)
4989 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4990 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4995 /* Replace all occurrence of Z by replace_reg.
4996 Stop when the last instruction to replace is reached.
4997 Also stop when we detect a change in the flow (but it's not
4998 necessary; just safeguard). */
5000 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
5004 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
5007 if (GET_CODE (insn
) != INSN
5008 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
5011 body
= PATTERN (insn
);
5012 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5013 || GET_CODE (body
) == ASM_OPERANDS
5014 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5018 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
5020 printf ("Reg mentioned here...:\n");
5025 /* Stack pointer was decremented by 2 due to the push.
5026 Correct that by adding 2 to the destination. */
5027 if (info
.must_push_reg
5028 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
5032 src
= SET_SRC (body
);
5033 dst
= SET_DEST (body
);
5034 if (SP_REG_P (src
) && Z_REG_P (dst
))
5035 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
5038 /* Replace any (REG:HI Z) occurrence by either X or Y. */
5039 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
5041 INSN_CODE (insn
) = -1;
5042 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
5043 fatal_insn ("cannot do z-register replacement", insn
);
5046 /* Likewise for (REG:QI Z). */
5047 if (reg_mentioned_p (z_reg
, insn
))
5049 if (replace_reg_qi
== NULL_RTX
)
5050 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
5051 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
5054 /* If there is a REG_INC note on Z, replace it with a
5055 REG_INC note on the replacement register. This is necessary
5056 to make sure that the flow pass will identify the change
5057 and it will not remove a possible insn that saves Z. */
5058 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
5060 if (REG_NOTE_KIND (note
) == REG_INC
5061 && GET_CODE (XEXP (note
, 0)) == REG
5062 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
5064 XEXP (note
, 0) = replace_reg
;
5068 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5072 /* Save Z before restoring the old value. */
5073 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
5075 rtx save_pos_insn
= insn
;
5077 /* If Z is clobber by the last insn, we have to save its value
5078 before the last instruction. */
5079 if (info
.save_before_last
)
5080 save_pos_insn
= PREV_INSN (save_pos_insn
);
5082 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
5083 gen_rtx (REG
, HImode
, info
.regno
)),
5087 if (info
.must_push_reg
&& info
.last
)
5091 body
= PATTERN (info
.last
);
5092 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
5094 gen_rtx (USE
, VOIDmode
,
5096 gen_rtx (USE
, VOIDmode
,
5097 gen_rtx (REG
, HImode
,
5099 PATTERN (info
.last
) = new_body
;
5101 /* Force recognition on insn since we changed it. */
5102 INSN_CODE (insn
) = -1;
5104 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
5106 fatal_insn ("invalid Z register replacement for insn", insn
);
5108 insn
= NEXT_INSN (info
.last
);
5111 /* Restore replacement register unless it was died. */
5112 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
5116 if (info
.must_push_reg
&& 0)
5117 dst
= gen_rtx (MEM
, HImode
,
5118 gen_rtx (POST_INC
, HImode
,
5119 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
5121 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
5123 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
5130 /* Scan all the insn and re-affects some registers
5131 - The Z register (if it was used), is affected to X or Y depending
5132 on the instruction. */
5135 m68hc11_reassign_regs (first
)
5140 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5141 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5142 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5143 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5145 /* Scan all insns to replace Z by X or Y preserving the old value
5146 of X/Y and restoring it afterward. */
5148 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5152 if (GET_CODE (insn
) == CODE_LABEL
5153 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5156 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5159 body
= PATTERN (insn
);
5160 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5163 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5164 || GET_CODE (body
) == ASM_OPERANDS
5165 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5168 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5169 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5172 /* If Z appears in this insn, replace it in the current insn
5173 and the next ones until the flow changes or we have to
5174 restore back the replacement register. */
5176 if (reg_mentioned_p (z_reg
, body
))
5178 m68hc11_z_replacement (insn
);
5183 printf ("insn not handled by Z replacement:\n");
5191 /* Machine-dependent reorg pass.
5192 Specific optimizations are defined here:
5193 - this pass changes the Z register into either X or Y
5194 (it preserves X/Y previous values in a memory slot in page0).
5196 When this pass is finished, the global variable
5197 'z_replacement_completed' is set to 2. */
5205 z_replacement_completed
= 0;
5206 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5207 first
= get_insns ();
5209 /* Some RTX are shared at this point. This breaks the Z register
5210 replacement, unshare everything. */
5211 unshare_all_rtl_again (first
);
5213 /* Force a split of all splitable insn. This is necessary for the
5214 Z register replacement mechanism because we end up with basic insns. */
5215 split_all_insns_noflow ();
5218 z_replacement_completed
= 1;
5219 m68hc11_reassign_regs (first
);
5222 compute_bb_for_insn ();
5224 /* After some splitting, there are some oportunities for CSE pass.
5225 This happens quite often when 32-bit or above patterns are split. */
5226 if (optimize
> 0 && split_done
)
5228 reload_cse_regs (first
);
5231 /* Re-create the REG_DEAD notes. These notes are used in the machine
5232 description to use the best assembly directives. */
5235 /* Before recomputing the REG_DEAD notes, remove all of them.
5236 This is necessary because the reload_cse_regs() pass can
5237 have replaced some (MEM) with a register. In that case,
5238 the REG_DEAD that could exist for that register may become
5240 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5246 pnote
= ®_NOTES (insn
);
5249 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5250 *pnote
= XEXP (*pnote
, 1);
5252 pnote
= &XEXP (*pnote
, 1);
5257 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5260 z_replacement_completed
= 2;
5262 /* If optimizing, then go ahead and split insns that must be
5263 split after Z register replacement. This gives more opportunities
5264 for peephole (in particular for consecutives xgdx/xgdy). */
5266 split_all_insns_noflow ();
5268 /* Once insns are split after the z_replacement_completed == 2,
5269 we must not re-run the life_analysis. The xgdx/xgdy patterns
5270 are not recognized and the life_analysis pass removes some
5271 insns because it thinks some (SETs) are noops or made to dead
5272 stores (which is false due to the swap).
5274 Do a simple pass to eliminate the noop set that the final
5275 split could generate (because it was easier for split definition). */
5279 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5283 if (INSN_DELETED_P (insn
))
5285 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5288 /* Remove the (set (R) (R)) insns generated by some splits. */
5289 body
= PATTERN (insn
);
5290 if (GET_CODE (body
) == SET
5291 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5293 PUT_CODE (insn
, NOTE
);
5294 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5295 NOTE_SOURCE_FILE (insn
) = 0;
5303 /* Cost functions. */
5305 /* Cost of moving memory. */
5307 m68hc11_memory_move_cost (mode
, class, in
)
5308 enum machine_mode mode
;
5309 enum reg_class
class;
5310 int in ATTRIBUTE_UNUSED
;
5312 if (class <= H_REGS
&& class > NO_REGS
)
5314 if (GET_MODE_SIZE (mode
) <= 2)
5315 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5317 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5321 if (GET_MODE_SIZE (mode
) <= 2)
5322 return COSTS_N_INSNS (3);
5324 return COSTS_N_INSNS (4);
5329 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5330 Reload does not check the constraint of set insns when the two registers
5331 have a move cost of 2. Setting a higher cost will force reload to check
5334 m68hc11_register_move_cost (mode
, from
, to
)
5335 enum machine_mode mode
;
5336 enum reg_class from
;
5339 /* All costs are symmetric, so reduce cases by putting the
5340 lower number class as the destination. */
5343 enum reg_class tmp
= to
;
5344 to
= from
, from
= tmp
;
5347 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5348 else if (from
<= S_REGS
)
5349 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5351 return COSTS_N_INSNS (2);
5355 /* Provide the costs of an addressing mode that contains ADDR.
5356 If ADDR is not a valid address, its cost is irrelevant. */
5359 m68hc11_address_cost (addr
)
5364 switch (GET_CODE (addr
))
5367 /* Make the cost of hard registers and specially SP, FP small. */
5368 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5385 register rtx plus0
= XEXP (addr
, 0);
5386 register rtx plus1
= XEXP (addr
, 1);
5388 if (GET_CODE (plus0
) != REG
)
5391 switch (GET_CODE (plus1
))
5394 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5395 || INTVAL (plus1
) < m68hc11_min_offset
)
5397 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5401 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5423 if (SP_REG_P (XEXP (addr
, 0)))
5432 printf ("Address cost: %d for :", cost
);
5441 m68hc11_shift_cost (mode
, x
, shift
)
5442 enum machine_mode mode
;
5448 total
= rtx_cost (x
, SET
);
5450 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5451 else if (mode
== HImode
)
5452 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5453 else if (shift
== 8 || shift
== 16 || shift
== 32)
5454 total
+= m68hc11_cost
->shiftHI_const
[8];
5455 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5457 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5460 /* For SI and others, the cost is higher. */
5461 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5462 total
*= GET_MODE_SIZE (mode
) / 2;
5464 /* When optimizing for size, make shift more costly so that
5465 multiplications are preferred. */
5466 if (optimize_size
&& (shift
% 8) != 0)
5473 m68hc11_rtx_costs_1 (x
, code
, outer_code
)
5476 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5478 enum machine_mode mode
= GET_MODE (x
);
5489 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5491 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5494 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5495 total
+= m68hc11_cost
->shift_var
;
5501 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5502 total
+= m68hc11_cost
->logical
;
5504 /* Logical instructions are byte instructions only. */
5505 total
*= GET_MODE_SIZE (mode
);
5510 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5511 total
+= m68hc11_cost
->add
;
5512 if (GET_MODE_SIZE (mode
) > 2)
5514 total
*= GET_MODE_SIZE (mode
) / 2;
5521 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5525 total
+= m68hc11_cost
->divQI
;
5529 total
+= m68hc11_cost
->divHI
;
5534 total
+= m68hc11_cost
->divSI
;
5540 /* mul instruction produces 16-bit result. */
5541 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5542 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5543 return m68hc11_cost
->multQI
5544 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5545 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5547 /* emul instruction produces 32-bit result for 68HC12. */
5548 if (TARGET_M6812
&& mode
== SImode
5549 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5550 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5551 return m68hc11_cost
->multHI
5552 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5553 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5555 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5559 total
+= m68hc11_cost
->multQI
;
5563 total
+= m68hc11_cost
->multHI
;
5568 total
+= m68hc11_cost
->multSI
;
5575 extra_cost
= COSTS_N_INSNS (2);
5582 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5585 return total
+ COSTS_N_INSNS (1);
5589 return total
+ COSTS_N_INSNS (2);
5593 return total
+ COSTS_N_INSNS (4);
5595 return total
+ COSTS_N_INSNS (8);
5598 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5599 return COSTS_N_INSNS (1);
5601 return COSTS_N_INSNS (1);
5604 return COSTS_N_INSNS (4);
5609 m68hc11_rtx_costs (x
, code
, outer_code
, total
)
5611 int code
, outer_code
;
5616 /* Constants are cheap. Moving them in registers must be avoided
5617 because most instructions do not handle two register operands. */
5623 /* Logical and arithmetic operations with a constant operand are
5624 better because they are not supported with two registers. */
5626 if (outer_code
== SET
&& x
== const0_rtx
)
5627 /* After reload, the reload_cse pass checks the cost to change
5628 a SET into a PLUS. Make const0 cheap then. */
5629 *total
= 1 - reload_completed
;
5634 if (outer_code
== SET
)
5635 *total
= 1 - reload_completed
;
5657 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5666 /* print_options - called at the start of the code generation for a
5669 extern char *asm_file_name
;
5672 #include <sys/types.h>
5681 extern int save_argc
;
5682 extern char **save_argv
;
5684 fprintf (out
, ";;; Command:\t");
5685 for (i
= 0; i
< save_argc
; i
++)
5687 fprintf (out
, "%s", save_argv
[i
]);
5688 if (i
+ 1 < save_argc
)
5691 fprintf (out
, "\n");
5693 a_time
= ctime (&c_time
);
5694 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5697 #define __VERSION__ "[unknown]"
5699 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5701 fprintf (out
, ";;; (META)compiled by CC.\n");
5706 m68hc11_asm_file_start (out
, main_file
)
5708 const char *main_file
;
5710 fprintf (out
, ";;;-----------------------------------------\n");
5711 fprintf (out
, ";;; Start %s gcc assembly output\n",
5714 : TARGET_M68S12
? "MC68HCS12" : "MC68HC12");
5715 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5716 print_options (out
);
5717 fprintf (out
, ";;;-----------------------------------------\n");
5718 output_file_directive (out
, main_file
);
5721 fprintf (out
, "\t.mode mshort\n");
5723 fprintf (out
, "\t.mode mlong\n");
5728 m68hc11_asm_out_constructor (symbol
, priority
)
5732 default_ctor_section_asm_out_constructor (symbol
, priority
);
5733 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5737 m68hc11_asm_out_destructor (symbol
, priority
)
5741 default_dtor_section_asm_out_destructor (symbol
, priority
);
5742 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5745 #include "gt-m68hc11.h"