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 /* Set to 1 when the current function is placed in 68HC12 banked
105 memory and must return with rtc. */
106 int current_function_far
;
108 /* Min offset that is valid for the indirect addressing mode. */
109 HOST_WIDE_INT m68hc11_min_offset
= 0;
111 /* Max offset that is valid for the indirect addressing mode. */
112 HOST_WIDE_INT m68hc11_max_offset
= 256;
114 /* The class value for base registers. */
115 enum reg_class m68hc11_base_reg_class
= A_REGS
;
117 /* The class value for index registers. This is NO_REGS for 68HC11. */
118 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
120 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
122 /* Tables that tell whether a given hard register is valid for
123 a base or an index register. It is filled at init time depending
124 on the target processor. */
125 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
126 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
128 /* A correction offset which is applied to the stack pointer.
129 This is 1 for 68HC11 and 0 for 68HC12. */
130 int m68hc11_sp_correction
;
132 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
133 rtx m68hc11_compare_op0
;
134 rtx m68hc11_compare_op1
;
137 const struct processor_costs
*m68hc11_cost
;
139 /* Costs for a 68HC11. */
140 static const struct processor_costs m6811_cost
= {
145 /* non-constant shift */
148 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
149 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
150 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
153 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
154 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
155 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
156 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
157 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
158 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
163 COSTS_N_INSNS (20 * 4),
165 COSTS_N_INSNS (20 * 16),
174 /* Costs for a 68HC12. */
175 static const struct processor_costs m6812_cost
= {
180 /* non-constant shift */
183 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
184 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
185 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
188 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
189 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
190 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
191 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
192 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
193 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
200 COSTS_N_INSNS (3 * 4),
209 /* Machine specific options */
211 const char *m68hc11_regparm_string
;
212 const char *m68hc11_reg_alloc_order
;
213 const char *m68hc11_soft_reg_count
;
215 static int nb_soft_regs
;
217 /* Initialize the GCC target structure. */
218 #undef TARGET_ATTRIBUTE_TABLE
219 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
221 #undef TARGET_ASM_ALIGNED_HI_OP
222 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
224 #undef TARGET_ASM_FUNCTION_EPILOGUE
225 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
227 #undef TARGET_ENCODE_SECTION_INFO
228 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
230 struct gcc_target targetm
= TARGET_INITIALIZER
;
233 m68hc11_override_options ()
235 memset (m68hc11_reg_valid_for_index
, 0,
236 sizeof (m68hc11_reg_valid_for_index
));
237 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
239 /* Compilation with -fpic generates a wrong code. */
242 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
243 (flag_pic
> 1) ? "PIC" : "pic");
247 /* Configure for a 68hc11 processor. */
250 /* If gcc was built for a 68hc12, invalidate that because
251 a -m68hc11 option was specified on the command line. */
252 if (TARGET_DEFAULT
!= MASK_M6811
)
253 target_flags
&= ~TARGET_DEFAULT
;
256 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
257 m68hc11_cost
= &m6811_cost
;
258 m68hc11_min_offset
= 0;
259 m68hc11_max_offset
= 256;
260 m68hc11_index_reg_class
= NO_REGS
;
261 m68hc11_base_reg_class
= A_REGS
;
262 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
263 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
264 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
265 m68hc11_sp_correction
= 1;
266 m68hc11_tmp_regs_class
= D_REGS
;
267 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
268 m68hc11_soft_reg_count
= "4";
271 /* Configure for a 68hc12 processor. */
274 m68hc11_cost
= &m6812_cost
;
275 m68hc11_min_offset
= -65536;
276 m68hc11_max_offset
= 65536;
277 m68hc11_index_reg_class
= D_REGS
;
278 m68hc11_base_reg_class
= A_OR_SP_REGS
;
279 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
280 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
281 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
282 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
283 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
284 m68hc11_sp_correction
= 0;
285 m68hc11_tmp_regs_class
= TMP_REGS
;
286 target_flags
&= ~MASK_M6811
;
287 target_flags
|= MASK_NO_DIRECT_MODE
| MASK_MIN_MAX
;
288 if (m68hc11_soft_reg_count
== 0)
289 m68hc11_soft_reg_count
= "0";
291 if (TARGET_LONG_CALLS
)
292 current_function_far
= 1;
299 m68hc11_conditional_register_usage ()
302 int cnt
= atoi (m68hc11_soft_reg_count
);
306 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
307 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
310 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
313 call_used_regs
[i
] = 1;
316 /* For 68HC12, the Z register emulation is not necessary when the
317 frame pointer is not used. The frame pointer is eliminated and
318 replaced by the stack register (which is a BASE_REG_CLASS). */
319 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
321 fixed_regs
[HARD_Z_REGNUM
] = 1;
326 /* Reload and register operations. */
328 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
334 /* regs_inited = 1; */
335 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
336 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
337 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
338 da_reg
= gen_rtx (REG
, QImode
, HARD_A_REGNUM
);
339 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
341 stack_push_word
= gen_rtx (MEM
, HImode
,
342 gen_rtx (PRE_DEC
, HImode
,
343 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
344 stack_pop_word
= gen_rtx (MEM
, HImode
,
345 gen_rtx (POST_INC
, HImode
,
346 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
350 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
351 - 8 bit values are stored anywhere (except the SP register).
352 - 16 bit values can be stored in any register whose mode is 16
353 - 32 bit values can be stored in D, X registers or in a soft register
354 (except the last one because we need 2 soft registers)
355 - Values whose size is > 32 bit are not stored in real hard
356 registers. They may be stored in soft registers if there are
359 hard_regno_mode_ok (regno
, mode
)
361 enum machine_mode mode
;
363 switch (GET_MODE_SIZE (mode
))
366 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
369 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
372 return G_REGNO_P (regno
);
375 /* We have to accept a QImode in X or Y registers. Otherwise, the
376 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
377 in the insns. Reload fails if the insn rejects the register class 'a'
378 as well as if it accepts it. Patterns that failed were
379 zero_extend_qihi2 and iorqi3. */
381 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
389 preferred_reload_class (operand
, class)
391 enum reg_class
class;
393 enum machine_mode mode
;
395 mode
= GET_MODE (operand
);
399 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
402 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
403 return m68hc11_base_reg_class
;
405 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
406 || GET_CODE (operand
) == CONST_INT
))
408 /* S_REGS class must not be used. The movhi template does not
409 work to move a memory to a soft register.
410 Restrict to a hard reg. */
415 case D_OR_A_OR_S_REGS
:
421 case D_OR_SP_OR_S_REGS
:
422 class = D_OR_SP_REGS
;
424 case D_OR_Y_OR_S_REGS
:
427 case D_OR_X_OR_S_REGS
:
443 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
447 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
451 else if (class >= S_REGS
&& S_REG_P (operand
))
457 case D_OR_A_OR_S_REGS
:
463 case D_OR_SP_OR_S_REGS
:
464 class = D_OR_SP_REGS
;
466 case D_OR_Y_OR_S_REGS
:
469 case D_OR_X_OR_S_REGS
:
485 else if (class >= S_REGS
)
489 printf ("Class = %s for: ", reg_class_names
[class]);
497 printf (" => class=%s\n", reg_class_names
[class]);
505 /* Return 1 if the operand is a valid indexed addressing mode.
506 For 68hc11: n,r with n in [0..255] and r in A_REGS class
507 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
509 register_indirect_p (operand
, mode
, strict
)
511 enum machine_mode mode
;
516 switch (GET_CODE (operand
))
522 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
523 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
527 base
= XEXP (operand
, 0);
528 if (GET_CODE (base
) == MEM
)
531 offset
= XEXP (operand
, 1);
532 if (GET_CODE (offset
) == MEM
)
535 if (GET_CODE (base
) == REG
)
537 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
543 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
545 if (GET_CODE (offset
) == REG
)
547 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
553 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
558 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
564 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
571 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
572 a 68HC12 1-byte index addressing mode. */
574 m68hc11_small_indexed_indirect_p (operand
, mode
)
576 enum machine_mode mode
;
580 if (GET_CODE (operand
) == REG
&& reload_in_progress
581 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
582 && reg_equiv_memory_loc
[REGNO (operand
)])
584 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
585 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
588 if (GET_CODE (operand
) != MEM
)
591 operand
= XEXP (operand
, 0);
592 if (CONSTANT_ADDRESS_P (operand
))
595 if (PUSH_POP_ADDRESS_P (operand
))
598 if (!register_indirect_p (operand
, mode
, reload_completed
))
601 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
602 && (reload_completed
| reload_in_progress
))
604 base
= XEXP (operand
, 0);
605 offset
= XEXP (operand
, 1);
607 /* The offset can be a symbol address and this is too big
608 for the operand constraint. */
609 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
612 if (GET_CODE (base
) == CONST_INT
)
615 switch (GET_MODE_SIZE (mode
))
618 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
623 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
628 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
637 m68hc11_register_indirect_p (operand
, mode
)
639 enum machine_mode mode
;
641 if (GET_CODE (operand
) != MEM
)
644 operand
= XEXP (operand
, 0);
645 return register_indirect_p (operand
, mode
,
646 (reload_completed
| reload_in_progress
));
650 go_if_legitimate_address_internal (operand
, mode
, strict
)
652 enum machine_mode mode
;
655 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
657 /* Reject the global variables if they are too wide. This forces
658 a load of their address in a register and generates smaller code. */
659 if (GET_MODE_SIZE (mode
) == 8)
664 if (register_indirect_p (operand
, mode
, strict
))
668 if (PUSH_POP_ADDRESS_P (operand
))
672 if (symbolic_memory_operand (operand
, mode
))
680 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
682 enum machine_mode mode
;
689 printf ("Checking: ");
694 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
698 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
705 printf ("go_if_legitimate%s, ret 0: %d:",
706 (strict
? "_strict" : ""), mode
);
715 m68hc11_legitimize_address (operand
, old_operand
, mode
)
716 rtx
*operand ATTRIBUTE_UNUSED
;
717 rtx old_operand ATTRIBUTE_UNUSED
;
718 enum machine_mode mode ATTRIBUTE_UNUSED
;
725 m68hc11_reload_operands (operands
)
728 enum machine_mode mode
;
730 if (regs_inited
== 0)
733 mode
= GET_MODE (operands
[1]);
735 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
736 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
738 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
739 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
741 if (GET_CODE (base
) != REG
)
748 /* If the offset is out of range, we have to compute the address
749 with a separate add instruction. We try to do with with an 8-bit
750 add on the A register. This is possible only if the lowest part
751 of the offset (ie, big_offset % 256) is a valid constant offset
752 with respect to the mode. If it's not, we have to generate a
753 16-bit add on the D register. From:
755 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
759 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
760 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
761 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
762 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
764 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
765 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
768 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
771 rtx reg
= operands
[0];
773 int val
= INTVAL (big_offset
);
776 /* We use the 'operands[0]' as a scratch register to compute the
777 address. Make sure 'base' is in that register. */
778 if (!rtx_equal_p (base
, operands
[0]))
780 emit_move_insn (reg
, base
);
790 vh
= (val
>> 8) & 0x0FF;
794 /* Create the lowest part offset that still remains to be added.
795 If it's not a valid offset, do a 16-bit add. */
796 offset
= GEN_INT (vl
);
797 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
799 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
800 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
805 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
806 gen_rtx (PLUS
, HImode
, reg
,
807 GEN_INT (vh
<< 8))));
809 emit_move_insn (operands
[0],
810 gen_rtx (MEM
, GET_MODE (operands
[1]),
811 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
816 /* Use the normal gen_movhi pattern. */
821 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
824 enum machine_mode dmode
;
825 enum machine_mode smode
;
835 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
839 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
840 dmode
, 1, operands
[1], smode
);
841 equiv
= gen_rtx (code
, dmode
, operands
[1]);
845 ret
= emit_library_call_value (libcall
, NULL_RTX
,
847 operands
[1], smode
, operands
[2],
849 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
856 insns
= get_insns ();
858 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
861 /* Returns true if X is a PRE/POST increment decrement
862 (same as auto_inc_p() in rtlanal.c but do not take into
863 account the stack). */
865 m68hc11_auto_inc_p (x
)
868 return GET_CODE (x
) == PRE_DEC
869 || GET_CODE (x
) == POST_INC
870 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
874 /* Predicates for machine description. */
877 memory_reload_operand (operand
, mode
)
879 enum machine_mode mode ATTRIBUTE_UNUSED
;
881 return GET_CODE (operand
) == MEM
882 && GET_CODE (XEXP (operand
, 0)) == PLUS
883 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
884 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
885 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
886 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
890 tst_operand (operand
, mode
)
892 enum machine_mode mode
;
894 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
896 rtx addr
= XEXP (operand
, 0);
897 if (m68hc11_auto_inc_p (addr
))
900 return nonimmediate_operand (operand
, mode
);
904 cmp_operand (operand
, mode
)
906 enum machine_mode mode
;
908 if (GET_CODE (operand
) == MEM
)
910 rtx addr
= XEXP (operand
, 0);
911 if (m68hc11_auto_inc_p (addr
))
914 return general_operand (operand
, mode
);
918 non_push_operand (operand
, mode
)
920 enum machine_mode mode
;
922 if (general_operand (operand
, mode
) == 0)
925 if (push_operand (operand
, mode
) == 1)
931 reg_or_some_mem_operand (operand
, mode
)
933 enum machine_mode mode
;
935 if (GET_CODE (operand
) == MEM
)
937 rtx op
= XEXP (operand
, 0);
939 if (symbolic_memory_operand (op
, mode
))
942 if (IS_STACK_PUSH (operand
))
945 if (m68hc11_register_indirect_p (operand
, mode
))
951 return register_operand (operand
, mode
);
955 m68hc11_symbolic_p (operand
, mode
)
957 enum machine_mode mode
;
959 if (GET_CODE (operand
) == MEM
)
961 rtx op
= XEXP (operand
, 0);
963 if (symbolic_memory_operand (op
, mode
))
970 m68hc11_indirect_p (operand
, mode
)
972 enum machine_mode mode
;
974 if (GET_CODE (operand
) == MEM
)
976 rtx op
= XEXP (operand
, 0);
978 if (symbolic_memory_operand (op
, mode
))
981 if (reload_in_progress
)
984 operand
= XEXP (operand
, 0);
985 return register_indirect_p (operand
, mode
, reload_completed
);
991 stack_register_operand (operand
, mode
)
993 enum machine_mode mode ATTRIBUTE_UNUSED
;
995 return SP_REG_P (operand
);
999 d_register_operand (operand
, mode
)
1001 enum machine_mode mode ATTRIBUTE_UNUSED
;
1003 if (GET_CODE (operand
) == SUBREG
)
1004 operand
= XEXP (operand
, 0);
1006 return GET_CODE (operand
) == REG
1007 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1008 || REGNO (operand
) == HARD_D_REGNUM
1009 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1013 hard_addr_reg_operand (operand
, mode
)
1015 enum machine_mode mode ATTRIBUTE_UNUSED
;
1017 if (GET_CODE (operand
) == SUBREG
)
1018 operand
= XEXP (operand
, 0);
1020 return GET_CODE (operand
) == REG
1021 && (REGNO (operand
) == HARD_X_REGNUM
1022 || REGNO (operand
) == HARD_Y_REGNUM
1023 || REGNO (operand
) == HARD_Z_REGNUM
);
1027 hard_reg_operand (operand
, mode
)
1029 enum machine_mode mode ATTRIBUTE_UNUSED
;
1031 if (GET_CODE (operand
) == SUBREG
)
1032 operand
= XEXP (operand
, 0);
1034 return GET_CODE (operand
) == REG
1035 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1036 || H_REGNO_P (REGNO (operand
)));
1040 memory_indexed_operand (operand
, mode
)
1042 enum machine_mode mode ATTRIBUTE_UNUSED
;
1044 if (GET_CODE (operand
) != MEM
)
1047 operand
= XEXP (operand
, 0);
1048 if (GET_CODE (operand
) == PLUS
)
1050 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1051 operand
= XEXP (operand
, 0);
1052 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1053 operand
= XEXP (operand
, 1);
1055 return GET_CODE (operand
) == REG
1056 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1057 || A_REGNO_P (REGNO (operand
)));
1061 push_pop_operand_p (operand
)
1064 if (GET_CODE (operand
) != MEM
)
1068 operand
= XEXP (operand
, 0);
1069 return PUSH_POP_ADDRESS_P (operand
);
1072 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1073 reference and a constant. */
1076 symbolic_memory_operand (op
, mode
)
1078 enum machine_mode mode
;
1080 switch (GET_CODE (op
))
1088 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1089 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1090 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1092 /* ??? This clause seems to be irrelevant. */
1094 return GET_MODE (op
) == mode
;
1097 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1098 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1106 m68hc11_logical_operator (op
, mode
)
1108 enum machine_mode mode ATTRIBUTE_UNUSED
;
1110 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1114 m68hc11_arith_operator (op
, mode
)
1116 enum machine_mode mode ATTRIBUTE_UNUSED
;
1118 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1119 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1120 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1121 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1122 || GET_CODE (op
) == ROTATERT
;
1126 m68hc11_non_shift_operator (op
, mode
)
1128 enum machine_mode mode ATTRIBUTE_UNUSED
;
1130 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1131 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1136 m68hc11_unary_operator (op
, mode
)
1138 enum machine_mode mode ATTRIBUTE_UNUSED
;
1140 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1141 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1144 /* Emit the code to build the trampoline used to call a nested function.
1148 ldy #&CXT movw #&CXT,*_.d1
1149 sty *_.d1 jmp FNADDR
1154 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1159 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1162 if (*static_chain_reg
== '*')
1166 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1167 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1168 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1170 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1171 gen_rtx_CONST (QImode
,
1172 gen_rtx_SYMBOL_REF (Pmode
,
1173 static_chain_reg
)));
1174 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1176 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1180 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1181 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1182 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1183 gen_rtx_CONST (HImode
,
1184 gen_rtx_SYMBOL_REF (Pmode
,
1185 static_chain_reg
)));
1186 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1188 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1192 /* Declaration of types. */
1194 const struct attribute_spec m68hc11_attribute_table
[] =
1196 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1197 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1198 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1199 { NULL
, 0, 0, false, false, false, NULL
}
1202 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1203 arguments as in struct attribute_spec.handler. */
1205 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1208 tree args ATTRIBUTE_UNUSED
;
1209 int flags ATTRIBUTE_UNUSED
;
1212 if (TREE_CODE (*node
) != FUNCTION_TYPE
1213 && TREE_CODE (*node
) != FIELD_DECL
1214 && TREE_CODE (*node
) != TYPE_DECL
)
1216 warning ("`%s' attribute only applies to functions",
1217 IDENTIFIER_POINTER (name
));
1218 *no_add_attrs
= true;
1224 /* We want to recognize trap handlers so that we handle calls to traps
1225 in a special manner (by issuing the trap). This information is stored
1226 in SYMBOL_REF_FLAG. */
1229 m68hc11_encode_section_info (decl
, first
)
1231 int first ATTRIBUTE_UNUSED
;
1237 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1240 rtl
= DECL_RTL (decl
);
1242 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1243 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1244 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1248 /* Argument support functions. */
1250 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1251 Arrays are passed by references and other types by value.
1253 SCz: I tried to pass DImode by reference but it seems that this
1254 does not work very well. */
1256 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1257 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1258 enum machine_mode mode ATTRIBUTE_UNUSED
;
1260 int named ATTRIBUTE_UNUSED
;
1262 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1263 /* Consider complex values as aggregates, so care for TCmode. */
1264 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1265 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1269 /* Define the offset between two registers, one to be eliminated, and the
1270 other its replacement, at the start of a routine. */
1272 m68hc11_initial_elimination_offset (from
, to
)
1281 /* For a trap handler, we must take into account the registers which
1282 are pushed on the stack during the trap (except the PC). */
1283 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1284 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1285 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1288 /* For a function using 'call/rtc' we must take into account the
1289 page register which is pushed in the call. */
1290 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1295 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1297 /* 2 is for the saved frame.
1298 1 is for the 'sts' correction when creating the frame. */
1299 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1302 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1304 return m68hc11_sp_correction
;
1307 /* Push any 2 byte pseudo hard registers that we need to save. */
1308 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1310 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1316 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1318 return get_frame_size () + size
;
1321 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1328 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1329 for a call to a function whose data type is FNTYPE.
1330 For a library call, FNTYPE is 0. */
1333 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1334 CUMULATIVE_ARGS
*cum
;
1340 z_replacement_completed
= 0;
1344 /* For a library call, we must find out the type of the return value.
1345 When the return value is bigger than 4 bytes, it is returned in
1346 memory. In that case, the first argument of the library call is a
1347 pointer to the memory location. Because the first argument is passed in
1348 register D, we have to identify this, so that the first function
1349 parameter is not passed in D either. */
1355 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1358 /* If the library ends in 'di' or in 'df', we assume it's
1359 returning some DImode or some DFmode which are 64-bit wide. */
1360 name
= XSTR (libname
, 0);
1361 len
= strlen (name
);
1363 && ((name
[len
- 2] == 'd'
1364 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1365 || (name
[len
- 3] == 'd'
1366 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1368 /* We are in. Mark the first parameter register as already used. */
1375 ret_type
= TREE_TYPE (fntype
);
1377 if (ret_type
&& aggregate_value_p (ret_type
))
1384 /* Update the data in CUM to advance over an argument
1385 of mode MODE and data type TYPE.
1386 (TYPE is null for libcalls where that information may not be available.) */
1389 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1390 CUMULATIVE_ARGS
*cum
;
1391 enum machine_mode mode
;
1393 int named ATTRIBUTE_UNUSED
;
1395 if (mode
!= BLKmode
)
1397 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1400 cum
->words
= GET_MODE_SIZE (mode
);
1404 cum
->words
+= GET_MODE_SIZE (mode
);
1405 if (cum
->words
<= HARD_REG_SIZE
)
1411 cum
->words
+= int_size_in_bytes (type
);
1416 /* Define where to put the arguments to a function.
1417 Value is zero to push the argument on the stack,
1418 or a hard register in which to store the argument.
1420 MODE is the argument's machine mode.
1421 TYPE is the data type of the argument (as a tree).
1422 This is null for libcalls where that information may
1424 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1425 the preceding args and about the function being called.
1426 NAMED is nonzero if this argument is a named parameter
1427 (otherwise it is an extra parameter matching an ellipsis). */
1430 m68hc11_function_arg (cum
, mode
, type
, named
)
1431 const CUMULATIVE_ARGS
*cum
;
1432 enum machine_mode mode
;
1433 tree type ATTRIBUTE_UNUSED
;
1434 int named ATTRIBUTE_UNUSED
;
1436 if (cum
->words
!= 0)
1441 if (mode
!= BLKmode
)
1443 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1444 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1446 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1450 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1456 m68hc11_va_arg (valist
, type
)
1461 HOST_WIDE_INT align
;
1462 HOST_WIDE_INT rounded_size
;
1466 /* Compute the rounded size of the type. */
1467 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1468 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1472 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1474 if (pad_direction
== downward
)
1476 /* Small args are padded downward. */
1479 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1480 if (rounded_size
> align
)
1483 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1484 build_int_2 (rounded_size
- adj
, 0));
1487 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1488 addr
= copy_to_reg (addr
);
1490 /* Compute new value for AP. */
1491 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1492 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1493 build_int_2 (rounded_size
, 0)));
1494 TREE_SIDE_EFFECTS (t
) = 1;
1495 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1500 /* If defined, a C expression which determines whether, and in which direction,
1501 to pad out an argument with extra space. The value should be of type
1502 `enum direction': either `upward' to pad above the argument,
1503 `downward' to pad below, or `none' to inhibit padding.
1505 Structures are stored left shifted in their argument slot. */
1507 m68hc11_function_arg_padding (mode
, type
)
1508 enum machine_mode mode
;
1511 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1514 /* This is the default definition. */
1515 return (!BYTES_BIG_ENDIAN
1518 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1519 && int_size_in_bytes (type
) <
1520 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1521 PARM_BOUNDARY
) ? downward
: upward
));
1525 /* Function prologue and epilogue. */
1527 /* Emit a move after the reload pass has completed. This is used to
1528 emit the prologue and epilogue. */
1530 emit_move_after_reload (to
, from
, scratch
)
1531 rtx to
, from
, scratch
;
1535 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1537 insn
= emit_move_insn (to
, from
);
1541 emit_move_insn (scratch
, from
);
1542 insn
= emit_move_insn (to
, scratch
);
1545 /* Put a REG_INC note to tell the flow analysis that the instruction
1547 if (IS_STACK_PUSH (to
))
1549 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1550 XEXP (XEXP (to
, 0), 0),
1553 else if (IS_STACK_POP (from
))
1555 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1556 XEXP (XEXP (from
, 0), 0),
1560 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1561 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1562 The problem is that we are lying to gcc and use `txs' for x = sp
1563 (which is not really true because txs is really x = sp + 1). */
1564 else if (TARGET_M6811
&& SP_REG_P (from
))
1566 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1573 m68hc11_total_frame_size ()
1578 size
= get_frame_size ();
1579 if (current_function_interrupt
)
1581 size
+= 3 * HARD_REG_SIZE
;
1583 if (frame_pointer_needed
)
1584 size
+= HARD_REG_SIZE
;
1586 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1587 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1588 size
+= HARD_REG_SIZE
;
1594 m68hc11_output_function_epilogue (out
, size
)
1595 FILE *out ATTRIBUTE_UNUSED
;
1596 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1598 /* We catch the function epilogue generation to have a chance
1599 to clear the z_replacement_completed flag. */
1600 z_replacement_completed
= 0;
1611 if (reload_completed
!= 1)
1614 size
= get_frame_size ();
1618 /* Generate specific prologue for interrupt handlers. */
1619 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1620 current_function_interrupt
= lookup_attribute ("interrupt",
1621 func_attr
) != NULL_TREE
;
1622 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1624 /* Get the scratch register to build the frame and push registers.
1625 If the first argument is a 32-bit quantity, the D+X registers
1626 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1627 For 68HC12, this scratch register is not used. */
1628 if (current_function_args_info
.nregs
== 2)
1633 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1634 Other soft registers in page0 need not to be saved because they
1635 will be restored by C functions. For a trap handler, we don't
1636 need to preserve these registers because this is a synchronous call. */
1637 if (current_function_interrupt
)
1639 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1640 emit_move_after_reload (stack_push_word
,
1641 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1642 emit_move_after_reload (stack_push_word
,
1643 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1647 /* Save current stack frame. */
1648 if (frame_pointer_needed
)
1649 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1651 /* Allocate local variables. */
1652 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1654 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1655 stack_pointer_rtx
, GEN_INT (-size
)));
1661 insn
= gen_rtx_PARALLEL
1664 gen_rtx_SET (VOIDmode
,
1666 gen_rtx_PLUS (HImode
,
1669 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1676 /* Allocate by pushing scratch values. */
1677 for (i
= 2; i
<= size
; i
+= 2)
1678 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1681 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1682 stack_pointer_rtx
, GEN_INT (-1)));
1685 /* Create the frame pointer. */
1686 if (frame_pointer_needed
)
1687 emit_move_after_reload (hard_frame_pointer_rtx
,
1688 stack_pointer_rtx
, scratch
);
1690 /* Push any 2 byte pseudo hard registers that we need to save. */
1691 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1693 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1695 emit_move_after_reload (stack_push_word
,
1696 gen_rtx (REG
, HImode
, regno
), scratch
);
1709 if (reload_completed
!= 1)
1712 size
= get_frame_size ();
1714 /* If we are returning a value in two registers, we have to preserve the
1715 X register and use the Y register to restore the stack and the saved
1716 registers. Otherwise, use X because it's faster (and smaller). */
1717 if (current_function_return_rtx
== 0)
1719 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1720 return_size
= HARD_REG_SIZE
;
1722 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1724 if (return_size
> HARD_REG_SIZE
)
1729 /* Pop any 2 byte pseudo hard registers that we saved. */
1730 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1732 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1734 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1735 stack_pop_word
, scratch
);
1739 /* de-allocate auto variables */
1740 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1742 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1743 stack_pointer_rtx
, GEN_INT (size
)));
1749 insn
= gen_rtx_PARALLEL
1752 gen_rtx_SET (VOIDmode
,
1754 gen_rtx_PLUS (HImode
,
1757 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1764 for (i
= 2; i
<= size
; i
+= 2)
1765 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1767 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1768 stack_pointer_rtx
, GEN_INT (1)));
1771 /* Restore previous frame pointer. */
1772 if (frame_pointer_needed
)
1773 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1775 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1776 if (current_function_interrupt
)
1778 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1779 stack_pop_word
, scratch
);
1780 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1781 stack_pop_word
, scratch
);
1782 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1785 /* If the trap handler returns some value, copy the value
1786 in D, X onto the stack so that the rti will pop the return value
1788 else if (current_function_trap
&& return_size
!= 0)
1790 rtx addr_reg
= stack_pointer_rtx
;
1794 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1797 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1798 gen_rtx (PLUS
, HImode
, addr_reg
,
1799 GEN_INT (1))), d_reg
, 0);
1800 if (return_size
> HARD_REG_SIZE
)
1801 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1802 gen_rtx (PLUS
, HImode
, addr_reg
,
1803 GEN_INT (3))), ix_reg
, 0);
1806 emit_jump_insn (gen_return ());
1810 /* Low and High part extraction for 68HC11. These routines are
1811 similar to gen_lowpart and gen_highpart but they have been
1812 fixed to work for constants and 68HC11 specific registers. */
1815 m68hc11_gen_lowpart (mode
, x
)
1816 enum machine_mode mode
;
1819 /* We assume that the low part of an auto-inc mode is the same with
1820 the mode changed and that the caller split the larger mode in the
1822 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1824 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1827 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1828 floating-point constant. A CONST_DOUBLE is used whenever the
1829 constant requires more than one word in order to be adequately
1831 if (GET_CODE (x
) == CONST_DOUBLE
)
1835 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1839 if (GET_MODE (x
) == SFmode
)
1841 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1842 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1848 split_double (x
, &first
, &second
);
1852 return GEN_INT (l
[0]);
1854 return gen_int_mode (l
[0], HImode
);
1858 l
[0] = CONST_DOUBLE_LOW (x
);
1861 return GEN_INT (l
[0]);
1862 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1863 return gen_int_mode (l
[0], HImode
);
1868 if (mode
== QImode
&& D_REG_P (x
))
1869 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1871 /* gen_lowpart crashes when it is called with a SUBREG. */
1872 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1875 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1876 else if (mode
== HImode
)
1877 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1881 x
= gen_lowpart (mode
, x
);
1883 /* Return a different rtx to avoid to share it in several insns
1884 (when used by a split pattern). Sharing addresses within
1885 a MEM breaks the Z register replacement (and reloading). */
1886 if (GET_CODE (x
) == MEM
)
1892 m68hc11_gen_highpart (mode
, x
)
1893 enum machine_mode mode
;
1896 /* We assume that the high part of an auto-inc mode is the same with
1897 the mode changed and that the caller split the larger mode in the
1899 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1901 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1904 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1905 floating-point constant. A CONST_DOUBLE is used whenever the
1906 constant requires more than one word in order to be adequately
1908 if (GET_CODE (x
) == CONST_DOUBLE
)
1912 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1916 if (GET_MODE (x
) == SFmode
)
1918 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1919 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1925 split_double (x
, &first
, &second
);
1929 return GEN_INT (l
[1]);
1931 return gen_int_mode ((l
[1] >> 16), HImode
);
1935 l
[1] = CONST_DOUBLE_HIGH (x
);
1939 return GEN_INT (l
[1]);
1940 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1941 return gen_int_mode ((l
[0] >> 16), HImode
);
1945 if (GET_CODE (x
) == CONST_INT
)
1947 HOST_WIDE_INT val
= INTVAL (x
);
1951 return gen_int_mode (val
>> 8, QImode
);
1953 else if (mode
== HImode
)
1955 return gen_int_mode (val
>> 16, HImode
);
1958 if (mode
== QImode
&& D_REG_P (x
))
1959 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1961 /* There is no way in GCC to represent the upper part of a word register.
1962 To obtain the 8-bit upper part of a soft register, we change the
1963 reg into a mem rtx. This is possible because they are physically
1964 located in memory. There is no offset because we are big-endian. */
1965 if (mode
== QImode
&& S_REG_P (x
))
1969 /* Avoid the '*' for direct addressing mode when this
1970 addressing mode is disabled. */
1971 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1972 return gen_rtx (MEM
, QImode
,
1973 gen_rtx (SYMBOL_REF
, Pmode
,
1974 ®_names
[REGNO (x
)][pos
]));
1977 /* gen_highpart crashes when it is called with a SUBREG. */
1978 if (GET_CODE (x
) == SUBREG
)
1980 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
1982 if (GET_CODE (x
) == REG
)
1984 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
1985 return gen_rtx (REG
, mode
, REGNO (x
));
1987 return gen_rtx_SUBREG (mode
, x
, 0);
1990 if (GET_CODE (x
) == MEM
)
1992 x
= change_address (x
, mode
, 0);
1994 /* Return a different rtx to avoid to share it in several insns
1995 (when used by a split pattern). Sharing addresses within
1996 a MEM breaks the Z register replacement (and reloading). */
1997 if (GET_CODE (x
) == MEM
)
2005 /* Obscure register manipulation. */
2007 /* Finds backward in the instructions to see if register 'reg' is
2008 dead. This is used when generating code to see if we can use 'reg'
2009 as a scratch register. This allows us to choose a better generation
2010 of code when we know that some register dies or can be clobbered. */
2013 dead_register_here (x
, reg
)
2021 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2025 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2026 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2032 if (GET_CODE (body
) == CALL_INSN
)
2034 if (GET_CODE (body
) == JUMP_INSN
)
2037 if (GET_CODE (body
) == SET
)
2039 rtx dst
= XEXP (body
, 0);
2041 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2043 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2046 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2049 else if (reg_mentioned_p (reg
, p
)
2050 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2054 /* Scan forward to see if the register is set in some insns and never
2056 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2060 if (GET_CODE (p
) == CODE_LABEL
2061 || GET_CODE (p
) == JUMP_INSN
2062 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2065 if (GET_CODE (p
) != INSN
)
2069 if (GET_CODE (body
) == SET
)
2071 rtx src
= XEXP (body
, 1);
2072 rtx dst
= XEXP (body
, 0);
2074 if (GET_CODE (dst
) == REG
2075 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2079 /* Register is used (may be in source or in dest). */
2080 if (reg_mentioned_p (reg
, p
)
2081 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2082 && reg_mentioned_p (x_reg
, p
)))
2085 return p
== 0 ? 1 : 0;
2089 /* Code generation operations called from machine description file. */
2091 /* Print the name of register 'regno' in the assembly file. */
2093 asm_print_register (file
, regno
)
2097 const char *name
= reg_names
[regno
];
2099 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2102 fprintf (file
, "%s", name
);
2105 /* A C compound statement to output to stdio stream STREAM the
2106 assembler syntax for an instruction operand X. X is an RTL
2109 CODE is a value that can be used to specify one of several ways
2110 of printing the operand. It is used when identical operands
2111 must be printed differently depending on the context. CODE
2112 comes from the `%' specification that was used to request
2113 printing of the operand. If the specification was just `%DIGIT'
2114 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2115 is the ASCII code for LTR.
2117 If X is a register, this macro should print the register's name.
2118 The names can be found in an array `reg_names' whose type is
2119 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2121 When the machine description has a specification `%PUNCT' (a `%'
2122 followed by a punctuation character), this macro is called with
2123 a null pointer for X and the punctuation character for CODE.
2125 The M68HC11 specific codes are:
2127 'b' for the low part of the operand.
2128 'h' for the high part of the operand
2129 The 'b' or 'h' modifiers have no effect if the operand has
2130 the QImode and is not a S_REG_P (soft register). If the
2131 operand is a hard register, these two modifiers have no effect.
2132 't' generate the temporary scratch register. The operand is
2134 'T' generate the low-part temporary scratch register. The operand is
2138 print_operand (file
, op
, letter
)
2145 asm_print_register (file
, SOFT_TMP_REGNUM
);
2148 else if (letter
== 'T')
2150 asm_print_register (file
, SOFT_TMP_REGNUM
);
2151 fprintf (file
, "+1");
2154 else if (letter
== '#')
2156 asm_fprintf (file
, "%0I");
2159 if (GET_CODE (op
) == REG
)
2161 if (letter
== 'b' && S_REG_P (op
))
2163 asm_print_register (file
, REGNO (op
));
2164 fprintf (file
, "+1");
2168 asm_print_register (file
, REGNO (op
));
2173 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2176 asm_fprintf (file
, "%0I%%lo(");
2178 asm_fprintf (file
, "%0I%%hi(");
2180 output_addr_const (file
, op
);
2181 fprintf (file
, ")");
2185 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2186 are specified. If we already have a QImode, there is nothing to do. */
2187 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2191 op
= m68hc11_gen_lowpart (QImode
, op
);
2193 else if (letter
== 'h')
2195 op
= m68hc11_gen_highpart (QImode
, op
);
2199 if (GET_CODE (op
) == MEM
)
2201 rtx base
= XEXP (op
, 0);
2202 switch (GET_CODE (base
))
2207 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2208 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2217 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2218 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2219 fprintf (file
, "-");
2228 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2229 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2230 fprintf (file
, "+");
2239 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2240 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2247 output_address (base
);
2251 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2256 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2257 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2258 asm_fprintf (file
, "%I0x%lx", l
);
2260 else if (GET_CODE (op
) == CONST_DOUBLE
2261 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2265 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2266 sizeof (dstr
), 0, 1);
2267 asm_fprintf (file
, "%I0r%s", dstr
);
2271 int need_parenthesize
= 0;
2274 asm_fprintf (file
, "%0I");
2276 need_parenthesize
= must_parenthesize (op
);
2278 if (need_parenthesize
)
2279 fprintf (file
, "(");
2281 output_addr_const (file
, op
);
2282 if (need_parenthesize
)
2283 fprintf (file
, ")");
2287 /* Returns true if the operand 'op' must be printed with parenthesis
2288 arround it. This must be done only if there is a symbol whose name
2289 is a processor register. */
2291 must_parenthesize (op
)
2296 switch (GET_CODE (op
))
2299 name
= XSTR (op
, 0);
2300 /* Avoid a conflict between symbol name and a possible
2302 return (strcasecmp (name
, "a") == 0
2303 || strcasecmp (name
, "b") == 0
2304 || strcasecmp (name
, "d") == 0
2305 || strcasecmp (name
, "x") == 0
2306 || strcasecmp (name
, "y") == 0
2307 || strcasecmp (name
, "ix") == 0
2308 || strcasecmp (name
, "iy") == 0
2309 || strcasecmp (name
, "pc") == 0
2310 || strcasecmp (name
, "sp") == 0
2311 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2315 return must_parenthesize (XEXP (op
, 0))
2316 || must_parenthesize (XEXP (op
, 1));
2322 return must_parenthesize (XEXP (op
, 0));
2333 /* A C compound statement to output to stdio stream STREAM the
2334 assembler syntax for an instruction operand that is a memory
2335 reference whose address is ADDR. ADDR is an RTL expression. */
2338 print_operand_address (file
, addr
)
2344 int need_parenthesis
= 0;
2346 switch (GET_CODE (addr
))
2349 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2352 fprintf (file
, "0,");
2353 asm_print_register (file
, REGNO (addr
));
2357 base
= XEXP (addr
, 0);
2358 switch (GET_CODE (base
))
2363 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2364 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2373 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2374 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2375 fprintf (file
, "-");
2384 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2385 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2386 fprintf (file
, "+");
2395 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2396 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2403 need_parenthesis
= must_parenthesize (base
);
2404 if (need_parenthesis
)
2405 fprintf (file
, "(");
2407 output_addr_const (file
, base
);
2408 if (need_parenthesis
)
2409 fprintf (file
, ")");
2415 base
= XEXP (addr
, 0);
2416 offset
= XEXP (addr
, 1);
2417 if (!G_REG_P (base
) && G_REG_P (offset
))
2419 base
= XEXP (addr
, 1);
2420 offset
= XEXP (addr
, 0);
2422 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2424 need_parenthesis
= must_parenthesize (addr
);
2426 if (need_parenthesis
)
2427 fprintf (file
, "(");
2429 output_addr_const (file
, base
);
2430 fprintf (file
, "+");
2431 output_addr_const (file
, offset
);
2432 if (need_parenthesis
)
2433 fprintf (file
, ")");
2435 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2441 asm_print_register (file
, REGNO (offset
));
2442 fprintf (file
, ",");
2443 asm_print_register (file
, REGNO (base
));
2450 need_parenthesis
= must_parenthesize (offset
);
2451 if (need_parenthesis
)
2452 fprintf (file
, "(");
2454 output_addr_const (file
, offset
);
2455 if (need_parenthesis
)
2456 fprintf (file
, ")");
2457 fprintf (file
, ",");
2458 asm_print_register (file
, REGNO (base
));
2468 if (GET_CODE (addr
) == CONST_INT
2469 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2471 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2475 need_parenthesis
= must_parenthesize (addr
);
2476 if (need_parenthesis
)
2477 fprintf (file
, "(");
2479 output_addr_const (file
, addr
);
2480 if (need_parenthesis
)
2481 fprintf (file
, ")");
2488 /* Splitting of some instructions. */
2491 m68hc11_expand_compare (code
, op0
, op1
)
2497 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2501 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2502 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2503 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2510 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2512 rtx op0
, op1
, label
;
2516 switch (GET_MODE (op0
))
2520 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2521 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2522 gen_rtx_LABEL_REF (VOIDmode
, label
),
2524 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2528 /* SCz: from i386.c */
2531 /* Don't expand the comparison early, so that we get better code
2532 when jump or whoever decides to reverse the comparison. */
2537 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2538 &m68hc11_compare_op1
);
2540 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2541 m68hc11_compare_op0
, m68hc11_compare_op1
);
2542 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2543 gen_rtx_LABEL_REF (VOIDmode
, label
),
2545 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2547 use_fcomi
= ix86_use_fcomi_compare (code
);
2548 vec
= rtvec_alloc (3 + !use_fcomi
);
2549 RTVEC_ELT (vec
, 0) = tmp
;
2551 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2553 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2556 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2558 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2564 /* Expand SImode branch into multiple compare+branch. */
2566 rtx lo
[2], hi
[2], label2
;
2567 enum rtx_code code1
, code2
, code3
;
2569 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2574 code
= swap_condition (code
);
2576 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2577 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2578 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2579 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2581 /* Otherwise, if we are doing less-than, op1 is a constant and the
2582 low word is zero, then we can just examine the high word. */
2584 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2585 && (code
== LT
|| code
== LTU
))
2587 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2591 /* Otherwise, we need two or three jumps. */
2593 label2
= gen_label_rtx ();
2596 code2
= swap_condition (code
);
2597 code3
= unsigned_condition (code
);
2638 * if (hi(a) < hi(b)) goto true;
2639 * if (hi(a) > hi(b)) goto false;
2640 * if (lo(a) < lo(b)) goto true;
2644 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2646 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2648 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2651 emit_label (label2
);
2661 /* Return the increment/decrement mode of a MEM if it is such.
2662 Return CONST if it is anything else. */
2667 if (GET_CODE (x
) != MEM
)
2671 if (GET_CODE (x
) == PRE_INC
2672 || GET_CODE (x
) == PRE_DEC
2673 || GET_CODE (x
) == POST_INC
2674 || GET_CODE (x
) == POST_DEC
)
2675 return GET_CODE (x
);
2681 m68hc11_make_autoinc_notes (x
, data
)
2687 switch (GET_CODE (*x
))
2694 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2703 /* Split a DI, SI or HI move into several smaller move operations.
2704 The scratch register 'scratch' is used as a temporary to load
2705 store intermediate values. It must be a hard register. */
2707 m68hc11_split_move (to
, from
, scratch
)
2708 rtx to
, from
, scratch
;
2710 rtx low_to
, low_from
;
2711 rtx high_to
, high_from
;
2713 enum machine_mode mode
;
2715 int autoinc_from
= autoinc_mode (from
);
2716 int autoinc_to
= autoinc_mode (to
);
2718 mode
= GET_MODE (to
);
2720 /* If the TO and FROM contain autoinc modes that are not compatible
2721 together (one pop and the other a push), we must change one to
2722 an offsetable operand and generate an appropriate add at the end. */
2723 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2728 /* The source uses an autoinc mode which is not compatible with
2729 a split (this would result in a word swap). */
2730 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2732 code
= GET_CODE (XEXP (from
, 0));
2733 reg
= XEXP (XEXP (from
, 0), 0);
2734 offset
= GET_MODE_SIZE (GET_MODE (from
));
2735 if (code
== POST_DEC
)
2738 if (code
== PRE_INC
)
2739 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2741 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2742 if (code
== POST_DEC
)
2743 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2747 /* Likewise for destination. */
2748 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2750 code
= GET_CODE (XEXP (to
, 0));
2751 reg
= XEXP (XEXP (to
, 0), 0);
2752 offset
= GET_MODE_SIZE (GET_MODE (to
));
2753 if (code
== POST_DEC
)
2756 if (code
== PRE_INC
)
2757 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2759 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2760 if (code
== POST_DEC
)
2761 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2765 /* The source and destination auto increment modes must be compatible
2766 with each other: same direction. */
2767 if ((autoinc_to
!= autoinc_from
2768 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2769 /* The destination address register must not be used within
2770 the source operand because the source address would change
2771 while doing the copy. */
2772 || (autoinc_to
!= CONST
2773 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2774 && !IS_STACK_PUSH (to
)))
2776 /* Must change the destination. */
2777 code
= GET_CODE (XEXP (to
, 0));
2778 reg
= XEXP (XEXP (to
, 0), 0);
2779 offset
= GET_MODE_SIZE (GET_MODE (to
));
2780 if (code
== PRE_DEC
|| code
== POST_DEC
)
2783 if (code
== PRE_DEC
|| code
== PRE_INC
)
2784 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2785 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2786 if (code
== POST_DEC
|| code
== POST_INC
)
2787 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2792 /* Likewise, the source address register must not be used within
2793 the destination operand. */
2794 if (autoinc_from
!= CONST
2795 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2796 && !IS_STACK_PUSH (to
))
2798 /* Must change the source. */
2799 code
= GET_CODE (XEXP (from
, 0));
2800 reg
= XEXP (XEXP (from
, 0), 0);
2801 offset
= GET_MODE_SIZE (GET_MODE (from
));
2802 if (code
== PRE_DEC
|| code
== POST_DEC
)
2805 if (code
== PRE_DEC
|| code
== PRE_INC
)
2806 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2807 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2808 if (code
== POST_DEC
|| code
== POST_INC
)
2809 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2815 if (GET_MODE_SIZE (mode
) == 8)
2817 else if (GET_MODE_SIZE (mode
) == 4)
2823 && IS_STACK_PUSH (to
)
2824 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2830 else if (mode
== HImode
)
2838 low_to
= m68hc11_gen_lowpart (mode
, to
);
2839 high_to
= m68hc11_gen_highpart (mode
, to
);
2841 low_from
= m68hc11_gen_lowpart (mode
, from
);
2842 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2844 if (INTVAL (from
) >= 0)
2845 high_from
= const0_rtx
;
2847 high_from
= constm1_rtx
;
2850 high_from
= m68hc11_gen_highpart (mode
, from
);
2854 high_from
= adjust_address (high_from
, mode
, offset
);
2855 low_from
= high_from
;
2858 /* When copying with a POST_INC mode, we must copy the
2859 high part and then the low part to guarantee a correct
2862 && GET_MODE_SIZE (mode
) >= 2
2863 && autoinc_from
!= autoinc_to
2864 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2873 low_from
= high_from
;
2878 m68hc11_split_move (low_to
, low_from
, scratch
);
2879 m68hc11_split_move (high_to
, high_from
, scratch
);
2881 else if (H_REG_P (to
) || H_REG_P (from
)
2882 || (low_from
== const0_rtx
2883 && high_from
== const0_rtx
2884 && ! push_operand (to
, GET_MODE (to
))
2885 && ! H_REG_P (scratch
))
2887 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2888 || m68hc11_small_indexed_indirect_p (from
,
2890 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2891 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2893 insn
= emit_move_insn (low_to
, low_from
);
2894 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2896 insn
= emit_move_insn (high_to
, high_from
);
2897 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2901 insn
= emit_move_insn (scratch
, low_from
);
2902 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2903 insn
= emit_move_insn (low_to
, scratch
);
2904 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2906 insn
= emit_move_insn (scratch
, high_from
);
2907 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2908 insn
= emit_move_insn (high_to
, scratch
);
2909 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2914 simplify_logical (mode
, code
, operand
, result
)
2915 enum machine_mode mode
;
2924 if (GET_CODE (operand
) != CONST_INT
)
2932 val
= INTVAL (operand
);
2936 if ((val
& mask
) == 0)
2938 if ((val
& mask
) == mask
)
2939 *result
= constm1_rtx
;
2943 if ((val
& mask
) == 0)
2944 *result
= const0_rtx
;
2945 if ((val
& mask
) == mask
)
2950 if ((val
& mask
) == 0)
2958 m68hc11_emit_logical (mode
, code
, operands
)
2959 enum machine_mode mode
;
2966 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2967 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2969 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2970 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2972 if (result
&& GET_CODE (result
) == CONST_INT
)
2974 if (!H_REG_P (operands
[0]) && operands
[3]
2975 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2977 emit_move_insn (operands
[3], result
);
2978 emit_move_insn (operands
[0], operands
[3]);
2982 emit_move_insn (operands
[0], result
);
2985 else if (operands
[1] != 0 && operands
[2] != 0)
2989 if (!H_REG_P (operands
[0]) && operands
[3])
2991 emit_move_insn (operands
[3], operands
[1]);
2992 emit_insn (gen_rtx (SET
, mode
,
2994 gen_rtx (code
, mode
,
2995 operands
[3], operands
[2])));
2996 insn
= emit_move_insn (operands
[0], operands
[3]);
3000 insn
= emit_insn (gen_rtx (SET
, mode
,
3002 gen_rtx (code
, mode
,
3003 operands
[0], operands
[2])));
3007 /* The logical operation is similar to a copy. */
3012 if (GET_CODE (operands
[1]) == CONST_INT
)
3017 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3019 emit_move_insn (operands
[3], src
);
3020 emit_move_insn (operands
[0], operands
[3]);
3024 emit_move_insn (operands
[0], src
);
3030 m68hc11_split_logical (mode
, code
, operands
)
3031 enum machine_mode mode
;
3038 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3039 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3040 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3042 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3044 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3046 if (INTVAL (operands
[1]) >= 0)
3047 high
[1] = const0_rtx
;
3049 high
[1] = constm1_rtx
;
3052 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3054 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3056 if (INTVAL (operands
[2]) >= 0)
3057 high
[2] = const0_rtx
;
3059 high
[2] = constm1_rtx
;
3062 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3064 low
[3] = operands
[3];
3065 high
[3] = operands
[3];
3068 m68hc11_split_logical (HImode
, code
, low
);
3069 m68hc11_split_logical (HImode
, code
, high
);
3073 m68hc11_emit_logical (mode
, code
, low
);
3074 m68hc11_emit_logical (mode
, code
, high
);
3078 /* Code generation. */
3081 m68hc11_output_swap (insn
, operands
)
3082 rtx insn ATTRIBUTE_UNUSED
;
3085 /* We have to be careful with the cc_status. An address register swap
3086 is generated for some comparison. The comparison is made with D
3087 but the branch really uses the address register. See the split
3088 pattern for compare. The xgdx/xgdy preserve the flags but after
3089 the exchange, the flags will reflect to the value of X and not D.
3090 Tell this by setting the cc_status according to the cc_prev_status. */
3091 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3093 if (cc_prev_status
.value1
!= 0
3094 && (D_REG_P (cc_prev_status
.value1
)
3095 || X_REG_P (cc_prev_status
.value1
)))
3097 cc_status
= cc_prev_status
;
3098 if (D_REG_P (cc_status
.value1
))
3099 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3102 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3108 output_asm_insn ("xgdx", operands
);
3112 if (cc_prev_status
.value1
!= 0
3113 && (D_REG_P (cc_prev_status
.value1
)
3114 || Y_REG_P (cc_prev_status
.value1
)))
3116 cc_status
= cc_prev_status
;
3117 if (D_REG_P (cc_status
.value1
))
3118 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3121 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3127 output_asm_insn ("xgdy", operands
);
3131 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3132 This is used to decide whether a move that set flags should be used
3135 next_insn_test_reg (insn
, reg
)
3141 insn
= next_nonnote_insn (insn
);
3142 if (GET_CODE (insn
) != INSN
)
3145 body
= PATTERN (insn
);
3146 if (sets_cc0_p (body
) != 1)
3149 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3155 /* Generate the code to move a 16-bit operand into another one. */
3158 m68hc11_gen_movhi (insn
, operands
)
3164 /* Move a register or memory to the same location.
3165 This is possible because such insn can appear
3166 in a non-optimizing mode. */
3167 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3169 cc_status
= cc_prev_status
;
3175 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3177 cc_status
= cc_prev_status
;
3178 switch (REGNO (operands
[1]))
3183 output_asm_insn ("psh%1", operands
);
3185 case HARD_SP_REGNUM
:
3186 output_asm_insn ("sts\t-2,sp", operands
);
3193 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3195 cc_status
= cc_prev_status
;
3196 switch (REGNO (operands
[0]))
3201 output_asm_insn ("pul%0", operands
);
3208 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3210 m68hc11_notice_keep_cc (operands
[0]);
3211 output_asm_insn ("tfr\t%1,%0", operands
);
3213 else if (H_REG_P (operands
[0]))
3215 if (SP_REG_P (operands
[0]))
3216 output_asm_insn ("lds\t%1", operands
);
3218 output_asm_insn ("ld%0\t%1", operands
);
3220 else if (H_REG_P (operands
[1]))
3222 if (SP_REG_P (operands
[1]))
3223 output_asm_insn ("sts\t%0", operands
);
3225 output_asm_insn ("st%1\t%0", operands
);
3229 rtx from
= operands
[1];
3230 rtx to
= operands
[0];
3232 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3233 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3234 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3235 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3241 ops
[0] = operands
[2];
3244 m68hc11_gen_movhi (insn
, ops
);
3246 ops
[1] = operands
[2];
3247 m68hc11_gen_movhi (insn
, ops
);
3251 /* !!!! SCz wrong here. */
3252 fatal_insn ("move insn not handled", insn
);
3257 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3259 output_asm_insn ("clr\t%h0", operands
);
3260 output_asm_insn ("clr\t%b0", operands
);
3264 m68hc11_notice_keep_cc (operands
[0]);
3265 output_asm_insn ("movw\t%1,%0", operands
);
3272 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3274 cc_status
= cc_prev_status
;
3275 switch (REGNO (operands
[0]))
3279 output_asm_insn ("pul%0", operands
);
3282 output_asm_insn ("pula", operands
);
3283 output_asm_insn ("pulb", operands
);
3290 /* Some moves to a hard register are special. Not all of them
3291 are really supported and we have to use a temporary
3292 location to provide them (either the stack of a temp var). */
3293 if (H_REG_P (operands
[0]))
3295 switch (REGNO (operands
[0]))
3298 if (X_REG_P (operands
[1]))
3300 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3302 m68hc11_output_swap (insn
, operands
);
3304 else if (next_insn_test_reg (insn
, operands
[0]))
3306 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3310 m68hc11_notice_keep_cc (operands
[0]);
3311 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3314 else if (Y_REG_P (operands
[1]))
3316 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3318 m68hc11_output_swap (insn
, operands
);
3322 /* %t means *ZTMP scratch register. */
3323 output_asm_insn ("sty\t%t1", operands
);
3324 output_asm_insn ("ldd\t%t1", operands
);
3327 else if (SP_REG_P (operands
[1]))
3332 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3333 output_asm_insn ("xgdx", operands
);
3334 output_asm_insn ("tsx", operands
);
3335 output_asm_insn ("xgdx", operands
);
3337 else if (IS_STACK_POP (operands
[1]))
3339 output_asm_insn ("pula\n\tpulb", operands
);
3341 else if (GET_CODE (operands
[1]) == CONST_INT
3342 && INTVAL (operands
[1]) == 0)
3344 output_asm_insn ("clra\n\tclrb", operands
);
3348 output_asm_insn ("ldd\t%1", operands
);
3353 if (D_REG_P (operands
[1]))
3355 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3357 m68hc11_output_swap (insn
, operands
);
3359 else if (next_insn_test_reg (insn
, operands
[0]))
3361 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3365 m68hc11_notice_keep_cc (operands
[0]);
3366 output_asm_insn ("pshb", operands
);
3367 output_asm_insn ("psha", operands
);
3368 output_asm_insn ("pulx", operands
);
3371 else if (Y_REG_P (operands
[1]))
3373 /* When both D and Y are dead, use the sequence xgdy, xgdx
3374 to move Y into X. The D and Y registers are modified. */
3375 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3376 && dead_register_here (insn
, d_reg
))
3378 output_asm_insn ("xgdy", operands
);
3379 output_asm_insn ("xgdx", operands
);
3384 output_asm_insn ("sty\t%t1", operands
);
3385 output_asm_insn ("ldx\t%t1", operands
);
3388 else if (SP_REG_P (operands
[1]))
3390 /* tsx, tsy preserve the flags */
3391 cc_status
= cc_prev_status
;
3392 output_asm_insn ("tsx", operands
);
3396 output_asm_insn ("ldx\t%1", operands
);
3401 if (D_REG_P (operands
[1]))
3403 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3405 m68hc11_output_swap (insn
, operands
);
3409 output_asm_insn ("std\t%t1", operands
);
3410 output_asm_insn ("ldy\t%t1", operands
);
3413 else if (X_REG_P (operands
[1]))
3415 /* When both D and X are dead, use the sequence xgdx, xgdy
3416 to move X into Y. The D and X registers are modified. */
3417 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3418 && dead_register_here (insn
, d_reg
))
3420 output_asm_insn ("xgdx", operands
);
3421 output_asm_insn ("xgdy", operands
);
3426 output_asm_insn ("stx\t%t1", operands
);
3427 output_asm_insn ("ldy\t%t1", operands
);
3430 else if (SP_REG_P (operands
[1]))
3432 /* tsx, tsy preserve the flags */
3433 cc_status
= cc_prev_status
;
3434 output_asm_insn ("tsy", operands
);
3438 output_asm_insn ("ldy\t%1", operands
);
3442 case HARD_SP_REGNUM
:
3443 if (D_REG_P (operands
[1]))
3445 m68hc11_notice_keep_cc (operands
[0]);
3446 output_asm_insn ("xgdx", operands
);
3447 output_asm_insn ("txs", operands
);
3448 output_asm_insn ("xgdx", operands
);
3450 else if (X_REG_P (operands
[1]))
3452 /* tys, txs preserve the flags */
3453 cc_status
= cc_prev_status
;
3454 output_asm_insn ("txs", operands
);
3456 else if (Y_REG_P (operands
[1]))
3458 /* tys, txs preserve the flags */
3459 cc_status
= cc_prev_status
;
3460 output_asm_insn ("tys", operands
);
3464 /* lds sets the flags but the des does not. */
3466 output_asm_insn ("lds\t%1", operands
);
3467 output_asm_insn ("des", operands
);
3472 fatal_insn ("invalid register in the move instruction", insn
);
3477 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3478 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3480 output_asm_insn ("sts\t%0", operands
);
3484 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3486 cc_status
= cc_prev_status
;
3487 switch (REGNO (operands
[1]))
3491 output_asm_insn ("psh%1", operands
);
3494 output_asm_insn ("pshb", operands
);
3495 output_asm_insn ("psha", operands
);
3503 /* Operand 1 must be a hard register. */
3504 if (!H_REG_P (operands
[1]))
3506 fatal_insn ("invalid operand in the instruction", insn
);
3509 reg
= REGNO (operands
[1]);
3513 output_asm_insn ("std\t%0", operands
);
3517 output_asm_insn ("stx\t%0", operands
);
3521 output_asm_insn ("sty\t%0", operands
);
3524 case HARD_SP_REGNUM
:
3528 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3530 output_asm_insn ("pshx", operands
);
3531 output_asm_insn ("tsx", operands
);
3532 output_asm_insn ("inx", operands
);
3533 output_asm_insn ("inx", operands
);
3534 output_asm_insn ("stx\t%0", operands
);
3535 output_asm_insn ("pulx", operands
);
3538 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3540 output_asm_insn ("sty\t%t0", operands
);
3541 output_asm_insn ("tsy", operands
);
3542 output_asm_insn ("sty\t%0", operands
);
3543 output_asm_insn ("ldy\t%t0", operands
);
3547 output_asm_insn ("stx\t%t0", operands
);
3548 output_asm_insn ("tsx", operands
);
3549 output_asm_insn ("stx\t%0", operands
);
3550 output_asm_insn ("ldx\t%t0", operands
);
3556 fatal_insn ("invalid register in the move instruction", insn
);
3562 m68hc11_gen_movqi (insn
, operands
)
3566 /* Move a register or memory to the same location.
3567 This is possible because such insn can appear
3568 in a non-optimizing mode. */
3569 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3571 cc_status
= cc_prev_status
;
3578 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3580 m68hc11_notice_keep_cc (operands
[0]);
3581 output_asm_insn ("tfr\t%1,%0", operands
);
3583 else if (H_REG_P (operands
[0]))
3585 if (Q_REG_P (operands
[0]))
3586 output_asm_insn ("lda%0\t%b1", operands
);
3587 else if (D_REG_P (operands
[0]))
3588 output_asm_insn ("ldab\t%b1", operands
);
3592 else if (H_REG_P (operands
[1]))
3594 if (Q_REG_P (operands
[1]))
3595 output_asm_insn ("sta%1\t%b0", operands
);
3596 else if (D_REG_P (operands
[1]))
3597 output_asm_insn ("stab\t%b0", operands
);
3603 rtx from
= operands
[1];
3604 rtx to
= operands
[0];
3606 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3607 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3608 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3609 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3615 ops
[0] = operands
[2];
3618 m68hc11_gen_movqi (insn
, ops
);
3620 ops
[1] = operands
[2];
3621 m68hc11_gen_movqi (insn
, ops
);
3625 /* !!!! SCz wrong here. */
3626 fatal_insn ("move insn not handled", insn
);
3631 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3633 output_asm_insn ("clr\t%b0", operands
);
3637 m68hc11_notice_keep_cc (operands
[0]);
3638 output_asm_insn ("movb\t%b1,%b0", operands
);
3646 if (H_REG_P (operands
[0]))
3648 switch (REGNO (operands
[0]))
3652 if (X_REG_P (operands
[1]))
3654 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3656 m68hc11_output_swap (insn
, operands
);
3660 output_asm_insn ("stx\t%t1", operands
);
3661 output_asm_insn ("ldab\t%T0", operands
);
3664 else if (Y_REG_P (operands
[1]))
3666 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3668 m68hc11_output_swap (insn
, operands
);
3672 output_asm_insn ("sty\t%t1", operands
);
3673 output_asm_insn ("ldab\t%T0", operands
);
3676 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3677 && !DA_REG_P (operands
[1]))
3679 output_asm_insn ("ldab\t%b1", operands
);
3681 else if (DA_REG_P (operands
[1]))
3683 output_asm_insn ("tab", operands
);
3687 cc_status
= cc_prev_status
;
3693 if (X_REG_P (operands
[1]))
3695 output_asm_insn ("stx\t%t1", operands
);
3696 output_asm_insn ("ldaa\t%T0", operands
);
3698 else if (Y_REG_P (operands
[1]))
3700 output_asm_insn ("sty\t%t1", operands
);
3701 output_asm_insn ("ldaa\t%T0", operands
);
3703 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3704 && !DA_REG_P (operands
[1]))
3706 output_asm_insn ("ldaa\t%b1", operands
);
3708 else if (!DA_REG_P (operands
[1]))
3710 output_asm_insn ("tba", operands
);
3714 cc_status
= cc_prev_status
;
3719 if (D_REG_P (operands
[1]))
3721 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3723 m68hc11_output_swap (insn
, operands
);
3727 output_asm_insn ("stab\t%T1", operands
);
3728 output_asm_insn ("ldx\t%t1", operands
);
3732 else if (Y_REG_P (operands
[1]))
3734 output_asm_insn ("sty\t%t0", operands
);
3735 output_asm_insn ("ldx\t%t0", operands
);
3737 else if (GET_CODE (operands
[1]) == CONST_INT
)
3739 output_asm_insn ("ldx\t%1", operands
);
3741 else if (dead_register_here (insn
, d_reg
))
3743 output_asm_insn ("ldab\t%b1", operands
);
3744 output_asm_insn ("xgdx", operands
);
3746 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3748 output_asm_insn ("xgdx", operands
);
3749 output_asm_insn ("ldab\t%b1", operands
);
3750 output_asm_insn ("xgdx", operands
);
3754 output_asm_insn ("pshb", operands
);
3755 output_asm_insn ("ldab\t%b1", operands
);
3756 output_asm_insn ("stab\t%T1", operands
);
3757 output_asm_insn ("ldx\t%t1", operands
);
3758 output_asm_insn ("pulb", operands
);
3764 if (D_REG_P (operands
[1]))
3766 output_asm_insn ("stab\t%T1", operands
);
3767 output_asm_insn ("ldy\t%t1", operands
);
3770 else if (X_REG_P (operands
[1]))
3772 output_asm_insn ("stx\t%t1", operands
);
3773 output_asm_insn ("ldy\t%t1", operands
);
3776 else if (GET_CODE (operands
[1]) == CONST_INT
)
3778 output_asm_insn ("ldy\t%1", operands
);
3780 else if (dead_register_here (insn
, d_reg
))
3782 output_asm_insn ("ldab\t%b1", operands
);
3783 output_asm_insn ("xgdy", operands
);
3785 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3787 output_asm_insn ("xgdy", operands
);
3788 output_asm_insn ("ldab\t%b1", operands
);
3789 output_asm_insn ("xgdy", operands
);
3793 output_asm_insn ("pshb", operands
);
3794 output_asm_insn ("ldab\t%b1", operands
);
3795 output_asm_insn ("stab\t%T1", operands
);
3796 output_asm_insn ("ldy\t%t1", operands
);
3797 output_asm_insn ("pulb", operands
);
3803 fatal_insn ("invalid register in the instruction", insn
);
3807 else if (H_REG_P (operands
[1]))
3809 switch (REGNO (operands
[1]))
3813 output_asm_insn ("stab\t%b0", operands
);
3817 output_asm_insn ("staa\t%b0", operands
);
3821 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3825 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3829 fatal_insn ("invalid register in the move instruction", insn
);
3836 fatal_insn ("operand 1 must be a hard register", insn
);
3840 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3841 The source and destination must be D or A and the shift must
3844 m68hc11_gen_rotate (code
, insn
, operands
)
3851 if (GET_CODE (operands
[2]) != CONST_INT
3852 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3853 fatal_insn ("invalid rotate insn", insn
);
3855 val
= INTVAL (operands
[2]);
3856 if (code
== ROTATERT
)
3857 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3859 if (GET_MODE (operands
[0]) != QImode
)
3862 /* Rotate by 8-bits if the shift is within [5..11]. */
3863 if (val
>= 5 && val
<= 11)
3866 output_asm_insn ("exg\ta,b", operands
);
3869 output_asm_insn ("psha", operands
);
3870 output_asm_insn ("tba", operands
);
3871 output_asm_insn ("pulb", operands
);
3876 /* If the shift is big, invert the rotation. */
3884 /* Set the carry to bit-15, but don't change D yet. */
3885 if (GET_MODE (operands
[0]) != QImode
)
3887 output_asm_insn ("asra", operands
);
3888 output_asm_insn ("rola", operands
);
3893 /* Rotate B first to move the carry to bit-0. */
3894 if (D_REG_P (operands
[0]))
3895 output_asm_insn ("rolb", operands
);
3897 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3898 output_asm_insn ("rola", operands
);
3903 /* Set the carry to bit-8 of D. */
3904 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3906 output_asm_insn ("tap", operands
);
3911 /* Rotate B first to move the carry to bit-7. */
3912 if (D_REG_P (operands
[0]))
3913 output_asm_insn ("rorb", operands
);
3915 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3916 output_asm_insn ("rora", operands
);
3923 /* Store in cc_status the expressions that the condition codes will
3924 describe after execution of an instruction whose pattern is EXP.
3925 Do not alter them if the instruction would not alter the cc's. */
3928 m68hc11_notice_update_cc (exp
, insn
)
3930 rtx insn ATTRIBUTE_UNUSED
;
3932 /* recognize SET insn's. */
3933 if (GET_CODE (exp
) == SET
)
3935 /* Jumps do not alter the cc's. */
3936 if (SET_DEST (exp
) == pc_rtx
)
3939 /* NOTE: most instructions don't affect the carry bit, but the
3940 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3941 the conditions.h header. */
3943 /* Function calls clobber the cc's. */
3944 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3949 /* Tests and compares set the cc's in predictable ways. */
3950 else if (SET_DEST (exp
) == cc0_rtx
)
3952 cc_status
.flags
= 0;
3953 cc_status
.value1
= XEXP (exp
, 0);
3954 cc_status
.value2
= XEXP (exp
, 1);
3958 /* All other instructions affect the condition codes. */
3959 cc_status
.flags
= 0;
3960 cc_status
.value1
= XEXP (exp
, 0);
3961 cc_status
.value2
= XEXP (exp
, 1);
3966 /* Default action if we haven't recognized something
3967 and returned earlier. */
3971 if (cc_status
.value2
!= 0)
3972 switch (GET_CODE (cc_status
.value2
))
3974 /* These logical operations can generate several insns.
3975 The flags are setup according to what is generated. */
3981 /* The (not ...) generates several 'com' instructions for
3982 non QImode. We have to invalidate the flags. */
3984 if (GET_MODE (cc_status
.value2
) != QImode
)
3996 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3997 cc_status
.flags
|= CC_NO_OVERFLOW
;
4000 /* The asl sets the overflow bit in such a way that this
4001 makes the flags unusable for a next compare insn. */
4005 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4006 cc_status
.flags
|= CC_NO_OVERFLOW
;
4009 /* A load/store instruction does not affect the carry. */
4014 cc_status
.flags
|= CC_NO_OVERFLOW
;
4020 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4022 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4023 cc_status
.value2
= 0;
4026 /* The current instruction does not affect the flags but changes
4027 the register 'reg'. See if the previous flags can be kept for the
4028 next instruction to avoid a comparison. */
4030 m68hc11_notice_keep_cc (reg
)
4034 || cc_prev_status
.value1
== 0
4035 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4036 || (cc_prev_status
.value2
4037 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4040 cc_status
= cc_prev_status
;
4045 /* Machine Specific Reorg. */
4047 /* Z register replacement:
4049 GCC treats the Z register as an index base address register like
4050 X or Y. In general, it uses it during reload to compute the address
4051 of some operand. This helps the reload pass to avoid to fall into the
4052 register spill failure.
4054 The Z register is in the A_REGS class. In the machine description,
4055 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4057 It can appear everywhere an X or Y register can appear, except for
4058 some templates in the clobber section (when a clobber of X or Y is asked).
4059 For a given instruction, the template must ensure that no more than
4060 2 'A' registers are used. Otherwise, the register replacement is not
4063 To replace the Z register, the algorithm is not terrific:
4064 1. Insns that do not use the Z register are not changed
4065 2. When a Z register is used, we scan forward the insns to see
4066 a potential register to use: either X or Y and sometimes D.
4067 We stop when a call, a label or a branch is seen, or when we
4068 detect that both X and Y are used (probably at different times, but it does
4070 3. The register that will be used for the replacement of Z is saved
4071 in a .page0 register or on the stack. If the first instruction that
4072 used Z, uses Z as an input, the value is loaded from another .page0
4073 register. The replacement register is pushed on the stack in the
4074 rare cases where a compare insn uses Z and we couldn't find if X/Y
4076 4. The Z register is replaced in all instructions until we reach
4077 the end of the Z-block, as detected by step 2.
4078 5. If we detect that Z is still alive, its value is saved.
4079 If the replacement register is alive, its old value is loaded.
4081 The Z register can be disabled with -ffixed-z.
4091 int must_restore_reg
;
4102 int save_before_last
;
4103 int z_loaded_with_sp
;
4108 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4109 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4110 static void m68hc11_z_replacement
PARAMS ((rtx
));
4111 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4113 int z_replacement_completed
= 0;
4115 /* Analyze the insn to find out which replacement register to use and
4116 the boundaries of the replacement.
4117 Returns 0 if we reached the last insn to be replaced, 1 if we can
4118 continue replacement in next insns. */
4121 m68hc11_check_z_replacement (insn
, info
)
4123 struct replace_info
*info
;
4125 int this_insn_uses_ix
;
4126 int this_insn_uses_iy
;
4127 int this_insn_uses_z
;
4128 int this_insn_uses_z_in_dst
;
4129 int this_insn_uses_d
;
4133 /* A call is said to clobber the Z register, we don't need
4134 to save the value of Z. We also don't need to restore
4135 the replacement register (unless it is used by the call). */
4136 if (GET_CODE (insn
) == CALL_INSN
)
4138 body
= PATTERN (insn
);
4140 info
->can_use_d
= 0;
4142 /* If the call is an indirect call with Z, we have to use the
4143 Y register because X can be used as an input (D+X).
4144 We also must not save Z nor restore Y. */
4145 if (reg_mentioned_p (z_reg
, body
))
4147 insn
= NEXT_INSN (insn
);
4150 info
->found_call
= 1;
4151 info
->must_restore_reg
= 0;
4152 info
->last
= NEXT_INSN (insn
);
4154 info
->need_save_z
= 0;
4157 if (GET_CODE (insn
) == CODE_LABEL
4158 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4161 if (GET_CODE (insn
) == JUMP_INSN
)
4163 if (reg_mentioned_p (z_reg
, insn
) == 0)
4166 info
->can_use_d
= 0;
4167 info
->must_save_reg
= 0;
4168 info
->must_restore_reg
= 0;
4169 info
->need_save_z
= 0;
4170 info
->last
= NEXT_INSN (insn
);
4173 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4178 /* Z register dies here. */
4179 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4181 body
= PATTERN (insn
);
4182 if (GET_CODE (body
) == SET
)
4184 rtx src
= XEXP (body
, 1);
4185 rtx dst
= XEXP (body
, 0);
4187 /* Condition code is set here. We have to restore the X/Y and
4188 save into Z before any test/compare insn because once we save/restore
4189 we can change the condition codes. When the compare insn uses Z and
4190 we can't use X/Y, the comparison is made with the *ZREG soft register
4191 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4194 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4195 || (GET_CODE (src
) == COMPARE
&&
4196 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4197 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4199 if (insn
== info
->first
)
4201 info
->must_load_z
= 0;
4202 info
->must_save_reg
= 0;
4203 info
->must_restore_reg
= 0;
4204 info
->need_save_z
= 0;
4205 info
->found_call
= 1;
4206 info
->regno
= SOFT_Z_REGNUM
;
4211 if (reg_mentioned_p (z_reg
, src
) == 0)
4213 info
->can_use_d
= 0;
4217 if (insn
!= info
->first
)
4220 /* Compare insn which uses Z. We have to save/restore the X/Y
4221 register without modifying the condition codes. For this
4222 we have to use a push/pop insn. */
4223 info
->must_push_reg
= 1;
4227 /* Z reg is set to something new. We don't need to load it. */
4230 if (!reg_mentioned_p (z_reg
, src
))
4232 /* Z reg is used before being set. Treat this as
4233 a new sequence of Z register replacement. */
4234 if (insn
!= info
->first
)
4238 info
->must_load_z
= 0;
4240 info
->z_set_count
++;
4241 info
->z_value
= src
;
4243 info
->z_loaded_with_sp
= 1;
4245 else if (reg_mentioned_p (z_reg
, dst
))
4246 info
->can_use_d
= 0;
4248 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4249 | reg_mentioned_p (d_reg
, dst
);
4250 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4251 | reg_mentioned_p (ix_reg
, dst
);
4252 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4253 | reg_mentioned_p (iy_reg
, dst
);
4254 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4256 /* If z is used as an address operand (like (MEM (reg z))),
4257 we can't replace it with d. */
4258 if (this_insn_uses_z
&& !Z_REG_P (src
)
4259 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4260 && Z_REG_P (XEXP (src
, 0))
4261 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4262 && insn
== info
->first
4263 && dead_register_here (insn
, d_reg
)))
4264 info
->can_use_d
= 0;
4266 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4267 if (TARGET_M6812
&& !z_dies_here
4268 && ((this_insn_uses_z
&& side_effects_p (src
))
4269 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4271 info
->need_save_z
= 1;
4272 info
->z_set_count
++;
4274 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4276 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4278 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4281 if (this_insn_uses_d
)
4282 info
->can_use_d
= 0;
4284 /* IX and IY are used at the same time, we have to restore
4285 the value of the scratch register before this insn. */
4286 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4291 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4292 info
->can_use_d
= 0;
4294 if (info
->x_used
== 0 && this_insn_uses_ix
)
4298 /* We have a (set (REG:HI X) (REG:HI Z)).
4299 Since we use Z as the replacement register, this insn
4300 is no longer necessary. We turn it into a note. We must
4301 not reload the old value of X. */
4302 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4306 info
->need_save_z
= 0;
4309 info
->must_save_reg
= 0;
4310 info
->must_restore_reg
= 0;
4311 info
->found_call
= 1;
4312 info
->can_use_d
= 0;
4313 PUT_CODE (insn
, NOTE
);
4314 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4315 NOTE_SOURCE_FILE (insn
) = 0;
4316 info
->last
= NEXT_INSN (insn
);
4321 && (rtx_equal_p (src
, z_reg
)
4322 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4326 info
->need_save_z
= 0;
4329 info
->last
= NEXT_INSN (insn
);
4330 info
->must_save_reg
= 0;
4331 info
->must_restore_reg
= 0;
4333 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4334 && !reg_mentioned_p (ix_reg
, src
))
4339 info
->need_save_z
= 0;
4343 info
->save_before_last
= 1;
4345 info
->must_restore_reg
= 0;
4346 info
->last
= NEXT_INSN (insn
);
4348 else if (info
->can_use_d
)
4350 info
->last
= NEXT_INSN (insn
);
4356 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4357 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4359 info
->need_save_z
= 0;
4361 info
->last
= NEXT_INSN (insn
);
4362 info
->regno
= HARD_X_REGNUM
;
4363 info
->must_save_reg
= 0;
4364 info
->must_restore_reg
= 0;
4367 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4369 info
->regno
= HARD_X_REGNUM
;
4370 info
->must_restore_reg
= 0;
4371 info
->must_save_reg
= 0;
4375 if (info
->y_used
== 0 && this_insn_uses_iy
)
4379 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4383 info
->need_save_z
= 0;
4386 info
->must_save_reg
= 0;
4387 info
->must_restore_reg
= 0;
4388 info
->found_call
= 1;
4389 info
->can_use_d
= 0;
4390 PUT_CODE (insn
, NOTE
);
4391 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4392 NOTE_SOURCE_FILE (insn
) = 0;
4393 info
->last
= NEXT_INSN (insn
);
4398 && (rtx_equal_p (src
, z_reg
)
4399 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4404 info
->need_save_z
= 0;
4406 info
->last
= NEXT_INSN (insn
);
4407 info
->must_save_reg
= 0;
4408 info
->must_restore_reg
= 0;
4410 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4411 && !reg_mentioned_p (iy_reg
, src
))
4416 info
->need_save_z
= 0;
4420 info
->save_before_last
= 1;
4422 info
->must_restore_reg
= 0;
4423 info
->last
= NEXT_INSN (insn
);
4425 else if (info
->can_use_d
)
4427 info
->last
= NEXT_INSN (insn
);
4434 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4435 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4437 info
->need_save_z
= 0;
4439 info
->last
= NEXT_INSN (insn
);
4440 info
->regno
= HARD_Y_REGNUM
;
4441 info
->must_save_reg
= 0;
4442 info
->must_restore_reg
= 0;
4445 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4447 info
->regno
= HARD_Y_REGNUM
;
4448 info
->must_restore_reg
= 0;
4449 info
->must_save_reg
= 0;
4455 info
->need_save_z
= 0;
4457 if (info
->last
== 0)
4458 info
->last
= NEXT_INSN (insn
);
4461 return info
->last
!= NULL_RTX
? 0 : 1;
4463 if (GET_CODE (body
) == PARALLEL
)
4466 char ix_clobber
= 0;
4467 char iy_clobber
= 0;
4469 this_insn_uses_iy
= 0;
4470 this_insn_uses_ix
= 0;
4471 this_insn_uses_z
= 0;
4473 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4476 int uses_ix
, uses_iy
, uses_z
;
4478 x
= XVECEXP (body
, 0, i
);
4480 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4481 info
->can_use_d
= 0;
4483 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4484 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4485 uses_z
= reg_mentioned_p (z_reg
, x
);
4486 if (GET_CODE (x
) == CLOBBER
)
4488 ix_clobber
|= uses_ix
;
4489 iy_clobber
|= uses_iy
;
4490 z_clobber
|= uses_z
;
4494 this_insn_uses_ix
|= uses_ix
;
4495 this_insn_uses_iy
|= uses_iy
;
4496 this_insn_uses_z
|= uses_z
;
4498 if (uses_z
&& GET_CODE (x
) == SET
)
4500 rtx dst
= XEXP (x
, 0);
4503 info
->z_set_count
++;
4505 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4506 info
->need_save_z
= 1;
4509 info
->need_save_z
= 0;
4513 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4514 this_insn_uses_ix
, this_insn_uses_iy
,
4515 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4518 if (this_insn_uses_z
)
4519 info
->can_use_d
= 0;
4521 if (z_clobber
&& info
->first
!= insn
)
4523 info
->need_save_z
= 0;
4527 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4529 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4531 info
->must_load_z
= 0;
4533 if (dead_register_here (insn
, d_reg
))
4535 info
->regno
= HARD_D_REGNUM
;
4536 info
->must_save_reg
= 0;
4537 info
->must_restore_reg
= 0;
4539 else if (dead_register_here (insn
, ix_reg
))
4541 info
->regno
= HARD_X_REGNUM
;
4542 info
->must_save_reg
= 0;
4543 info
->must_restore_reg
= 0;
4545 else if (dead_register_here (insn
, iy_reg
))
4547 info
->regno
= HARD_Y_REGNUM
;
4548 info
->must_save_reg
= 0;
4549 info
->must_restore_reg
= 0;
4551 if (info
->regno
>= 0)
4553 info
->last
= NEXT_INSN (insn
);
4556 if (this_insn_uses_ix
== 0)
4558 info
->regno
= HARD_X_REGNUM
;
4559 info
->must_save_reg
= 1;
4560 info
->must_restore_reg
= 1;
4562 else if (this_insn_uses_iy
== 0)
4564 info
->regno
= HARD_Y_REGNUM
;
4565 info
->must_save_reg
= 1;
4566 info
->must_restore_reg
= 1;
4570 info
->regno
= HARD_D_REGNUM
;
4571 info
->must_save_reg
= 1;
4572 info
->must_restore_reg
= 1;
4574 info
->last
= NEXT_INSN (insn
);
4578 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4579 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4581 if (this_insn_uses_z
)
4583 if (info
->y_used
== 0 && iy_clobber
)
4585 info
->regno
= HARD_Y_REGNUM
;
4586 info
->must_save_reg
= 0;
4587 info
->must_restore_reg
= 0;
4589 if (info
->first
!= insn
4590 && ((info
->y_used
&& ix_clobber
)
4591 || (info
->x_used
&& iy_clobber
)))
4594 info
->last
= NEXT_INSN (insn
);
4595 info
->save_before_last
= 1;
4599 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4601 if (this_insn_uses_z
)
4603 fatal_insn ("cannot do z-register replacement", insn
);
4607 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4614 if (iy_clobber
|| z_clobber
)
4616 info
->last
= NEXT_INSN (insn
);
4617 info
->save_before_last
= 1;
4622 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4629 if (ix_clobber
|| z_clobber
)
4631 info
->last
= NEXT_INSN (insn
);
4632 info
->save_before_last
= 1;
4639 info
->need_save_z
= 0;
4643 if (GET_CODE (body
) == CLOBBER
)
4646 /* IX and IY are used at the same time, we have to restore
4647 the value of the scratch register before this insn. */
4648 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4652 if (info
->x_used
== 0 && this_insn_uses_ix
)
4660 if (info
->y_used
== 0 && this_insn_uses_iy
)
4674 m68hc11_find_z_replacement (insn
, info
)
4676 struct replace_info
*info
;
4680 info
->replace_reg
= NULL_RTX
;
4681 info
->must_load_z
= 1;
4682 info
->need_save_z
= 1;
4683 info
->must_save_reg
= 1;
4684 info
->must_restore_reg
= 1;
4688 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4689 info
->found_call
= 0;
4693 info
->z_set_count
= 0;
4694 info
->z_value
= NULL_RTX
;
4695 info
->must_push_reg
= 0;
4696 info
->save_before_last
= 0;
4697 info
->z_loaded_with_sp
= 0;
4699 /* Scan the insn forward to find an address register that is not used.
4701 - the flow of the program changes,
4702 - when we detect that both X and Y are necessary,
4703 - when the Z register dies,
4704 - when the condition codes are set. */
4706 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4708 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4712 /* May be we can use Y or X if they contain the same value as Z.
4713 This happens very often after the reload. */
4714 if (info
->z_set_count
== 1)
4716 rtx p
= info
->first
;
4721 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4723 else if (info
->y_used
)
4725 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4727 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4730 info
->regno
= HARD_Y_REGNUM
;
4732 info
->regno
= HARD_X_REGNUM
;
4733 info
->must_load_z
= 0;
4734 info
->must_save_reg
= 0;
4735 info
->must_restore_reg
= 0;
4736 info
->found_call
= 1;
4739 if (info
->z_set_count
== 0)
4740 info
->need_save_z
= 0;
4743 info
->need_save_z
= 0;
4745 if (info
->last
== 0)
4748 if (info
->regno
>= 0)
4751 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4753 else if (info
->can_use_d
)
4755 reg
= HARD_D_REGNUM
;
4756 info
->replace_reg
= d_reg
;
4758 else if (info
->x_used
)
4760 reg
= HARD_Y_REGNUM
;
4761 info
->replace_reg
= iy_reg
;
4765 reg
= HARD_X_REGNUM
;
4766 info
->replace_reg
= ix_reg
;
4770 if (info
->must_save_reg
&& info
->must_restore_reg
)
4772 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4774 info
->must_save_reg
= 0;
4775 info
->must_restore_reg
= 0;
4780 /* The insn uses the Z register. Find a replacement register for it
4781 (either X or Y) and replace it in the insn and the next ones until
4782 the flow changes or the replacement register is used. Instructions
4783 are emited before and after the Z-block to preserve the value of
4784 Z and of the replacement register. */
4787 m68hc11_z_replacement (insn
)
4792 struct replace_info info
;
4794 /* Find trivial case where we only need to replace z with the
4795 equivalent soft register. */
4796 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4798 rtx body
= PATTERN (insn
);
4799 rtx src
= XEXP (body
, 1);
4800 rtx dst
= XEXP (body
, 0);
4802 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4804 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4807 else if (Z_REG_P (src
)
4808 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4810 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4813 else if (D_REG_P (dst
)
4814 && m68hc11_arith_operator (src
, GET_MODE (src
))
4815 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4817 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4820 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4821 && INTVAL (src
) == 0)
4823 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4824 /* Force it to be re-recognized. */
4825 INSN_CODE (insn
) = -1;
4830 m68hc11_find_z_replacement (insn
, &info
);
4832 replace_reg
= info
.replace_reg
;
4833 replace_reg_qi
= NULL_RTX
;
4835 /* Save the X register in a .page0 location. */
4836 if (info
.must_save_reg
&& !info
.must_push_reg
)
4840 if (info
.must_push_reg
&& 0)
4841 dst
= gen_rtx (MEM
, HImode
,
4842 gen_rtx (PRE_DEC
, HImode
,
4843 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4845 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4847 emit_insn_before (gen_movhi (dst
,
4848 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4850 if (info
.must_load_z
&& !info
.must_push_reg
)
4852 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4853 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4858 /* Replace all occurrence of Z by replace_reg.
4859 Stop when the last instruction to replace is reached.
4860 Also stop when we detect a change in the flow (but it's not
4861 necessary; just safeguard). */
4863 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4867 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4870 if (GET_CODE (insn
) != INSN
4871 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4874 body
= PATTERN (insn
);
4875 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4876 || GET_CODE (body
) == ASM_OPERANDS
4877 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4881 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4883 printf ("Reg mentioned here...:\n");
4888 /* Stack pointer was decremented by 2 due to the push.
4889 Correct that by adding 2 to the destination. */
4890 if (info
.must_push_reg
4891 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4895 src
= SET_SRC (body
);
4896 dst
= SET_DEST (body
);
4897 if (SP_REG_P (src
) && Z_REG_P (dst
))
4898 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4901 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4902 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4904 INSN_CODE (insn
) = -1;
4905 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4906 fatal_insn ("cannot do z-register replacement", insn
);
4909 /* Likewise for (REG:QI Z). */
4910 if (reg_mentioned_p (z_reg
, insn
))
4912 if (replace_reg_qi
== NULL_RTX
)
4913 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4914 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4917 /* If there is a REG_INC note on Z, replace it with a
4918 REG_INC note on the replacement register. This is necessary
4919 to make sure that the flow pass will identify the change
4920 and it will not remove a possible insn that saves Z. */
4921 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4923 if (REG_NOTE_KIND (note
) == REG_INC
4924 && GET_CODE (XEXP (note
, 0)) == REG
4925 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4927 XEXP (note
, 0) = replace_reg
;
4931 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4935 /* Save Z before restoring the old value. */
4936 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4938 rtx save_pos_insn
= insn
;
4940 /* If Z is clobber by the last insn, we have to save its value
4941 before the last instruction. */
4942 if (info
.save_before_last
)
4943 save_pos_insn
= PREV_INSN (save_pos_insn
);
4945 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4946 gen_rtx (REG
, HImode
, info
.regno
)),
4950 if (info
.must_push_reg
&& info
.last
)
4954 body
= PATTERN (info
.last
);
4955 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4957 gen_rtx (USE
, VOIDmode
,
4959 gen_rtx (USE
, VOIDmode
,
4960 gen_rtx (REG
, HImode
,
4962 PATTERN (info
.last
) = new_body
;
4964 /* Force recognition on insn since we changed it. */
4965 INSN_CODE (insn
) = -1;
4967 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4969 fatal_insn ("invalid Z register replacement for insn", insn
);
4971 insn
= NEXT_INSN (info
.last
);
4974 /* Restore replacement register unless it was died. */
4975 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4979 if (info
.must_push_reg
&& 0)
4980 dst
= gen_rtx (MEM
, HImode
,
4981 gen_rtx (POST_INC
, HImode
,
4982 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4984 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4986 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4993 /* Scan all the insn and re-affects some registers
4994 - The Z register (if it was used), is affected to X or Y depending
4995 on the instruction. */
4998 m68hc11_reassign_regs (first
)
5003 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5004 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5005 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5006 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5008 /* Scan all insns to replace Z by X or Y preserving the old value
5009 of X/Y and restoring it afterward. */
5011 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5015 if (GET_CODE (insn
) == CODE_LABEL
5016 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5019 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5022 body
= PATTERN (insn
);
5023 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5026 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5027 || GET_CODE (body
) == ASM_OPERANDS
5028 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5031 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5032 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5035 /* If Z appears in this insn, replace it in the current insn
5036 and the next ones until the flow changes or we have to
5037 restore back the replacement register. */
5039 if (reg_mentioned_p (z_reg
, body
))
5041 m68hc11_z_replacement (insn
);
5046 printf ("insn not handled by Z replacement:\n");
5055 m68hc11_reorg (first
)
5061 z_replacement_completed
= 0;
5062 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5064 /* Some RTX are shared at this point. This breaks the Z register
5065 replacement, unshare everything. */
5066 unshare_all_rtl_again (first
);
5068 /* Force a split of all splitable insn. This is necessary for the
5069 Z register replacement mechanism because we end up with basic insns. */
5070 split_all_insns_noflow ();
5073 z_replacement_completed
= 1;
5074 m68hc11_reassign_regs (first
);
5077 compute_bb_for_insn ();
5079 /* After some splitting, there are some oportunities for CSE pass.
5080 This happens quite often when 32-bit or above patterns are split. */
5081 if (optimize
> 0 && split_done
)
5083 reload_cse_regs (first
);
5086 /* Re-create the REG_DEAD notes. These notes are used in the machine
5087 description to use the best assembly directives. */
5090 /* Before recomputing the REG_DEAD notes, remove all of them.
5091 This is necessary because the reload_cse_regs() pass can
5092 have replaced some (MEM) with a register. In that case,
5093 the REG_DEAD that could exist for that register may become
5095 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5101 pnote
= ®_NOTES (insn
);
5104 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5105 *pnote
= XEXP (*pnote
, 1);
5107 pnote
= &XEXP (*pnote
, 1);
5112 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5115 z_replacement_completed
= 2;
5117 /* If optimizing, then go ahead and split insns that must be
5118 split after Z register replacement. This gives more opportunities
5119 for peephole (in particular for consecutives xgdx/xgdy). */
5121 split_all_insns_noflow ();
5123 /* Once insns are split after the z_replacement_completed == 2,
5124 we must not re-run the life_analysis. The xgdx/xgdy patterns
5125 are not recognized and the life_analysis pass removes some
5126 insns because it thinks some (SETs) are noops or made to dead
5127 stores (which is false due to the swap).
5129 Do a simple pass to eliminate the noop set that the final
5130 split could generate (because it was easier for split definition). */
5134 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5138 if (INSN_DELETED_P (insn
))
5140 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5143 /* Remove the (set (R) (R)) insns generated by some splits. */
5144 body
= PATTERN (insn
);
5145 if (GET_CODE (body
) == SET
5146 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5148 PUT_CODE (insn
, NOTE
);
5149 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5150 NOTE_SOURCE_FILE (insn
) = 0;
5158 /* Cost functions. */
5160 /* Cost of moving memory. */
5162 m68hc11_memory_move_cost (mode
, class, in
)
5163 enum machine_mode mode
;
5164 enum reg_class
class;
5165 int in ATTRIBUTE_UNUSED
;
5167 if (class <= H_REGS
&& class > NO_REGS
)
5169 if (GET_MODE_SIZE (mode
) <= 2)
5170 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5172 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5176 if (GET_MODE_SIZE (mode
) <= 2)
5177 return COSTS_N_INSNS (2);
5179 return COSTS_N_INSNS (4);
5184 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5185 Reload does not check the constraint of set insns when the two registers
5186 have a move cost of 2. Setting a higher cost will force reload to check
5189 m68hc11_register_move_cost (mode
, from
, to
)
5190 enum machine_mode mode
;
5191 enum reg_class from
;
5194 /* All costs are symmetric, so reduce cases by putting the
5195 lower number class as the destination. */
5198 enum reg_class tmp
= to
;
5199 to
= from
, from
= tmp
;
5202 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5203 else if (from
<= S_REGS
)
5204 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5206 return COSTS_N_INSNS (2);
5210 /* Provide the costs of an addressing mode that contains ADDR.
5211 If ADDR is not a valid address, its cost is irrelevant. */
5214 m68hc11_address_cost (addr
)
5219 switch (GET_CODE (addr
))
5222 /* Make the cost of hard registers and specially SP, FP small. */
5223 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5240 register rtx plus0
= XEXP (addr
, 0);
5241 register rtx plus1
= XEXP (addr
, 1);
5243 if (GET_CODE (plus0
) != REG
)
5246 switch (GET_CODE (plus1
))
5249 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5250 || INTVAL (plus1
) < m68hc11_min_offset
)
5252 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5256 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5278 if (SP_REG_P (XEXP (addr
, 0)))
5287 printf ("Address cost: %d for :", cost
);
5296 m68hc11_shift_cost (mode
, x
, shift
)
5297 enum machine_mode mode
;
5303 total
= rtx_cost (x
, SET
);
5305 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5306 else if (mode
== HImode
)
5307 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5308 else if (shift
== 8 || shift
== 16 || shift
== 32)
5309 total
+= m68hc11_cost
->shiftHI_const
[8];
5310 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5312 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5315 /* For SI and others, the cost is higher. */
5316 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5317 total
*= GET_MODE_SIZE (mode
) / 2;
5319 /* When optimizing for size, make shift more costly so that
5320 multiplications are preferred. */
5321 if (optimize_size
&& (shift
% 8) != 0)
5328 m68hc11_rtx_costs (x
, code
, outer_code
)
5331 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5333 enum machine_mode mode
= GET_MODE (x
);
5344 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5346 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5349 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5350 total
+= m68hc11_cost
->shift_var
;
5356 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5357 total
+= m68hc11_cost
->logical
;
5359 /* Logical instructions are byte instructions only. */
5360 total
*= GET_MODE_SIZE (mode
);
5365 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5366 total
+= m68hc11_cost
->add
;
5367 if (GET_MODE_SIZE (mode
) > 2)
5369 total
*= GET_MODE_SIZE (mode
) / 2;
5376 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5380 total
+= m68hc11_cost
->divQI
;
5384 total
+= m68hc11_cost
->divHI
;
5389 total
+= m68hc11_cost
->divSI
;
5395 /* mul instruction produces 16-bit result. */
5396 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5397 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5398 return m68hc11_cost
->multQI
5399 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5400 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5402 /* emul instruction produces 32-bit result for 68HC12. */
5403 if (TARGET_M6812
&& mode
== SImode
5404 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5405 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5406 return m68hc11_cost
->multHI
5407 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5408 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5410 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5414 total
+= m68hc11_cost
->multQI
;
5418 total
+= m68hc11_cost
->multHI
;
5423 total
+= m68hc11_cost
->multSI
;
5430 extra_cost
= COSTS_N_INSNS (2);
5437 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5440 return total
+ COSTS_N_INSNS (1);
5444 return total
+ COSTS_N_INSNS (2);
5448 return total
+ COSTS_N_INSNS (4);
5450 return total
+ COSTS_N_INSNS (8);
5453 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5454 return COSTS_N_INSNS (1);
5456 return COSTS_N_INSNS (1);
5459 return COSTS_N_INSNS (4);
5464 /* print_options - called at the start of the code generation for a
5467 extern char *asm_file_name
;
5470 #include <sys/types.h>
5479 extern int save_argc
;
5480 extern char **save_argv
;
5482 fprintf (out
, ";;; Command:\t");
5483 for (i
= 0; i
< save_argc
; i
++)
5485 fprintf (out
, "%s", save_argv
[i
]);
5486 if (i
+ 1 < save_argc
)
5489 fprintf (out
, "\n");
5491 a_time
= ctime (&c_time
);
5492 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5495 #define __VERSION__ "[unknown]"
5497 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5499 fprintf (out
, ";;; (META)compiled by CC.\n");
5504 m68hc11_asm_file_start (out
, main_file
)
5506 const char *main_file
;
5508 fprintf (out
, ";;;-----------------------------------------\n");
5509 fprintf (out
, ";;; Start MC68HC11 gcc assembly output\n");
5510 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5511 print_options (out
);
5512 fprintf (out
, ";;;-----------------------------------------\n");
5513 output_file_directive (out
, main_file
);
5516 fprintf (out
, "\t.mode mshort\n");
5518 fprintf (out
, "\t.mode mlong\n");
5523 m68hc11_asm_out_constructor (symbol
, priority
)
5527 default_ctor_section_asm_out_constructor (symbol
, priority
);
5528 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5532 m68hc11_asm_out_destructor (symbol
, priority
)
5536 default_dtor_section_asm_out_destructor (symbol
, priority
);
5537 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");