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 int go_if_legitimate_address_internal
PARAMS((rtx
, enum machine_mode
,
67 static int register_indirect_p
PARAMS((rtx
, enum machine_mode
, int));
68 static rtx m68hc11_expand_compare
PARAMS((enum rtx_code
, rtx
, rtx
));
69 static int must_parenthesize
PARAMS ((rtx
));
70 static int m68hc11_address_cost
PARAMS ((rtx
));
71 static int m68hc11_shift_cost
PARAMS ((enum machine_mode
, rtx
, int));
72 static int m68hc11_rtx_costs_1
PARAMS ((rtx
, enum rtx_code
, enum rtx_code
));
73 static bool m68hc11_rtx_costs
PARAMS ((rtx
, int, int, int *));
74 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
75 static tree m68hc11_handle_fntype_attribute
PARAMS ((tree
*, tree
, tree
, int, bool *));
76 const struct attribute_spec m68hc11_attribute_table
[];
78 void create_regs_rtx
PARAMS ((void));
80 static void asm_print_register
PARAMS ((FILE *, int));
81 static void m68hc11_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
82 static void m68hc11_asm_out_constructor
PARAMS ((rtx
, int));
83 static void m68hc11_asm_out_destructor
PARAMS ((rtx
, int));
84 static void m68hc11_encode_section_info
PARAMS((tree
, int));
85 static int autoinc_mode
PARAMS((rtx
));
86 static int m68hc11_make_autoinc_notes
PARAMS((rtx
*, void *));
88 /* Must be set to 1 to produce debug messages. */
91 extern FILE *asm_out_file
;
96 rtx m68hc11_soft_tmp_reg
;
97 static GTY(()) rtx stack_push_word
;
98 static GTY(()) rtx stack_pop_word
;
99 static GTY(()) rtx z_reg
;
100 static GTY(()) rtx z_reg_qi
;
101 static int regs_inited
= 0;
103 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
104 int current_function_interrupt
;
106 /* Set to 1 by expand_prologue() when the function is a trap handler. */
107 int current_function_trap
;
109 /* Set to 1 when the current function is placed in 68HC12 banked
110 memory and must return with rtc. */
111 int current_function_far
;
113 /* Min offset that is valid for the indirect addressing mode. */
114 HOST_WIDE_INT m68hc11_min_offset
= 0;
116 /* Max offset that is valid for the indirect addressing mode. */
117 HOST_WIDE_INT m68hc11_max_offset
= 256;
119 /* The class value for base registers. */
120 enum reg_class m68hc11_base_reg_class
= A_REGS
;
122 /* The class value for index registers. This is NO_REGS for 68HC11. */
123 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
125 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
127 /* Tables that tell whether a given hard register is valid for
128 a base or an index register. It is filled at init time depending
129 on the target processor. */
130 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
131 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
133 /* A correction offset which is applied to the stack pointer.
134 This is 1 for 68HC11 and 0 for 68HC12. */
135 int m68hc11_sp_correction
;
137 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
138 rtx m68hc11_compare_op0
;
139 rtx m68hc11_compare_op1
;
142 const struct processor_costs
*m68hc11_cost
;
144 /* Costs for a 68HC11. */
145 static const struct processor_costs m6811_cost
= {
150 /* non-constant shift */
153 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
154 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
155 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
158 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
159 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
160 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
161 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
162 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
163 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
168 COSTS_N_INSNS (20 * 4),
170 COSTS_N_INSNS (20 * 16),
179 /* Costs for a 68HC12. */
180 static const struct processor_costs m6812_cost
= {
185 /* non-constant shift */
188 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
189 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
190 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
193 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
194 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
195 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
196 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
197 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
198 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
205 COSTS_N_INSNS (3 * 4),
214 /* Machine specific options */
216 const char *m68hc11_regparm_string
;
217 const char *m68hc11_reg_alloc_order
;
218 const char *m68hc11_soft_reg_count
;
220 static int nb_soft_regs
;
222 /* Initialize the GCC target structure. */
223 #undef TARGET_ATTRIBUTE_TABLE
224 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
226 #undef TARGET_ASM_ALIGNED_HI_OP
227 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
229 #undef TARGET_ASM_FUNCTION_EPILOGUE
230 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
232 #undef TARGET_ENCODE_SECTION_INFO
233 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
235 #undef TARGET_RTX_COSTS
236 #define TARGET_RTX_COSTS m68hc11_rtx_costs
237 #undef TARGET_ADDRESS_COST
238 #define TARGET_ADDRESS_COST m68hc11_address_cost
240 struct gcc_target targetm
= TARGET_INITIALIZER
;
243 m68hc11_override_options ()
245 memset (m68hc11_reg_valid_for_index
, 0,
246 sizeof (m68hc11_reg_valid_for_index
));
247 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
249 /* Compilation with -fpic generates a wrong code. */
252 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
253 (flag_pic
> 1) ? "PIC" : "pic");
257 /* Configure for a 68hc11 processor. */
260 /* If gcc was built for a 68hc12, invalidate that because
261 a -m68hc11 option was specified on the command line. */
262 if (TARGET_DEFAULT
!= MASK_M6811
)
263 target_flags
&= ~TARGET_DEFAULT
;
266 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
267 m68hc11_cost
= &m6811_cost
;
268 m68hc11_min_offset
= 0;
269 m68hc11_max_offset
= 256;
270 m68hc11_index_reg_class
= NO_REGS
;
271 m68hc11_base_reg_class
= A_REGS
;
272 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
273 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
274 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
275 m68hc11_sp_correction
= 1;
276 m68hc11_tmp_regs_class
= D_REGS
;
277 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
278 m68hc11_soft_reg_count
= "4";
281 /* Configure for a 68hc12 processor. */
284 m68hc11_cost
= &m6812_cost
;
285 m68hc11_min_offset
= -65536;
286 m68hc11_max_offset
= 65536;
287 m68hc11_index_reg_class
= D_REGS
;
288 m68hc11_base_reg_class
= A_OR_SP_REGS
;
289 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
290 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
291 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
292 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
293 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
294 m68hc11_sp_correction
= 0;
295 m68hc11_tmp_regs_class
= TMP_REGS
;
296 target_flags
&= ~MASK_M6811
;
297 target_flags
|= MASK_NO_DIRECT_MODE
| MASK_MIN_MAX
;
298 if (m68hc11_soft_reg_count
== 0)
299 m68hc11_soft_reg_count
= "0";
301 if (TARGET_LONG_CALLS
)
302 current_function_far
= 1;
309 m68hc11_conditional_register_usage ()
312 int cnt
= atoi (m68hc11_soft_reg_count
);
316 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
317 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
320 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
323 call_used_regs
[i
] = 1;
326 /* For 68HC12, the Z register emulation is not necessary when the
327 frame pointer is not used. The frame pointer is eliminated and
328 replaced by the stack register (which is a BASE_REG_CLASS). */
329 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
331 fixed_regs
[HARD_Z_REGNUM
] = 1;
336 /* Reload and register operations. */
338 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
344 /* regs_inited = 1; */
345 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
346 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
347 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
348 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
350 stack_push_word
= gen_rtx (MEM
, HImode
,
351 gen_rtx (PRE_DEC
, HImode
,
352 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
353 stack_pop_word
= gen_rtx (MEM
, HImode
,
354 gen_rtx (POST_INC
, HImode
,
355 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
359 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
360 - 8 bit values are stored anywhere (except the SP register).
361 - 16 bit values can be stored in any register whose mode is 16
362 - 32 bit values can be stored in D, X registers or in a soft register
363 (except the last one because we need 2 soft registers)
364 - Values whose size is > 32 bit are not stored in real hard
365 registers. They may be stored in soft registers if there are
368 hard_regno_mode_ok (regno
, mode
)
370 enum machine_mode mode
;
372 switch (GET_MODE_SIZE (mode
))
375 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
378 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
381 return G_REGNO_P (regno
);
384 /* We have to accept a QImode in X or Y registers. Otherwise, the
385 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
386 in the insns. Reload fails if the insn rejects the register class 'a'
387 as well as if it accepts it. Patterns that failed were
388 zero_extend_qihi2 and iorqi3. */
390 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
398 preferred_reload_class (operand
, class)
400 enum reg_class
class;
402 enum machine_mode mode
;
404 mode
= GET_MODE (operand
);
408 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
411 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
412 return m68hc11_base_reg_class
;
414 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
415 || GET_CODE (operand
) == CONST_INT
))
417 /* S_REGS class must not be used. The movhi template does not
418 work to move a memory to a soft register.
419 Restrict to a hard reg. */
424 case D_OR_A_OR_S_REGS
:
430 case D_OR_SP_OR_S_REGS
:
431 class = D_OR_SP_REGS
;
433 case D_OR_Y_OR_S_REGS
:
436 case D_OR_X_OR_S_REGS
:
452 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
456 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
460 else if (class >= S_REGS
&& S_REG_P (operand
))
466 case D_OR_A_OR_S_REGS
:
472 case D_OR_SP_OR_S_REGS
:
473 class = D_OR_SP_REGS
;
475 case D_OR_Y_OR_S_REGS
:
478 case D_OR_X_OR_S_REGS
:
494 else if (class >= S_REGS
)
498 printf ("Class = %s for: ", reg_class_names
[class]);
506 printf (" => class=%s\n", reg_class_names
[class]);
514 /* Return 1 if the operand is a valid indexed addressing mode.
515 For 68hc11: n,r with n in [0..255] and r in A_REGS class
516 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
518 register_indirect_p (operand
, mode
, strict
)
520 enum machine_mode mode
;
525 switch (GET_CODE (operand
))
531 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
532 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
536 base
= XEXP (operand
, 0);
537 if (GET_CODE (base
) == MEM
)
540 offset
= XEXP (operand
, 1);
541 if (GET_CODE (offset
) == MEM
)
544 if (GET_CODE (base
) == REG
)
546 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
552 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
554 if (GET_CODE (offset
) == REG
)
556 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
562 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
567 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
573 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
580 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
581 a 68HC12 1-byte index addressing mode. */
583 m68hc11_small_indexed_indirect_p (operand
, mode
)
585 enum machine_mode mode
;
589 if (GET_CODE (operand
) == REG
&& reload_in_progress
590 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
591 && reg_equiv_memory_loc
[REGNO (operand
)])
593 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
594 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
597 if (GET_CODE (operand
) != MEM
)
600 operand
= XEXP (operand
, 0);
601 if (CONSTANT_ADDRESS_P (operand
))
604 if (PUSH_POP_ADDRESS_P (operand
))
607 if (!register_indirect_p (operand
, mode
, reload_completed
))
610 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
611 && (reload_completed
| reload_in_progress
))
613 base
= XEXP (operand
, 0);
614 offset
= XEXP (operand
, 1);
616 /* The offset can be a symbol address and this is too big
617 for the operand constraint. */
618 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
621 if (GET_CODE (base
) == CONST_INT
)
624 switch (GET_MODE_SIZE (mode
))
627 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
632 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
637 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
646 m68hc11_register_indirect_p (operand
, mode
)
648 enum machine_mode mode
;
650 if (GET_CODE (operand
) != MEM
)
653 operand
= XEXP (operand
, 0);
654 return register_indirect_p (operand
, mode
,
655 (reload_completed
| reload_in_progress
));
659 go_if_legitimate_address_internal (operand
, mode
, strict
)
661 enum machine_mode mode
;
664 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
666 /* Reject the global variables if they are too wide. This forces
667 a load of their address in a register and generates smaller code. */
668 if (GET_MODE_SIZE (mode
) == 8)
673 if (register_indirect_p (operand
, mode
, strict
))
677 if (PUSH_POP_ADDRESS_P (operand
))
681 if (symbolic_memory_operand (operand
, mode
))
689 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
691 enum machine_mode mode
;
698 printf ("Checking: ");
703 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
707 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
714 printf ("go_if_legitimate%s, ret 0: %d:",
715 (strict
? "_strict" : ""), mode
);
724 m68hc11_legitimize_address (operand
, old_operand
, mode
)
725 rtx
*operand ATTRIBUTE_UNUSED
;
726 rtx old_operand ATTRIBUTE_UNUSED
;
727 enum machine_mode mode ATTRIBUTE_UNUSED
;
734 m68hc11_reload_operands (operands
)
737 enum machine_mode mode
;
739 if (regs_inited
== 0)
742 mode
= GET_MODE (operands
[1]);
744 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
745 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
747 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
748 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
750 if (GET_CODE (base
) != REG
)
757 /* If the offset is out of range, we have to compute the address
758 with a separate add instruction. We try to do with with an 8-bit
759 add on the A register. This is possible only if the lowest part
760 of the offset (ie, big_offset % 256) is a valid constant offset
761 with respect to the mode. If it's not, we have to generate a
762 16-bit add on the D register. From:
764 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
768 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
769 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
770 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
771 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
773 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
774 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
777 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
780 rtx reg
= operands
[0];
782 int val
= INTVAL (big_offset
);
785 /* We use the 'operands[0]' as a scratch register to compute the
786 address. Make sure 'base' is in that register. */
787 if (!rtx_equal_p (base
, operands
[0]))
789 emit_move_insn (reg
, base
);
799 vh
= (val
>> 8) & 0x0FF;
803 /* Create the lowest part offset that still remains to be added.
804 If it's not a valid offset, do a 16-bit add. */
805 offset
= GEN_INT (vl
);
806 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
808 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
809 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
814 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
815 gen_rtx (PLUS
, HImode
, reg
,
816 GEN_INT (vh
<< 8))));
818 emit_move_insn (operands
[0],
819 gen_rtx (MEM
, GET_MODE (operands
[1]),
820 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
825 /* Use the normal gen_movhi pattern. */
830 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
833 enum machine_mode dmode
;
834 enum machine_mode smode
;
844 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
848 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
849 dmode
, 1, operands
[1], smode
);
850 equiv
= gen_rtx (code
, dmode
, operands
[1]);
854 ret
= emit_library_call_value (libcall
, NULL_RTX
,
856 operands
[1], smode
, operands
[2],
858 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
865 insns
= get_insns ();
867 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
870 /* Returns true if X is a PRE/POST increment decrement
871 (same as auto_inc_p() in rtlanal.c but do not take into
872 account the stack). */
874 m68hc11_auto_inc_p (x
)
877 return GET_CODE (x
) == PRE_DEC
878 || GET_CODE (x
) == POST_INC
879 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
883 /* Predicates for machine description. */
886 memory_reload_operand (operand
, mode
)
888 enum machine_mode mode ATTRIBUTE_UNUSED
;
890 return GET_CODE (operand
) == MEM
891 && GET_CODE (XEXP (operand
, 0)) == PLUS
892 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
893 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
894 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
895 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
899 tst_operand (operand
, mode
)
901 enum machine_mode mode
;
903 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
905 rtx addr
= XEXP (operand
, 0);
906 if (m68hc11_auto_inc_p (addr
))
909 return nonimmediate_operand (operand
, mode
);
913 cmp_operand (operand
, mode
)
915 enum machine_mode mode
;
917 if (GET_CODE (operand
) == MEM
)
919 rtx addr
= XEXP (operand
, 0);
920 if (m68hc11_auto_inc_p (addr
))
923 return general_operand (operand
, mode
);
927 non_push_operand (operand
, mode
)
929 enum machine_mode mode
;
931 if (general_operand (operand
, mode
) == 0)
934 if (push_operand (operand
, mode
) == 1)
940 reg_or_some_mem_operand (operand
, mode
)
942 enum machine_mode mode
;
944 if (GET_CODE (operand
) == MEM
)
946 rtx op
= XEXP (operand
, 0);
948 if (symbolic_memory_operand (op
, mode
))
951 if (IS_STACK_PUSH (operand
))
954 if (m68hc11_register_indirect_p (operand
, mode
))
960 return register_operand (operand
, mode
);
964 m68hc11_symbolic_p (operand
, mode
)
966 enum machine_mode mode
;
968 if (GET_CODE (operand
) == MEM
)
970 rtx op
= XEXP (operand
, 0);
972 if (symbolic_memory_operand (op
, mode
))
979 m68hc11_indirect_p (operand
, mode
)
981 enum machine_mode mode
;
983 if (GET_CODE (operand
) == MEM
)
985 rtx op
= XEXP (operand
, 0);
987 if (symbolic_memory_operand (op
, mode
))
990 if (reload_in_progress
)
993 operand
= XEXP (operand
, 0);
994 return register_indirect_p (operand
, mode
, reload_completed
);
1000 stack_register_operand (operand
, mode
)
1002 enum machine_mode mode ATTRIBUTE_UNUSED
;
1004 return SP_REG_P (operand
);
1008 d_register_operand (operand
, mode
)
1010 enum machine_mode mode ATTRIBUTE_UNUSED
;
1012 if (GET_CODE (operand
) == SUBREG
)
1013 operand
= XEXP (operand
, 0);
1015 return GET_CODE (operand
) == REG
1016 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1017 || REGNO (operand
) == HARD_D_REGNUM
1018 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1022 hard_addr_reg_operand (operand
, mode
)
1024 enum machine_mode mode ATTRIBUTE_UNUSED
;
1026 if (GET_CODE (operand
) == SUBREG
)
1027 operand
= XEXP (operand
, 0);
1029 return GET_CODE (operand
) == REG
1030 && (REGNO (operand
) == HARD_X_REGNUM
1031 || REGNO (operand
) == HARD_Y_REGNUM
1032 || REGNO (operand
) == HARD_Z_REGNUM
);
1036 hard_reg_operand (operand
, mode
)
1038 enum machine_mode mode ATTRIBUTE_UNUSED
;
1040 if (GET_CODE (operand
) == SUBREG
)
1041 operand
= XEXP (operand
, 0);
1043 return GET_CODE (operand
) == REG
1044 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1045 || H_REGNO_P (REGNO (operand
)));
1049 memory_indexed_operand (operand
, mode
)
1051 enum machine_mode mode ATTRIBUTE_UNUSED
;
1053 if (GET_CODE (operand
) != MEM
)
1056 operand
= XEXP (operand
, 0);
1057 if (GET_CODE (operand
) == PLUS
)
1059 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1060 operand
= XEXP (operand
, 0);
1061 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1062 operand
= XEXP (operand
, 1);
1064 return GET_CODE (operand
) == REG
1065 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1066 || A_REGNO_P (REGNO (operand
)));
1070 push_pop_operand_p (operand
)
1073 if (GET_CODE (operand
) != MEM
)
1077 operand
= XEXP (operand
, 0);
1078 return PUSH_POP_ADDRESS_P (operand
);
1081 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1082 reference and a constant. */
1085 symbolic_memory_operand (op
, mode
)
1087 enum machine_mode mode
;
1089 switch (GET_CODE (op
))
1097 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1098 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1099 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1101 /* ??? This clause seems to be irrelevant. */
1103 return GET_MODE (op
) == mode
;
1106 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1107 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1115 m68hc11_logical_operator (op
, mode
)
1117 enum machine_mode mode ATTRIBUTE_UNUSED
;
1119 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1123 m68hc11_arith_operator (op
, mode
)
1125 enum machine_mode mode ATTRIBUTE_UNUSED
;
1127 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1128 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1129 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1130 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1131 || GET_CODE (op
) == ROTATERT
;
1135 m68hc11_non_shift_operator (op
, mode
)
1137 enum machine_mode mode ATTRIBUTE_UNUSED
;
1139 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1140 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1143 /* Return true if op is a shift operator. */
1145 m68hc11_shift_operator (op
, mode
)
1147 enum machine_mode mode ATTRIBUTE_UNUSED
;
1149 return GET_CODE (op
) == ROTATE
|| GET_CODE (op
) == ROTATERT
1150 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ASHIFT
1151 || GET_CODE (op
) == ASHIFTRT
;
1155 m68hc11_unary_operator (op
, mode
)
1157 enum machine_mode mode ATTRIBUTE_UNUSED
;
1159 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1160 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1163 /* Emit the code to build the trampoline used to call a nested function.
1167 ldy #&CXT movw #&CXT,*_.d1
1168 sty *_.d1 jmp FNADDR
1173 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1178 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1181 if (*static_chain_reg
== '*')
1185 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1186 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1187 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1189 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1190 gen_rtx_CONST (QImode
,
1191 gen_rtx_SYMBOL_REF (Pmode
,
1192 static_chain_reg
)));
1193 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1195 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1199 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1200 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1201 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1202 gen_rtx_CONST (HImode
,
1203 gen_rtx_SYMBOL_REF (Pmode
,
1204 static_chain_reg
)));
1205 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1207 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1211 /* Declaration of types. */
1213 const struct attribute_spec m68hc11_attribute_table
[] =
1215 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1216 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1217 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1218 { NULL
, 0, 0, false, false, false, NULL
}
1221 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1222 arguments as in struct attribute_spec.handler. */
1224 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1227 tree args ATTRIBUTE_UNUSED
;
1228 int flags ATTRIBUTE_UNUSED
;
1231 if (TREE_CODE (*node
) != FUNCTION_TYPE
1232 && TREE_CODE (*node
) != FIELD_DECL
1233 && TREE_CODE (*node
) != TYPE_DECL
)
1235 warning ("`%s' attribute only applies to functions",
1236 IDENTIFIER_POINTER (name
));
1237 *no_add_attrs
= true;
1243 /* We want to recognize trap handlers so that we handle calls to traps
1244 in a special manner (by issuing the trap). This information is stored
1245 in SYMBOL_REF_FLAG. */
1248 m68hc11_encode_section_info (decl
, first
)
1250 int first ATTRIBUTE_UNUSED
;
1256 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1259 rtl
= DECL_RTL (decl
);
1261 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1262 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1263 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1267 /* Argument support functions. */
1269 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1270 Arrays are passed by references and other types by value.
1272 SCz: I tried to pass DImode by reference but it seems that this
1273 does not work very well. */
1275 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1276 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1277 enum machine_mode mode ATTRIBUTE_UNUSED
;
1279 int named ATTRIBUTE_UNUSED
;
1281 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1282 /* Consider complex values as aggregates, so care for TCmode. */
1283 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1284 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1288 /* Define the offset between two registers, one to be eliminated, and the
1289 other its replacement, at the start of a routine. */
1291 m68hc11_initial_elimination_offset (from
, to
)
1300 /* For a trap handler, we must take into account the registers which
1301 are pushed on the stack during the trap (except the PC). */
1302 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1303 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1304 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1307 /* For a function using 'call/rtc' we must take into account the
1308 page register which is pushed in the call. */
1309 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1314 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1316 /* 2 is for the saved frame.
1317 1 is for the 'sts' correction when creating the frame. */
1318 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1321 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1323 return m68hc11_sp_correction
;
1326 /* Push any 2 byte pseudo hard registers that we need to save. */
1327 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1329 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1335 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1337 return get_frame_size () + size
;
1340 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1347 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1348 for a call to a function whose data type is FNTYPE.
1349 For a library call, FNTYPE is 0. */
1352 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1353 CUMULATIVE_ARGS
*cum
;
1359 z_replacement_completed
= 0;
1363 /* For a library call, we must find out the type of the return value.
1364 When the return value is bigger than 4 bytes, it is returned in
1365 memory. In that case, the first argument of the library call is a
1366 pointer to the memory location. Because the first argument is passed in
1367 register D, we have to identify this, so that the first function
1368 parameter is not passed in D either. */
1374 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1377 /* If the library ends in 'di' or in 'df', we assume it's
1378 returning some DImode or some DFmode which are 64-bit wide. */
1379 name
= XSTR (libname
, 0);
1380 len
= strlen (name
);
1382 && ((name
[len
- 2] == 'd'
1383 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1384 || (name
[len
- 3] == 'd'
1385 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1387 /* We are in. Mark the first parameter register as already used. */
1394 ret_type
= TREE_TYPE (fntype
);
1396 if (ret_type
&& aggregate_value_p (ret_type
))
1403 /* Update the data in CUM to advance over an argument
1404 of mode MODE and data type TYPE.
1405 (TYPE is null for libcalls where that information may not be available.) */
1408 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1409 CUMULATIVE_ARGS
*cum
;
1410 enum machine_mode mode
;
1412 int named ATTRIBUTE_UNUSED
;
1414 if (mode
!= BLKmode
)
1416 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1419 cum
->words
= GET_MODE_SIZE (mode
);
1423 cum
->words
+= GET_MODE_SIZE (mode
);
1424 if (cum
->words
<= HARD_REG_SIZE
)
1430 cum
->words
+= int_size_in_bytes (type
);
1435 /* Define where to put the arguments to a function.
1436 Value is zero to push the argument on the stack,
1437 or a hard register in which to store the argument.
1439 MODE is the argument's machine mode.
1440 TYPE is the data type of the argument (as a tree).
1441 This is null for libcalls where that information may
1443 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1444 the preceding args and about the function being called.
1445 NAMED is nonzero if this argument is a named parameter
1446 (otherwise it is an extra parameter matching an ellipsis). */
1449 m68hc11_function_arg (cum
, mode
, type
, named
)
1450 const CUMULATIVE_ARGS
*cum
;
1451 enum machine_mode mode
;
1452 tree type ATTRIBUTE_UNUSED
;
1453 int named ATTRIBUTE_UNUSED
;
1455 if (cum
->words
!= 0)
1460 if (mode
!= BLKmode
)
1462 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1463 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1465 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1469 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1475 m68hc11_va_arg (valist
, type
)
1480 HOST_WIDE_INT align
;
1481 HOST_WIDE_INT rounded_size
;
1485 /* Compute the rounded size of the type. */
1486 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1487 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1491 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1493 if (pad_direction
== downward
)
1495 /* Small args are padded downward. */
1498 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1499 if (rounded_size
> align
)
1502 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1503 build_int_2 (rounded_size
- adj
, 0));
1506 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1507 addr
= copy_to_reg (addr
);
1509 /* Compute new value for AP. */
1510 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1511 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1512 build_int_2 (rounded_size
, 0)));
1513 TREE_SIDE_EFFECTS (t
) = 1;
1514 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1519 /* If defined, a C expression which determines whether, and in which direction,
1520 to pad out an argument with extra space. The value should be of type
1521 `enum direction': either `upward' to pad above the argument,
1522 `downward' to pad below, or `none' to inhibit padding.
1524 Structures are stored left shifted in their argument slot. */
1526 m68hc11_function_arg_padding (mode
, type
)
1527 enum machine_mode mode
;
1530 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1533 /* This is the default definition. */
1534 return (!BYTES_BIG_ENDIAN
1537 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1538 && int_size_in_bytes (type
) <
1539 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1540 PARM_BOUNDARY
) ? downward
: upward
));
1544 /* Function prologue and epilogue. */
1546 /* Emit a move after the reload pass has completed. This is used to
1547 emit the prologue and epilogue. */
1549 emit_move_after_reload (to
, from
, scratch
)
1550 rtx to
, from
, scratch
;
1554 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1556 insn
= emit_move_insn (to
, from
);
1560 emit_move_insn (scratch
, from
);
1561 insn
= emit_move_insn (to
, scratch
);
1564 /* Put a REG_INC note to tell the flow analysis that the instruction
1566 if (IS_STACK_PUSH (to
))
1568 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1569 XEXP (XEXP (to
, 0), 0),
1572 else if (IS_STACK_POP (from
))
1574 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1575 XEXP (XEXP (from
, 0), 0),
1579 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1580 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1581 The problem is that we are lying to gcc and use `txs' for x = sp
1582 (which is not really true because txs is really x = sp + 1). */
1583 else if (TARGET_M6811
&& SP_REG_P (from
))
1585 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1592 m68hc11_total_frame_size ()
1597 size
= get_frame_size ();
1598 if (current_function_interrupt
)
1600 size
+= 3 * HARD_REG_SIZE
;
1602 if (frame_pointer_needed
)
1603 size
+= HARD_REG_SIZE
;
1605 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1606 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1607 size
+= HARD_REG_SIZE
;
1613 m68hc11_output_function_epilogue (out
, size
)
1614 FILE *out ATTRIBUTE_UNUSED
;
1615 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1617 /* We catch the function epilogue generation to have a chance
1618 to clear the z_replacement_completed flag. */
1619 z_replacement_completed
= 0;
1630 if (reload_completed
!= 1)
1633 size
= get_frame_size ();
1637 /* Generate specific prologue for interrupt handlers. */
1638 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1639 current_function_interrupt
= lookup_attribute ("interrupt",
1640 func_attr
) != NULL_TREE
;
1641 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1643 /* Get the scratch register to build the frame and push registers.
1644 If the first argument is a 32-bit quantity, the D+X registers
1645 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1646 For 68HC12, this scratch register is not used. */
1647 if (current_function_args_info
.nregs
== 2)
1652 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1653 Other soft registers in page0 need not to be saved because they
1654 will be restored by C functions. For a trap handler, we don't
1655 need to preserve these registers because this is a synchronous call. */
1656 if (current_function_interrupt
)
1658 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1659 emit_move_after_reload (stack_push_word
,
1660 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1661 emit_move_after_reload (stack_push_word
,
1662 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1666 /* Save current stack frame. */
1667 if (frame_pointer_needed
)
1668 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1670 /* Allocate local variables. */
1671 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1673 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1674 stack_pointer_rtx
, GEN_INT (-size
)));
1676 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1680 insn
= gen_rtx_PARALLEL
1683 gen_rtx_SET (VOIDmode
,
1685 gen_rtx_PLUS (HImode
,
1688 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1695 /* Allocate by pushing scratch values. */
1696 for (i
= 2; i
<= size
; i
+= 2)
1697 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1700 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1701 stack_pointer_rtx
, GEN_INT (-1)));
1704 /* Create the frame pointer. */
1705 if (frame_pointer_needed
)
1706 emit_move_after_reload (hard_frame_pointer_rtx
,
1707 stack_pointer_rtx
, scratch
);
1709 /* Push any 2 byte pseudo hard registers that we need to save. */
1710 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1712 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1714 emit_move_after_reload (stack_push_word
,
1715 gen_rtx (REG
, HImode
, regno
), scratch
);
1728 if (reload_completed
!= 1)
1731 size
= get_frame_size ();
1733 /* If we are returning a value in two registers, we have to preserve the
1734 X register and use the Y register to restore the stack and the saved
1735 registers. Otherwise, use X because it's faster (and smaller). */
1736 if (current_function_return_rtx
== 0)
1738 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1739 return_size
= HARD_REG_SIZE
;
1741 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1743 if (return_size
> HARD_REG_SIZE
)
1748 /* Pop any 2 byte pseudo hard registers that we saved. */
1749 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1751 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1753 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1754 stack_pop_word
, scratch
);
1758 /* de-allocate auto variables */
1759 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1761 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1762 stack_pointer_rtx
, GEN_INT (size
)));
1764 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1768 insn
= gen_rtx_PARALLEL
1771 gen_rtx_SET (VOIDmode
,
1773 gen_rtx_PLUS (HImode
,
1776 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1783 for (i
= 2; i
<= size
; i
+= 2)
1784 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1786 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1787 stack_pointer_rtx
, GEN_INT (1)));
1790 /* Restore previous frame pointer. */
1791 if (frame_pointer_needed
)
1792 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1794 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1795 if (current_function_interrupt
)
1797 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1798 stack_pop_word
, scratch
);
1799 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1800 stack_pop_word
, scratch
);
1801 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1804 /* If the trap handler returns some value, copy the value
1805 in D, X onto the stack so that the rti will pop the return value
1807 else if (current_function_trap
&& return_size
!= 0)
1809 rtx addr_reg
= stack_pointer_rtx
;
1813 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1816 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1817 gen_rtx (PLUS
, HImode
, addr_reg
,
1818 GEN_INT (1))), d_reg
, 0);
1819 if (return_size
> HARD_REG_SIZE
)
1820 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1821 gen_rtx (PLUS
, HImode
, addr_reg
,
1822 GEN_INT (3))), ix_reg
, 0);
1825 emit_jump_insn (gen_return ());
1829 /* Low and High part extraction for 68HC11. These routines are
1830 similar to gen_lowpart and gen_highpart but they have been
1831 fixed to work for constants and 68HC11 specific registers. */
1834 m68hc11_gen_lowpart (mode
, x
)
1835 enum machine_mode mode
;
1838 /* We assume that the low part of an auto-inc mode is the same with
1839 the mode changed and that the caller split the larger mode in the
1841 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1843 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1846 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1847 floating-point constant. A CONST_DOUBLE is used whenever the
1848 constant requires more than one word in order to be adequately
1850 if (GET_CODE (x
) == CONST_DOUBLE
)
1854 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1858 if (GET_MODE (x
) == SFmode
)
1860 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1861 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1867 split_double (x
, &first
, &second
);
1871 return GEN_INT (l
[0]);
1873 return gen_int_mode (l
[0], HImode
);
1877 l
[0] = CONST_DOUBLE_LOW (x
);
1880 return GEN_INT (l
[0]);
1881 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1882 return gen_int_mode (l
[0], HImode
);
1887 if (mode
== QImode
&& D_REG_P (x
))
1888 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1890 /* gen_lowpart crashes when it is called with a SUBREG. */
1891 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1894 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1895 else if (mode
== HImode
)
1896 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1900 x
= gen_lowpart (mode
, x
);
1902 /* Return a different rtx to avoid to share it in several insns
1903 (when used by a split pattern). Sharing addresses within
1904 a MEM breaks the Z register replacement (and reloading). */
1905 if (GET_CODE (x
) == MEM
)
1911 m68hc11_gen_highpart (mode
, x
)
1912 enum machine_mode mode
;
1915 /* We assume that the high part of an auto-inc mode is the same with
1916 the mode changed and that the caller split the larger mode in the
1918 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1920 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1923 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1924 floating-point constant. A CONST_DOUBLE is used whenever the
1925 constant requires more than one word in order to be adequately
1927 if (GET_CODE (x
) == CONST_DOUBLE
)
1931 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1935 if (GET_MODE (x
) == SFmode
)
1937 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1938 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1944 split_double (x
, &first
, &second
);
1948 return GEN_INT (l
[1]);
1950 return gen_int_mode ((l
[1] >> 16), HImode
);
1954 l
[1] = CONST_DOUBLE_HIGH (x
);
1958 return GEN_INT (l
[1]);
1959 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1960 return gen_int_mode ((l
[0] >> 16), HImode
);
1964 if (GET_CODE (x
) == CONST_INT
)
1966 HOST_WIDE_INT val
= INTVAL (x
);
1970 return gen_int_mode (val
>> 8, QImode
);
1972 else if (mode
== HImode
)
1974 return gen_int_mode (val
>> 16, HImode
);
1977 if (mode
== QImode
&& D_REG_P (x
))
1978 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1980 /* There is no way in GCC to represent the upper part of a word register.
1981 To obtain the 8-bit upper part of a soft register, we change the
1982 reg into a mem rtx. This is possible because they are physically
1983 located in memory. There is no offset because we are big-endian. */
1984 if (mode
== QImode
&& S_REG_P (x
))
1988 /* Avoid the '*' for direct addressing mode when this
1989 addressing mode is disabled. */
1990 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1991 return gen_rtx (MEM
, QImode
,
1992 gen_rtx (SYMBOL_REF
, Pmode
,
1993 ®_names
[REGNO (x
)][pos
]));
1996 /* gen_highpart crashes when it is called with a SUBREG. */
1997 if (GET_CODE (x
) == SUBREG
)
1999 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
2001 if (GET_CODE (x
) == REG
)
2003 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
2004 return gen_rtx (REG
, mode
, REGNO (x
));
2006 return gen_rtx_SUBREG (mode
, x
, 0);
2009 if (GET_CODE (x
) == MEM
)
2011 x
= change_address (x
, mode
, 0);
2013 /* Return a different rtx to avoid to share it in several insns
2014 (when used by a split pattern). Sharing addresses within
2015 a MEM breaks the Z register replacement (and reloading). */
2016 if (GET_CODE (x
) == MEM
)
2024 /* Obscure register manipulation. */
2026 /* Finds backward in the instructions to see if register 'reg' is
2027 dead. This is used when generating code to see if we can use 'reg'
2028 as a scratch register. This allows us to choose a better generation
2029 of code when we know that some register dies or can be clobbered. */
2032 dead_register_here (x
, reg
)
2040 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2044 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2045 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2051 if (GET_CODE (body
) == CALL_INSN
)
2053 if (GET_CODE (body
) == JUMP_INSN
)
2056 if (GET_CODE (body
) == SET
)
2058 rtx dst
= XEXP (body
, 0);
2060 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2062 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2065 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2068 else if (reg_mentioned_p (reg
, p
)
2069 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2073 /* Scan forward to see if the register is set in some insns and never
2075 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2079 if (GET_CODE (p
) == CODE_LABEL
2080 || GET_CODE (p
) == JUMP_INSN
2081 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2084 if (GET_CODE (p
) != INSN
)
2088 if (GET_CODE (body
) == SET
)
2090 rtx src
= XEXP (body
, 1);
2091 rtx dst
= XEXP (body
, 0);
2093 if (GET_CODE (dst
) == REG
2094 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2098 /* Register is used (may be in source or in dest). */
2099 if (reg_mentioned_p (reg
, p
)
2100 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2101 && reg_mentioned_p (x_reg
, p
)))
2104 return p
== 0 ? 1 : 0;
2108 /* Code generation operations called from machine description file. */
2110 /* Print the name of register 'regno' in the assembly file. */
2112 asm_print_register (file
, regno
)
2116 const char *name
= reg_names
[regno
];
2118 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2121 fprintf (file
, "%s", name
);
2124 /* A C compound statement to output to stdio stream STREAM the
2125 assembler syntax for an instruction operand X. X is an RTL
2128 CODE is a value that can be used to specify one of several ways
2129 of printing the operand. It is used when identical operands
2130 must be printed differently depending on the context. CODE
2131 comes from the `%' specification that was used to request
2132 printing of the operand. If the specification was just `%DIGIT'
2133 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2134 is the ASCII code for LTR.
2136 If X is a register, this macro should print the register's name.
2137 The names can be found in an array `reg_names' whose type is
2138 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2140 When the machine description has a specification `%PUNCT' (a `%'
2141 followed by a punctuation character), this macro is called with
2142 a null pointer for X and the punctuation character for CODE.
2144 The M68HC11 specific codes are:
2146 'b' for the low part of the operand.
2147 'h' for the high part of the operand
2148 The 'b' or 'h' modifiers have no effect if the operand has
2149 the QImode and is not a S_REG_P (soft register). If the
2150 operand is a hard register, these two modifiers have no effect.
2151 't' generate the temporary scratch register. The operand is
2153 'T' generate the low-part temporary scratch register. The operand is
2157 print_operand (file
, op
, letter
)
2164 asm_print_register (file
, SOFT_TMP_REGNUM
);
2167 else if (letter
== 'T')
2169 asm_print_register (file
, SOFT_TMP_REGNUM
);
2170 fprintf (file
, "+1");
2173 else if (letter
== '#')
2175 asm_fprintf (file
, "%0I");
2178 if (GET_CODE (op
) == REG
)
2180 if (letter
== 'b' && S_REG_P (op
))
2182 asm_print_register (file
, REGNO (op
));
2183 fprintf (file
, "+1");
2187 asm_print_register (file
, REGNO (op
));
2192 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2195 asm_fprintf (file
, "%0I%%lo(");
2197 asm_fprintf (file
, "%0I%%hi(");
2199 output_addr_const (file
, op
);
2200 fprintf (file
, ")");
2204 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2205 are specified. If we already have a QImode, there is nothing to do. */
2206 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2210 op
= m68hc11_gen_lowpart (QImode
, op
);
2212 else if (letter
== 'h')
2214 op
= m68hc11_gen_highpart (QImode
, op
);
2218 if (GET_CODE (op
) == MEM
)
2220 rtx base
= XEXP (op
, 0);
2221 switch (GET_CODE (base
))
2226 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2227 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2236 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2237 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2238 fprintf (file
, "-");
2247 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2248 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2249 fprintf (file
, "+");
2258 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2259 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2266 output_address (base
);
2270 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2275 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2276 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2277 asm_fprintf (file
, "%I0x%lx", l
);
2279 else if (GET_CODE (op
) == CONST_DOUBLE
2280 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2284 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2285 sizeof (dstr
), 0, 1);
2286 asm_fprintf (file
, "%I0r%s", dstr
);
2290 int need_parenthesize
= 0;
2293 asm_fprintf (file
, "%0I");
2295 need_parenthesize
= must_parenthesize (op
);
2297 if (need_parenthesize
)
2298 fprintf (file
, "(");
2300 output_addr_const (file
, op
);
2301 if (need_parenthesize
)
2302 fprintf (file
, ")");
2306 /* Returns true if the operand 'op' must be printed with parenthesis
2307 arround it. This must be done only if there is a symbol whose name
2308 is a processor register. */
2310 must_parenthesize (op
)
2315 switch (GET_CODE (op
))
2318 name
= XSTR (op
, 0);
2319 /* Avoid a conflict between symbol name and a possible
2321 return (strcasecmp (name
, "a") == 0
2322 || strcasecmp (name
, "b") == 0
2323 || strcasecmp (name
, "d") == 0
2324 || strcasecmp (name
, "x") == 0
2325 || strcasecmp (name
, "y") == 0
2326 || strcasecmp (name
, "ix") == 0
2327 || strcasecmp (name
, "iy") == 0
2328 || strcasecmp (name
, "pc") == 0
2329 || strcasecmp (name
, "sp") == 0
2330 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2334 return must_parenthesize (XEXP (op
, 0))
2335 || must_parenthesize (XEXP (op
, 1));
2341 return must_parenthesize (XEXP (op
, 0));
2352 /* A C compound statement to output to stdio stream STREAM the
2353 assembler syntax for an instruction operand that is a memory
2354 reference whose address is ADDR. ADDR is an RTL expression. */
2357 print_operand_address (file
, addr
)
2363 int need_parenthesis
= 0;
2365 switch (GET_CODE (addr
))
2368 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2371 fprintf (file
, "0,");
2372 asm_print_register (file
, REGNO (addr
));
2376 base
= XEXP (addr
, 0);
2377 switch (GET_CODE (base
))
2382 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2383 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2392 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2393 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2394 fprintf (file
, "-");
2403 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2404 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2405 fprintf (file
, "+");
2414 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2415 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2422 need_parenthesis
= must_parenthesize (base
);
2423 if (need_parenthesis
)
2424 fprintf (file
, "(");
2426 output_addr_const (file
, base
);
2427 if (need_parenthesis
)
2428 fprintf (file
, ")");
2434 base
= XEXP (addr
, 0);
2435 offset
= XEXP (addr
, 1);
2436 if (!G_REG_P (base
) && G_REG_P (offset
))
2438 base
= XEXP (addr
, 1);
2439 offset
= XEXP (addr
, 0);
2441 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2443 need_parenthesis
= must_parenthesize (addr
);
2445 if (need_parenthesis
)
2446 fprintf (file
, "(");
2448 output_addr_const (file
, base
);
2449 fprintf (file
, "+");
2450 output_addr_const (file
, offset
);
2451 if (need_parenthesis
)
2452 fprintf (file
, ")");
2454 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2460 asm_print_register (file
, REGNO (offset
));
2461 fprintf (file
, ",");
2462 asm_print_register (file
, REGNO (base
));
2469 need_parenthesis
= must_parenthesize (offset
);
2470 if (need_parenthesis
)
2471 fprintf (file
, "(");
2473 output_addr_const (file
, offset
);
2474 if (need_parenthesis
)
2475 fprintf (file
, ")");
2476 fprintf (file
, ",");
2477 asm_print_register (file
, REGNO (base
));
2487 if (GET_CODE (addr
) == CONST_INT
2488 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2490 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2494 need_parenthesis
= must_parenthesize (addr
);
2495 if (need_parenthesis
)
2496 fprintf (file
, "(");
2498 output_addr_const (file
, addr
);
2499 if (need_parenthesis
)
2500 fprintf (file
, ")");
2507 /* Splitting of some instructions. */
2510 m68hc11_expand_compare (code
, op0
, op1
)
2516 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2520 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2521 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2522 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2529 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2531 rtx op0
, op1
, label
;
2535 switch (GET_MODE (op0
))
2539 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2540 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2541 gen_rtx_LABEL_REF (VOIDmode
, label
),
2543 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2547 /* SCz: from i386.c */
2550 /* Don't expand the comparison early, so that we get better code
2551 when jump or whoever decides to reverse the comparison. */
2556 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2557 &m68hc11_compare_op1
);
2559 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2560 m68hc11_compare_op0
, m68hc11_compare_op1
);
2561 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2562 gen_rtx_LABEL_REF (VOIDmode
, label
),
2564 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2566 use_fcomi
= ix86_use_fcomi_compare (code
);
2567 vec
= rtvec_alloc (3 + !use_fcomi
);
2568 RTVEC_ELT (vec
, 0) = tmp
;
2570 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2572 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2575 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2577 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2583 /* Expand SImode branch into multiple compare+branch. */
2585 rtx lo
[2], hi
[2], label2
;
2586 enum rtx_code code1
, code2
, code3
;
2588 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2593 code
= swap_condition (code
);
2595 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2596 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2597 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2598 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2600 /* Otherwise, if we are doing less-than, op1 is a constant and the
2601 low word is zero, then we can just examine the high word. */
2603 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2604 && (code
== LT
|| code
== LTU
))
2606 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2610 /* Otherwise, we need two or three jumps. */
2612 label2
= gen_label_rtx ();
2615 code2
= swap_condition (code
);
2616 code3
= unsigned_condition (code
);
2657 * if (hi(a) < hi(b)) goto true;
2658 * if (hi(a) > hi(b)) goto false;
2659 * if (lo(a) < lo(b)) goto true;
2663 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2665 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2667 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2670 emit_label (label2
);
2680 /* Return the increment/decrement mode of a MEM if it is such.
2681 Return CONST if it is anything else. */
2686 if (GET_CODE (x
) != MEM
)
2690 if (GET_CODE (x
) == PRE_INC
2691 || GET_CODE (x
) == PRE_DEC
2692 || GET_CODE (x
) == POST_INC
2693 || GET_CODE (x
) == POST_DEC
)
2694 return GET_CODE (x
);
2700 m68hc11_make_autoinc_notes (x
, data
)
2706 switch (GET_CODE (*x
))
2713 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2722 /* Split a DI, SI or HI move into several smaller move operations.
2723 The scratch register 'scratch' is used as a temporary to load
2724 store intermediate values. It must be a hard register. */
2726 m68hc11_split_move (to
, from
, scratch
)
2727 rtx to
, from
, scratch
;
2729 rtx low_to
, low_from
;
2730 rtx high_to
, high_from
;
2732 enum machine_mode mode
;
2734 int autoinc_from
= autoinc_mode (from
);
2735 int autoinc_to
= autoinc_mode (to
);
2737 mode
= GET_MODE (to
);
2739 /* If the TO and FROM contain autoinc modes that are not compatible
2740 together (one pop and the other a push), we must change one to
2741 an offsetable operand and generate an appropriate add at the end. */
2742 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2747 /* The source uses an autoinc mode which is not compatible with
2748 a split (this would result in a word swap). */
2749 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2751 code
= GET_CODE (XEXP (from
, 0));
2752 reg
= XEXP (XEXP (from
, 0), 0);
2753 offset
= GET_MODE_SIZE (GET_MODE (from
));
2754 if (code
== POST_DEC
)
2757 if (code
== PRE_INC
)
2758 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2760 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2761 if (code
== POST_DEC
)
2762 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2766 /* Likewise for destination. */
2767 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2769 code
= GET_CODE (XEXP (to
, 0));
2770 reg
= XEXP (XEXP (to
, 0), 0);
2771 offset
= GET_MODE_SIZE (GET_MODE (to
));
2772 if (code
== POST_DEC
)
2775 if (code
== PRE_INC
)
2776 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2778 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2779 if (code
== POST_DEC
)
2780 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2784 /* The source and destination auto increment modes must be compatible
2785 with each other: same direction. */
2786 if ((autoinc_to
!= autoinc_from
2787 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2788 /* The destination address register must not be used within
2789 the source operand because the source address would change
2790 while doing the copy. */
2791 || (autoinc_to
!= CONST
2792 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2793 && !IS_STACK_PUSH (to
)))
2795 /* Must change the destination. */
2796 code
= GET_CODE (XEXP (to
, 0));
2797 reg
= XEXP (XEXP (to
, 0), 0);
2798 offset
= GET_MODE_SIZE (GET_MODE (to
));
2799 if (code
== PRE_DEC
|| code
== POST_DEC
)
2802 if (code
== PRE_DEC
|| code
== PRE_INC
)
2803 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2804 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2805 if (code
== POST_DEC
|| code
== POST_INC
)
2806 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2811 /* Likewise, the source address register must not be used within
2812 the destination operand. */
2813 if (autoinc_from
!= CONST
2814 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2815 && !IS_STACK_PUSH (to
))
2817 /* Must change the source. */
2818 code
= GET_CODE (XEXP (from
, 0));
2819 reg
= XEXP (XEXP (from
, 0), 0);
2820 offset
= GET_MODE_SIZE (GET_MODE (from
));
2821 if (code
== PRE_DEC
|| code
== POST_DEC
)
2824 if (code
== PRE_DEC
|| code
== PRE_INC
)
2825 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2826 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2827 if (code
== POST_DEC
|| code
== POST_INC
)
2828 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2834 if (GET_MODE_SIZE (mode
) == 8)
2836 else if (GET_MODE_SIZE (mode
) == 4)
2842 && IS_STACK_PUSH (to
)
2843 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2849 else if (mode
== HImode
)
2857 low_to
= m68hc11_gen_lowpart (mode
, to
);
2858 high_to
= m68hc11_gen_highpart (mode
, to
);
2860 low_from
= m68hc11_gen_lowpart (mode
, from
);
2861 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2863 if (INTVAL (from
) >= 0)
2864 high_from
= const0_rtx
;
2866 high_from
= constm1_rtx
;
2869 high_from
= m68hc11_gen_highpart (mode
, from
);
2873 high_from
= adjust_address (high_from
, mode
, offset
);
2874 low_from
= high_from
;
2877 /* When copying with a POST_INC mode, we must copy the
2878 high part and then the low part to guarantee a correct
2881 && GET_MODE_SIZE (mode
) >= 2
2882 && autoinc_from
!= autoinc_to
2883 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2892 low_from
= high_from
;
2897 m68hc11_split_move (low_to
, low_from
, scratch
);
2898 m68hc11_split_move (high_to
, high_from
, scratch
);
2900 else if (H_REG_P (to
) || H_REG_P (from
)
2901 || (low_from
== const0_rtx
2902 && high_from
== const0_rtx
2903 && ! push_operand (to
, GET_MODE (to
))
2904 && ! H_REG_P (scratch
))
2906 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2907 || m68hc11_small_indexed_indirect_p (from
,
2909 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2910 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2912 insn
= emit_move_insn (low_to
, low_from
);
2913 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2915 insn
= emit_move_insn (high_to
, high_from
);
2916 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2920 insn
= emit_move_insn (scratch
, low_from
);
2921 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2922 insn
= emit_move_insn (low_to
, scratch
);
2923 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2925 insn
= emit_move_insn (scratch
, high_from
);
2926 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2927 insn
= emit_move_insn (high_to
, scratch
);
2928 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2933 simplify_logical (mode
, code
, operand
, result
)
2934 enum machine_mode mode
;
2943 if (GET_CODE (operand
) != CONST_INT
)
2951 val
= INTVAL (operand
);
2955 if ((val
& mask
) == 0)
2957 if ((val
& mask
) == mask
)
2958 *result
= constm1_rtx
;
2962 if ((val
& mask
) == 0)
2963 *result
= const0_rtx
;
2964 if ((val
& mask
) == mask
)
2969 if ((val
& mask
) == 0)
2977 m68hc11_emit_logical (mode
, code
, operands
)
2978 enum machine_mode mode
;
2985 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2986 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2988 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2989 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2991 if (result
&& GET_CODE (result
) == CONST_INT
)
2993 if (!H_REG_P (operands
[0]) && operands
[3]
2994 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2996 emit_move_insn (operands
[3], result
);
2997 emit_move_insn (operands
[0], operands
[3]);
3001 emit_move_insn (operands
[0], result
);
3004 else if (operands
[1] != 0 && operands
[2] != 0)
3008 if (!H_REG_P (operands
[0]) && operands
[3])
3010 emit_move_insn (operands
[3], operands
[1]);
3011 emit_insn (gen_rtx (SET
, mode
,
3013 gen_rtx (code
, mode
,
3014 operands
[3], operands
[2])));
3015 insn
= emit_move_insn (operands
[0], operands
[3]);
3019 insn
= emit_insn (gen_rtx (SET
, mode
,
3021 gen_rtx (code
, mode
,
3022 operands
[0], operands
[2])));
3026 /* The logical operation is similar to a copy. */
3031 if (GET_CODE (operands
[1]) == CONST_INT
)
3036 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3038 emit_move_insn (operands
[3], src
);
3039 emit_move_insn (operands
[0], operands
[3]);
3043 emit_move_insn (operands
[0], src
);
3049 m68hc11_split_logical (mode
, code
, operands
)
3050 enum machine_mode mode
;
3057 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3058 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3059 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3061 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3063 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3065 if (INTVAL (operands
[1]) >= 0)
3066 high
[1] = const0_rtx
;
3068 high
[1] = constm1_rtx
;
3071 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3073 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3075 if (INTVAL (operands
[2]) >= 0)
3076 high
[2] = const0_rtx
;
3078 high
[2] = constm1_rtx
;
3081 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3083 low
[3] = operands
[3];
3084 high
[3] = operands
[3];
3087 m68hc11_split_logical (HImode
, code
, low
);
3088 m68hc11_split_logical (HImode
, code
, high
);
3092 m68hc11_emit_logical (mode
, code
, low
);
3093 m68hc11_emit_logical (mode
, code
, high
);
3097 /* Code generation. */
3100 m68hc11_output_swap (insn
, operands
)
3101 rtx insn ATTRIBUTE_UNUSED
;
3104 /* We have to be careful with the cc_status. An address register swap
3105 is generated for some comparison. The comparison is made with D
3106 but the branch really uses the address register. See the split
3107 pattern for compare. The xgdx/xgdy preserve the flags but after
3108 the exchange, the flags will reflect to the value of X and not D.
3109 Tell this by setting the cc_status according to the cc_prev_status. */
3110 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3112 if (cc_prev_status
.value1
!= 0
3113 && (D_REG_P (cc_prev_status
.value1
)
3114 || X_REG_P (cc_prev_status
.value1
)))
3116 cc_status
= cc_prev_status
;
3117 if (D_REG_P (cc_status
.value1
))
3118 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3121 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3127 output_asm_insn ("xgdx", operands
);
3131 if (cc_prev_status
.value1
!= 0
3132 && (D_REG_P (cc_prev_status
.value1
)
3133 || Y_REG_P (cc_prev_status
.value1
)))
3135 cc_status
= cc_prev_status
;
3136 if (D_REG_P (cc_status
.value1
))
3137 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3140 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3146 output_asm_insn ("xgdy", operands
);
3150 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3151 This is used to decide whether a move that set flags should be used
3154 next_insn_test_reg (insn
, reg
)
3160 insn
= next_nonnote_insn (insn
);
3161 if (GET_CODE (insn
) != INSN
)
3164 body
= PATTERN (insn
);
3165 if (sets_cc0_p (body
) != 1)
3168 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3174 /* Generate the code to move a 16-bit operand into another one. */
3177 m68hc11_gen_movhi (insn
, operands
)
3183 /* Move a register or memory to the same location.
3184 This is possible because such insn can appear
3185 in a non-optimizing mode. */
3186 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3188 cc_status
= cc_prev_status
;
3194 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3196 cc_status
= cc_prev_status
;
3197 switch (REGNO (operands
[1]))
3202 output_asm_insn ("psh%1", operands
);
3204 case HARD_SP_REGNUM
:
3205 output_asm_insn ("sts\t-2,sp", operands
);
3212 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3214 cc_status
= cc_prev_status
;
3215 switch (REGNO (operands
[0]))
3220 output_asm_insn ("pul%0", operands
);
3227 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3229 m68hc11_notice_keep_cc (operands
[0]);
3230 output_asm_insn ("tfr\t%1,%0", operands
);
3232 else if (H_REG_P (operands
[0]))
3234 if (SP_REG_P (operands
[0]))
3235 output_asm_insn ("lds\t%1", operands
);
3237 output_asm_insn ("ld%0\t%1", operands
);
3239 else if (H_REG_P (operands
[1]))
3241 if (SP_REG_P (operands
[1]))
3242 output_asm_insn ("sts\t%0", operands
);
3244 output_asm_insn ("st%1\t%0", operands
);
3248 rtx from
= operands
[1];
3249 rtx to
= operands
[0];
3251 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3252 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3253 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3254 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3260 ops
[0] = operands
[2];
3263 m68hc11_gen_movhi (insn
, ops
);
3265 ops
[1] = operands
[2];
3266 m68hc11_gen_movhi (insn
, ops
);
3270 /* !!!! SCz wrong here. */
3271 fatal_insn ("move insn not handled", insn
);
3276 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3278 output_asm_insn ("clr\t%h0", operands
);
3279 output_asm_insn ("clr\t%b0", operands
);
3283 m68hc11_notice_keep_cc (operands
[0]);
3284 output_asm_insn ("movw\t%1,%0", operands
);
3291 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3293 cc_status
= cc_prev_status
;
3294 switch (REGNO (operands
[0]))
3298 output_asm_insn ("pul%0", operands
);
3301 output_asm_insn ("pula", operands
);
3302 output_asm_insn ("pulb", operands
);
3309 /* Some moves to a hard register are special. Not all of them
3310 are really supported and we have to use a temporary
3311 location to provide them (either the stack of a temp var). */
3312 if (H_REG_P (operands
[0]))
3314 switch (REGNO (operands
[0]))
3317 if (X_REG_P (operands
[1]))
3319 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3321 m68hc11_output_swap (insn
, operands
);
3323 else if (next_insn_test_reg (insn
, operands
[0]))
3325 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3329 m68hc11_notice_keep_cc (operands
[0]);
3330 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3333 else if (Y_REG_P (operands
[1]))
3335 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3337 m68hc11_output_swap (insn
, operands
);
3341 /* %t means *ZTMP scratch register. */
3342 output_asm_insn ("sty\t%t1", operands
);
3343 output_asm_insn ("ldd\t%t1", operands
);
3346 else if (SP_REG_P (operands
[1]))
3351 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3352 output_asm_insn ("xgdx", operands
);
3353 output_asm_insn ("tsx", operands
);
3354 output_asm_insn ("xgdx", operands
);
3356 else if (IS_STACK_POP (operands
[1]))
3358 output_asm_insn ("pula\n\tpulb", operands
);
3360 else if (GET_CODE (operands
[1]) == CONST_INT
3361 && INTVAL (operands
[1]) == 0)
3363 output_asm_insn ("clra\n\tclrb", operands
);
3367 output_asm_insn ("ldd\t%1", operands
);
3372 if (D_REG_P (operands
[1]))
3374 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3376 m68hc11_output_swap (insn
, operands
);
3378 else if (next_insn_test_reg (insn
, operands
[0]))
3380 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3384 m68hc11_notice_keep_cc (operands
[0]);
3385 output_asm_insn ("pshb", operands
);
3386 output_asm_insn ("psha", operands
);
3387 output_asm_insn ("pulx", operands
);
3390 else if (Y_REG_P (operands
[1]))
3392 /* When both D and Y are dead, use the sequence xgdy, xgdx
3393 to move Y into X. The D and Y registers are modified. */
3394 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3395 && dead_register_here (insn
, d_reg
))
3397 output_asm_insn ("xgdy", operands
);
3398 output_asm_insn ("xgdx", operands
);
3403 output_asm_insn ("sty\t%t1", operands
);
3404 output_asm_insn ("ldx\t%t1", operands
);
3407 else if (SP_REG_P (operands
[1]))
3409 /* tsx, tsy preserve the flags */
3410 cc_status
= cc_prev_status
;
3411 output_asm_insn ("tsx", operands
);
3415 output_asm_insn ("ldx\t%1", operands
);
3420 if (D_REG_P (operands
[1]))
3422 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3424 m68hc11_output_swap (insn
, operands
);
3428 output_asm_insn ("std\t%t1", operands
);
3429 output_asm_insn ("ldy\t%t1", operands
);
3432 else if (X_REG_P (operands
[1]))
3434 /* When both D and X are dead, use the sequence xgdx, xgdy
3435 to move X into Y. The D and X registers are modified. */
3436 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3437 && dead_register_here (insn
, d_reg
))
3439 output_asm_insn ("xgdx", operands
);
3440 output_asm_insn ("xgdy", operands
);
3445 output_asm_insn ("stx\t%t1", operands
);
3446 output_asm_insn ("ldy\t%t1", operands
);
3449 else if (SP_REG_P (operands
[1]))
3451 /* tsx, tsy preserve the flags */
3452 cc_status
= cc_prev_status
;
3453 output_asm_insn ("tsy", operands
);
3457 output_asm_insn ("ldy\t%1", operands
);
3461 case HARD_SP_REGNUM
:
3462 if (D_REG_P (operands
[1]))
3464 m68hc11_notice_keep_cc (operands
[0]);
3465 output_asm_insn ("xgdx", operands
);
3466 output_asm_insn ("txs", operands
);
3467 output_asm_insn ("xgdx", operands
);
3469 else if (X_REG_P (operands
[1]))
3471 /* tys, txs preserve the flags */
3472 cc_status
= cc_prev_status
;
3473 output_asm_insn ("txs", operands
);
3475 else if (Y_REG_P (operands
[1]))
3477 /* tys, txs preserve the flags */
3478 cc_status
= cc_prev_status
;
3479 output_asm_insn ("tys", operands
);
3483 /* lds sets the flags but the des does not. */
3485 output_asm_insn ("lds\t%1", operands
);
3486 output_asm_insn ("des", operands
);
3491 fatal_insn ("invalid register in the move instruction", insn
);
3496 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3497 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3499 output_asm_insn ("sts\t%0", operands
);
3503 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3505 cc_status
= cc_prev_status
;
3506 switch (REGNO (operands
[1]))
3510 output_asm_insn ("psh%1", operands
);
3513 output_asm_insn ("pshb", operands
);
3514 output_asm_insn ("psha", operands
);
3522 /* Operand 1 must be a hard register. */
3523 if (!H_REG_P (operands
[1]))
3525 fatal_insn ("invalid operand in the instruction", insn
);
3528 reg
= REGNO (operands
[1]);
3532 output_asm_insn ("std\t%0", operands
);
3536 output_asm_insn ("stx\t%0", operands
);
3540 output_asm_insn ("sty\t%0", operands
);
3543 case HARD_SP_REGNUM
:
3547 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3549 output_asm_insn ("pshx", operands
);
3550 output_asm_insn ("tsx", operands
);
3551 output_asm_insn ("inx", operands
);
3552 output_asm_insn ("inx", operands
);
3553 output_asm_insn ("stx\t%0", operands
);
3554 output_asm_insn ("pulx", operands
);
3557 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3559 output_asm_insn ("sty\t%t0", operands
);
3560 output_asm_insn ("tsy", operands
);
3561 output_asm_insn ("sty\t%0", operands
);
3562 output_asm_insn ("ldy\t%t0", operands
);
3566 output_asm_insn ("stx\t%t0", operands
);
3567 output_asm_insn ("tsx", operands
);
3568 output_asm_insn ("stx\t%0", operands
);
3569 output_asm_insn ("ldx\t%t0", operands
);
3575 fatal_insn ("invalid register in the move instruction", insn
);
3581 m68hc11_gen_movqi (insn
, operands
)
3585 /* Move a register or memory to the same location.
3586 This is possible because such insn can appear
3587 in a non-optimizing mode. */
3588 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3590 cc_status
= cc_prev_status
;
3597 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3599 m68hc11_notice_keep_cc (operands
[0]);
3600 output_asm_insn ("tfr\t%1,%0", operands
);
3602 else if (H_REG_P (operands
[0]))
3604 if (Q_REG_P (operands
[0]))
3605 output_asm_insn ("lda%0\t%b1", operands
);
3606 else if (D_REG_P (operands
[0]))
3607 output_asm_insn ("ldab\t%b1", operands
);
3611 else if (H_REG_P (operands
[1]))
3613 if (Q_REG_P (operands
[1]))
3614 output_asm_insn ("sta%1\t%b0", operands
);
3615 else if (D_REG_P (operands
[1]))
3616 output_asm_insn ("stab\t%b0", operands
);
3622 rtx from
= operands
[1];
3623 rtx to
= operands
[0];
3625 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3626 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3627 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3628 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3634 ops
[0] = operands
[2];
3637 m68hc11_gen_movqi (insn
, ops
);
3639 ops
[1] = operands
[2];
3640 m68hc11_gen_movqi (insn
, ops
);
3644 /* !!!! SCz wrong here. */
3645 fatal_insn ("move insn not handled", insn
);
3650 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3652 output_asm_insn ("clr\t%b0", operands
);
3656 m68hc11_notice_keep_cc (operands
[0]);
3657 output_asm_insn ("movb\t%b1,%b0", operands
);
3665 if (H_REG_P (operands
[0]))
3667 switch (REGNO (operands
[0]))
3671 if (X_REG_P (operands
[1]))
3673 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3675 m68hc11_output_swap (insn
, operands
);
3679 output_asm_insn ("stx\t%t1", operands
);
3680 output_asm_insn ("ldab\t%T0", operands
);
3683 else if (Y_REG_P (operands
[1]))
3685 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3687 m68hc11_output_swap (insn
, operands
);
3691 output_asm_insn ("sty\t%t1", operands
);
3692 output_asm_insn ("ldab\t%T0", operands
);
3695 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3696 && !DA_REG_P (operands
[1]))
3698 output_asm_insn ("ldab\t%b1", operands
);
3700 else if (DA_REG_P (operands
[1]))
3702 output_asm_insn ("tab", operands
);
3706 cc_status
= cc_prev_status
;
3712 if (X_REG_P (operands
[1]))
3714 output_asm_insn ("stx\t%t1", operands
);
3715 output_asm_insn ("ldaa\t%T0", operands
);
3717 else if (Y_REG_P (operands
[1]))
3719 output_asm_insn ("sty\t%t1", operands
);
3720 output_asm_insn ("ldaa\t%T0", operands
);
3722 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3723 && !DA_REG_P (operands
[1]))
3725 output_asm_insn ("ldaa\t%b1", operands
);
3727 else if (!DA_REG_P (operands
[1]))
3729 output_asm_insn ("tba", operands
);
3733 cc_status
= cc_prev_status
;
3738 if (D_REG_P (operands
[1]))
3740 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3742 m68hc11_output_swap (insn
, operands
);
3746 output_asm_insn ("stab\t%T1", operands
);
3747 output_asm_insn ("ldx\t%t1", operands
);
3751 else if (Y_REG_P (operands
[1]))
3753 output_asm_insn ("sty\t%t0", operands
);
3754 output_asm_insn ("ldx\t%t0", operands
);
3756 else if (GET_CODE (operands
[1]) == CONST_INT
)
3758 output_asm_insn ("ldx\t%1", operands
);
3760 else if (dead_register_here (insn
, d_reg
))
3762 output_asm_insn ("ldab\t%b1", operands
);
3763 output_asm_insn ("xgdx", operands
);
3765 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3767 output_asm_insn ("xgdx", operands
);
3768 output_asm_insn ("ldab\t%b1", operands
);
3769 output_asm_insn ("xgdx", operands
);
3773 output_asm_insn ("pshb", operands
);
3774 output_asm_insn ("ldab\t%b1", operands
);
3775 output_asm_insn ("stab\t%T1", operands
);
3776 output_asm_insn ("ldx\t%t1", operands
);
3777 output_asm_insn ("pulb", operands
);
3783 if (D_REG_P (operands
[1]))
3785 output_asm_insn ("stab\t%T1", operands
);
3786 output_asm_insn ("ldy\t%t1", operands
);
3789 else if (X_REG_P (operands
[1]))
3791 output_asm_insn ("stx\t%t1", operands
);
3792 output_asm_insn ("ldy\t%t1", operands
);
3795 else if (GET_CODE (operands
[1]) == CONST_INT
)
3797 output_asm_insn ("ldy\t%1", operands
);
3799 else if (dead_register_here (insn
, d_reg
))
3801 output_asm_insn ("ldab\t%b1", operands
);
3802 output_asm_insn ("xgdy", operands
);
3804 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3806 output_asm_insn ("xgdy", operands
);
3807 output_asm_insn ("ldab\t%b1", operands
);
3808 output_asm_insn ("xgdy", operands
);
3812 output_asm_insn ("pshb", operands
);
3813 output_asm_insn ("ldab\t%b1", operands
);
3814 output_asm_insn ("stab\t%T1", operands
);
3815 output_asm_insn ("ldy\t%t1", operands
);
3816 output_asm_insn ("pulb", operands
);
3822 fatal_insn ("invalid register in the instruction", insn
);
3826 else if (H_REG_P (operands
[1]))
3828 switch (REGNO (operands
[1]))
3832 output_asm_insn ("stab\t%b0", operands
);
3836 output_asm_insn ("staa\t%b0", operands
);
3840 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3844 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3848 fatal_insn ("invalid register in the move instruction", insn
);
3855 fatal_insn ("operand 1 must be a hard register", insn
);
3859 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3860 The source and destination must be D or A and the shift must
3863 m68hc11_gen_rotate (code
, insn
, operands
)
3870 if (GET_CODE (operands
[2]) != CONST_INT
3871 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3872 fatal_insn ("invalid rotate insn", insn
);
3874 val
= INTVAL (operands
[2]);
3875 if (code
== ROTATERT
)
3876 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3878 if (GET_MODE (operands
[0]) != QImode
)
3881 /* Rotate by 8-bits if the shift is within [5..11]. */
3882 if (val
>= 5 && val
<= 11)
3885 output_asm_insn ("exg\ta,b", operands
);
3888 output_asm_insn ("psha", operands
);
3889 output_asm_insn ("tba", operands
);
3890 output_asm_insn ("pulb", operands
);
3895 /* If the shift is big, invert the rotation. */
3903 /* Set the carry to bit-15, but don't change D yet. */
3904 if (GET_MODE (operands
[0]) != QImode
)
3906 output_asm_insn ("asra", operands
);
3907 output_asm_insn ("rola", operands
);
3912 /* Rotate B first to move the carry to bit-0. */
3913 if (D_REG_P (operands
[0]))
3914 output_asm_insn ("rolb", operands
);
3916 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3917 output_asm_insn ("rola", operands
);
3922 /* Set the carry to bit-8 of D. */
3923 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3925 output_asm_insn ("tap", operands
);
3930 /* Rotate B first to move the carry to bit-7. */
3931 if (D_REG_P (operands
[0]))
3932 output_asm_insn ("rorb", operands
);
3934 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3935 output_asm_insn ("rora", operands
);
3942 /* Store in cc_status the expressions that the condition codes will
3943 describe after execution of an instruction whose pattern is EXP.
3944 Do not alter them if the instruction would not alter the cc's. */
3947 m68hc11_notice_update_cc (exp
, insn
)
3949 rtx insn ATTRIBUTE_UNUSED
;
3951 /* recognize SET insn's. */
3952 if (GET_CODE (exp
) == SET
)
3954 /* Jumps do not alter the cc's. */
3955 if (SET_DEST (exp
) == pc_rtx
)
3958 /* NOTE: most instructions don't affect the carry bit, but the
3959 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3960 the conditions.h header. */
3962 /* Function calls clobber the cc's. */
3963 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3968 /* Tests and compares set the cc's in predictable ways. */
3969 else if (SET_DEST (exp
) == cc0_rtx
)
3971 cc_status
.flags
= 0;
3972 cc_status
.value1
= XEXP (exp
, 0);
3973 cc_status
.value2
= XEXP (exp
, 1);
3977 /* All other instructions affect the condition codes. */
3978 cc_status
.flags
= 0;
3979 cc_status
.value1
= XEXP (exp
, 0);
3980 cc_status
.value2
= XEXP (exp
, 1);
3985 /* Default action if we haven't recognized something
3986 and returned earlier. */
3990 if (cc_status
.value2
!= 0)
3991 switch (GET_CODE (cc_status
.value2
))
3993 /* These logical operations can generate several insns.
3994 The flags are setup according to what is generated. */
4000 /* The (not ...) generates several 'com' instructions for
4001 non QImode. We have to invalidate the flags. */
4003 if (GET_MODE (cc_status
.value2
) != QImode
)
4015 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4016 cc_status
.flags
|= CC_NO_OVERFLOW
;
4019 /* The asl sets the overflow bit in such a way that this
4020 makes the flags unusable for a next compare insn. */
4024 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4025 cc_status
.flags
|= CC_NO_OVERFLOW
;
4028 /* A load/store instruction does not affect the carry. */
4033 cc_status
.flags
|= CC_NO_OVERFLOW
;
4039 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4041 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4042 cc_status
.value2
= 0;
4045 /* The current instruction does not affect the flags but changes
4046 the register 'reg'. See if the previous flags can be kept for the
4047 next instruction to avoid a comparison. */
4049 m68hc11_notice_keep_cc (reg
)
4053 || cc_prev_status
.value1
== 0
4054 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4055 || (cc_prev_status
.value2
4056 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4059 cc_status
= cc_prev_status
;
4064 /* Machine Specific Reorg. */
4066 /* Z register replacement:
4068 GCC treats the Z register as an index base address register like
4069 X or Y. In general, it uses it during reload to compute the address
4070 of some operand. This helps the reload pass to avoid to fall into the
4071 register spill failure.
4073 The Z register is in the A_REGS class. In the machine description,
4074 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4076 It can appear everywhere an X or Y register can appear, except for
4077 some templates in the clobber section (when a clobber of X or Y is asked).
4078 For a given instruction, the template must ensure that no more than
4079 2 'A' registers are used. Otherwise, the register replacement is not
4082 To replace the Z register, the algorithm is not terrific:
4083 1. Insns that do not use the Z register are not changed
4084 2. When a Z register is used, we scan forward the insns to see
4085 a potential register to use: either X or Y and sometimes D.
4086 We stop when a call, a label or a branch is seen, or when we
4087 detect that both X and Y are used (probably at different times, but it does
4089 3. The register that will be used for the replacement of Z is saved
4090 in a .page0 register or on the stack. If the first instruction that
4091 used Z, uses Z as an input, the value is loaded from another .page0
4092 register. The replacement register is pushed on the stack in the
4093 rare cases where a compare insn uses Z and we couldn't find if X/Y
4095 4. The Z register is replaced in all instructions until we reach
4096 the end of the Z-block, as detected by step 2.
4097 5. If we detect that Z is still alive, its value is saved.
4098 If the replacement register is alive, its old value is loaded.
4100 The Z register can be disabled with -ffixed-z.
4110 int must_restore_reg
;
4121 int save_before_last
;
4122 int z_loaded_with_sp
;
4125 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4126 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4127 static void m68hc11_z_replacement
PARAMS ((rtx
));
4128 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4130 int z_replacement_completed
= 0;
4132 /* Analyze the insn to find out which replacement register to use and
4133 the boundaries of the replacement.
4134 Returns 0 if we reached the last insn to be replaced, 1 if we can
4135 continue replacement in next insns. */
4138 m68hc11_check_z_replacement (insn
, info
)
4140 struct replace_info
*info
;
4142 int this_insn_uses_ix
;
4143 int this_insn_uses_iy
;
4144 int this_insn_uses_z
;
4145 int this_insn_uses_z_in_dst
;
4146 int this_insn_uses_d
;
4150 /* A call is said to clobber the Z register, we don't need
4151 to save the value of Z. We also don't need to restore
4152 the replacement register (unless it is used by the call). */
4153 if (GET_CODE (insn
) == CALL_INSN
)
4155 body
= PATTERN (insn
);
4157 info
->can_use_d
= 0;
4159 /* If the call is an indirect call with Z, we have to use the
4160 Y register because X can be used as an input (D+X).
4161 We also must not save Z nor restore Y. */
4162 if (reg_mentioned_p (z_reg
, body
))
4164 insn
= NEXT_INSN (insn
);
4167 info
->found_call
= 1;
4168 info
->must_restore_reg
= 0;
4169 info
->last
= NEXT_INSN (insn
);
4171 info
->need_save_z
= 0;
4174 if (GET_CODE (insn
) == CODE_LABEL
4175 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4178 if (GET_CODE (insn
) == JUMP_INSN
)
4180 if (reg_mentioned_p (z_reg
, insn
) == 0)
4183 info
->can_use_d
= 0;
4184 info
->must_save_reg
= 0;
4185 info
->must_restore_reg
= 0;
4186 info
->need_save_z
= 0;
4187 info
->last
= NEXT_INSN (insn
);
4190 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4195 /* Z register dies here. */
4196 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4198 body
= PATTERN (insn
);
4199 if (GET_CODE (body
) == SET
)
4201 rtx src
= XEXP (body
, 1);
4202 rtx dst
= XEXP (body
, 0);
4204 /* Condition code is set here. We have to restore the X/Y and
4205 save into Z before any test/compare insn because once we save/restore
4206 we can change the condition codes. When the compare insn uses Z and
4207 we can't use X/Y, the comparison is made with the *ZREG soft register
4208 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4211 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4212 || (GET_CODE (src
) == COMPARE
&&
4213 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4214 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4216 if (insn
== info
->first
)
4218 info
->must_load_z
= 0;
4219 info
->must_save_reg
= 0;
4220 info
->must_restore_reg
= 0;
4221 info
->need_save_z
= 0;
4222 info
->found_call
= 1;
4223 info
->regno
= SOFT_Z_REGNUM
;
4228 if (reg_mentioned_p (z_reg
, src
) == 0)
4230 info
->can_use_d
= 0;
4234 if (insn
!= info
->first
)
4237 /* Compare insn which uses Z. We have to save/restore the X/Y
4238 register without modifying the condition codes. For this
4239 we have to use a push/pop insn. */
4240 info
->must_push_reg
= 1;
4244 /* Z reg is set to something new. We don't need to load it. */
4247 if (!reg_mentioned_p (z_reg
, src
))
4249 /* Z reg is used before being set. Treat this as
4250 a new sequence of Z register replacement. */
4251 if (insn
!= info
->first
)
4255 info
->must_load_z
= 0;
4257 info
->z_set_count
++;
4258 info
->z_value
= src
;
4260 info
->z_loaded_with_sp
= 1;
4262 else if (reg_mentioned_p (z_reg
, dst
))
4263 info
->can_use_d
= 0;
4265 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4266 | reg_mentioned_p (d_reg
, dst
);
4267 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4268 | reg_mentioned_p (ix_reg
, dst
);
4269 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4270 | reg_mentioned_p (iy_reg
, dst
);
4271 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4273 /* If z is used as an address operand (like (MEM (reg z))),
4274 we can't replace it with d. */
4275 if (this_insn_uses_z
&& !Z_REG_P (src
)
4276 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4277 && Z_REG_P (XEXP (src
, 0))
4278 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4279 && insn
== info
->first
4280 && dead_register_here (insn
, d_reg
)))
4281 info
->can_use_d
= 0;
4283 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4284 if (TARGET_M6812
&& !z_dies_here
4285 && ((this_insn_uses_z
&& side_effects_p (src
))
4286 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4288 info
->need_save_z
= 1;
4289 info
->z_set_count
++;
4291 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4293 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4295 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4298 if (this_insn_uses_d
)
4299 info
->can_use_d
= 0;
4301 /* IX and IY are used at the same time, we have to restore
4302 the value of the scratch register before this insn. */
4303 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4308 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4309 info
->can_use_d
= 0;
4311 if (info
->x_used
== 0 && this_insn_uses_ix
)
4315 /* We have a (set (REG:HI X) (REG:HI Z)).
4316 Since we use Z as the replacement register, this insn
4317 is no longer necessary. We turn it into a note. We must
4318 not reload the old value of X. */
4319 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4323 info
->need_save_z
= 0;
4326 info
->must_save_reg
= 0;
4327 info
->must_restore_reg
= 0;
4328 info
->found_call
= 1;
4329 info
->can_use_d
= 0;
4330 PUT_CODE (insn
, NOTE
);
4331 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4332 NOTE_SOURCE_FILE (insn
) = 0;
4333 info
->last
= NEXT_INSN (insn
);
4338 && (rtx_equal_p (src
, z_reg
)
4339 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4343 info
->need_save_z
= 0;
4346 info
->last
= NEXT_INSN (insn
);
4347 info
->must_save_reg
= 0;
4348 info
->must_restore_reg
= 0;
4350 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4351 && !reg_mentioned_p (ix_reg
, src
))
4356 info
->need_save_z
= 0;
4358 else if (TARGET_M6812
&& side_effects_p (src
))
4361 info
->must_restore_reg
= 0;
4366 info
->save_before_last
= 1;
4368 info
->must_restore_reg
= 0;
4369 info
->last
= NEXT_INSN (insn
);
4371 else if (info
->can_use_d
)
4373 info
->last
= NEXT_INSN (insn
);
4379 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4380 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4382 info
->need_save_z
= 0;
4384 info
->last
= NEXT_INSN (insn
);
4385 info
->regno
= HARD_X_REGNUM
;
4386 info
->must_save_reg
= 0;
4387 info
->must_restore_reg
= 0;
4390 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4392 info
->regno
= HARD_X_REGNUM
;
4393 info
->must_restore_reg
= 0;
4394 info
->must_save_reg
= 0;
4398 if (info
->y_used
== 0 && this_insn_uses_iy
)
4402 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4406 info
->need_save_z
= 0;
4409 info
->must_save_reg
= 0;
4410 info
->must_restore_reg
= 0;
4411 info
->found_call
= 1;
4412 info
->can_use_d
= 0;
4413 PUT_CODE (insn
, NOTE
);
4414 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4415 NOTE_SOURCE_FILE (insn
) = 0;
4416 info
->last
= NEXT_INSN (insn
);
4421 && (rtx_equal_p (src
, z_reg
)
4422 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4427 info
->need_save_z
= 0;
4429 info
->last
= NEXT_INSN (insn
);
4430 info
->must_save_reg
= 0;
4431 info
->must_restore_reg
= 0;
4433 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4434 && !reg_mentioned_p (iy_reg
, src
))
4439 info
->need_save_z
= 0;
4441 else if (TARGET_M6812
&& side_effects_p (src
))
4444 info
->must_restore_reg
= 0;
4449 info
->save_before_last
= 1;
4451 info
->must_restore_reg
= 0;
4452 info
->last
= NEXT_INSN (insn
);
4454 else if (info
->can_use_d
)
4456 info
->last
= NEXT_INSN (insn
);
4463 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4464 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4466 info
->need_save_z
= 0;
4468 info
->last
= NEXT_INSN (insn
);
4469 info
->regno
= HARD_Y_REGNUM
;
4470 info
->must_save_reg
= 0;
4471 info
->must_restore_reg
= 0;
4474 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4476 info
->regno
= HARD_Y_REGNUM
;
4477 info
->must_restore_reg
= 0;
4478 info
->must_save_reg
= 0;
4484 info
->need_save_z
= 0;
4486 if (info
->last
== 0)
4487 info
->last
= NEXT_INSN (insn
);
4490 return info
->last
!= NULL_RTX
? 0 : 1;
4492 if (GET_CODE (body
) == PARALLEL
)
4495 char ix_clobber
= 0;
4496 char iy_clobber
= 0;
4498 this_insn_uses_iy
= 0;
4499 this_insn_uses_ix
= 0;
4500 this_insn_uses_z
= 0;
4502 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4505 int uses_ix
, uses_iy
, uses_z
;
4507 x
= XVECEXP (body
, 0, i
);
4509 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4510 info
->can_use_d
= 0;
4512 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4513 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4514 uses_z
= reg_mentioned_p (z_reg
, x
);
4515 if (GET_CODE (x
) == CLOBBER
)
4517 ix_clobber
|= uses_ix
;
4518 iy_clobber
|= uses_iy
;
4519 z_clobber
|= uses_z
;
4523 this_insn_uses_ix
|= uses_ix
;
4524 this_insn_uses_iy
|= uses_iy
;
4525 this_insn_uses_z
|= uses_z
;
4527 if (uses_z
&& GET_CODE (x
) == SET
)
4529 rtx dst
= XEXP (x
, 0);
4532 info
->z_set_count
++;
4534 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4535 info
->need_save_z
= 1;
4538 info
->need_save_z
= 0;
4542 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4543 this_insn_uses_ix
, this_insn_uses_iy
,
4544 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4547 if (this_insn_uses_z
)
4548 info
->can_use_d
= 0;
4550 if (z_clobber
&& info
->first
!= insn
)
4552 info
->need_save_z
= 0;
4556 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4558 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4560 info
->must_load_z
= 0;
4562 if (dead_register_here (insn
, d_reg
))
4564 info
->regno
= HARD_D_REGNUM
;
4565 info
->must_save_reg
= 0;
4566 info
->must_restore_reg
= 0;
4568 else if (dead_register_here (insn
, ix_reg
))
4570 info
->regno
= HARD_X_REGNUM
;
4571 info
->must_save_reg
= 0;
4572 info
->must_restore_reg
= 0;
4574 else if (dead_register_here (insn
, iy_reg
))
4576 info
->regno
= HARD_Y_REGNUM
;
4577 info
->must_save_reg
= 0;
4578 info
->must_restore_reg
= 0;
4580 if (info
->regno
>= 0)
4582 info
->last
= NEXT_INSN (insn
);
4585 if (this_insn_uses_ix
== 0)
4587 info
->regno
= HARD_X_REGNUM
;
4588 info
->must_save_reg
= 1;
4589 info
->must_restore_reg
= 1;
4591 else if (this_insn_uses_iy
== 0)
4593 info
->regno
= HARD_Y_REGNUM
;
4594 info
->must_save_reg
= 1;
4595 info
->must_restore_reg
= 1;
4599 info
->regno
= HARD_D_REGNUM
;
4600 info
->must_save_reg
= 1;
4601 info
->must_restore_reg
= 1;
4603 info
->last
= NEXT_INSN (insn
);
4607 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4608 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4610 if (this_insn_uses_z
)
4612 if (info
->y_used
== 0 && iy_clobber
)
4614 info
->regno
= HARD_Y_REGNUM
;
4615 info
->must_save_reg
= 0;
4616 info
->must_restore_reg
= 0;
4618 if (info
->first
!= insn
4619 && ((info
->y_used
&& ix_clobber
)
4620 || (info
->x_used
&& iy_clobber
)))
4623 info
->last
= NEXT_INSN (insn
);
4624 info
->save_before_last
= 1;
4628 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4630 if (this_insn_uses_z
)
4632 fatal_insn ("cannot do z-register replacement", insn
);
4636 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4643 if (iy_clobber
|| z_clobber
)
4645 info
->last
= NEXT_INSN (insn
);
4646 info
->save_before_last
= 1;
4651 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4658 if (ix_clobber
|| z_clobber
)
4660 info
->last
= NEXT_INSN (insn
);
4661 info
->save_before_last
= 1;
4668 info
->need_save_z
= 0;
4672 if (GET_CODE (body
) == CLOBBER
)
4675 /* IX and IY are used at the same time, we have to restore
4676 the value of the scratch register before this insn. */
4677 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4681 if (info
->x_used
== 0 && this_insn_uses_ix
)
4689 if (info
->y_used
== 0 && this_insn_uses_iy
)
4703 m68hc11_find_z_replacement (insn
, info
)
4705 struct replace_info
*info
;
4709 info
->replace_reg
= NULL_RTX
;
4710 info
->must_load_z
= 1;
4711 info
->need_save_z
= 1;
4712 info
->must_save_reg
= 1;
4713 info
->must_restore_reg
= 1;
4717 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4718 info
->found_call
= 0;
4722 info
->z_set_count
= 0;
4723 info
->z_value
= NULL_RTX
;
4724 info
->must_push_reg
= 0;
4725 info
->save_before_last
= 0;
4726 info
->z_loaded_with_sp
= 0;
4728 /* Scan the insn forward to find an address register that is not used.
4730 - the flow of the program changes,
4731 - when we detect that both X and Y are necessary,
4732 - when the Z register dies,
4733 - when the condition codes are set. */
4735 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4737 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4741 /* May be we can use Y or X if they contain the same value as Z.
4742 This happens very often after the reload. */
4743 if (info
->z_set_count
== 1)
4745 rtx p
= info
->first
;
4750 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4752 else if (info
->y_used
)
4754 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4756 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4759 info
->regno
= HARD_Y_REGNUM
;
4761 info
->regno
= HARD_X_REGNUM
;
4762 info
->must_load_z
= 0;
4763 info
->must_save_reg
= 0;
4764 info
->must_restore_reg
= 0;
4765 info
->found_call
= 1;
4768 if (info
->z_set_count
== 0)
4769 info
->need_save_z
= 0;
4772 info
->need_save_z
= 0;
4774 if (info
->last
== 0)
4777 if (info
->regno
>= 0)
4780 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4782 else if (info
->can_use_d
)
4784 reg
= HARD_D_REGNUM
;
4785 info
->replace_reg
= d_reg
;
4787 else if (info
->x_used
)
4789 reg
= HARD_Y_REGNUM
;
4790 info
->replace_reg
= iy_reg
;
4794 reg
= HARD_X_REGNUM
;
4795 info
->replace_reg
= ix_reg
;
4799 if (info
->must_save_reg
&& info
->must_restore_reg
)
4801 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4803 info
->must_save_reg
= 0;
4804 info
->must_restore_reg
= 0;
4809 /* The insn uses the Z register. Find a replacement register for it
4810 (either X or Y) and replace it in the insn and the next ones until
4811 the flow changes or the replacement register is used. Instructions
4812 are emited before and after the Z-block to preserve the value of
4813 Z and of the replacement register. */
4816 m68hc11_z_replacement (insn
)
4821 struct replace_info info
;
4823 /* Find trivial case where we only need to replace z with the
4824 equivalent soft register. */
4825 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4827 rtx body
= PATTERN (insn
);
4828 rtx src
= XEXP (body
, 1);
4829 rtx dst
= XEXP (body
, 0);
4831 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4833 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4836 else if (Z_REG_P (src
)
4837 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4839 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4842 else if (D_REG_P (dst
)
4843 && m68hc11_arith_operator (src
, GET_MODE (src
))
4844 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4846 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4849 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4850 && INTVAL (src
) == 0)
4852 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4853 /* Force it to be re-recognized. */
4854 INSN_CODE (insn
) = -1;
4859 m68hc11_find_z_replacement (insn
, &info
);
4861 replace_reg
= info
.replace_reg
;
4862 replace_reg_qi
= NULL_RTX
;
4864 /* Save the X register in a .page0 location. */
4865 if (info
.must_save_reg
&& !info
.must_push_reg
)
4869 if (info
.must_push_reg
&& 0)
4870 dst
= gen_rtx (MEM
, HImode
,
4871 gen_rtx (PRE_DEC
, HImode
,
4872 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4874 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4876 emit_insn_before (gen_movhi (dst
,
4877 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4879 if (info
.must_load_z
&& !info
.must_push_reg
)
4881 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4882 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4887 /* Replace all occurrence of Z by replace_reg.
4888 Stop when the last instruction to replace is reached.
4889 Also stop when we detect a change in the flow (but it's not
4890 necessary; just safeguard). */
4892 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4896 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4899 if (GET_CODE (insn
) != INSN
4900 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4903 body
= PATTERN (insn
);
4904 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4905 || GET_CODE (body
) == ASM_OPERANDS
4906 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4910 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4912 printf ("Reg mentioned here...:\n");
4917 /* Stack pointer was decremented by 2 due to the push.
4918 Correct that by adding 2 to the destination. */
4919 if (info
.must_push_reg
4920 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4924 src
= SET_SRC (body
);
4925 dst
= SET_DEST (body
);
4926 if (SP_REG_P (src
) && Z_REG_P (dst
))
4927 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4930 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4931 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4933 INSN_CODE (insn
) = -1;
4934 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4935 fatal_insn ("cannot do z-register replacement", insn
);
4938 /* Likewise for (REG:QI Z). */
4939 if (reg_mentioned_p (z_reg
, insn
))
4941 if (replace_reg_qi
== NULL_RTX
)
4942 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4943 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4946 /* If there is a REG_INC note on Z, replace it with a
4947 REG_INC note on the replacement register. This is necessary
4948 to make sure that the flow pass will identify the change
4949 and it will not remove a possible insn that saves Z. */
4950 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4952 if (REG_NOTE_KIND (note
) == REG_INC
4953 && GET_CODE (XEXP (note
, 0)) == REG
4954 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4956 XEXP (note
, 0) = replace_reg
;
4960 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4964 /* Save Z before restoring the old value. */
4965 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4967 rtx save_pos_insn
= insn
;
4969 /* If Z is clobber by the last insn, we have to save its value
4970 before the last instruction. */
4971 if (info
.save_before_last
)
4972 save_pos_insn
= PREV_INSN (save_pos_insn
);
4974 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4975 gen_rtx (REG
, HImode
, info
.regno
)),
4979 if (info
.must_push_reg
&& info
.last
)
4983 body
= PATTERN (info
.last
);
4984 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4986 gen_rtx (USE
, VOIDmode
,
4988 gen_rtx (USE
, VOIDmode
,
4989 gen_rtx (REG
, HImode
,
4991 PATTERN (info
.last
) = new_body
;
4993 /* Force recognition on insn since we changed it. */
4994 INSN_CODE (insn
) = -1;
4996 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4998 fatal_insn ("invalid Z register replacement for insn", insn
);
5000 insn
= NEXT_INSN (info
.last
);
5003 /* Restore replacement register unless it was died. */
5004 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
5008 if (info
.must_push_reg
&& 0)
5009 dst
= gen_rtx (MEM
, HImode
,
5010 gen_rtx (POST_INC
, HImode
,
5011 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
5013 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
5015 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
5022 /* Scan all the insn and re-affects some registers
5023 - The Z register (if it was used), is affected to X or Y depending
5024 on the instruction. */
5027 m68hc11_reassign_regs (first
)
5032 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5033 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5034 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5035 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5037 /* Scan all insns to replace Z by X or Y preserving the old value
5038 of X/Y and restoring it afterward. */
5040 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5044 if (GET_CODE (insn
) == CODE_LABEL
5045 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5048 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5051 body
= PATTERN (insn
);
5052 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5055 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5056 || GET_CODE (body
) == ASM_OPERANDS
5057 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5060 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5061 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5064 /* If Z appears in this insn, replace it in the current insn
5065 and the next ones until the flow changes or we have to
5066 restore back the replacement register. */
5068 if (reg_mentioned_p (z_reg
, body
))
5070 m68hc11_z_replacement (insn
);
5075 printf ("insn not handled by Z replacement:\n");
5084 m68hc11_reorg (first
)
5090 z_replacement_completed
= 0;
5091 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5093 /* Some RTX are shared at this point. This breaks the Z register
5094 replacement, unshare everything. */
5095 unshare_all_rtl_again (first
);
5097 /* Force a split of all splitable insn. This is necessary for the
5098 Z register replacement mechanism because we end up with basic insns. */
5099 split_all_insns_noflow ();
5102 z_replacement_completed
= 1;
5103 m68hc11_reassign_regs (first
);
5106 compute_bb_for_insn ();
5108 /* After some splitting, there are some oportunities for CSE pass.
5109 This happens quite often when 32-bit or above patterns are split. */
5110 if (optimize
> 0 && split_done
)
5112 reload_cse_regs (first
);
5115 /* Re-create the REG_DEAD notes. These notes are used in the machine
5116 description to use the best assembly directives. */
5119 /* Before recomputing the REG_DEAD notes, remove all of them.
5120 This is necessary because the reload_cse_regs() pass can
5121 have replaced some (MEM) with a register. In that case,
5122 the REG_DEAD that could exist for that register may become
5124 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5130 pnote
= ®_NOTES (insn
);
5133 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5134 *pnote
= XEXP (*pnote
, 1);
5136 pnote
= &XEXP (*pnote
, 1);
5141 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5144 z_replacement_completed
= 2;
5146 /* If optimizing, then go ahead and split insns that must be
5147 split after Z register replacement. This gives more opportunities
5148 for peephole (in particular for consecutives xgdx/xgdy). */
5150 split_all_insns_noflow ();
5152 /* Once insns are split after the z_replacement_completed == 2,
5153 we must not re-run the life_analysis. The xgdx/xgdy patterns
5154 are not recognized and the life_analysis pass removes some
5155 insns because it thinks some (SETs) are noops or made to dead
5156 stores (which is false due to the swap).
5158 Do a simple pass to eliminate the noop set that the final
5159 split could generate (because it was easier for split definition). */
5163 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5167 if (INSN_DELETED_P (insn
))
5169 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5172 /* Remove the (set (R) (R)) insns generated by some splits. */
5173 body
= PATTERN (insn
);
5174 if (GET_CODE (body
) == SET
5175 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5177 PUT_CODE (insn
, NOTE
);
5178 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5179 NOTE_SOURCE_FILE (insn
) = 0;
5187 /* Cost functions. */
5189 /* Cost of moving memory. */
5191 m68hc11_memory_move_cost (mode
, class, in
)
5192 enum machine_mode mode
;
5193 enum reg_class
class;
5194 int in ATTRIBUTE_UNUSED
;
5196 if (class <= H_REGS
&& class > NO_REGS
)
5198 if (GET_MODE_SIZE (mode
) <= 2)
5199 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5201 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5205 if (GET_MODE_SIZE (mode
) <= 2)
5206 return COSTS_N_INSNS (3);
5208 return COSTS_N_INSNS (4);
5213 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5214 Reload does not check the constraint of set insns when the two registers
5215 have a move cost of 2. Setting a higher cost will force reload to check
5218 m68hc11_register_move_cost (mode
, from
, to
)
5219 enum machine_mode mode
;
5220 enum reg_class from
;
5223 /* All costs are symmetric, so reduce cases by putting the
5224 lower number class as the destination. */
5227 enum reg_class tmp
= to
;
5228 to
= from
, from
= tmp
;
5231 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5232 else if (from
<= S_REGS
)
5233 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5235 return COSTS_N_INSNS (2);
5239 /* Provide the costs of an addressing mode that contains ADDR.
5240 If ADDR is not a valid address, its cost is irrelevant. */
5243 m68hc11_address_cost (addr
)
5248 switch (GET_CODE (addr
))
5251 /* Make the cost of hard registers and specially SP, FP small. */
5252 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5269 register rtx plus0
= XEXP (addr
, 0);
5270 register rtx plus1
= XEXP (addr
, 1);
5272 if (GET_CODE (plus0
) != REG
)
5275 switch (GET_CODE (plus1
))
5278 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5279 || INTVAL (plus1
) < m68hc11_min_offset
)
5281 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5285 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5307 if (SP_REG_P (XEXP (addr
, 0)))
5316 printf ("Address cost: %d for :", cost
);
5325 m68hc11_shift_cost (mode
, x
, shift
)
5326 enum machine_mode mode
;
5332 total
= rtx_cost (x
, SET
);
5334 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5335 else if (mode
== HImode
)
5336 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5337 else if (shift
== 8 || shift
== 16 || shift
== 32)
5338 total
+= m68hc11_cost
->shiftHI_const
[8];
5339 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5341 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5344 /* For SI and others, the cost is higher. */
5345 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5346 total
*= GET_MODE_SIZE (mode
) / 2;
5348 /* When optimizing for size, make shift more costly so that
5349 multiplications are preferred. */
5350 if (optimize_size
&& (shift
% 8) != 0)
5357 m68hc11_rtx_costs_1 (x
, code
, outer_code
)
5360 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5362 enum machine_mode mode
= GET_MODE (x
);
5373 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5375 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5378 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5379 total
+= m68hc11_cost
->shift_var
;
5385 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5386 total
+= m68hc11_cost
->logical
;
5388 /* Logical instructions are byte instructions only. */
5389 total
*= GET_MODE_SIZE (mode
);
5394 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5395 total
+= m68hc11_cost
->add
;
5396 if (GET_MODE_SIZE (mode
) > 2)
5398 total
*= GET_MODE_SIZE (mode
) / 2;
5405 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5409 total
+= m68hc11_cost
->divQI
;
5413 total
+= m68hc11_cost
->divHI
;
5418 total
+= m68hc11_cost
->divSI
;
5424 /* mul instruction produces 16-bit result. */
5425 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5426 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5427 return m68hc11_cost
->multQI
5428 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5429 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5431 /* emul instruction produces 32-bit result for 68HC12. */
5432 if (TARGET_M6812
&& mode
== SImode
5433 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5434 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5435 return m68hc11_cost
->multHI
5436 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5437 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5439 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5443 total
+= m68hc11_cost
->multQI
;
5447 total
+= m68hc11_cost
->multHI
;
5452 total
+= m68hc11_cost
->multSI
;
5459 extra_cost
= COSTS_N_INSNS (2);
5466 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5469 return total
+ COSTS_N_INSNS (1);
5473 return total
+ COSTS_N_INSNS (2);
5477 return total
+ COSTS_N_INSNS (4);
5479 return total
+ COSTS_N_INSNS (8);
5482 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5483 return COSTS_N_INSNS (1);
5485 return COSTS_N_INSNS (1);
5488 return COSTS_N_INSNS (4);
5493 m68hc11_rtx_costs (x
, code
, outer_code
, total
)
5495 int code
, outer_code
;
5500 /* Constants are cheap. Moving them in registers must be avoided
5501 because most instructions do not handle two register operands. */
5507 /* Logical and arithmetic operations with a constant operand are
5508 better because they are not supported with two registers. */
5510 if (outer_code
== SET
&& x
== const0_rtx
)
5511 /* After reload, the reload_cse pass checks the cost to change
5512 a SET into a PLUS. Make const0 cheap then. */
5513 *total
= 1 - reload_completed
;
5518 if (outer_code
== SET
)
5519 *total
= 1 - reload_completed
;
5541 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5550 /* print_options - called at the start of the code generation for a
5553 extern char *asm_file_name
;
5556 #include <sys/types.h>
5565 extern int save_argc
;
5566 extern char **save_argv
;
5568 fprintf (out
, ";;; Command:\t");
5569 for (i
= 0; i
< save_argc
; i
++)
5571 fprintf (out
, "%s", save_argv
[i
]);
5572 if (i
+ 1 < save_argc
)
5575 fprintf (out
, "\n");
5577 a_time
= ctime (&c_time
);
5578 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5581 #define __VERSION__ "[unknown]"
5583 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5585 fprintf (out
, ";;; (META)compiled by CC.\n");
5590 m68hc11_asm_file_start (out
, main_file
)
5592 const char *main_file
;
5594 fprintf (out
, ";;;-----------------------------------------\n");
5595 fprintf (out
, ";;; Start %s gcc assembly output\n",
5598 : TARGET_M68S12
? "MC68HCS12" : "MC68HC12");
5599 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5600 print_options (out
);
5601 fprintf (out
, ";;;-----------------------------------------\n");
5602 output_file_directive (out
, main_file
);
5605 fprintf (out
, "\t.mode mshort\n");
5607 fprintf (out
, "\t.mode mlong\n");
5612 m68hc11_asm_out_constructor (symbol
, priority
)
5616 default_ctor_section_asm_out_constructor (symbol
, priority
);
5617 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5621 m68hc11_asm_out_destructor (symbol
, priority
)
5625 default_dtor_section_asm_out_destructor (symbol
, priority
);
5626 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5629 #include "gt-m68hc11.h"