1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002 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
42 #include "hard-reg-set.h"
44 #include "insn-config.h"
45 #include "conditions.h"
47 #include "insn-attr.h"
52 #include "basic-block.h"
57 #include "target-def.h"
59 static void print_options
PARAMS ((FILE *));
60 static void emit_move_after_reload
PARAMS ((rtx
, rtx
, rtx
));
61 static rtx simplify_logical
PARAMS ((enum machine_mode
, int, rtx
, rtx
*));
62 static void m68hc11_emit_logical
PARAMS ((enum machine_mode
, int, rtx
*));
63 static int go_if_legitimate_address_internal
PARAMS((rtx
, enum machine_mode
,
65 static int register_indirect_p
PARAMS((rtx
, enum machine_mode
, int));
66 static rtx m68hc11_expand_compare
PARAMS((enum rtx_code
, rtx
, rtx
));
67 static int m68hc11_autoinc_compatible_p
PARAMS ((rtx
, rtx
));
68 static int must_parenthesize
PARAMS ((rtx
));
69 static int m68hc11_shift_cost
PARAMS ((enum machine_mode
, rtx
, int));
70 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
71 static tree m68hc11_handle_fntype_attribute
PARAMS ((tree
*, tree
, tree
, int, bool *));
72 const struct attribute_spec m68hc11_attribute_table
[];
74 void create_regs_rtx
PARAMS ((void));
76 static void asm_print_register
PARAMS ((FILE *, int));
77 static void m68hc11_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
78 static void m68hc11_asm_out_constructor
PARAMS ((rtx
, int));
79 static void m68hc11_asm_out_destructor
PARAMS ((rtx
, int));
80 static void m68hc11_encode_section_info
PARAMS((tree
, int));
82 rtx m68hc11_soft_tmp_reg
;
84 /* Must be set to 1 to produce debug messages. */
87 extern FILE *asm_out_file
;
95 static int regs_inited
= 0;
98 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
99 int current_function_interrupt
;
101 /* Set to 1 by expand_prologue() when the function is a trap handler. */
102 int current_function_trap
;
104 /* Min offset that is valid for the indirect addressing mode. */
105 HOST_WIDE_INT m68hc11_min_offset
= 0;
107 /* Max offset that is valid for the indirect addressing mode. */
108 HOST_WIDE_INT m68hc11_max_offset
= 256;
110 /* The class value for base registers. */
111 enum reg_class m68hc11_base_reg_class
= A_REGS
;
113 /* The class value for index registers. This is NO_REGS for 68HC11. */
114 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
116 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
118 /* Tables that tell whether a given hard register is valid for
119 a base or an index register. It is filled at init time depending
120 on the target processor. */
121 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
122 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
124 /* A correction offset which is applied to the stack pointer.
125 This is 1 for 68HC11 and 0 for 68HC12. */
126 int m68hc11_sp_correction
;
128 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
129 rtx m68hc11_compare_op0
;
130 rtx m68hc11_compare_op1
;
133 const struct processor_costs
*m68hc11_cost
;
135 /* Costs for a 68HC11. */
136 static const struct processor_costs m6811_cost
= {
141 /* non-constant shift */
144 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
145 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
146 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
149 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
150 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
151 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
152 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
153 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
154 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
159 COSTS_N_INSNS (20 * 4),
161 COSTS_N_INSNS (20 * 16),
170 /* Costs for a 68HC12. */
171 static const struct processor_costs m6812_cost
= {
176 /* non-constant shift */
179 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
180 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
181 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
184 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
185 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
186 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
187 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
188 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
189 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
196 COSTS_N_INSNS (3 * 4),
205 /* Machine specific options */
207 const char *m68hc11_regparm_string
;
208 const char *m68hc11_reg_alloc_order
;
209 const char *m68hc11_soft_reg_count
;
211 static int nb_soft_regs
;
213 /* Initialize the GCC target structure. */
214 #undef TARGET_ATTRIBUTE_TABLE
215 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
217 #undef TARGET_ASM_ALIGNED_HI_OP
218 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
220 #undef TARGET_ASM_FUNCTION_EPILOGUE
221 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
223 #undef TARGET_ENCODE_SECTION_INFO
224 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
226 struct gcc_target targetm
= TARGET_INITIALIZER
;
229 m68hc11_override_options ()
231 memset (m68hc11_reg_valid_for_index
, 0,
232 sizeof (m68hc11_reg_valid_for_index
));
233 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
235 /* Compilation with -fpic generates a wrong code. */
238 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
239 (flag_pic
> 1) ? "PIC" : "pic");
243 /* Configure for a 68hc11 processor. */
246 /* If gcc was built for a 68hc12, invalidate that because
247 a -m68hc11 option was specified on the command line. */
248 if (TARGET_DEFAULT
!= MASK_M6811
)
249 target_flags
&= ~TARGET_DEFAULT
;
252 target_flags
&= ~TARGET_AUTO_INC_DEC
;
253 m68hc11_cost
= &m6811_cost
;
254 m68hc11_min_offset
= 0;
255 m68hc11_max_offset
= 256;
256 m68hc11_index_reg_class
= NO_REGS
;
257 m68hc11_base_reg_class
= A_REGS
;
258 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
259 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
260 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
261 m68hc11_sp_correction
= 1;
262 m68hc11_tmp_regs_class
= D_REGS
;
263 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
264 m68hc11_soft_reg_count
= "4";
267 /* Configure for a 68hc12 processor. */
270 m68hc11_cost
= &m6812_cost
;
271 m68hc11_min_offset
= -65536;
272 m68hc11_max_offset
= 65536;
273 m68hc11_index_reg_class
= D_REGS
;
274 m68hc11_base_reg_class
= A_OR_SP_REGS
;
275 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
276 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
277 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
278 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
279 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
280 m68hc11_sp_correction
= 0;
281 m68hc11_tmp_regs_class
= TMP_REGS
;
282 target_flags
&= ~MASK_M6811
;
283 target_flags
|= MASK_NO_DIRECT_MODE
;
284 if (m68hc11_soft_reg_count
== 0)
285 m68hc11_soft_reg_count
= "0";
292 m68hc11_conditional_register_usage ()
295 int cnt
= atoi (m68hc11_soft_reg_count
);
299 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
300 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
303 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
306 call_used_regs
[i
] = 1;
309 /* For 68HC12, the Z register emulation is not necessary when the
310 frame pointer is not used. The frame pointer is eliminated and
311 replaced by the stack register (which is a BASE_REG_CLASS). */
312 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
314 fixed_regs
[HARD_Z_REGNUM
] = 1;
319 /* Reload and register operations. */
321 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
327 /* regs_inited = 1; */
328 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
329 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
330 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
331 da_reg
= gen_rtx (REG
, QImode
, HARD_A_REGNUM
);
332 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
334 stack_push_word
= gen_rtx (MEM
, HImode
,
335 gen_rtx (PRE_DEC
, HImode
,
336 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
337 stack_pop_word
= gen_rtx (MEM
, HImode
,
338 gen_rtx (POST_INC
, HImode
,
339 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
343 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
344 - 8 bit values are stored anywhere (except the SP register).
345 - 16 bit values can be stored in any register whose mode is 16
346 - 32 bit values can be stored in D, X registers or in a soft register
347 (except the last one because we need 2 soft registers)
348 - Values whose size is > 32 bit are not stored in real hard
349 registers. They may be stored in soft registers if there are
352 hard_regno_mode_ok (regno
, mode
)
354 enum machine_mode mode
;
356 switch (GET_MODE_SIZE (mode
))
359 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
362 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
365 return G_REGNO_P (regno
);
368 /* We have to accept a QImode in X or Y registers. Otherwise, the
369 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
370 in the insns. Reload fails if the insn rejects the register class 'a'
371 as well as if it accepts it. Patterns that failed were
372 zero_extend_qihi2 and iorqi3. */
374 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
382 preferred_reload_class (operand
, class)
384 enum reg_class
class;
386 enum machine_mode mode
;
388 mode
= GET_MODE (operand
);
392 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
395 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
396 return m68hc11_base_reg_class
;
398 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
399 || GET_CODE (operand
) == CONST_INT
))
401 /* S_REGS class must not be used. The movhi template does not
402 work to move a memory to a soft register.
403 Restrict to a hard reg. */
408 case D_OR_A_OR_S_REGS
:
414 case D_OR_SP_OR_S_REGS
:
415 class = D_OR_SP_REGS
;
417 case D_OR_Y_OR_S_REGS
:
420 case D_OR_X_OR_S_REGS
:
436 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
440 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
444 else if (class >= S_REGS
&& S_REG_P (operand
))
450 case D_OR_A_OR_S_REGS
:
456 case D_OR_SP_OR_S_REGS
:
457 class = D_OR_SP_REGS
;
459 case D_OR_Y_OR_S_REGS
:
462 case D_OR_X_OR_S_REGS
:
478 else if (class >= S_REGS
)
482 printf ("Class = %s for: ", reg_class_names
[class]);
490 printf (" => class=%s\n", reg_class_names
[class]);
498 /* Return 1 if the operand is a valid indexed addressing mode.
499 For 68hc11: n,r with n in [0..255] and r in A_REGS class
500 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
502 register_indirect_p (operand
, mode
, strict
)
504 enum machine_mode mode
;
509 switch (GET_CODE (operand
))
515 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
516 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
520 base
= XEXP (operand
, 0);
521 if (GET_CODE (base
) == MEM
)
524 offset
= XEXP (operand
, 1);
525 if (GET_CODE (offset
) == MEM
)
528 if (GET_CODE (base
) == REG
)
530 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
536 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
538 if (GET_CODE (offset
) == REG
)
540 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
546 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
551 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
557 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
564 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
565 a 68HC12 1-byte index addressing mode. */
567 m68hc11_small_indexed_indirect_p (operand
, mode
)
569 enum machine_mode mode
;
573 if (GET_CODE (operand
) == REG
&& reload_in_progress
574 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
575 && reg_equiv_memory_loc
[REGNO (operand
)])
577 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
578 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
581 if (GET_CODE (operand
) != MEM
)
584 operand
= XEXP (operand
, 0);
585 if (CONSTANT_ADDRESS_P (operand
))
588 if (PUSH_POP_ADDRESS_P (operand
))
591 if (!register_indirect_p (operand
, mode
, reload_completed
))
594 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
595 && (reload_completed
| reload_in_progress
))
597 base
= XEXP (operand
, 0);
598 offset
= XEXP (operand
, 1);
600 /* The offset can be a symbol address and this is too big
601 for the operand constraint. */
602 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
605 if (GET_CODE (base
) == CONST_INT
)
608 switch (GET_MODE_SIZE (mode
))
611 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
616 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
621 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
630 m68hc11_register_indirect_p (operand
, mode
)
632 enum machine_mode mode
;
634 if (GET_CODE (operand
) != MEM
)
637 operand
= XEXP (operand
, 0);
638 return register_indirect_p (operand
, mode
,
639 (reload_completed
| reload_in_progress
));
643 go_if_legitimate_address_internal (operand
, mode
, strict
)
645 enum machine_mode mode
;
648 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
650 /* Reject the global variables if they are too wide. This forces
651 a load of their address in a register and generates smaller code. */
652 if (GET_MODE_SIZE (mode
) == 8)
657 if (register_indirect_p (operand
, mode
, strict
))
661 if (PUSH_POP_ADDRESS_P (operand
))
665 if (symbolic_memory_operand (operand
, mode
))
673 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
675 enum machine_mode mode
;
682 printf ("Checking: ");
687 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
691 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
698 printf ("go_if_legitimate%s, ret 0: %d:",
699 (strict
? "_strict" : ""), mode
);
708 m68hc11_legitimize_address (operand
, old_operand
, mode
)
709 rtx
*operand ATTRIBUTE_UNUSED
;
710 rtx old_operand ATTRIBUTE_UNUSED
;
711 enum machine_mode mode ATTRIBUTE_UNUSED
;
718 m68hc11_reload_operands (operands
)
721 enum machine_mode mode
;
723 if (regs_inited
== 0)
726 mode
= GET_MODE (operands
[1]);
728 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
729 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
731 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
732 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
734 if (GET_CODE (base
) != REG
)
741 /* If the offset is out of range, we have to compute the address
742 with a separate add instruction. We try to do with with an 8-bit
743 add on the A register. This is possible only if the lowest part
744 of the offset (ie, big_offset % 256) is a valid constant offset
745 with respect to the mode. If it's not, we have to generate a
746 16-bit add on the D register. From:
748 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
752 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
753 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
754 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
755 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
757 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
758 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
761 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
764 rtx reg
= operands
[0];
766 int val
= INTVAL (big_offset
);
769 /* We use the 'operands[0]' as a scratch register to compute the
770 address. Make sure 'base' is in that register. */
771 if (!rtx_equal_p (base
, operands
[0]))
773 emit_move_insn (reg
, base
);
783 vh
= (val
>> 8) & 0x0FF;
787 /* Create the lowest part offset that still remains to be added.
788 If it's not a valid offset, do a 16-bit add. */
789 offset
= GEN_INT (vl
);
790 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
792 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
793 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
798 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
799 gen_rtx (PLUS
, HImode
, reg
,
800 GEN_INT (vh
<< 8))));
802 emit_move_insn (operands
[0],
803 gen_rtx (MEM
, GET_MODE (operands
[1]),
804 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
809 /* Use the normal gen_movhi pattern. */
814 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
817 enum machine_mode dmode
;
818 enum machine_mode smode
;
828 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
832 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
833 dmode
, 1, operands
[1], smode
);
834 equiv
= gen_rtx (code
, dmode
, operands
[1]);
838 ret
= emit_library_call_value (libcall
, NULL_RTX
,
840 operands
[1], smode
, operands
[2],
842 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
849 insns
= get_insns ();
851 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
854 /* Returns true if X is a PRE/POST increment decrement
855 (same as auto_inc_p() in rtlanal.c but do not take into
856 account the stack). */
858 m68hc11_auto_inc_p (x
)
861 return GET_CODE (x
) == PRE_DEC
862 || GET_CODE (x
) == POST_INC
863 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
867 /* Predicates for machine description. */
870 memory_reload_operand (operand
, mode
)
872 enum machine_mode mode ATTRIBUTE_UNUSED
;
874 return GET_CODE (operand
) == MEM
875 && GET_CODE (XEXP (operand
, 0)) == PLUS
876 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
877 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
878 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
879 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
883 tst_operand (operand
, mode
)
885 enum machine_mode mode
;
887 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
889 rtx addr
= XEXP (operand
, 0);
890 if (m68hc11_auto_inc_p (addr
))
893 return nonimmediate_operand (operand
, mode
);
897 cmp_operand (operand
, mode
)
899 enum machine_mode mode
;
901 if (GET_CODE (operand
) == MEM
)
903 rtx addr
= XEXP (operand
, 0);
904 if (m68hc11_auto_inc_p (addr
))
907 return general_operand (operand
, mode
);
911 non_push_operand (operand
, mode
)
913 enum machine_mode mode
;
915 if (general_operand (operand
, mode
) == 0)
918 if (push_operand (operand
, mode
) == 1)
924 reg_or_some_mem_operand (operand
, mode
)
926 enum machine_mode mode
;
928 if (GET_CODE (operand
) == MEM
)
930 rtx op
= XEXP (operand
, 0);
932 if (symbolic_memory_operand (op
, mode
))
935 if (IS_STACK_PUSH (operand
))
938 if (m68hc11_register_indirect_p (operand
, mode
))
944 return register_operand (operand
, mode
);
948 m68hc11_symbolic_p (operand
, mode
)
950 enum machine_mode mode
;
952 if (GET_CODE (operand
) == MEM
)
954 rtx op
= XEXP (operand
, 0);
956 if (symbolic_memory_operand (op
, mode
))
963 m68hc11_indirect_p (operand
, mode
)
965 enum machine_mode mode
;
967 if (GET_CODE (operand
) == MEM
)
969 rtx op
= XEXP (operand
, 0);
971 if (symbolic_memory_operand (op
, mode
))
974 if (reload_in_progress
)
977 operand
= XEXP (operand
, 0);
978 return register_indirect_p (operand
, mode
, reload_completed
);
984 stack_register_operand (operand
, mode
)
986 enum machine_mode mode ATTRIBUTE_UNUSED
;
988 return SP_REG_P (operand
);
992 d_register_operand (operand
, mode
)
994 enum machine_mode mode ATTRIBUTE_UNUSED
;
996 if (GET_CODE (operand
) == SUBREG
)
997 operand
= XEXP (operand
, 0);
999 return GET_CODE (operand
) == REG
1000 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1001 || REGNO (operand
) == HARD_D_REGNUM
1002 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1006 hard_addr_reg_operand (operand
, mode
)
1008 enum machine_mode mode ATTRIBUTE_UNUSED
;
1010 if (GET_CODE (operand
) == SUBREG
)
1011 operand
= XEXP (operand
, 0);
1013 return GET_CODE (operand
) == REG
1014 && (REGNO (operand
) == HARD_X_REGNUM
1015 || REGNO (operand
) == HARD_Y_REGNUM
1016 || REGNO (operand
) == HARD_Z_REGNUM
);
1020 hard_reg_operand (operand
, mode
)
1022 enum machine_mode mode ATTRIBUTE_UNUSED
;
1024 if (GET_CODE (operand
) == SUBREG
)
1025 operand
= XEXP (operand
, 0);
1027 return GET_CODE (operand
) == REG
1028 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1029 || H_REGNO_P (REGNO (operand
)));
1033 memory_indexed_operand (operand
, mode
)
1035 enum machine_mode mode ATTRIBUTE_UNUSED
;
1037 if (GET_CODE (operand
) != MEM
)
1040 operand
= XEXP (operand
, 0);
1041 if (GET_CODE (operand
) == PLUS
)
1043 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1044 operand
= XEXP (operand
, 0);
1045 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1046 operand
= XEXP (operand
, 1);
1048 return GET_CODE (operand
) == REG
1049 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1050 || A_REGNO_P (REGNO (operand
)));
1054 push_pop_operand_p (operand
)
1057 if (GET_CODE (operand
) != MEM
)
1061 operand
= XEXP (operand
, 0);
1062 return PUSH_POP_ADDRESS_P (operand
);
1065 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1066 reference and a constant. */
1069 symbolic_memory_operand (op
, mode
)
1071 enum machine_mode mode
;
1073 switch (GET_CODE (op
))
1081 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1082 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1083 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1085 /* ??? This clause seems to be irrelevant. */
1087 return GET_MODE (op
) == mode
;
1090 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1091 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1099 m68hc11_logical_operator (op
, mode
)
1101 enum machine_mode mode ATTRIBUTE_UNUSED
;
1103 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1107 m68hc11_arith_operator (op
, mode
)
1109 enum machine_mode mode ATTRIBUTE_UNUSED
;
1111 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1112 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1113 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1114 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1115 || GET_CODE (op
) == ROTATERT
;
1119 m68hc11_non_shift_operator (op
, mode
)
1121 enum machine_mode mode ATTRIBUTE_UNUSED
;
1123 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1124 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1129 m68hc11_unary_operator (op
, mode
)
1131 enum machine_mode mode ATTRIBUTE_UNUSED
;
1133 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1134 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1137 /* Emit the code to build the trampoline used to call a nested function.
1141 ldy #&CXT movw #&CXT,*_.d1
1142 sty *_.d1 jmp FNADDR
1147 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1152 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1155 if (*static_chain_reg
== '*')
1159 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1160 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1161 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1163 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1164 gen_rtx_CONST (QImode
,
1165 gen_rtx_SYMBOL_REF (Pmode
,
1166 static_chain_reg
)));
1167 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1169 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1173 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1174 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1175 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1176 gen_rtx_CONST (HImode
,
1177 gen_rtx_SYMBOL_REF (Pmode
,
1178 static_chain_reg
)));
1179 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1181 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1185 /* Declaration of types. */
1187 const struct attribute_spec m68hc11_attribute_table
[] =
1189 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1190 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1191 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1192 { NULL
, 0, 0, false, false, false, NULL
}
1195 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1196 arguments as in struct attribute_spec.handler. */
1198 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1201 tree args ATTRIBUTE_UNUSED
;
1202 int flags ATTRIBUTE_UNUSED
;
1205 if (TREE_CODE (*node
) != FUNCTION_TYPE
1206 && TREE_CODE (*node
) != FIELD_DECL
1207 && TREE_CODE (*node
) != TYPE_DECL
)
1209 warning ("`%s' attribute only applies to functions",
1210 IDENTIFIER_POINTER (name
));
1211 *no_add_attrs
= true;
1217 /* We want to recognize trap handlers so that we handle calls to traps
1218 in a special manner (by issuing the trap). This information is stored
1219 in SYMBOL_REF_FLAG. */
1222 m68hc11_encode_section_info (decl
, first
)
1224 int first ATTRIBUTE_UNUSED
;
1230 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1233 rtl
= DECL_RTL (decl
);
1235 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1236 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1237 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1241 /* Argument support functions. */
1243 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1244 Arrays are passed by references and other types by value.
1246 SCz: I tried to pass DImode by reference but it seems that this
1247 does not work very well. */
1249 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1250 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1251 enum machine_mode mode ATTRIBUTE_UNUSED
;
1253 int named ATTRIBUTE_UNUSED
;
1255 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1256 /* Consider complex values as aggregates, so care for TCmode. */
1257 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1258 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1262 /* Define the offset between two registers, one to be eliminated, and the
1263 other its replacement, at the start of a routine. */
1265 m68hc11_initial_elimination_offset (from
, to
)
1274 /* For a trap handler, we must take into account the registers which
1275 are pushed on the stack during the trap (except the PC). */
1276 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1277 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1278 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1283 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1285 /* 2 is for the saved frame.
1286 1 is for the 'sts' correction when creating the frame. */
1287 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1290 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1292 return m68hc11_sp_correction
;
1295 /* Push any 2 byte pseudo hard registers that we need to save. */
1296 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1298 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1304 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1306 return get_frame_size () + size
;
1309 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1316 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1317 for a call to a function whose data type is FNTYPE.
1318 For a library call, FNTYPE is 0. */
1321 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1322 CUMULATIVE_ARGS
*cum
;
1328 z_replacement_completed
= 0;
1332 /* For a library call, we must find out the type of the return value.
1333 When the return value is bigger than 4 bytes, it is returned in
1334 memory. In that case, the first argument of the library call is a
1335 pointer to the memory location. Because the first argument is passed in
1336 register D, we have to identify this, so that the first function
1337 parameter is not passed in D either. */
1343 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1346 /* If the library ends in 'di' or in 'df', we assume it's
1347 returning some DImode or some DFmode which are 64-bit wide. */
1348 name
= XSTR (libname
, 0);
1349 len
= strlen (name
);
1351 && ((name
[len
- 2] == 'd'
1352 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1353 || (name
[len
- 3] == 'd'
1354 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1356 /* We are in. Mark the first parameter register as already used. */
1363 ret_type
= TREE_TYPE (fntype
);
1365 if (ret_type
&& aggregate_value_p (ret_type
))
1372 /* Update the data in CUM to advance over an argument
1373 of mode MODE and data type TYPE.
1374 (TYPE is null for libcalls where that information may not be available.) */
1377 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1378 CUMULATIVE_ARGS
*cum
;
1379 enum machine_mode mode
;
1381 int named ATTRIBUTE_UNUSED
;
1383 if (mode
!= BLKmode
)
1385 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1388 cum
->words
= GET_MODE_SIZE (mode
);
1392 cum
->words
+= GET_MODE_SIZE (mode
);
1393 if (cum
->words
<= HARD_REG_SIZE
)
1399 cum
->words
+= int_size_in_bytes (type
);
1404 /* Define where to put the arguments to a function.
1405 Value is zero to push the argument on the stack,
1406 or a hard register in which to store the argument.
1408 MODE is the argument's machine mode.
1409 TYPE is the data type of the argument (as a tree).
1410 This is null for libcalls where that information may
1412 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1413 the preceding args and about the function being called.
1414 NAMED is nonzero if this argument is a named parameter
1415 (otherwise it is an extra parameter matching an ellipsis). */
1418 m68hc11_function_arg (cum
, mode
, type
, named
)
1419 const CUMULATIVE_ARGS
*cum
;
1420 enum machine_mode mode
;
1421 tree type ATTRIBUTE_UNUSED
;
1422 int named ATTRIBUTE_UNUSED
;
1424 if (cum
->words
!= 0)
1429 if (mode
!= BLKmode
)
1431 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1432 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1434 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1438 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1444 m68hc11_va_arg (valist
, type
)
1449 HOST_WIDE_INT align
;
1450 HOST_WIDE_INT rounded_size
;
1454 /* Compute the rounded size of the type. */
1455 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1456 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1460 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1462 if (pad_direction
== downward
)
1464 /* Small args are padded downward. */
1467 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1468 if (rounded_size
> align
)
1471 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1472 build_int_2 (rounded_size
- adj
, 0));
1475 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1476 addr
= copy_to_reg (addr
);
1478 /* Compute new value for AP. */
1479 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1480 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1481 build_int_2 (rounded_size
, 0)));
1482 TREE_SIDE_EFFECTS (t
) = 1;
1483 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1488 /* If defined, a C expression which determines whether, and in which direction,
1489 to pad out an argument with extra space. The value should be of type
1490 `enum direction': either `upward' to pad above the argument,
1491 `downward' to pad below, or `none' to inhibit padding.
1493 Structures are stored left shifted in their argument slot. */
1495 m68hc11_function_arg_padding (mode
, type
)
1496 enum machine_mode mode
;
1499 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1502 /* This is the default definition. */
1503 return (!BYTES_BIG_ENDIAN
1506 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1507 && int_size_in_bytes (type
) <
1508 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1509 PARM_BOUNDARY
) ? downward
: upward
));
1513 /* Function prologue and epilogue. */
1515 /* Emit a move after the reload pass has completed. This is used to
1516 emit the prologue and epilogue. */
1518 emit_move_after_reload (to
, from
, scratch
)
1519 rtx to
, from
, scratch
;
1523 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1525 insn
= emit_move_insn (to
, from
);
1529 emit_move_insn (scratch
, from
);
1530 insn
= emit_move_insn (to
, scratch
);
1533 /* Put a REG_INC note to tell the flow analysis that the instruction
1535 if (IS_STACK_PUSH (to
))
1537 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1538 XEXP (XEXP (to
, 0), 0),
1541 else if (IS_STACK_POP (from
))
1543 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1544 XEXP (XEXP (from
, 0), 0),
1548 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1549 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1550 The problem is that we are lying to gcc and use `txs' for x = sp
1551 (which is not really true because txs is really x = sp + 1). */
1552 else if (TARGET_M6811
&& SP_REG_P (from
))
1554 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1561 m68hc11_total_frame_size ()
1566 size
= get_frame_size ();
1567 if (current_function_interrupt
)
1569 size
+= 3 * HARD_REG_SIZE
;
1571 if (frame_pointer_needed
)
1572 size
+= HARD_REG_SIZE
;
1574 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1575 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1576 size
+= HARD_REG_SIZE
;
1582 m68hc11_output_function_epilogue (out
, size
)
1583 FILE *out ATTRIBUTE_UNUSED
;
1584 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1586 /* We catch the function epilogue generation to have a chance
1587 to clear the z_replacement_completed flag. */
1588 z_replacement_completed
= 0;
1599 if (reload_completed
!= 1)
1602 size
= get_frame_size ();
1606 /* Generate specific prologue for interrupt handlers. */
1607 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1608 current_function_interrupt
= lookup_attribute ("interrupt",
1609 func_attr
) != NULL_TREE
;
1610 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1612 /* Get the scratch register to build the frame and push registers.
1613 If the first argument is a 32-bit quantity, the D+X registers
1614 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1615 For 68HC12, this scratch register is not used. */
1616 if (current_function_args_info
.nregs
== 2)
1621 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1622 Other soft registers in page0 need not to be saved because they
1623 will be restored by C functions. For a trap handler, we don't
1624 need to preserve these registers because this is a synchronous call. */
1625 if (current_function_interrupt
)
1627 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1628 emit_move_after_reload (stack_push_word
,
1629 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1630 emit_move_after_reload (stack_push_word
,
1631 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1635 /* Save current stack frame. */
1636 if (frame_pointer_needed
)
1637 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1639 /* Allocate local variables. */
1640 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1642 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1643 stack_pointer_rtx
, GEN_INT (-size
)));
1649 insn
= gen_rtx_PARALLEL
1652 gen_rtx_SET (VOIDmode
,
1654 gen_rtx_PLUS (HImode
,
1657 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1664 /* Allocate by pushing scratch values. */
1665 for (i
= 2; i
<= size
; i
+= 2)
1666 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1669 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1670 stack_pointer_rtx
, GEN_INT (-1)));
1673 /* Create the frame pointer. */
1674 if (frame_pointer_needed
)
1675 emit_move_after_reload (hard_frame_pointer_rtx
,
1676 stack_pointer_rtx
, scratch
);
1678 /* Push any 2 byte pseudo hard registers that we need to save. */
1679 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1681 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1683 emit_move_after_reload (stack_push_word
,
1684 gen_rtx (REG
, HImode
, regno
), scratch
);
1697 if (reload_completed
!= 1)
1700 size
= get_frame_size ();
1702 /* If we are returning a value in two registers, we have to preserve the
1703 X register and use the Y register to restore the stack and the saved
1704 registers. Otherwise, use X because it's faster (and smaller). */
1705 if (current_function_return_rtx
== 0)
1707 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1708 return_size
= HARD_REG_SIZE
;
1710 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1712 if (return_size
> HARD_REG_SIZE
)
1717 /* Pop any 2 byte pseudo hard registers that we saved. */
1718 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1720 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1722 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1723 stack_pop_word
, scratch
);
1727 /* de-allocate auto variables */
1728 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1730 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1731 stack_pointer_rtx
, GEN_INT (size
)));
1737 insn
= gen_rtx_PARALLEL
1740 gen_rtx_SET (VOIDmode
,
1742 gen_rtx_PLUS (HImode
,
1745 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1752 for (i
= 2; i
<= size
; i
+= 2)
1753 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1755 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1756 stack_pointer_rtx
, GEN_INT (1)));
1759 /* Restore previous frame pointer. */
1760 if (frame_pointer_needed
)
1761 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1763 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1764 if (current_function_interrupt
)
1766 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1767 stack_pop_word
, scratch
);
1768 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1769 stack_pop_word
, scratch
);
1770 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1773 /* If the trap handler returns some value, copy the value
1774 in D, X onto the stack so that the rti will pop the return value
1776 else if (current_function_trap
&& return_size
!= 0)
1778 rtx addr_reg
= stack_pointer_rtx
;
1782 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1785 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1786 gen_rtx (PLUS
, HImode
, addr_reg
,
1787 GEN_INT (1))), d_reg
, 0);
1788 if (return_size
> HARD_REG_SIZE
)
1789 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1790 gen_rtx (PLUS
, HImode
, addr_reg
,
1791 GEN_INT (3))), ix_reg
, 0);
1794 emit_jump_insn (gen_return ());
1798 /* Low and High part extraction for 68HC11. These routines are
1799 similar to gen_lowpart and gen_highpart but they have been
1800 fixed to work for constants and 68HC11 specific registers. */
1803 m68hc11_gen_lowpart (mode
, x
)
1804 enum machine_mode mode
;
1807 /* We assume that the low part of an auto-inc mode is the same with
1808 the mode changed and that the caller split the larger mode in the
1810 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1812 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1815 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1816 floating-point constant. A CONST_DOUBLE is used whenever the
1817 constant requires more than one word in order to be adequately
1819 if (GET_CODE (x
) == CONST_DOUBLE
)
1823 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1827 if (GET_MODE (x
) == SFmode
)
1829 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1830 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1836 split_double (x
, &first
, &second
);
1840 return GEN_INT (l
[0]);
1842 return gen_int_mode (l
[0], HImode
);
1846 l
[0] = CONST_DOUBLE_LOW (x
);
1849 return GEN_INT (l
[0]);
1850 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1851 return gen_int_mode (l
[0], HImode
);
1856 if (mode
== QImode
&& D_REG_P (x
))
1857 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1859 /* gen_lowpart crashes when it is called with a SUBREG. */
1860 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1863 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1864 else if (mode
== HImode
)
1865 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1869 x
= gen_lowpart (mode
, x
);
1871 /* Return a different rtx to avoid to share it in several insns
1872 (when used by a split pattern). Sharing addresses within
1873 a MEM breaks the Z register replacement (and reloading). */
1874 if (GET_CODE (x
) == MEM
)
1880 m68hc11_gen_highpart (mode
, x
)
1881 enum machine_mode mode
;
1884 /* We assume that the high part of an auto-inc mode is the same with
1885 the mode changed and that the caller split the larger mode in the
1887 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1889 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1892 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1893 floating-point constant. A CONST_DOUBLE is used whenever the
1894 constant requires more than one word in order to be adequately
1896 if (GET_CODE (x
) == CONST_DOUBLE
)
1900 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1904 if (GET_MODE (x
) == SFmode
)
1906 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1907 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1913 split_double (x
, &first
, &second
);
1917 return GEN_INT (l
[1]);
1919 return gen_int_mode ((l
[1] >> 16), HImode
);
1923 l
[1] = CONST_DOUBLE_HIGH (x
);
1927 return GEN_INT (l
[1]);
1928 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1929 return gen_int_mode ((l
[0] >> 16), HImode
);
1933 if (GET_CODE (x
) == CONST_INT
)
1935 HOST_WIDE_INT val
= INTVAL (x
);
1939 return gen_int_mode (val
>> 8, QImode
);
1941 else if (mode
== HImode
)
1943 return gen_int_mode (val
>> 16, HImode
);
1946 if (mode
== QImode
&& D_REG_P (x
))
1947 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1949 /* There is no way in GCC to represent the upper part of a word register.
1950 To obtain the 8-bit upper part of a soft register, we change the
1951 reg into a mem rtx. This is possible because they are physically
1952 located in memory. There is no offset because we are big-endian. */
1953 if (mode
== QImode
&& S_REG_P (x
))
1957 /* Avoid the '*' for direct addressing mode when this
1958 addressing mode is disabled. */
1959 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1960 return gen_rtx (MEM
, QImode
,
1961 gen_rtx (SYMBOL_REF
, Pmode
,
1962 ®_names
[REGNO (x
)][pos
]));
1965 /* gen_highpart crashes when it is called with a SUBREG. */
1966 if (GET_CODE (x
) == SUBREG
)
1968 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
1970 if (GET_CODE (x
) == REG
)
1972 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
1973 return gen_rtx (REG
, mode
, REGNO (x
));
1975 return gen_rtx_SUBREG (mode
, x
, 0);
1978 if (GET_CODE (x
) == MEM
)
1980 x
= change_address (x
, mode
, 0);
1982 /* Return a different rtx to avoid to share it in several insns
1983 (when used by a split pattern). Sharing addresses within
1984 a MEM breaks the Z register replacement (and reloading). */
1985 if (GET_CODE (x
) == MEM
)
1993 /* Obscure register manipulation. */
1995 /* Finds backward in the instructions to see if register 'reg' is
1996 dead. This is used when generating code to see if we can use 'reg'
1997 as a scratch register. This allows us to choose a better generation
1998 of code when we know that some register dies or can be clobbered. */
2001 dead_register_here (x
, reg
)
2009 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2013 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2014 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2020 if (GET_CODE (body
) == CALL_INSN
)
2022 if (GET_CODE (body
) == JUMP_INSN
)
2025 if (GET_CODE (body
) == SET
)
2027 rtx dst
= XEXP (body
, 0);
2029 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2031 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2034 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2037 else if (reg_mentioned_p (reg
, p
)
2038 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2042 /* Scan forward to see if the register is set in some insns and never
2044 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2048 if (GET_CODE (p
) == CODE_LABEL
2049 || GET_CODE (p
) == JUMP_INSN
2050 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2053 if (GET_CODE (p
) != INSN
)
2057 if (GET_CODE (body
) == SET
)
2059 rtx src
= XEXP (body
, 1);
2060 rtx dst
= XEXP (body
, 0);
2062 if (GET_CODE (dst
) == REG
2063 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2067 /* Register is used (may be in source or in dest). */
2068 if (reg_mentioned_p (reg
, p
)
2069 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2070 && reg_mentioned_p (x_reg
, p
)))
2073 return p
== 0 ? 1 : 0;
2077 /* Code generation operations called from machine description file. */
2079 /* Print the name of register 'regno' in the assembly file. */
2081 asm_print_register (file
, regno
)
2085 const char *name
= reg_names
[regno
];
2087 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2090 asm_fprintf (file
, "%s", name
);
2093 /* A C compound statement to output to stdio stream STREAM the
2094 assembler syntax for an instruction operand X. X is an RTL
2097 CODE is a value that can be used to specify one of several ways
2098 of printing the operand. It is used when identical operands
2099 must be printed differently depending on the context. CODE
2100 comes from the `%' specification that was used to request
2101 printing of the operand. If the specification was just `%DIGIT'
2102 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2103 is the ASCII code for LTR.
2105 If X is a register, this macro should print the register's name.
2106 The names can be found in an array `reg_names' whose type is
2107 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2109 When the machine description has a specification `%PUNCT' (a `%'
2110 followed by a punctuation character), this macro is called with
2111 a null pointer for X and the punctuation character for CODE.
2113 The M68HC11 specific codes are:
2115 'b' for the low part of the operand.
2116 'h' for the high part of the operand
2117 The 'b' or 'h' modifiers have no effect if the operand has
2118 the QImode and is not a S_REG_P (soft register). If the
2119 operand is a hard register, these two modifiers have no effect.
2120 't' generate the temporary scratch register. The operand is
2122 'T' generate the low-part temporary scratch register. The operand is
2126 print_operand (file
, op
, letter
)
2133 asm_print_register (file
, SOFT_TMP_REGNUM
);
2136 else if (letter
== 'T')
2138 asm_print_register (file
, SOFT_TMP_REGNUM
);
2139 asm_fprintf (file
, "+1");
2142 else if (letter
== '#')
2144 asm_fprintf (file
, "%0I");
2147 if (GET_CODE (op
) == REG
)
2149 if (letter
== 'b' && S_REG_P (op
))
2151 asm_print_register (file
, REGNO (op
));
2152 asm_fprintf (file
, "+1");
2156 asm_print_register (file
, REGNO (op
));
2161 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2164 asm_fprintf (file
, "%0I%%lo(");
2166 asm_fprintf (file
, "%0I%%hi(");
2168 output_addr_const (file
, op
);
2169 asm_fprintf (file
, ")");
2173 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2174 are specified. If we already have a QImode, there is nothing to do. */
2175 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2179 op
= m68hc11_gen_lowpart (QImode
, op
);
2181 else if (letter
== 'h')
2183 op
= m68hc11_gen_highpart (QImode
, op
);
2187 if (GET_CODE (op
) == MEM
)
2189 rtx base
= XEXP (op
, 0);
2190 switch (GET_CODE (base
))
2195 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2196 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2205 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2206 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2207 asm_fprintf (file
, "-");
2216 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2217 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2218 asm_fprintf (file
, "+");
2227 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2228 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2235 output_address (base
);
2239 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2244 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2245 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2246 asm_fprintf (file
, "%I0x%lx", l
);
2248 else if (GET_CODE (op
) == CONST_DOUBLE
2249 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2254 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2255 REAL_VALUE_TO_DECIMAL (r
, "%.20g", dstr
);
2256 asm_fprintf (file
, "%I0r%s", dstr
);
2260 int need_parenthesize
= 0;
2263 asm_fprintf (file
, "%0I");
2265 need_parenthesize
= must_parenthesize (op
);
2267 if (need_parenthesize
)
2268 asm_fprintf (file
, "(");
2270 output_addr_const (file
, op
);
2271 if (need_parenthesize
)
2272 asm_fprintf (file
, ")");
2276 /* Returns true if the operand 'op' must be printed with parenthesis
2277 arround it. This must be done only if there is a symbol whose name
2278 is a processor register. */
2280 must_parenthesize (op
)
2285 switch (GET_CODE (op
))
2288 name
= XSTR (op
, 0);
2289 /* Avoid a conflict between symbol name and a possible
2291 return (strcasecmp (name
, "a") == 0
2292 || strcasecmp (name
, "b") == 0
2293 || strcasecmp (name
, "d") == 0
2294 || strcasecmp (name
, "x") == 0
2295 || strcasecmp (name
, "y") == 0
2296 || strcasecmp (name
, "ix") == 0
2297 || strcasecmp (name
, "iy") == 0
2298 || strcasecmp (name
, "pc") == 0
2299 || strcasecmp (name
, "sp") == 0
2300 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2304 return must_parenthesize (XEXP (op
, 0))
2305 || must_parenthesize (XEXP (op
, 1));
2311 return must_parenthesize (XEXP (op
, 0));
2322 /* A C compound statement to output to stdio stream STREAM the
2323 assembler syntax for an instruction operand that is a memory
2324 reference whose address is ADDR. ADDR is an RTL expression. */
2327 print_operand_address (file
, addr
)
2333 int need_parenthesis
= 0;
2335 switch (GET_CODE (addr
))
2338 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2341 asm_fprintf (file
, "0,");
2342 asm_print_register (file
, REGNO (addr
));
2346 base
= XEXP (addr
, 0);
2347 switch (GET_CODE (base
))
2352 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2353 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2362 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2363 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2364 asm_fprintf (file
, "-");
2373 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2374 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2375 asm_fprintf (file
, "+");
2384 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2385 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2392 need_parenthesis
= must_parenthesize (base
);
2393 if (need_parenthesis
)
2394 asm_fprintf (file
, "(");
2396 output_addr_const (file
, base
);
2397 if (need_parenthesis
)
2398 asm_fprintf (file
, ")");
2404 base
= XEXP (addr
, 0);
2405 offset
= XEXP (addr
, 1);
2406 if (!G_REG_P (base
) && G_REG_P (offset
))
2408 base
= XEXP (addr
, 1);
2409 offset
= XEXP (addr
, 0);
2411 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2413 need_parenthesis
= must_parenthesize (addr
);
2415 if (need_parenthesis
)
2416 asm_fprintf (file
, "(");
2418 output_addr_const (file
, base
);
2419 asm_fprintf (file
, "+");
2420 output_addr_const (file
, offset
);
2421 if (need_parenthesis
)
2422 asm_fprintf (file
, ")");
2424 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2430 asm_print_register (file
, REGNO (offset
));
2431 asm_fprintf (file
, ",");
2432 asm_print_register (file
, REGNO (base
));
2439 need_parenthesis
= must_parenthesize (offset
);
2440 if (need_parenthesis
)
2441 asm_fprintf (file
, "(");
2443 output_addr_const (file
, offset
);
2444 if (need_parenthesis
)
2445 asm_fprintf (file
, ")");
2446 asm_fprintf (file
, ",");
2447 asm_print_register (file
, REGNO (base
));
2457 if (GET_CODE (addr
) == CONST_INT
2458 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2460 asm_fprintf (file
, "%d", INTVAL (addr
));
2464 need_parenthesis
= must_parenthesize (addr
);
2465 if (need_parenthesis
)
2466 asm_fprintf (file
, "(");
2468 output_addr_const (file
, addr
);
2469 if (need_parenthesis
)
2470 asm_fprintf (file
, ")");
2477 /* Splitting of some instructions. */
2480 m68hc11_expand_compare (code
, op0
, op1
)
2486 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2490 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2491 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2492 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2499 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2501 rtx op0
, op1
, label
;
2505 switch (GET_MODE (op0
))
2509 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2510 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2511 gen_rtx_LABEL_REF (VOIDmode
, label
),
2513 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2517 /* SCz: from i386.c */
2520 /* Don't expand the comparison early, so that we get better code
2521 when jump or whoever decides to reverse the comparison. */
2526 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2527 &m68hc11_compare_op1
);
2529 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2530 m68hc11_compare_op0
, m68hc11_compare_op1
);
2531 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2532 gen_rtx_LABEL_REF (VOIDmode
, label
),
2534 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2536 use_fcomi
= ix86_use_fcomi_compare (code
);
2537 vec
= rtvec_alloc (3 + !use_fcomi
);
2538 RTVEC_ELT (vec
, 0) = tmp
;
2540 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2542 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2545 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2547 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2553 /* Expand SImode branch into multiple compare+branch. */
2555 rtx lo
[2], hi
[2], label2
;
2556 enum rtx_code code1
, code2
, code3
;
2558 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2563 code
= swap_condition (code
);
2565 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2566 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2567 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2568 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2570 /* Otherwise, if we are doing less-than, op1 is a constant and the
2571 low word is zero, then we can just examine the high word. */
2573 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2574 && (code
== LT
|| code
== LTU
))
2576 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2580 /* Otherwise, we need two or three jumps. */
2582 label2
= gen_label_rtx ();
2585 code2
= swap_condition (code
);
2586 code3
= unsigned_condition (code
);
2627 * if (hi(a) < hi(b)) goto true;
2628 * if (hi(a) > hi(b)) goto false;
2629 * if (lo(a) < lo(b)) goto true;
2633 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2635 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2637 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2640 emit_label (label2
);
2650 /* Return the increment/decrement mode of a MEM if it is such.
2651 Return CONST if it is anything else. */
2656 if (GET_CODE (x
) != MEM
)
2660 if (GET_CODE (x
) == PRE_INC
2661 || GET_CODE (x
) == PRE_DEC
2662 || GET_CODE (x
) == POST_INC
2663 || GET_CODE (x
) == POST_DEC
)
2664 return GET_CODE (x
);
2670 m68hc11_make_autoinc_notes (x
, data
)
2676 switch (GET_CODE (*x
))
2683 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2692 /* Split a DI, SI or HI move into several smaller move operations.
2693 The scratch register 'scratch' is used as a temporary to load
2694 store intermediate values. It must be a hard register. */
2696 m68hc11_split_move (to
, from
, scratch
)
2697 rtx to
, from
, scratch
;
2699 rtx low_to
, low_from
;
2700 rtx high_to
, high_from
;
2702 enum machine_mode mode
;
2704 int autoinc_from
= autoinc_mode (from
);
2705 int autoinc_to
= autoinc_mode (to
);
2707 mode
= GET_MODE (to
);
2709 /* If the TO and FROM contain autoinc modes that are not compatible
2710 together (one pop and the other a push), we must change one to
2711 an offsetable operand and generate an appropriate add at the end. */
2712 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2717 /* The source uses an autoinc mode which is not compatible with
2718 a split (this would result in a word swap). */
2719 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2721 code
= GET_CODE (XEXP (from
, 0));
2722 reg
= XEXP (XEXP (from
, 0), 0);
2723 offset
= GET_MODE_SIZE (GET_MODE (from
));
2724 if (code
== POST_DEC
)
2727 if (code
== PRE_INC
)
2728 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2730 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2731 if (code
== POST_DEC
)
2732 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2736 /* Likewise for destination. */
2737 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2739 code
= GET_CODE (XEXP (to
, 0));
2740 reg
= XEXP (XEXP (to
, 0), 0);
2741 offset
= GET_MODE_SIZE (GET_MODE (to
));
2742 if (code
== POST_DEC
)
2745 if (code
== PRE_INC
)
2746 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2748 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2749 if (code
== POST_DEC
)
2750 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2754 /* The source and destination auto increment modes must be compatible
2755 with each other: same direction. */
2756 if ((autoinc_to
!= autoinc_from
2757 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2758 /* The destination address register must not be used within
2759 the source operand because the source address would change
2760 while doing the copy. */
2761 || (autoinc_to
!= CONST
2762 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2763 && !IS_STACK_PUSH (to
)))
2765 /* Must change the destination. */
2766 code
= GET_CODE (XEXP (to
, 0));
2767 reg
= XEXP (XEXP (to
, 0), 0);
2768 offset
= GET_MODE_SIZE (GET_MODE (to
));
2769 if (code
== PRE_DEC
|| code
== POST_DEC
)
2772 if (code
== PRE_DEC
|| code
== PRE_INC
)
2773 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2774 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2775 if (code
== POST_DEC
|| code
== POST_INC
)
2776 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2781 /* Likewise, the source address register must not be used within
2782 the destination operand. */
2783 if (autoinc_from
!= CONST
2784 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2785 && !IS_STACK_PUSH (to
))
2787 /* Must change the source. */
2788 code
= GET_CODE (XEXP (from
, 0));
2789 reg
= XEXP (XEXP (from
, 0), 0);
2790 offset
= GET_MODE_SIZE (GET_MODE (from
));
2791 if (code
== PRE_DEC
|| code
== POST_DEC
)
2794 if (code
== PRE_DEC
|| code
== PRE_INC
)
2795 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2796 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2797 if (code
== POST_DEC
|| code
== POST_INC
)
2798 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2804 if (GET_MODE_SIZE (mode
) == 8)
2806 else if (GET_MODE_SIZE (mode
) == 4)
2812 && IS_STACK_PUSH (to
)
2813 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2819 else if (mode
== HImode
)
2827 low_to
= m68hc11_gen_lowpart (mode
, to
);
2828 high_to
= m68hc11_gen_highpart (mode
, to
);
2830 low_from
= m68hc11_gen_lowpart (mode
, from
);
2831 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2833 if (INTVAL (from
) >= 0)
2834 high_from
= const0_rtx
;
2836 high_from
= constm1_rtx
;
2839 high_from
= m68hc11_gen_highpart (mode
, from
);
2843 high_from
= adjust_address (high_from
, mode
, offset
);
2844 low_from
= high_from
;
2847 /* When copying with a POST_INC mode, we must copy the
2848 high part and then the low part to guarantee a correct
2851 && GET_MODE_SIZE (mode
) >= 2
2852 && autoinc_from
!= autoinc_to
2853 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2862 low_from
= high_from
;
2867 m68hc11_split_move (low_to
, low_from
, scratch
);
2868 m68hc11_split_move (high_to
, high_from
, scratch
);
2870 else if (H_REG_P (to
) || H_REG_P (from
)
2871 || (low_from
== const0_rtx
2872 && high_from
== const0_rtx
2873 && ! push_operand (to
, GET_MODE (to
))
2874 && ! H_REG_P (scratch
))
2876 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2877 || m68hc11_small_indexed_indirect_p (from
,
2879 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2880 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2882 insn
= emit_move_insn (low_to
, low_from
);
2883 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2885 insn
= emit_move_insn (high_to
, high_from
);
2886 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2890 insn
= emit_move_insn (scratch
, low_from
);
2891 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2892 insn
= emit_move_insn (low_to
, scratch
);
2893 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2895 insn
= emit_move_insn (scratch
, high_from
);
2896 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2897 insn
= emit_move_insn (high_to
, scratch
);
2898 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2903 simplify_logical (mode
, code
, operand
, result
)
2904 enum machine_mode mode
;
2913 if (GET_CODE (operand
) != CONST_INT
)
2921 val
= INTVAL (operand
);
2925 if ((val
& mask
) == 0)
2927 if ((val
& mask
) == mask
)
2928 *result
= constm1_rtx
;
2932 if ((val
& mask
) == 0)
2933 *result
= const0_rtx
;
2934 if ((val
& mask
) == mask
)
2939 if ((val
& mask
) == 0)
2947 m68hc11_emit_logical (mode
, code
, operands
)
2948 enum machine_mode mode
;
2955 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2956 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2958 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2959 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2961 if (result
&& GET_CODE (result
) == CONST_INT
)
2963 if (!H_REG_P (operands
[0]) && operands
[3]
2964 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2966 emit_move_insn (operands
[3], result
);
2967 emit_move_insn (operands
[0], operands
[3]);
2971 emit_move_insn (operands
[0], result
);
2974 else if (operands
[1] != 0 && operands
[2] != 0)
2978 if (!H_REG_P (operands
[0]) && operands
[3])
2980 emit_move_insn (operands
[3], operands
[1]);
2981 emit_insn (gen_rtx (SET
, mode
,
2983 gen_rtx (code
, mode
,
2984 operands
[3], operands
[2])));
2985 insn
= emit_move_insn (operands
[0], operands
[3]);
2989 insn
= emit_insn (gen_rtx (SET
, mode
,
2991 gen_rtx (code
, mode
,
2992 operands
[0], operands
[2])));
2996 /* The logical operation is similar to a copy. */
3001 if (GET_CODE (operands
[1]) == CONST_INT
)
3006 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3008 emit_move_insn (operands
[3], src
);
3009 emit_move_insn (operands
[0], operands
[3]);
3013 emit_move_insn (operands
[0], src
);
3019 m68hc11_split_logical (mode
, code
, operands
)
3020 enum machine_mode mode
;
3027 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3028 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3029 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3031 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3033 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3035 if (INTVAL (operands
[1]) >= 0)
3036 high
[1] = const0_rtx
;
3038 high
[1] = constm1_rtx
;
3041 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3043 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3045 if (INTVAL (operands
[2]) >= 0)
3046 high
[2] = const0_rtx
;
3048 high
[2] = constm1_rtx
;
3051 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3053 low
[3] = operands
[3];
3054 high
[3] = operands
[3];
3057 m68hc11_split_logical (HImode
, code
, low
);
3058 m68hc11_split_logical (HImode
, code
, high
);
3062 m68hc11_emit_logical (mode
, code
, low
);
3063 m68hc11_emit_logical (mode
, code
, high
);
3067 /* Code generation. */
3070 m68hc11_output_swap (insn
, operands
)
3071 rtx insn ATTRIBUTE_UNUSED
;
3074 /* We have to be careful with the cc_status. An address register swap
3075 is generated for some comparison. The comparison is made with D
3076 but the branch really uses the address register. See the split
3077 pattern for compare. The xgdx/xgdy preserve the flags but after
3078 the exchange, the flags will reflect to the value of X and not D.
3079 Tell this by setting the cc_status according to the cc_prev_status. */
3080 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3082 if (cc_prev_status
.value1
!= 0
3083 && (D_REG_P (cc_prev_status
.value1
)
3084 || X_REG_P (cc_prev_status
.value1
)))
3086 cc_status
= cc_prev_status
;
3087 if (D_REG_P (cc_status
.value1
))
3088 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3091 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3097 output_asm_insn ("xgdx", operands
);
3101 if (cc_prev_status
.value1
!= 0
3102 && (D_REG_P (cc_prev_status
.value1
)
3103 || Y_REG_P (cc_prev_status
.value1
)))
3105 cc_status
= cc_prev_status
;
3106 if (D_REG_P (cc_status
.value1
))
3107 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3110 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3116 output_asm_insn ("xgdy", operands
);
3120 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3121 This is used to decide whether a move that set flags should be used
3124 next_insn_test_reg (insn
, reg
)
3130 insn
= next_nonnote_insn (insn
);
3131 if (GET_CODE (insn
) != INSN
)
3134 body
= PATTERN (insn
);
3135 if (sets_cc0_p (body
) != 1)
3138 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3144 /* Generate the code to move a 16-bit operand into another one. */
3147 m68hc11_gen_movhi (insn
, operands
)
3153 /* Move a register or memory to the same location.
3154 This is possible because such insn can appear
3155 in a non-optimizing mode. */
3156 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3158 cc_status
= cc_prev_status
;
3164 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3166 cc_status
= cc_prev_status
;
3167 switch (REGNO (operands
[1]))
3172 output_asm_insn ("psh%1", operands
);
3174 case HARD_SP_REGNUM
:
3175 output_asm_insn ("sts\t-2,sp", operands
);
3182 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3184 cc_status
= cc_prev_status
;
3185 switch (REGNO (operands
[0]))
3190 output_asm_insn ("pul%0", operands
);
3197 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3199 m68hc11_notice_keep_cc (operands
[0]);
3200 output_asm_insn ("tfr\t%1,%0", operands
);
3202 else if (H_REG_P (operands
[0]))
3204 if (SP_REG_P (operands
[0]))
3205 output_asm_insn ("lds\t%1", operands
);
3207 output_asm_insn ("ld%0\t%1", operands
);
3209 else if (H_REG_P (operands
[1]))
3211 if (SP_REG_P (operands
[1]))
3212 output_asm_insn ("sts\t%0", operands
);
3214 output_asm_insn ("st%1\t%0", operands
);
3218 rtx from
= operands
[1];
3219 rtx to
= operands
[0];
3221 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3222 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3223 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3224 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3230 ops
[0] = operands
[2];
3233 m68hc11_gen_movhi (insn
, ops
);
3235 ops
[1] = operands
[2];
3236 m68hc11_gen_movhi (insn
, ops
);
3240 /* !!!! SCz wrong here. */
3241 fatal_insn ("move insn not handled", insn
);
3246 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3248 output_asm_insn ("clr\t%h0", operands
);
3249 output_asm_insn ("clr\t%b0", operands
);
3253 m68hc11_notice_keep_cc (operands
[0]);
3254 output_asm_insn ("movw\t%1,%0", operands
);
3261 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3263 cc_status
= cc_prev_status
;
3264 switch (REGNO (operands
[0]))
3268 output_asm_insn ("pul%0", operands
);
3271 output_asm_insn ("pula", operands
);
3272 output_asm_insn ("pulb", operands
);
3279 /* Some moves to a hard register are special. Not all of them
3280 are really supported and we have to use a temporary
3281 location to provide them (either the stack of a temp var). */
3282 if (H_REG_P (operands
[0]))
3284 switch (REGNO (operands
[0]))
3287 if (X_REG_P (operands
[1]))
3289 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3291 m68hc11_output_swap (insn
, operands
);
3293 else if (next_insn_test_reg (insn
, operands
[0]))
3295 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3299 m68hc11_notice_keep_cc (operands
[0]);
3300 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3303 else if (Y_REG_P (operands
[1]))
3305 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3307 m68hc11_output_swap (insn
, operands
);
3311 /* %t means *ZTMP scratch register. */
3312 output_asm_insn ("sty\t%t1", operands
);
3313 output_asm_insn ("ldd\t%t1", operands
);
3316 else if (SP_REG_P (operands
[1]))
3321 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3322 output_asm_insn ("xgdx", operands
);
3323 output_asm_insn ("tsx", operands
);
3324 output_asm_insn ("xgdx", operands
);
3326 else if (IS_STACK_POP (operands
[1]))
3328 output_asm_insn ("pula\n\tpulb", operands
);
3330 else if (GET_CODE (operands
[1]) == CONST_INT
3331 && INTVAL (operands
[1]) == 0)
3333 output_asm_insn ("clra\n\tclrb", operands
);
3337 output_asm_insn ("ldd\t%1", operands
);
3342 if (D_REG_P (operands
[1]))
3344 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3346 m68hc11_output_swap (insn
, operands
);
3348 else if (next_insn_test_reg (insn
, operands
[0]))
3350 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3354 m68hc11_notice_keep_cc (operands
[0]);
3355 output_asm_insn ("pshb", operands
);
3356 output_asm_insn ("psha", operands
);
3357 output_asm_insn ("pulx", operands
);
3360 else if (Y_REG_P (operands
[1]))
3362 /* When both D and Y are dead, use the sequence xgdy, xgdx
3363 to move Y into X. The D and Y registers are modified. */
3364 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3365 && dead_register_here (insn
, d_reg
))
3367 output_asm_insn ("xgdy", operands
);
3368 output_asm_insn ("xgdx", operands
);
3373 output_asm_insn ("sty\t%t1", operands
);
3374 output_asm_insn ("ldx\t%t1", operands
);
3377 else if (SP_REG_P (operands
[1]))
3379 /* tsx, tsy preserve the flags */
3380 cc_status
= cc_prev_status
;
3381 output_asm_insn ("tsx", operands
);
3385 output_asm_insn ("ldx\t%1", operands
);
3390 if (D_REG_P (operands
[1]))
3392 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3394 m68hc11_output_swap (insn
, operands
);
3398 output_asm_insn ("std\t%t1", operands
);
3399 output_asm_insn ("ldy\t%t1", operands
);
3402 else if (X_REG_P (operands
[1]))
3404 /* When both D and X are dead, use the sequence xgdx, xgdy
3405 to move X into Y. The D and X registers are modified. */
3406 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3407 && dead_register_here (insn
, d_reg
))
3409 output_asm_insn ("xgdx", operands
);
3410 output_asm_insn ("xgdy", operands
);
3415 output_asm_insn ("stx\t%t1", operands
);
3416 output_asm_insn ("ldy\t%t1", operands
);
3419 else if (SP_REG_P (operands
[1]))
3421 /* tsx, tsy preserve the flags */
3422 cc_status
= cc_prev_status
;
3423 output_asm_insn ("tsy", operands
);
3427 output_asm_insn ("ldy\t%1", operands
);
3431 case HARD_SP_REGNUM
:
3432 if (D_REG_P (operands
[1]))
3434 m68hc11_notice_keep_cc (operands
[0]);
3435 output_asm_insn ("xgdx", operands
);
3436 output_asm_insn ("txs", operands
);
3437 output_asm_insn ("xgdx", operands
);
3439 else if (X_REG_P (operands
[1]))
3441 /* tys, txs preserve the flags */
3442 cc_status
= cc_prev_status
;
3443 output_asm_insn ("txs", operands
);
3445 else if (Y_REG_P (operands
[1]))
3447 /* tys, txs preserve the flags */
3448 cc_status
= cc_prev_status
;
3449 output_asm_insn ("tys", operands
);
3453 /* lds sets the flags but the des does not. */
3455 output_asm_insn ("lds\t%1", operands
);
3456 output_asm_insn ("des", operands
);
3461 fatal_insn ("invalid register in the move instruction", insn
);
3466 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3467 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3469 output_asm_insn ("sts\t%0", operands
);
3473 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3475 cc_status
= cc_prev_status
;
3476 switch (REGNO (operands
[1]))
3480 output_asm_insn ("psh%1", operands
);
3483 output_asm_insn ("pshb", operands
);
3484 output_asm_insn ("psha", operands
);
3492 /* Operand 1 must be a hard register. */
3493 if (!H_REG_P (operands
[1]))
3495 fatal_insn ("invalid operand in the instruction", insn
);
3498 reg
= REGNO (operands
[1]);
3502 output_asm_insn ("std\t%0", operands
);
3506 output_asm_insn ("stx\t%0", operands
);
3510 output_asm_insn ("sty\t%0", operands
);
3513 case HARD_SP_REGNUM
:
3517 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3519 output_asm_insn ("pshx", operands
);
3520 output_asm_insn ("tsx", operands
);
3521 output_asm_insn ("inx", operands
);
3522 output_asm_insn ("inx", operands
);
3523 output_asm_insn ("stx\t%0", operands
);
3524 output_asm_insn ("pulx", operands
);
3527 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3529 output_asm_insn ("sty\t%t0", operands
);
3530 output_asm_insn ("tsy", operands
);
3531 output_asm_insn ("sty\t%0", operands
);
3532 output_asm_insn ("ldy\t%t0", operands
);
3536 output_asm_insn ("stx\t%t0", operands
);
3537 output_asm_insn ("tsx", operands
);
3538 output_asm_insn ("stx\t%0", operands
);
3539 output_asm_insn ("ldx\t%t0", operands
);
3545 fatal_insn ("invalid register in the move instruction", insn
);
3551 m68hc11_gen_movqi (insn
, operands
)
3555 /* Move a register or memory to the same location.
3556 This is possible because such insn can appear
3557 in a non-optimizing mode. */
3558 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3560 cc_status
= cc_prev_status
;
3567 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3569 m68hc11_notice_keep_cc (operands
[0]);
3570 output_asm_insn ("tfr\t%1,%0", operands
);
3572 else if (H_REG_P (operands
[0]))
3574 if (Q_REG_P (operands
[0]))
3575 output_asm_insn ("lda%0\t%b1", operands
);
3576 else if (D_REG_P (operands
[0]))
3577 output_asm_insn ("ldab\t%b1", operands
);
3581 else if (H_REG_P (operands
[1]))
3583 if (Q_REG_P (operands
[1]))
3584 output_asm_insn ("sta%1\t%b0", operands
);
3585 else if (D_REG_P (operands
[1]))
3586 output_asm_insn ("stab\t%b0", operands
);
3592 rtx from
= operands
[1];
3593 rtx to
= operands
[0];
3595 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3596 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3597 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3598 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3604 ops
[0] = operands
[2];
3607 m68hc11_gen_movqi (insn
, ops
);
3609 ops
[1] = operands
[2];
3610 m68hc11_gen_movqi (insn
, ops
);
3614 /* !!!! SCz wrong here. */
3615 fatal_insn ("move insn not handled", insn
);
3620 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3622 output_asm_insn ("clr\t%b0", operands
);
3626 m68hc11_notice_keep_cc (operands
[0]);
3627 output_asm_insn ("movb\t%b1,%b0", operands
);
3635 if (H_REG_P (operands
[0]))
3637 switch (REGNO (operands
[0]))
3641 if (X_REG_P (operands
[1]))
3643 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3645 m68hc11_output_swap (insn
, operands
);
3649 output_asm_insn ("stx\t%t1", operands
);
3650 output_asm_insn ("ldab\t%T0", operands
);
3653 else if (Y_REG_P (operands
[1]))
3655 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3657 m68hc11_output_swap (insn
, operands
);
3661 output_asm_insn ("sty\t%t1", operands
);
3662 output_asm_insn ("ldab\t%T0", operands
);
3665 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3666 && !DA_REG_P (operands
[1]))
3668 output_asm_insn ("ldab\t%b1", operands
);
3670 else if (DA_REG_P (operands
[1]))
3672 output_asm_insn ("tab", operands
);
3676 cc_status
= cc_prev_status
;
3682 if (X_REG_P (operands
[1]))
3684 output_asm_insn ("stx\t%t1", operands
);
3685 output_asm_insn ("ldaa\t%T0", operands
);
3687 else if (Y_REG_P (operands
[1]))
3689 output_asm_insn ("sty\t%t1", operands
);
3690 output_asm_insn ("ldaa\t%T0", operands
);
3692 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3693 && !DA_REG_P (operands
[1]))
3695 output_asm_insn ("ldaa\t%b1", operands
);
3697 else if (!DA_REG_P (operands
[1]))
3699 output_asm_insn ("tba", operands
);
3703 cc_status
= cc_prev_status
;
3708 if (D_REG_P (operands
[1]))
3710 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3712 m68hc11_output_swap (insn
, operands
);
3716 output_asm_insn ("stab\t%T1", operands
);
3717 output_asm_insn ("ldx\t%t1", operands
);
3721 else if (Y_REG_P (operands
[1]))
3723 output_asm_insn ("sty\t%t0", operands
);
3724 output_asm_insn ("ldx\t%t0", operands
);
3726 else if (GET_CODE (operands
[1]) == CONST_INT
)
3728 output_asm_insn ("ldx\t%1", operands
);
3730 else if (dead_register_here (insn
, d_reg
))
3732 output_asm_insn ("ldab\t%b1", operands
);
3733 output_asm_insn ("xgdx", operands
);
3735 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3737 output_asm_insn ("xgdx", operands
);
3738 output_asm_insn ("ldab\t%b1", operands
);
3739 output_asm_insn ("xgdx", operands
);
3743 output_asm_insn ("pshb", operands
);
3744 output_asm_insn ("ldab\t%b1", operands
);
3745 output_asm_insn ("stab\t%T1", operands
);
3746 output_asm_insn ("ldx\t%t1", operands
);
3747 output_asm_insn ("pulb", operands
);
3753 if (D_REG_P (operands
[1]))
3755 output_asm_insn ("stab\t%T1", operands
);
3756 output_asm_insn ("ldy\t%t1", operands
);
3759 else if (X_REG_P (operands
[1]))
3761 output_asm_insn ("stx\t%t1", operands
);
3762 output_asm_insn ("ldy\t%t1", operands
);
3765 else if (GET_CODE (operands
[1]) == CONST_INT
)
3767 output_asm_insn ("ldy\t%1", operands
);
3769 else if (dead_register_here (insn
, d_reg
))
3771 output_asm_insn ("ldab\t%b1", operands
);
3772 output_asm_insn ("xgdy", operands
);
3774 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3776 output_asm_insn ("xgdy", operands
);
3777 output_asm_insn ("ldab\t%b1", operands
);
3778 output_asm_insn ("xgdy", operands
);
3782 output_asm_insn ("pshb", operands
);
3783 output_asm_insn ("ldab\t%b1", operands
);
3784 output_asm_insn ("stab\t%T1", operands
);
3785 output_asm_insn ("ldy\t%t1", operands
);
3786 output_asm_insn ("pulb", operands
);
3792 fatal_insn ("invalid register in the instruction", insn
);
3796 else if (H_REG_P (operands
[1]))
3798 switch (REGNO (operands
[1]))
3802 output_asm_insn ("stab\t%b0", operands
);
3806 output_asm_insn ("staa\t%b0", operands
);
3810 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3814 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3818 fatal_insn ("invalid register in the move instruction", insn
);
3825 fatal_insn ("operand 1 must be a hard register", insn
);
3829 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3830 The source and destination must be D or A and the shift must
3833 m68hc11_gen_rotate (code
, insn
, operands
)
3840 if (GET_CODE (operands
[2]) != CONST_INT
3841 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3842 fatal_insn ("invalid rotate insn", insn
);
3844 val
= INTVAL (operands
[2]);
3845 if (code
== ROTATERT
)
3846 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3848 if (GET_MODE (operands
[0]) != QImode
)
3851 /* Rotate by 8-bits if the shift is within [5..11]. */
3852 if (val
>= 5 && val
<= 11)
3855 output_asm_insn ("exg\ta,b", operands
);
3858 output_asm_insn ("psha", operands
);
3859 output_asm_insn ("tba", operands
);
3860 output_asm_insn ("pulb", operands
);
3865 /* If the shift is big, invert the rotation. */
3873 /* Set the carry to bit-15, but don't change D yet. */
3874 if (GET_MODE (operands
[0]) != QImode
)
3876 output_asm_insn ("asra", operands
);
3877 output_asm_insn ("rola", operands
);
3882 /* Rotate B first to move the carry to bit-0. */
3883 if (D_REG_P (operands
[0]))
3884 output_asm_insn ("rolb", operands
);
3886 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3887 output_asm_insn ("rola", operands
);
3892 /* Set the carry to bit-8 of D. */
3893 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3895 output_asm_insn ("tap", operands
);
3900 /* Rotate B first to move the carry to bit-7. */
3901 if (D_REG_P (operands
[0]))
3902 output_asm_insn ("rorb", operands
);
3904 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3905 output_asm_insn ("rora", operands
);
3912 /* Store in cc_status the expressions that the condition codes will
3913 describe after execution of an instruction whose pattern is EXP.
3914 Do not alter them if the instruction would not alter the cc's. */
3917 m68hc11_notice_update_cc (exp
, insn
)
3919 rtx insn ATTRIBUTE_UNUSED
;
3921 /* recognize SET insn's. */
3922 if (GET_CODE (exp
) == SET
)
3924 /* Jumps do not alter the cc's. */
3925 if (SET_DEST (exp
) == pc_rtx
)
3928 /* NOTE: most instructions don't affect the carry bit, but the
3929 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3930 the conditions.h header. */
3932 /* Function calls clobber the cc's. */
3933 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3938 /* Tests and compares set the cc's in predictable ways. */
3939 else if (SET_DEST (exp
) == cc0_rtx
)
3941 cc_status
.flags
= 0;
3942 cc_status
.value1
= XEXP (exp
, 0);
3943 cc_status
.value2
= XEXP (exp
, 1);
3947 /* All other instructions affect the condition codes. */
3948 cc_status
.flags
= 0;
3949 cc_status
.value1
= XEXP (exp
, 0);
3950 cc_status
.value2
= XEXP (exp
, 1);
3955 /* Default action if we haven't recognized something
3956 and returned earlier. */
3960 if (cc_status
.value2
!= 0)
3961 switch (GET_CODE (cc_status
.value2
))
3963 /* These logical operations can generate several insns.
3964 The flags are setup according to what is generated. */
3970 /* The (not ...) generates several 'com' instructions for
3971 non QImode. We have to invalidate the flags. */
3973 if (GET_MODE (cc_status
.value2
) != QImode
)
3985 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3986 cc_status
.flags
|= CC_NO_OVERFLOW
;
3989 /* The asl sets the overflow bit in such a way that this
3990 makes the flags unusable for a next compare insn. */
3994 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3995 cc_status
.flags
|= CC_NO_OVERFLOW
;
3998 /* A load/store instruction does not affect the carry. */
4003 cc_status
.flags
|= CC_NO_OVERFLOW
;
4009 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4011 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4012 cc_status
.value2
= 0;
4015 /* The current instruction does not affect the flags but changes
4016 the register 'reg'. See if the previous flags can be kept for the
4017 next instruction to avoid a comparison. */
4019 m68hc11_notice_keep_cc (reg
)
4023 || cc_prev_status
.value1
== 0
4024 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4025 || (cc_prev_status
.value2
4026 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4029 cc_status
= cc_prev_status
;
4034 /* Machine Specific Reorg. */
4036 /* Z register replacement:
4038 GCC treats the Z register as an index base address register like
4039 X or Y. In general, it uses it during reload to compute the address
4040 of some operand. This helps the reload pass to avoid to fall into the
4041 register spill failure.
4043 The Z register is in the A_REGS class. In the machine description,
4044 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4046 It can appear everywhere an X or Y register can appear, except for
4047 some templates in the clobber section (when a clobber of X or Y is asked).
4048 For a given instruction, the template must ensure that no more than
4049 2 'A' registers are used. Otherwise, the register replacement is not
4052 To replace the Z register, the algorithm is not terrific:
4053 1. Insns that do not use the Z register are not changed
4054 2. When a Z register is used, we scan forward the insns to see
4055 a potential register to use: either X or Y and sometimes D.
4056 We stop when a call, a label or a branch is seen, or when we
4057 detect that both X and Y are used (probably at different times, but it does
4059 3. The register that will be used for the replacement of Z is saved
4060 in a .page0 register or on the stack. If the first instruction that
4061 used Z, uses Z as an input, the value is loaded from another .page0
4062 register. The replacement register is pushed on the stack in the
4063 rare cases where a compare insn uses Z and we couldn't find if X/Y
4065 4. The Z register is replaced in all instructions until we reach
4066 the end of the Z-block, as detected by step 2.
4067 5. If we detect that Z is still alive, its value is saved.
4068 If the replacement register is alive, its old value is loaded.
4070 The Z register can be disabled with -ffixed-z.
4080 int must_restore_reg
;
4091 int save_before_last
;
4092 int z_loaded_with_sp
;
4097 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4098 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4099 static void m68hc11_z_replacement
PARAMS ((rtx
));
4100 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4102 int z_replacement_completed
= 0;
4104 /* Analyze the insn to find out which replacement register to use and
4105 the boundaries of the replacement.
4106 Returns 0 if we reached the last insn to be replaced, 1 if we can
4107 continue replacement in next insns. */
4110 m68hc11_check_z_replacement (insn
, info
)
4112 struct replace_info
*info
;
4114 int this_insn_uses_ix
;
4115 int this_insn_uses_iy
;
4116 int this_insn_uses_z
;
4117 int this_insn_uses_z_in_dst
;
4118 int this_insn_uses_d
;
4122 /* A call is said to clobber the Z register, we don't need
4123 to save the value of Z. We also don't need to restore
4124 the replacement register (unless it is used by the call). */
4125 if (GET_CODE (insn
) == CALL_INSN
)
4127 body
= PATTERN (insn
);
4129 info
->can_use_d
= 0;
4131 /* If the call is an indirect call with Z, we have to use the
4132 Y register because X can be used as an input (D+X).
4133 We also must not save Z nor restore Y. */
4134 if (reg_mentioned_p (z_reg
, body
))
4136 insn
= NEXT_INSN (insn
);
4139 info
->found_call
= 1;
4140 info
->must_restore_reg
= 0;
4141 info
->last
= NEXT_INSN (insn
);
4143 info
->need_save_z
= 0;
4146 if (GET_CODE (insn
) == CODE_LABEL
4147 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4150 if (GET_CODE (insn
) == JUMP_INSN
)
4152 if (reg_mentioned_p (z_reg
, insn
) == 0)
4155 info
->can_use_d
= 0;
4156 info
->must_save_reg
= 0;
4157 info
->must_restore_reg
= 0;
4158 info
->need_save_z
= 0;
4159 info
->last
= NEXT_INSN (insn
);
4162 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4167 /* Z register dies here. */
4168 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4170 body
= PATTERN (insn
);
4171 if (GET_CODE (body
) == SET
)
4173 rtx src
= XEXP (body
, 1);
4174 rtx dst
= XEXP (body
, 0);
4176 /* Condition code is set here. We have to restore the X/Y and
4177 save into Z before any test/compare insn because once we save/restore
4178 we can change the condition codes. When the compare insn uses Z and
4179 we can't use X/Y, the comparison is made with the *ZREG soft register
4180 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4183 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4184 || (GET_CODE (src
) == COMPARE
&&
4185 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4186 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4188 if (insn
== info
->first
)
4190 info
->must_load_z
= 0;
4191 info
->must_save_reg
= 0;
4192 info
->must_restore_reg
= 0;
4193 info
->need_save_z
= 0;
4194 info
->found_call
= 1;
4195 info
->regno
= SOFT_Z_REGNUM
;
4200 if (reg_mentioned_p (z_reg
, src
) == 0)
4202 info
->can_use_d
= 0;
4206 if (insn
!= info
->first
)
4209 /* Compare insn which uses Z. We have to save/restore the X/Y
4210 register without modifying the condition codes. For this
4211 we have to use a push/pop insn. */
4212 info
->must_push_reg
= 1;
4216 /* Z reg is set to something new. We don't need to load it. */
4219 if (!reg_mentioned_p (z_reg
, src
))
4221 /* Z reg is used before being set. Treat this as
4222 a new sequence of Z register replacement. */
4223 if (insn
!= info
->first
)
4227 info
->must_load_z
= 0;
4229 info
->z_set_count
++;
4230 info
->z_value
= src
;
4232 info
->z_loaded_with_sp
= 1;
4234 else if (reg_mentioned_p (z_reg
, dst
))
4235 info
->can_use_d
= 0;
4237 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4238 | reg_mentioned_p (d_reg
, dst
);
4239 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4240 | reg_mentioned_p (ix_reg
, dst
);
4241 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4242 | reg_mentioned_p (iy_reg
, dst
);
4243 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4245 /* If z is used as an address operand (like (MEM (reg z))),
4246 we can't replace it with d. */
4247 if (this_insn_uses_z
&& !Z_REG_P (src
)
4248 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4249 && Z_REG_P (XEXP (src
, 0))
4250 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4251 && insn
== info
->first
4252 && dead_register_here (insn
, d_reg
)))
4253 info
->can_use_d
= 0;
4255 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4256 if (TARGET_M6812
&& !z_dies_here
4257 && ((this_insn_uses_z
&& side_effects_p (src
))
4258 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4260 info
->need_save_z
= 1;
4261 info
->z_set_count
++;
4263 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4265 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4267 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4270 if (this_insn_uses_d
)
4271 info
->can_use_d
= 0;
4273 /* IX and IY are used at the same time, we have to restore
4274 the value of the scratch register before this insn. */
4275 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4280 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4281 info
->can_use_d
= 0;
4283 if (info
->x_used
== 0 && this_insn_uses_ix
)
4287 /* We have a (set (REG:HI X) (REG:HI Z)).
4288 Since we use Z as the replacement register, this insn
4289 is no longer necessary. We turn it into a note. We must
4290 not reload the old value of X. */
4291 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4295 info
->need_save_z
= 0;
4298 info
->must_save_reg
= 0;
4299 info
->must_restore_reg
= 0;
4300 info
->found_call
= 1;
4301 info
->can_use_d
= 0;
4302 PUT_CODE (insn
, NOTE
);
4303 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4304 NOTE_SOURCE_FILE (insn
) = 0;
4305 info
->last
= NEXT_INSN (insn
);
4310 && (rtx_equal_p (src
, z_reg
)
4311 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4315 info
->need_save_z
= 0;
4318 info
->last
= NEXT_INSN (insn
);
4319 info
->must_save_reg
= 0;
4320 info
->must_restore_reg
= 0;
4322 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4323 && !reg_mentioned_p (ix_reg
, src
))
4328 info
->need_save_z
= 0;
4332 info
->save_before_last
= 1;
4334 info
->must_restore_reg
= 0;
4335 info
->last
= NEXT_INSN (insn
);
4337 else if (info
->can_use_d
)
4339 info
->last
= NEXT_INSN (insn
);
4345 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4346 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4348 info
->need_save_z
= 0;
4350 info
->last
= NEXT_INSN (insn
);
4351 info
->regno
= HARD_X_REGNUM
;
4352 info
->must_save_reg
= 0;
4353 info
->must_restore_reg
= 0;
4356 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4358 info
->regno
= HARD_X_REGNUM
;
4359 info
->must_restore_reg
= 0;
4360 info
->must_save_reg
= 0;
4364 if (info
->y_used
== 0 && this_insn_uses_iy
)
4368 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4372 info
->need_save_z
= 0;
4375 info
->must_save_reg
= 0;
4376 info
->must_restore_reg
= 0;
4377 info
->found_call
= 1;
4378 info
->can_use_d
= 0;
4379 PUT_CODE (insn
, NOTE
);
4380 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4381 NOTE_SOURCE_FILE (insn
) = 0;
4382 info
->last
= NEXT_INSN (insn
);
4387 && (rtx_equal_p (src
, z_reg
)
4388 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4393 info
->need_save_z
= 0;
4395 info
->last
= NEXT_INSN (insn
);
4396 info
->must_save_reg
= 0;
4397 info
->must_restore_reg
= 0;
4399 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4400 && !reg_mentioned_p (iy_reg
, src
))
4405 info
->need_save_z
= 0;
4409 info
->save_before_last
= 1;
4411 info
->must_restore_reg
= 0;
4412 info
->last
= NEXT_INSN (insn
);
4414 else if (info
->can_use_d
)
4416 info
->last
= NEXT_INSN (insn
);
4423 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4424 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4426 info
->need_save_z
= 0;
4428 info
->last
= NEXT_INSN (insn
);
4429 info
->regno
= HARD_Y_REGNUM
;
4430 info
->must_save_reg
= 0;
4431 info
->must_restore_reg
= 0;
4434 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4436 info
->regno
= HARD_Y_REGNUM
;
4437 info
->must_restore_reg
= 0;
4438 info
->must_save_reg
= 0;
4444 info
->need_save_z
= 0;
4446 if (info
->last
== 0)
4447 info
->last
= NEXT_INSN (insn
);
4450 return info
->last
!= NULL_RTX
? 0 : 1;
4452 if (GET_CODE (body
) == PARALLEL
)
4455 char ix_clobber
= 0;
4456 char iy_clobber
= 0;
4458 this_insn_uses_iy
= 0;
4459 this_insn_uses_ix
= 0;
4460 this_insn_uses_z
= 0;
4462 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4465 int uses_ix
, uses_iy
, uses_z
;
4467 x
= XVECEXP (body
, 0, i
);
4469 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4470 info
->can_use_d
= 0;
4472 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4473 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4474 uses_z
= reg_mentioned_p (z_reg
, x
);
4475 if (GET_CODE (x
) == CLOBBER
)
4477 ix_clobber
|= uses_ix
;
4478 iy_clobber
|= uses_iy
;
4479 z_clobber
|= uses_z
;
4483 this_insn_uses_ix
|= uses_ix
;
4484 this_insn_uses_iy
|= uses_iy
;
4485 this_insn_uses_z
|= uses_z
;
4487 if (uses_z
&& GET_CODE (x
) == SET
)
4489 rtx dst
= XEXP (x
, 0);
4492 info
->z_set_count
++;
4494 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4495 info
->need_save_z
= 1;
4498 info
->need_save_z
= 0;
4502 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4503 this_insn_uses_ix
, this_insn_uses_iy
,
4504 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4507 if (this_insn_uses_z
)
4508 info
->can_use_d
= 0;
4510 if (z_clobber
&& info
->first
!= insn
)
4512 info
->need_save_z
= 0;
4516 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4518 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4520 info
->must_load_z
= 0;
4522 if (dead_register_here (insn
, d_reg
))
4524 info
->regno
= HARD_D_REGNUM
;
4525 info
->must_save_reg
= 0;
4526 info
->must_restore_reg
= 0;
4528 else if (dead_register_here (insn
, ix_reg
))
4530 info
->regno
= HARD_X_REGNUM
;
4531 info
->must_save_reg
= 0;
4532 info
->must_restore_reg
= 0;
4534 else if (dead_register_here (insn
, iy_reg
))
4536 info
->regno
= HARD_Y_REGNUM
;
4537 info
->must_save_reg
= 0;
4538 info
->must_restore_reg
= 0;
4540 if (info
->regno
>= 0)
4542 info
->last
= NEXT_INSN (insn
);
4545 if (this_insn_uses_ix
== 0)
4547 info
->regno
= HARD_X_REGNUM
;
4548 info
->must_save_reg
= 1;
4549 info
->must_restore_reg
= 1;
4551 else if (this_insn_uses_iy
== 0)
4553 info
->regno
= HARD_Y_REGNUM
;
4554 info
->must_save_reg
= 1;
4555 info
->must_restore_reg
= 1;
4559 info
->regno
= HARD_D_REGNUM
;
4560 info
->must_save_reg
= 1;
4561 info
->must_restore_reg
= 1;
4563 info
->last
= NEXT_INSN (insn
);
4567 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4568 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4570 if (this_insn_uses_z
)
4572 if (info
->y_used
== 0 && iy_clobber
)
4574 info
->regno
= HARD_Y_REGNUM
;
4575 info
->must_save_reg
= 0;
4576 info
->must_restore_reg
= 0;
4578 if (info
->first
!= insn
4579 && ((info
->y_used
&& ix_clobber
)
4580 || (info
->x_used
&& iy_clobber
)))
4583 info
->last
= NEXT_INSN (insn
);
4584 info
->save_before_last
= 1;
4588 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4590 if (this_insn_uses_z
)
4592 fatal_insn ("cannot do z-register replacement", insn
);
4596 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4603 if (iy_clobber
|| z_clobber
)
4605 info
->last
= NEXT_INSN (insn
);
4606 info
->save_before_last
= 1;
4611 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4618 if (ix_clobber
|| z_clobber
)
4620 info
->last
= NEXT_INSN (insn
);
4621 info
->save_before_last
= 1;
4628 info
->need_save_z
= 0;
4632 if (GET_CODE (body
) == CLOBBER
)
4635 /* IX and IY are used at the same time, we have to restore
4636 the value of the scratch register before this insn. */
4637 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4641 if (info
->x_used
== 0 && this_insn_uses_ix
)
4649 if (info
->y_used
== 0 && this_insn_uses_iy
)
4663 m68hc11_find_z_replacement (insn
, info
)
4665 struct replace_info
*info
;
4669 info
->replace_reg
= NULL_RTX
;
4670 info
->must_load_z
= 1;
4671 info
->need_save_z
= 1;
4672 info
->must_save_reg
= 1;
4673 info
->must_restore_reg
= 1;
4677 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4678 info
->found_call
= 0;
4682 info
->z_set_count
= 0;
4683 info
->z_value
= NULL_RTX
;
4684 info
->must_push_reg
= 0;
4685 info
->save_before_last
= 0;
4686 info
->z_loaded_with_sp
= 0;
4688 /* Scan the insn forward to find an address register that is not used.
4690 - the flow of the program changes,
4691 - when we detect that both X and Y are necessary,
4692 - when the Z register dies,
4693 - when the condition codes are set. */
4695 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4697 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4701 /* May be we can use Y or X if they contain the same value as Z.
4702 This happens very often after the reload. */
4703 if (info
->z_set_count
== 1)
4705 rtx p
= info
->first
;
4710 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4712 else if (info
->y_used
)
4714 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4716 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4719 info
->regno
= HARD_Y_REGNUM
;
4721 info
->regno
= HARD_X_REGNUM
;
4722 info
->must_load_z
= 0;
4723 info
->must_save_reg
= 0;
4724 info
->must_restore_reg
= 0;
4725 info
->found_call
= 1;
4728 if (info
->z_set_count
== 0)
4729 info
->need_save_z
= 0;
4732 info
->need_save_z
= 0;
4734 if (info
->last
== 0)
4737 if (info
->regno
>= 0)
4740 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4742 else if (info
->can_use_d
)
4744 reg
= HARD_D_REGNUM
;
4745 info
->replace_reg
= d_reg
;
4747 else if (info
->x_used
)
4749 reg
= HARD_Y_REGNUM
;
4750 info
->replace_reg
= iy_reg
;
4754 reg
= HARD_X_REGNUM
;
4755 info
->replace_reg
= ix_reg
;
4759 if (info
->must_save_reg
&& info
->must_restore_reg
)
4761 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4763 info
->must_save_reg
= 0;
4764 info
->must_restore_reg
= 0;
4769 /* The insn uses the Z register. Find a replacement register for it
4770 (either X or Y) and replace it in the insn and the next ones until
4771 the flow changes or the replacement register is used. Instructions
4772 are emited before and after the Z-block to preserve the value of
4773 Z and of the replacement register. */
4776 m68hc11_z_replacement (insn
)
4781 struct replace_info info
;
4783 /* Find trivial case where we only need to replace z with the
4784 equivalent soft register. */
4785 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4787 rtx body
= PATTERN (insn
);
4788 rtx src
= XEXP (body
, 1);
4789 rtx dst
= XEXP (body
, 0);
4791 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4793 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4796 else if (Z_REG_P (src
)
4797 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4799 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4802 else if (D_REG_P (dst
)
4803 && m68hc11_arith_operator (src
, GET_MODE (src
))
4804 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4806 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4809 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4810 && INTVAL (src
) == 0)
4812 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4813 /* Force it to be re-recognized. */
4814 INSN_CODE (insn
) = -1;
4819 m68hc11_find_z_replacement (insn
, &info
);
4821 replace_reg
= info
.replace_reg
;
4822 replace_reg_qi
= NULL_RTX
;
4824 /* Save the X register in a .page0 location. */
4825 if (info
.must_save_reg
&& !info
.must_push_reg
)
4829 if (info
.must_push_reg
&& 0)
4830 dst
= gen_rtx (MEM
, HImode
,
4831 gen_rtx (PRE_DEC
, HImode
,
4832 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4834 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4836 emit_insn_before (gen_movhi (dst
,
4837 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4839 if (info
.must_load_z
&& !info
.must_push_reg
)
4841 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4842 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4847 /* Replace all occurrence of Z by replace_reg.
4848 Stop when the last instruction to replace is reached.
4849 Also stop when we detect a change in the flow (but it's not
4850 necessary; just safeguard). */
4852 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4856 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4859 if (GET_CODE (insn
) != INSN
4860 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4863 body
= PATTERN (insn
);
4864 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4865 || GET_CODE (body
) == ASM_OPERANDS
4866 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4870 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4872 printf ("Reg mentioned here...:\n");
4877 /* Stack pointer was decremented by 2 due to the push.
4878 Correct that by adding 2 to the destination. */
4879 if (info
.must_push_reg
4880 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4884 src
= SET_SRC (body
);
4885 dst
= SET_DEST (body
);
4886 if (SP_REG_P (src
) && Z_REG_P (dst
))
4887 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4890 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4891 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4893 INSN_CODE (insn
) = -1;
4894 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4895 fatal_insn ("cannot do z-register replacement", insn
);
4898 /* Likewise for (REG:QI Z). */
4899 if (reg_mentioned_p (z_reg
, insn
))
4901 if (replace_reg_qi
== NULL_RTX
)
4902 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4903 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4906 /* If there is a REG_INC note on Z, replace it with a
4907 REG_INC note on the replacement register. This is necessary
4908 to make sure that the flow pass will identify the change
4909 and it will not remove a possible insn that saves Z. */
4910 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4912 if (REG_NOTE_KIND (note
) == REG_INC
4913 && GET_CODE (XEXP (note
, 0)) == REG
4914 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4916 XEXP (note
, 0) = replace_reg
;
4920 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4924 /* Save Z before restoring the old value. */
4925 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4927 rtx save_pos_insn
= insn
;
4929 /* If Z is clobber by the last insn, we have to save its value
4930 before the last instruction. */
4931 if (info
.save_before_last
)
4932 save_pos_insn
= PREV_INSN (save_pos_insn
);
4934 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4935 gen_rtx (REG
, HImode
, info
.regno
)),
4939 if (info
.must_push_reg
&& info
.last
)
4943 body
= PATTERN (info
.last
);
4944 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4946 gen_rtx (USE
, VOIDmode
,
4948 gen_rtx (USE
, VOIDmode
,
4949 gen_rtx (REG
, HImode
,
4951 PATTERN (info
.last
) = new_body
;
4953 /* Force recognition on insn since we changed it. */
4954 INSN_CODE (insn
) = -1;
4956 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4958 fatal_insn ("invalid Z register replacement for insn", insn
);
4960 insn
= NEXT_INSN (info
.last
);
4963 /* Restore replacement register unless it was died. */
4964 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4968 if (info
.must_push_reg
&& 0)
4969 dst
= gen_rtx (MEM
, HImode
,
4970 gen_rtx (POST_INC
, HImode
,
4971 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4973 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4975 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4982 /* Scan all the insn and re-affects some registers
4983 - The Z register (if it was used), is affected to X or Y depending
4984 on the instruction. */
4987 m68hc11_reassign_regs (first
)
4992 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
4993 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
4994 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
4995 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
4997 /* Scan all insns to replace Z by X or Y preserving the old value
4998 of X/Y and restoring it afterward. */
5000 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5004 if (GET_CODE (insn
) == CODE_LABEL
5005 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5008 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5011 body
= PATTERN (insn
);
5012 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5015 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5016 || GET_CODE (body
) == ASM_OPERANDS
5017 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5020 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5021 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5024 /* If Z appears in this insn, replace it in the current insn
5025 and the next ones until the flow changes or we have to
5026 restore back the replacement register. */
5028 if (reg_mentioned_p (z_reg
, body
))
5030 m68hc11_z_replacement (insn
);
5035 printf ("insn not handled by Z replacement:\n");
5044 m68hc11_reorg (first
)
5050 z_replacement_completed
= 0;
5051 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5053 /* Some RTX are shared at this point. This breaks the Z register
5054 replacement, unshare everything. */
5055 unshare_all_rtl_again (first
);
5057 /* Force a split of all splitable insn. This is necessary for the
5058 Z register replacement mechanism because we end up with basic insns. */
5059 split_all_insns_noflow ();
5062 z_replacement_completed
= 1;
5063 m68hc11_reassign_regs (first
);
5066 compute_bb_for_insn ();
5068 /* After some splitting, there are some oportunities for CSE pass.
5069 This happens quite often when 32-bit or above patterns are split. */
5070 if (optimize
> 0 && split_done
)
5072 reload_cse_regs (first
);
5075 /* Re-create the REG_DEAD notes. These notes are used in the machine
5076 description to use the best assembly directives. */
5079 /* Before recomputing the REG_DEAD notes, remove all of them.
5080 This is necessary because the reload_cse_regs() pass can
5081 have replaced some (MEM) with a register. In that case,
5082 the REG_DEAD that could exist for that register may become
5084 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5090 pnote
= ®_NOTES (insn
);
5093 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5094 *pnote
= XEXP (*pnote
, 1);
5096 pnote
= &XEXP (*pnote
, 1);
5101 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5104 z_replacement_completed
= 2;
5106 /* If optimizing, then go ahead and split insns that must be
5107 split after Z register replacement. This gives more opportunities
5108 for peephole (in particular for consecutives xgdx/xgdy). */
5110 split_all_insns_noflow ();
5112 /* Once insns are split after the z_replacement_completed == 2,
5113 we must not re-run the life_analysis. The xgdx/xgdy patterns
5114 are not recognized and the life_analysis pass removes some
5115 insns because it thinks some (SETs) are noops or made to dead
5116 stores (which is false due to the swap).
5118 Do a simple pass to eliminate the noop set that the final
5119 split could generate (because it was easier for split definition). */
5123 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5127 if (INSN_DELETED_P (insn
))
5129 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5132 /* Remove the (set (R) (R)) insns generated by some splits. */
5133 body
= PATTERN (insn
);
5134 if (GET_CODE (body
) == SET
5135 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5137 PUT_CODE (insn
, NOTE
);
5138 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5139 NOTE_SOURCE_FILE (insn
) = 0;
5147 /* Cost functions. */
5149 /* Cost of moving memory. */
5151 m68hc11_memory_move_cost (mode
, class, in
)
5152 enum machine_mode mode
;
5153 enum reg_class
class;
5154 int in ATTRIBUTE_UNUSED
;
5156 if (class <= H_REGS
&& class > NO_REGS
)
5158 if (GET_MODE_SIZE (mode
) <= 2)
5159 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5161 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5165 if (GET_MODE_SIZE (mode
) <= 2)
5166 return COSTS_N_INSNS (2);
5168 return COSTS_N_INSNS (4);
5173 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5174 Reload does not check the constraint of set insns when the two registers
5175 have a move cost of 2. Setting a higher cost will force reload to check
5178 m68hc11_register_move_cost (mode
, from
, to
)
5179 enum machine_mode mode
;
5180 enum reg_class from
;
5183 /* All costs are symmetric, so reduce cases by putting the
5184 lower number class as the destination. */
5187 enum reg_class tmp
= to
;
5188 to
= from
, from
= tmp
;
5191 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5192 else if (from
<= S_REGS
)
5193 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5195 return COSTS_N_INSNS (2);
5199 /* Provide the costs of an addressing mode that contains ADDR.
5200 If ADDR is not a valid address, its cost is irrelevant. */
5203 m68hc11_address_cost (addr
)
5208 switch (GET_CODE (addr
))
5211 /* Make the cost of hard registers and specially SP, FP small. */
5212 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5229 register rtx plus0
= XEXP (addr
, 0);
5230 register rtx plus1
= XEXP (addr
, 1);
5232 if (GET_CODE (plus0
) != REG
)
5235 switch (GET_CODE (plus1
))
5238 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5239 || INTVAL (plus1
) < m68hc11_min_offset
)
5241 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5245 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5267 if (SP_REG_P (XEXP (addr
, 0)))
5276 printf ("Address cost: %d for :", cost
);
5285 m68hc11_shift_cost (mode
, x
, shift
)
5286 enum machine_mode mode
;
5292 total
= rtx_cost (x
, SET
);
5294 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5295 else if (mode
== HImode
)
5296 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5297 else if (shift
== 8 || shift
== 16 || shift
== 32)
5298 total
+= m68hc11_cost
->shiftHI_const
[8];
5299 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5301 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5304 /* For SI and others, the cost is higher. */
5305 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5306 total
*= GET_MODE_SIZE (mode
) / 2;
5308 /* When optimizing for size, make shift more costly so that
5309 multiplications are preferred. */
5310 if (optimize_size
&& (shift
% 8) != 0)
5317 m68hc11_rtx_costs (x
, code
, outer_code
)
5320 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5322 enum machine_mode mode
= GET_MODE (x
);
5333 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5335 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5338 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5339 total
+= m68hc11_cost
->shift_var
;
5345 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5346 total
+= m68hc11_cost
->logical
;
5348 /* Logical instructions are byte instructions only. */
5349 total
*= GET_MODE_SIZE (mode
);
5354 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5355 total
+= m68hc11_cost
->add
;
5356 if (GET_MODE_SIZE (mode
) > 2)
5358 total
*= GET_MODE_SIZE (mode
) / 2;
5365 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5369 total
+= m68hc11_cost
->divQI
;
5373 total
+= m68hc11_cost
->divHI
;
5378 total
+= m68hc11_cost
->divSI
;
5384 /* mul instruction produces 16-bit result. */
5385 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5386 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5387 return m68hc11_cost
->multQI
5388 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5389 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5391 /* emul instruction produces 32-bit result for 68HC12. */
5392 if (TARGET_M6812
&& mode
== SImode
5393 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5394 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5395 return m68hc11_cost
->multHI
5396 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5397 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5399 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5403 total
+= m68hc11_cost
->multQI
;
5407 total
+= m68hc11_cost
->multHI
;
5412 total
+= m68hc11_cost
->multSI
;
5419 extra_cost
= COSTS_N_INSNS (2);
5426 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5429 return total
+ COSTS_N_INSNS (1);
5433 return total
+ COSTS_N_INSNS (2);
5437 return total
+ COSTS_N_INSNS (4);
5439 return total
+ COSTS_N_INSNS (8);
5442 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5443 return COSTS_N_INSNS (1);
5445 return COSTS_N_INSNS (1);
5448 return COSTS_N_INSNS (4);
5453 /* print_options - called at the start of the code generation for a
5456 extern char *asm_file_name
;
5459 #include <sys/types.h>
5468 extern int save_argc
;
5469 extern char **save_argv
;
5471 fprintf (out
, ";;; Command:\t");
5472 for (i
= 0; i
< save_argc
; i
++)
5474 fprintf (out
, "%s", save_argv
[i
]);
5475 if (i
+ 1 < save_argc
)
5478 fprintf (out
, "\n");
5480 a_time
= ctime (&c_time
);
5481 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5484 #define __VERSION__ "[unknown]"
5486 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5488 fprintf (out
, ";;; (META)compiled by CC.\n");
5493 m68hc11_asm_file_start (out
, main_file
)
5495 const char *main_file
;
5497 fprintf (out
, ";;;-----------------------------------------\n");
5498 fprintf (out
, ";;; Start MC68HC11 gcc assembly output\n");
5499 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5500 print_options (out
);
5501 fprintf (out
, ";;;-----------------------------------------\n");
5502 output_file_directive (out
, main_file
);
5507 m68hc11_asm_out_constructor (symbol
, priority
)
5511 default_ctor_section_asm_out_constructor (symbol
, priority
);
5512 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5516 m68hc11_asm_out_destructor (symbol
, priority
)
5520 default_dtor_section_asm_out_destructor (symbol
, priority
);
5521 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");