1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@nerim.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
23 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24 on gcc 2.6.3. I have used it as a starting point for this port.
25 However, this new port is a complete re-write. Its internal
26 design is completely different. The generated code is not
27 compatible with the gcc 2.6.3 port.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
42 #include "hard-reg-set.h"
44 #include "insn-config.h"
45 #include "conditions.h"
47 #include "insn-attr.h"
52 #include "basic-block.h"
57 #include "target-def.h"
59 static void print_options
PARAMS ((FILE *));
60 static void emit_move_after_reload
PARAMS ((rtx
, rtx
, rtx
));
61 static rtx simplify_logical
PARAMS ((enum machine_mode
, int, rtx
, rtx
*));
62 static void m68hc11_emit_logical
PARAMS ((enum machine_mode
, int, rtx
*));
63 static int go_if_legitimate_address_internal
PARAMS((rtx
, enum machine_mode
,
65 static int register_indirect_p
PARAMS((rtx
, enum machine_mode
, int));
66 static rtx m68hc11_expand_compare
PARAMS((enum rtx_code
, rtx
, rtx
));
67 static int m68hc11_autoinc_compatible_p
PARAMS ((rtx
, rtx
));
68 static int must_parenthesize
PARAMS ((rtx
));
69 static int m68hc11_shift_cost
PARAMS ((enum machine_mode
, rtx
, int));
70 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
71 static tree m68hc11_handle_fntype_attribute
PARAMS ((tree
*, tree
, tree
, int, bool *));
72 const struct attribute_spec m68hc11_attribute_table
[];
74 void create_regs_rtx
PARAMS ((void));
76 static void asm_print_register
PARAMS ((FILE *, int));
77 static void m68hc11_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
78 static void m68hc11_asm_out_constructor
PARAMS ((rtx
, int));
79 static void m68hc11_asm_out_destructor
PARAMS ((rtx
, int));
80 static void m68hc11_encode_section_info
PARAMS((tree
, int));
82 rtx m68hc11_soft_tmp_reg
;
84 /* Must be set to 1 to produce debug messages. */
87 extern FILE *asm_out_file
;
95 static int regs_inited
= 0;
98 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
99 int current_function_interrupt
;
101 /* Set to 1 by expand_prologue() when the function is a trap handler. */
102 int current_function_trap
;
104 /* Min offset that is valid for the indirect addressing mode. */
105 HOST_WIDE_INT m68hc11_min_offset
= 0;
107 /* Max offset that is valid for the indirect addressing mode. */
108 HOST_WIDE_INT m68hc11_max_offset
= 256;
110 /* The class value for base registers. */
111 enum reg_class m68hc11_base_reg_class
= A_REGS
;
113 /* The class value for index registers. This is NO_REGS for 68HC11. */
114 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
116 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
118 /* Tables that tell whether a given hard register is valid for
119 a base or an index register. It is filled at init time depending
120 on the target processor. */
121 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
122 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
124 /* A correction offset which is applied to the stack pointer.
125 This is 1 for 68HC11 and 0 for 68HC12. */
126 int m68hc11_sp_correction
;
128 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
129 rtx m68hc11_compare_op0
;
130 rtx m68hc11_compare_op1
;
133 const struct processor_costs
*m68hc11_cost
;
135 /* Costs for a 68HC11. */
136 static const struct processor_costs m6811_cost
= {
141 /* non-constant shift */
144 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
145 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
146 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
149 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
150 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
151 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
152 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
153 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
154 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
159 COSTS_N_INSNS (20 * 4),
161 COSTS_N_INSNS (20 * 16),
170 /* Costs for a 68HC12. */
171 static const struct processor_costs m6812_cost
= {
176 /* non-constant shift */
179 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
180 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
181 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
184 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
185 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
186 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
187 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
188 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
189 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
196 COSTS_N_INSNS (3 * 4),
205 /* Machine specific options */
207 const char *m68hc11_regparm_string
;
208 const char *m68hc11_reg_alloc_order
;
209 const char *m68hc11_soft_reg_count
;
211 static int nb_soft_regs
;
213 /* Initialize the GCC target structure. */
214 #undef TARGET_ATTRIBUTE_TABLE
215 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
217 #undef TARGET_ASM_ALIGNED_HI_OP
218 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
220 #undef TARGET_ASM_FUNCTION_EPILOGUE
221 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
223 #undef TARGET_ENCODE_SECTION_INFO
224 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
226 struct gcc_target targetm
= TARGET_INITIALIZER
;
229 m68hc11_override_options ()
231 memset (m68hc11_reg_valid_for_index
, 0,
232 sizeof (m68hc11_reg_valid_for_index
));
233 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
235 /* Compilation with -fpic generates a wrong code. */
238 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
239 (flag_pic
> 1) ? "PIC" : "pic");
243 /* Configure for a 68hc11 processor. */
246 /* If gcc was built for a 68hc12, invalidate that because
247 a -m68hc11 option was specified on the command line. */
248 if (TARGET_DEFAULT
!= MASK_M6811
)
249 target_flags
&= ~TARGET_DEFAULT
;
252 target_flags
&= ~TARGET_AUTO_INC_DEC
;
253 m68hc11_cost
= &m6811_cost
;
254 m68hc11_min_offset
= 0;
255 m68hc11_max_offset
= 256;
256 m68hc11_index_reg_class
= NO_REGS
;
257 m68hc11_base_reg_class
= A_REGS
;
258 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
259 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
260 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
261 m68hc11_sp_correction
= 1;
262 m68hc11_tmp_regs_class
= D_REGS
;
263 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
264 m68hc11_soft_reg_count
= "4";
267 /* Configure for a 68hc12 processor. */
270 m68hc11_cost
= &m6812_cost
;
271 m68hc11_min_offset
= -65536;
272 m68hc11_max_offset
= 65536;
273 m68hc11_index_reg_class
= D_REGS
;
274 m68hc11_base_reg_class
= A_OR_SP_REGS
;
275 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
276 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
277 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
278 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
279 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
280 m68hc11_sp_correction
= 0;
281 m68hc11_tmp_regs_class
= TMP_REGS
;
282 target_flags
&= ~MASK_M6811
;
283 target_flags
|= MASK_NO_DIRECT_MODE
;
284 if (m68hc11_soft_reg_count
== 0)
285 m68hc11_soft_reg_count
= "0";
292 m68hc11_optimization_options (level
, size
)
293 int level ATTRIBUTE_UNUSED
;
296 /* When optimizing for size, do not reorder basic blocks because
297 it duplicates some insns for speed and this results in larder code.
298 This reordering can still be enabled but explicitly. */
301 flag_reorder_blocks
= 0;
307 m68hc11_conditional_register_usage ()
310 int cnt
= atoi (m68hc11_soft_reg_count
);
314 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
315 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
318 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
321 call_used_regs
[i
] = 1;
324 /* For 68HC12, the Z register emulation is not necessary when the
325 frame pointer is not used. The frame pointer is eliminated and
326 replaced by the stack register (which is a BASE_REG_CLASS). */
327 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
329 fixed_regs
[HARD_Z_REGNUM
] = 1;
334 /* Reload and register operations. */
336 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
342 /* regs_inited = 1; */
343 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
344 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
345 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
346 da_reg
= gen_rtx (REG
, QImode
, HARD_A_REGNUM
);
347 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
349 stack_push_word
= gen_rtx (MEM
, HImode
,
350 gen_rtx (PRE_DEC
, HImode
,
351 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
352 stack_pop_word
= gen_rtx (MEM
, HImode
,
353 gen_rtx (POST_INC
, HImode
,
354 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
358 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
359 - 8 bit values are stored anywhere (except the SP register).
360 - 16 bit values can be stored in any register whose mode is 16
361 - 32 bit values can be stored in D, X registers or in a soft register
362 (except the last one because we need 2 soft registers)
363 - Values whose size is > 32 bit are not stored in real hard
364 registers. They may be stored in soft registers if there are
367 hard_regno_mode_ok (regno
, mode
)
369 enum machine_mode mode
;
371 switch (GET_MODE_SIZE (mode
))
374 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
377 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
380 return G_REGNO_P (regno
);
383 /* We have to accept a QImode in X or Y registers. Otherwise, the
384 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
385 in the insns. Reload fails if the insn rejects the register class 'a'
386 as well as if it accepts it. Patterns that failed were
387 zero_extend_qihi2 and iorqi3. */
389 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
397 preferred_reload_class (operand
, class)
399 enum reg_class
class;
401 enum machine_mode mode
;
403 mode
= GET_MODE (operand
);
407 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
410 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
411 return m68hc11_base_reg_class
;
413 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
414 || GET_CODE (operand
) == CONST_INT
))
416 /* S_REGS class must not be used. The movhi template does not
417 work to move a memory to a soft register.
418 Restrict to a hard reg. */
423 case D_OR_A_OR_S_REGS
:
429 case D_OR_SP_OR_S_REGS
:
430 class = D_OR_SP_REGS
;
432 case D_OR_Y_OR_S_REGS
:
435 case D_OR_X_OR_S_REGS
:
451 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
455 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
459 else if (class >= S_REGS
&& S_REG_P (operand
))
465 case D_OR_A_OR_S_REGS
:
471 case D_OR_SP_OR_S_REGS
:
472 class = D_OR_SP_REGS
;
474 case D_OR_Y_OR_S_REGS
:
477 case D_OR_X_OR_S_REGS
:
493 else if (class >= S_REGS
)
497 printf ("Class = %s for: ", reg_class_names
[class]);
505 printf (" => class=%s\n", reg_class_names
[class]);
513 /* Return 1 if the operand is a valid indexed addressing mode.
514 For 68hc11: n,r with n in [0..255] and r in A_REGS class
515 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
517 register_indirect_p (operand
, mode
, strict
)
519 enum machine_mode mode
;
524 switch (GET_CODE (operand
))
530 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
531 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
535 base
= XEXP (operand
, 0);
536 if (GET_CODE (base
) == MEM
)
539 offset
= XEXP (operand
, 1);
540 if (GET_CODE (offset
) == MEM
)
543 if (GET_CODE (base
) == REG
)
545 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
551 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
553 if (GET_CODE (offset
) == REG
)
555 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
561 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
566 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
572 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
579 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
580 a 68HC12 1-byte index addressing mode. */
582 m68hc11_small_indexed_indirect_p (operand
, mode
)
584 enum machine_mode mode
;
588 if (GET_CODE (operand
) == REG
&& reload_in_progress
589 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
590 && reg_equiv_memory_loc
[REGNO (operand
)])
592 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
593 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
596 if (GET_CODE (operand
) != MEM
)
599 operand
= XEXP (operand
, 0);
600 if (CONSTANT_ADDRESS_P (operand
))
603 if (PUSH_POP_ADDRESS_P (operand
))
606 if (!register_indirect_p (operand
, mode
, reload_completed
))
609 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
610 && (reload_completed
| reload_in_progress
))
612 base
= XEXP (operand
, 0);
613 offset
= XEXP (operand
, 1);
615 /* The offset can be a symbol address and this is too big
616 for the operand constraint. */
617 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
620 if (GET_CODE (base
) == CONST_INT
)
623 switch (GET_MODE_SIZE (mode
))
626 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
631 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
636 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
645 m68hc11_register_indirect_p (operand
, mode
)
647 enum machine_mode mode
;
649 if (GET_CODE (operand
) != MEM
)
652 operand
= XEXP (operand
, 0);
653 return register_indirect_p (operand
, mode
,
654 (reload_completed
| reload_in_progress
));
658 go_if_legitimate_address_internal (operand
, mode
, strict
)
660 enum machine_mode mode
;
663 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
665 /* Reject the global variables if they are too wide. This forces
666 a load of their address in a register and generates smaller code. */
667 if (GET_MODE_SIZE (mode
) == 8)
672 if (register_indirect_p (operand
, mode
, strict
))
676 if (PUSH_POP_ADDRESS_P (operand
))
680 if (symbolic_memory_operand (operand
, mode
))
688 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
690 enum machine_mode mode
;
697 printf ("Checking: ");
702 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
706 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
713 printf ("go_if_legitimate%s, ret 0: %d:",
714 (strict
? "_strict" : ""), mode
);
723 m68hc11_legitimize_address (operand
, old_operand
, mode
)
724 rtx
*operand ATTRIBUTE_UNUSED
;
725 rtx old_operand ATTRIBUTE_UNUSED
;
726 enum machine_mode mode ATTRIBUTE_UNUSED
;
733 m68hc11_reload_operands (operands
)
736 enum machine_mode mode
;
738 if (regs_inited
== 0)
741 mode
= GET_MODE (operands
[1]);
743 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
744 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
746 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
747 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
749 if (GET_CODE (base
) != REG
)
756 /* If the offset is out of range, we have to compute the address
757 with a separate add instruction. We try to do with with an 8-bit
758 add on the A register. This is possible only if the lowest part
759 of the offset (ie, big_offset % 256) is a valid constant offset
760 with respect to the mode. If it's not, we have to generate a
761 16-bit add on the D register. From:
763 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
767 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
768 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
769 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
770 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
772 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
773 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
776 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
779 rtx reg
= operands
[0];
781 int val
= INTVAL (big_offset
);
784 /* We use the 'operands[0]' as a scratch register to compute the
785 address. Make sure 'base' is in that register. */
786 if (!rtx_equal_p (base
, operands
[0]))
788 emit_move_insn (reg
, base
);
798 vh
= (val
>> 8) & 0x0FF;
802 /* Create the lowest part offset that still remains to be added.
803 If it's not a valid offset, do a 16-bit add. */
804 offset
= GEN_INT (vl
);
805 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
807 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
808 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
813 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
814 gen_rtx (PLUS
, HImode
, reg
,
815 GEN_INT (vh
<< 8))));
817 emit_move_insn (operands
[0],
818 gen_rtx (MEM
, GET_MODE (operands
[1]),
819 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
824 /* Use the normal gen_movhi pattern. */
829 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
832 enum machine_mode dmode
;
833 enum machine_mode smode
;
843 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
847 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
848 dmode
, 1, operands
[1], smode
);
849 equiv
= gen_rtx (code
, dmode
, operands
[1]);
853 ret
= emit_library_call_value (libcall
, NULL_RTX
,
855 operands
[1], smode
, operands
[2],
857 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
864 insns
= get_insns ();
866 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
869 /* Returns true if X is a PRE/POST increment decrement
870 (same as auto_inc_p() in rtlanal.c but do not take into
871 account the stack). */
873 m68hc11_auto_inc_p (x
)
876 return GET_CODE (x
) == PRE_DEC
877 || GET_CODE (x
) == POST_INC
878 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
882 /* Predicates for machine description. */
885 memory_reload_operand (operand
, mode
)
887 enum machine_mode mode ATTRIBUTE_UNUSED
;
889 return GET_CODE (operand
) == MEM
890 && GET_CODE (XEXP (operand
, 0)) == PLUS
891 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
892 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
893 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
894 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
898 tst_operand (operand
, mode
)
900 enum machine_mode mode
;
902 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
904 rtx addr
= XEXP (operand
, 0);
905 if (m68hc11_auto_inc_p (addr
))
908 return nonimmediate_operand (operand
, mode
);
912 cmp_operand (operand
, mode
)
914 enum machine_mode mode
;
916 if (GET_CODE (operand
) == MEM
)
918 rtx addr
= XEXP (operand
, 0);
919 if (m68hc11_auto_inc_p (addr
))
922 return general_operand (operand
, mode
);
926 non_push_operand (operand
, mode
)
928 enum machine_mode mode
;
930 if (general_operand (operand
, mode
) == 0)
933 if (push_operand (operand
, mode
) == 1)
939 reg_or_some_mem_operand (operand
, mode
)
941 enum machine_mode mode
;
943 if (GET_CODE (operand
) == MEM
)
945 rtx op
= XEXP (operand
, 0);
947 if (symbolic_memory_operand (op
, mode
))
950 if (IS_STACK_PUSH (operand
))
953 if (m68hc11_register_indirect_p (operand
, mode
))
959 return register_operand (operand
, mode
);
963 m68hc11_symbolic_p (operand
, mode
)
965 enum machine_mode mode
;
967 if (GET_CODE (operand
) == MEM
)
969 rtx op
= XEXP (operand
, 0);
971 if (symbolic_memory_operand (op
, mode
))
978 m68hc11_indirect_p (operand
, mode
)
980 enum machine_mode mode
;
982 if (GET_CODE (operand
) == MEM
)
984 rtx op
= XEXP (operand
, 0);
986 if (symbolic_memory_operand (op
, mode
))
989 if (reload_in_progress
)
992 operand
= XEXP (operand
, 0);
993 return register_indirect_p (operand
, mode
, reload_completed
);
999 stack_register_operand (operand
, mode
)
1001 enum machine_mode mode ATTRIBUTE_UNUSED
;
1003 return SP_REG_P (operand
);
1007 d_register_operand (operand
, mode
)
1009 enum machine_mode mode ATTRIBUTE_UNUSED
;
1011 if (GET_CODE (operand
) == SUBREG
)
1012 operand
= XEXP (operand
, 0);
1014 return GET_CODE (operand
) == REG
1015 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1016 || REGNO (operand
) == HARD_D_REGNUM
1017 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1021 hard_addr_reg_operand (operand
, mode
)
1023 enum machine_mode mode ATTRIBUTE_UNUSED
;
1025 if (GET_CODE (operand
) == SUBREG
)
1026 operand
= XEXP (operand
, 0);
1028 return GET_CODE (operand
) == REG
1029 && (REGNO (operand
) == HARD_X_REGNUM
1030 || REGNO (operand
) == HARD_Y_REGNUM
1031 || REGNO (operand
) == HARD_Z_REGNUM
);
1035 hard_reg_operand (operand
, mode
)
1037 enum machine_mode mode ATTRIBUTE_UNUSED
;
1039 if (GET_CODE (operand
) == SUBREG
)
1040 operand
= XEXP (operand
, 0);
1042 return GET_CODE (operand
) == REG
1043 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1044 || H_REGNO_P (REGNO (operand
)));
1048 memory_indexed_operand (operand
, mode
)
1050 enum machine_mode mode ATTRIBUTE_UNUSED
;
1052 if (GET_CODE (operand
) != MEM
)
1055 operand
= XEXP (operand
, 0);
1056 if (GET_CODE (operand
) == PLUS
)
1058 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1059 operand
= XEXP (operand
, 0);
1060 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1061 operand
= XEXP (operand
, 1);
1063 return GET_CODE (operand
) == REG
1064 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1065 || A_REGNO_P (REGNO (operand
)));
1069 push_pop_operand_p (operand
)
1072 if (GET_CODE (operand
) != MEM
)
1076 operand
= XEXP (operand
, 0);
1077 return PUSH_POP_ADDRESS_P (operand
);
1080 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1081 reference and a constant. */
1084 symbolic_memory_operand (op
, mode
)
1086 enum machine_mode mode
;
1088 switch (GET_CODE (op
))
1096 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1097 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1098 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1100 /* ??? This clause seems to be irrelevant. */
1102 return GET_MODE (op
) == mode
;
1105 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1106 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1114 m68hc11_logical_operator (op
, mode
)
1116 enum machine_mode mode ATTRIBUTE_UNUSED
;
1118 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1122 m68hc11_arith_operator (op
, mode
)
1124 enum machine_mode mode ATTRIBUTE_UNUSED
;
1126 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1127 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1128 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1129 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1130 || GET_CODE (op
) == ROTATERT
;
1134 m68hc11_non_shift_operator (op
, mode
)
1136 enum machine_mode mode ATTRIBUTE_UNUSED
;
1138 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1139 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1144 m68hc11_unary_operator (op
, mode
)
1146 enum machine_mode mode ATTRIBUTE_UNUSED
;
1148 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1149 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1152 /* Emit the code to build the trampoline used to call a nested function.
1156 ldy #&CXT movw #&CXT,*_.d1
1157 sty *_.d1 jmp FNADDR
1162 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1167 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1170 if (*static_chain_reg
== '*')
1174 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1175 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1176 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1178 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1179 gen_rtx_CONST (QImode
,
1180 gen_rtx_SYMBOL_REF (Pmode
,
1181 static_chain_reg
)));
1182 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1184 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1188 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1189 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1190 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1191 gen_rtx_CONST (HImode
,
1192 gen_rtx_SYMBOL_REF (Pmode
,
1193 static_chain_reg
)));
1194 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1196 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1200 /* Declaration of types. */
1202 const struct attribute_spec m68hc11_attribute_table
[] =
1204 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1205 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1206 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1207 { NULL
, 0, 0, false, false, false, NULL
}
1210 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1211 arguments as in struct attribute_spec.handler. */
1213 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1216 tree args ATTRIBUTE_UNUSED
;
1217 int flags ATTRIBUTE_UNUSED
;
1220 if (TREE_CODE (*node
) != FUNCTION_TYPE
1221 && TREE_CODE (*node
) != FIELD_DECL
1222 && TREE_CODE (*node
) != TYPE_DECL
)
1224 warning ("`%s' attribute only applies to functions",
1225 IDENTIFIER_POINTER (name
));
1226 *no_add_attrs
= true;
1232 /* We want to recognize trap handlers so that we handle calls to traps
1233 in a special manner (by issuing the trap). This information is stored
1234 in SYMBOL_REF_FLAG. */
1237 m68hc11_encode_section_info (decl
, first
)
1239 int first ATTRIBUTE_UNUSED
;
1245 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1248 rtl
= DECL_RTL (decl
);
1250 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1251 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1252 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1256 /* Argument support functions. */
1258 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1259 Arrays are passed by references and other types by value.
1261 SCz: I tried to pass DImode by reference but it seems that this
1262 does not work very well. */
1264 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1265 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1266 enum machine_mode mode ATTRIBUTE_UNUSED
;
1268 int named ATTRIBUTE_UNUSED
;
1270 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1271 /* Consider complex values as aggregates, so care for TCmode. */
1272 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1273 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1277 /* Define the offset between two registers, one to be eliminated, and the
1278 other its replacement, at the start of a routine. */
1280 m68hc11_initial_elimination_offset (from
, to
)
1289 /* For a trap handler, we must take into account the registers which
1290 are pushed on the stack during the trap (except the PC). */
1291 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1292 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1293 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1298 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1300 /* 2 is for the saved frame.
1301 1 is for the 'sts' correction when creating the frame. */
1302 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1305 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1307 return m68hc11_sp_correction
;
1310 /* Push any 2 byte pseudo hard registers that we need to save. */
1311 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1313 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1319 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1321 return get_frame_size () + size
;
1324 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1331 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1332 for a call to a function whose data type is FNTYPE.
1333 For a library call, FNTYPE is 0. */
1336 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1337 CUMULATIVE_ARGS
*cum
;
1343 z_replacement_completed
= 0;
1347 /* For a library call, we must find out the type of the return value.
1348 When the return value is bigger than 4 bytes, it is returned in
1349 memory. In that case, the first argument of the library call is a
1350 pointer to the memory location. Because the first argument is passed in
1351 register D, we have to identify this, so that the first function
1352 parameter is not passed in D either. */
1358 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1361 /* If the library ends in 'di' or in 'df', we assume it's
1362 returning some DImode or some DFmode which are 64-bit wide. */
1363 name
= XSTR (libname
, 0);
1364 len
= strlen (name
);
1366 && ((name
[len
- 2] == 'd'
1367 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1368 || (name
[len
- 3] == 'd'
1369 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1371 /* We are in. Mark the first parameter register as already used. */
1378 ret_type
= TREE_TYPE (fntype
);
1380 if (ret_type
&& aggregate_value_p (ret_type
))
1387 /* Update the data in CUM to advance over an argument
1388 of mode MODE and data type TYPE.
1389 (TYPE is null for libcalls where that information may not be available.) */
1392 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1393 CUMULATIVE_ARGS
*cum
;
1394 enum machine_mode mode
;
1396 int named ATTRIBUTE_UNUSED
;
1398 if (mode
!= BLKmode
)
1400 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1403 cum
->words
= GET_MODE_SIZE (mode
);
1407 cum
->words
+= GET_MODE_SIZE (mode
);
1408 if (cum
->words
<= HARD_REG_SIZE
)
1414 cum
->words
+= int_size_in_bytes (type
);
1419 /* Define where to put the arguments to a function.
1420 Value is zero to push the argument on the stack,
1421 or a hard register in which to store the argument.
1423 MODE is the argument's machine mode.
1424 TYPE is the data type of the argument (as a tree).
1425 This is null for libcalls where that information may
1427 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1428 the preceding args and about the function being called.
1429 NAMED is nonzero if this argument is a named parameter
1430 (otherwise it is an extra parameter matching an ellipsis). */
1433 m68hc11_function_arg (cum
, mode
, type
, named
)
1434 const CUMULATIVE_ARGS
*cum
;
1435 enum machine_mode mode
;
1436 tree type ATTRIBUTE_UNUSED
;
1437 int named ATTRIBUTE_UNUSED
;
1439 if (cum
->words
!= 0)
1444 if (mode
!= BLKmode
)
1446 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1447 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1449 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1453 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1459 m68hc11_va_arg (valist
, type
)
1464 HOST_WIDE_INT align
;
1465 HOST_WIDE_INT rounded_size
;
1469 /* Compute the rounded size of the type. */
1470 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1471 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1475 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1477 if (pad_direction
== downward
)
1479 /* Small args are padded downward. */
1482 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1483 if (rounded_size
> align
)
1486 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1487 build_int_2 (rounded_size
- adj
, 0));
1490 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1491 addr
= copy_to_reg (addr
);
1493 /* Compute new value for AP. */
1494 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1495 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1496 build_int_2 (rounded_size
, 0)));
1497 TREE_SIDE_EFFECTS (t
) = 1;
1498 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1503 /* If defined, a C expression which determines whether, and in which direction,
1504 to pad out an argument with extra space. The value should be of type
1505 `enum direction': either `upward' to pad above the argument,
1506 `downward' to pad below, or `none' to inhibit padding.
1508 Structures are stored left shifted in their argument slot. */
1510 m68hc11_function_arg_padding (mode
, type
)
1511 enum machine_mode mode
;
1514 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1517 /* This is the default definition. */
1518 return (!BYTES_BIG_ENDIAN
1521 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1522 && int_size_in_bytes (type
) <
1523 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1524 PARM_BOUNDARY
) ? downward
: upward
));
1528 /* Function prologue and epilogue. */
1530 /* Emit a move after the reload pass has completed. This is used to
1531 emit the prologue and epilogue. */
1533 emit_move_after_reload (to
, from
, scratch
)
1534 rtx to
, from
, scratch
;
1538 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1540 insn
= emit_move_insn (to
, from
);
1544 emit_move_insn (scratch
, from
);
1545 insn
= emit_move_insn (to
, scratch
);
1548 /* Put a REG_INC note to tell the flow analysis that the instruction
1550 if (IS_STACK_PUSH (to
))
1552 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1553 XEXP (XEXP (to
, 0), 0),
1556 else if (IS_STACK_POP (from
))
1558 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1559 XEXP (XEXP (from
, 0), 0),
1563 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1564 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1565 The problem is that we are lying to gcc and use `txs' for x = sp
1566 (which is not really true because txs is really x = sp + 1). */
1567 else if (TARGET_M6811
&& SP_REG_P (from
))
1569 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1576 m68hc11_total_frame_size ()
1581 size
= get_frame_size ();
1582 if (current_function_interrupt
)
1584 size
+= 3 * HARD_REG_SIZE
;
1586 if (frame_pointer_needed
)
1587 size
+= HARD_REG_SIZE
;
1589 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1590 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1591 size
+= HARD_REG_SIZE
;
1597 m68hc11_output_function_epilogue (out
, size
)
1598 FILE *out ATTRIBUTE_UNUSED
;
1599 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1601 /* We catch the function epilogue generation to have a chance
1602 to clear the z_replacement_completed flag. */
1603 z_replacement_completed
= 0;
1614 if (reload_completed
!= 1)
1617 size
= get_frame_size ();
1621 /* Generate specific prologue for interrupt handlers. */
1622 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1623 current_function_interrupt
= lookup_attribute ("interrupt",
1624 func_attr
) != NULL_TREE
;
1625 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1627 /* Get the scratch register to build the frame and push registers.
1628 If the first argument is a 32-bit quantity, the D+X registers
1629 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1630 For 68HC12, this scratch register is not used. */
1631 if (current_function_args_info
.nregs
== 2)
1636 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1637 Other soft registers in page0 need not to be saved because they
1638 will be restored by C functions. For a trap handler, we don't
1639 need to preserve these registers because this is a synchronous call. */
1640 if (current_function_interrupt
)
1642 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1643 emit_move_after_reload (stack_push_word
,
1644 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1645 emit_move_after_reload (stack_push_word
,
1646 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1650 /* Save current stack frame. */
1651 if (frame_pointer_needed
)
1652 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1654 /* Allocate local variables. */
1655 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1657 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1658 stack_pointer_rtx
, GEN_INT (-size
)));
1664 insn
= gen_rtx_PARALLEL
1667 gen_rtx_SET (VOIDmode
,
1669 gen_rtx_PLUS (HImode
,
1672 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1679 /* Allocate by pushing scratch values. */
1680 for (i
= 2; i
<= size
; i
+= 2)
1681 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1684 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1685 stack_pointer_rtx
, GEN_INT (-1)));
1688 /* Create the frame pointer. */
1689 if (frame_pointer_needed
)
1690 emit_move_after_reload (hard_frame_pointer_rtx
,
1691 stack_pointer_rtx
, scratch
);
1693 /* Push any 2 byte pseudo hard registers that we need to save. */
1694 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1696 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1698 emit_move_after_reload (stack_push_word
,
1699 gen_rtx (REG
, HImode
, regno
), scratch
);
1712 if (reload_completed
!= 1)
1715 size
= get_frame_size ();
1717 /* If we are returning a value in two registers, we have to preserve the
1718 X register and use the Y register to restore the stack and the saved
1719 registers. Otherwise, use X because it's faster (and smaller). */
1720 if (current_function_return_rtx
== 0)
1722 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1723 return_size
= HARD_REG_SIZE
;
1725 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1727 if (return_size
> HARD_REG_SIZE
)
1732 /* Pop any 2 byte pseudo hard registers that we saved. */
1733 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1735 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1737 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1738 stack_pop_word
, scratch
);
1742 /* de-allocate auto variables */
1743 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1745 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1746 stack_pointer_rtx
, GEN_INT (size
)));
1752 insn
= gen_rtx_PARALLEL
1755 gen_rtx_SET (VOIDmode
,
1757 gen_rtx_PLUS (HImode
,
1760 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1767 for (i
= 2; i
<= size
; i
+= 2)
1768 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1770 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1771 stack_pointer_rtx
, GEN_INT (1)));
1774 /* Restore previous frame pointer. */
1775 if (frame_pointer_needed
)
1776 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1778 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1779 if (current_function_interrupt
)
1781 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1782 stack_pop_word
, scratch
);
1783 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1784 stack_pop_word
, scratch
);
1785 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1788 /* If the trap handler returns some value, copy the value
1789 in D, X onto the stack so that the rti will pop the return value
1791 else if (current_function_trap
&& return_size
!= 0)
1793 rtx addr_reg
= stack_pointer_rtx
;
1797 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1800 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1801 gen_rtx (PLUS
, HImode
, addr_reg
,
1802 GEN_INT (1))), d_reg
, 0);
1803 if (return_size
> HARD_REG_SIZE
)
1804 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1805 gen_rtx (PLUS
, HImode
, addr_reg
,
1806 GEN_INT (3))), ix_reg
, 0);
1809 emit_jump_insn (gen_return ());
1813 /* Low and High part extraction for 68HC11. These routines are
1814 similar to gen_lowpart and gen_highpart but they have been
1815 fixed to work for constants and 68HC11 specific registers. */
1818 m68hc11_gen_lowpart (mode
, x
)
1819 enum machine_mode mode
;
1822 /* We assume that the low part of an auto-inc mode is the same with
1823 the mode changed and that the caller split the larger mode in the
1825 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1827 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1830 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1831 floating-point constant. A CONST_DOUBLE is used whenever the
1832 constant requires more than one word in order to be adequately
1834 if (GET_CODE (x
) == CONST_DOUBLE
)
1838 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1842 if (GET_MODE (x
) == SFmode
)
1844 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1845 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1851 split_double (x
, &first
, &second
);
1855 return GEN_INT (l
[0]);
1857 return gen_int_mode (l
[0], HImode
);
1861 l
[0] = CONST_DOUBLE_LOW (x
);
1864 return GEN_INT (l
[0]);
1865 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1866 return gen_int_mode (l
[0], HImode
);
1871 if (mode
== QImode
&& D_REG_P (x
))
1872 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1874 /* gen_lowpart crashes when it is called with a SUBREG. */
1875 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1878 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1879 else if (mode
== HImode
)
1880 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1884 x
= gen_lowpart (mode
, x
);
1886 /* Return a different rtx to avoid to share it in several insns
1887 (when used by a split pattern). Sharing addresses within
1888 a MEM breaks the Z register replacement (and reloading). */
1889 if (GET_CODE (x
) == MEM
)
1895 m68hc11_gen_highpart (mode
, x
)
1896 enum machine_mode mode
;
1899 /* We assume that the high part of an auto-inc mode is the same with
1900 the mode changed and that the caller split the larger mode in the
1902 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1904 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1907 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1908 floating-point constant. A CONST_DOUBLE is used whenever the
1909 constant requires more than one word in order to be adequately
1911 if (GET_CODE (x
) == CONST_DOUBLE
)
1915 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1919 if (GET_MODE (x
) == SFmode
)
1921 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1922 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1928 split_double (x
, &first
, &second
);
1932 return GEN_INT (l
[1]);
1934 return gen_int_mode ((l
[1] >> 16), HImode
);
1938 l
[1] = CONST_DOUBLE_HIGH (x
);
1942 return GEN_INT (l
[1]);
1943 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1944 return gen_int_mode ((l
[0] >> 16), HImode
);
1948 if (GET_CODE (x
) == CONST_INT
)
1950 HOST_WIDE_INT val
= INTVAL (x
);
1954 return gen_int_mode (val
>> 8, QImode
);
1956 else if (mode
== HImode
)
1958 return gen_int_mode (val
>> 16, HImode
);
1961 if (mode
== QImode
&& D_REG_P (x
))
1962 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1964 /* There is no way in GCC to represent the upper part of a word register.
1965 To obtain the 8-bit upper part of a soft register, we change the
1966 reg into a mem rtx. This is possible because they are physically
1967 located in memory. There is no offset because we are big-endian. */
1968 if (mode
== QImode
&& S_REG_P (x
))
1972 /* Avoid the '*' for direct addressing mode when this
1973 addressing mode is disabled. */
1974 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1975 return gen_rtx (MEM
, QImode
,
1976 gen_rtx (SYMBOL_REF
, Pmode
,
1977 ®_names
[REGNO (x
)][pos
]));
1980 /* gen_highpart crashes when it is called with a SUBREG. */
1981 if (GET_CODE (x
) == SUBREG
)
1983 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
1985 if (GET_CODE (x
) == REG
)
1987 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
1988 return gen_rtx (REG
, mode
, REGNO (x
));
1990 return gen_rtx_SUBREG (mode
, x
, 0);
1993 if (GET_CODE (x
) == MEM
)
1995 x
= change_address (x
, mode
, 0);
1997 /* Return a different rtx to avoid to share it in several insns
1998 (when used by a split pattern). Sharing addresses within
1999 a MEM breaks the Z register replacement (and reloading). */
2000 if (GET_CODE (x
) == MEM
)
2008 /* Obscure register manipulation. */
2010 /* Finds backward in the instructions to see if register 'reg' is
2011 dead. This is used when generating code to see if we can use 'reg'
2012 as a scratch register. This allows us to choose a better generation
2013 of code when we know that some register dies or can be clobbered. */
2016 dead_register_here (x
, reg
)
2024 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2028 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2029 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2035 if (GET_CODE (body
) == CALL_INSN
)
2037 if (GET_CODE (body
) == JUMP_INSN
)
2040 if (GET_CODE (body
) == SET
)
2042 rtx dst
= XEXP (body
, 0);
2044 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2046 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2049 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2052 else if (reg_mentioned_p (reg
, p
)
2053 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2057 /* Scan forward to see if the register is set in some insns and never
2059 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2063 if (GET_CODE (p
) == CODE_LABEL
2064 || GET_CODE (p
) == JUMP_INSN
2065 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2068 if (GET_CODE (p
) != INSN
)
2072 if (GET_CODE (body
) == SET
)
2074 rtx src
= XEXP (body
, 1);
2075 rtx dst
= XEXP (body
, 0);
2077 if (GET_CODE (dst
) == REG
2078 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2082 /* Register is used (may be in source or in dest). */
2083 if (reg_mentioned_p (reg
, p
)
2084 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2085 && reg_mentioned_p (x_reg
, p
)))
2088 return p
== 0 ? 1 : 0;
2092 /* Code generation operations called from machine description file. */
2094 /* Print the name of register 'regno' in the assembly file. */
2096 asm_print_register (file
, regno
)
2100 const char *name
= reg_names
[regno
];
2102 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2105 asm_fprintf (file
, "%s", name
);
2108 /* A C compound statement to output to stdio stream STREAM the
2109 assembler syntax for an instruction operand X. X is an RTL
2112 CODE is a value that can be used to specify one of several ways
2113 of printing the operand. It is used when identical operands
2114 must be printed differently depending on the context. CODE
2115 comes from the `%' specification that was used to request
2116 printing of the operand. If the specification was just `%DIGIT'
2117 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2118 is the ASCII code for LTR.
2120 If X is a register, this macro should print the register's name.
2121 The names can be found in an array `reg_names' whose type is
2122 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2124 When the machine description has a specification `%PUNCT' (a `%'
2125 followed by a punctuation character), this macro is called with
2126 a null pointer for X and the punctuation character for CODE.
2128 The M68HC11 specific codes are:
2130 'b' for the low part of the operand.
2131 'h' for the high part of the operand
2132 The 'b' or 'h' modifiers have no effect if the operand has
2133 the QImode and is not a S_REG_P (soft register). If the
2134 operand is a hard register, these two modifiers have no effect.
2135 't' generate the temporary scratch register. The operand is
2137 'T' generate the low-part temporary scratch register. The operand is
2141 print_operand (file
, op
, letter
)
2148 asm_print_register (file
, SOFT_TMP_REGNUM
);
2151 else if (letter
== 'T')
2153 asm_print_register (file
, SOFT_TMP_REGNUM
);
2154 asm_fprintf (file
, "+1");
2157 else if (letter
== '#')
2159 asm_fprintf (file
, "%0I");
2162 if (GET_CODE (op
) == REG
)
2164 if (letter
== 'b' && S_REG_P (op
))
2166 asm_print_register (file
, REGNO (op
));
2167 asm_fprintf (file
, "+1");
2171 asm_print_register (file
, REGNO (op
));
2176 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2179 asm_fprintf (file
, "%0I%%lo(");
2181 asm_fprintf (file
, "%0I%%hi(");
2183 output_addr_const (file
, op
);
2184 asm_fprintf (file
, ")");
2188 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2189 are specified. If we already have a QImode, there is nothing to do. */
2190 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2194 op
= m68hc11_gen_lowpart (QImode
, op
);
2196 else if (letter
== 'h')
2198 op
= m68hc11_gen_highpart (QImode
, op
);
2202 if (GET_CODE (op
) == MEM
)
2204 rtx base
= XEXP (op
, 0);
2205 switch (GET_CODE (base
))
2210 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2211 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2220 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2221 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2222 asm_fprintf (file
, "-");
2231 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2232 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2233 asm_fprintf (file
, "+");
2242 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2243 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2250 output_address (base
);
2254 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2259 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2260 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2261 asm_fprintf (file
, "%I0x%lx", l
);
2263 else if (GET_CODE (op
) == CONST_DOUBLE
2264 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2269 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2270 REAL_VALUE_TO_DECIMAL (r
, "%.20g", dstr
);
2271 asm_fprintf (file
, "%I0r%s", dstr
);
2275 int need_parenthesize
= 0;
2278 asm_fprintf (file
, "%0I");
2280 need_parenthesize
= must_parenthesize (op
);
2282 if (need_parenthesize
)
2283 asm_fprintf (file
, "(");
2285 output_addr_const (file
, op
);
2286 if (need_parenthesize
)
2287 asm_fprintf (file
, ")");
2291 /* Returns true if the operand 'op' must be printed with parenthesis
2292 arround it. This must be done only if there is a symbol whose name
2293 is a processor register. */
2295 must_parenthesize (op
)
2300 switch (GET_CODE (op
))
2303 name
= XSTR (op
, 0);
2304 /* Avoid a conflict between symbol name and a possible
2306 return (strcasecmp (name
, "a") == 0
2307 || strcasecmp (name
, "b") == 0
2308 || strcasecmp (name
, "d") == 0
2309 || strcasecmp (name
, "x") == 0
2310 || strcasecmp (name
, "y") == 0
2311 || strcasecmp (name
, "ix") == 0
2312 || strcasecmp (name
, "iy") == 0
2313 || strcasecmp (name
, "pc") == 0
2314 || strcasecmp (name
, "sp") == 0
2315 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2319 return must_parenthesize (XEXP (op
, 0))
2320 || must_parenthesize (XEXP (op
, 1));
2326 return must_parenthesize (XEXP (op
, 0));
2337 /* A C compound statement to output to stdio stream STREAM the
2338 assembler syntax for an instruction operand that is a memory
2339 reference whose address is ADDR. ADDR is an RTL expression. */
2342 print_operand_address (file
, addr
)
2348 int need_parenthesis
= 0;
2350 switch (GET_CODE (addr
))
2353 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2356 asm_fprintf (file
, "0,");
2357 asm_print_register (file
, REGNO (addr
));
2361 base
= XEXP (addr
, 0);
2362 switch (GET_CODE (base
))
2367 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2368 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2377 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2378 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2379 asm_fprintf (file
, "-");
2388 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2389 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2390 asm_fprintf (file
, "+");
2399 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2400 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2407 need_parenthesis
= must_parenthesize (base
);
2408 if (need_parenthesis
)
2409 asm_fprintf (file
, "(");
2411 output_addr_const (file
, base
);
2412 if (need_parenthesis
)
2413 asm_fprintf (file
, ")");
2419 base
= XEXP (addr
, 0);
2420 offset
= XEXP (addr
, 1);
2421 if (!G_REG_P (base
) && G_REG_P (offset
))
2423 base
= XEXP (addr
, 1);
2424 offset
= XEXP (addr
, 0);
2426 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2428 need_parenthesis
= must_parenthesize (addr
);
2430 if (need_parenthesis
)
2431 asm_fprintf (file
, "(");
2433 output_addr_const (file
, base
);
2434 asm_fprintf (file
, "+");
2435 output_addr_const (file
, offset
);
2436 if (need_parenthesis
)
2437 asm_fprintf (file
, ")");
2439 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2445 asm_print_register (file
, REGNO (offset
));
2446 asm_fprintf (file
, ",");
2447 asm_print_register (file
, REGNO (base
));
2454 need_parenthesis
= must_parenthesize (offset
);
2455 if (need_parenthesis
)
2456 asm_fprintf (file
, "(");
2458 output_addr_const (file
, offset
);
2459 if (need_parenthesis
)
2460 asm_fprintf (file
, ")");
2461 asm_fprintf (file
, ",");
2462 asm_print_register (file
, REGNO (base
));
2472 if (GET_CODE (addr
) == CONST_INT
2473 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2475 asm_fprintf (file
, "%d", INTVAL (addr
));
2479 need_parenthesis
= must_parenthesize (addr
);
2480 if (need_parenthesis
)
2481 asm_fprintf (file
, "(");
2483 output_addr_const (file
, addr
);
2484 if (need_parenthesis
)
2485 asm_fprintf (file
, ")");
2492 /* Splitting of some instructions. */
2495 m68hc11_expand_compare (code
, op0
, op1
)
2501 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2505 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2506 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2507 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2514 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2516 rtx op0
, op1
, label
;
2520 switch (GET_MODE (op0
))
2524 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2525 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2526 gen_rtx_LABEL_REF (VOIDmode
, label
),
2528 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2532 /* SCz: from i386.c */
2535 /* Don't expand the comparison early, so that we get better code
2536 when jump or whoever decides to reverse the comparison. */
2541 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2542 &m68hc11_compare_op1
);
2544 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2545 m68hc11_compare_op0
, m68hc11_compare_op1
);
2546 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2547 gen_rtx_LABEL_REF (VOIDmode
, label
),
2549 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2551 use_fcomi
= ix86_use_fcomi_compare (code
);
2552 vec
= rtvec_alloc (3 + !use_fcomi
);
2553 RTVEC_ELT (vec
, 0) = tmp
;
2555 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2557 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2560 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2562 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2568 /* Expand SImode branch into multiple compare+branch. */
2570 rtx lo
[2], hi
[2], label2
;
2571 enum rtx_code code1
, code2
, code3
;
2573 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2578 code
= swap_condition (code
);
2580 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2581 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2582 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2583 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2585 /* Otherwise, if we are doing less-than, op1 is a constant and the
2586 low word is zero, then we can just examine the high word. */
2588 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2589 && (code
== LT
|| code
== LTU
))
2591 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2595 /* Otherwise, we need two or three jumps. */
2597 label2
= gen_label_rtx ();
2600 code2
= swap_condition (code
);
2601 code3
= unsigned_condition (code
);
2642 * if (hi(a) < hi(b)) goto true;
2643 * if (hi(a) > hi(b)) goto false;
2644 * if (lo(a) < lo(b)) goto true;
2648 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2650 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2652 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2655 emit_label (label2
);
2665 /* Return the increment/decrement mode of a MEM if it is such.
2666 Return CONST if it is anything else. */
2671 if (GET_CODE (x
) != MEM
)
2675 if (GET_CODE (x
) == PRE_INC
2676 || GET_CODE (x
) == PRE_DEC
2677 || GET_CODE (x
) == POST_INC
2678 || GET_CODE (x
) == POST_DEC
)
2679 return GET_CODE (x
);
2685 m68hc11_make_autoinc_notes (x
, data
)
2691 switch (GET_CODE (*x
))
2698 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2707 /* Split a DI, SI or HI move into several smaller move operations.
2708 The scratch register 'scratch' is used as a temporary to load
2709 store intermediate values. It must be a hard register. */
2711 m68hc11_split_move (to
, from
, scratch
)
2712 rtx to
, from
, scratch
;
2714 rtx low_to
, low_from
;
2715 rtx high_to
, high_from
;
2717 enum machine_mode mode
;
2719 int autoinc_from
= autoinc_mode (from
);
2720 int autoinc_to
= autoinc_mode (to
);
2722 mode
= GET_MODE (to
);
2724 /* If the TO and FROM contain autoinc modes that are not compatible
2725 together (one pop and the other a push), we must change one to
2726 an offsetable operand and generate an appropriate add at the end. */
2727 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2732 /* The source uses an autoinc mode which is not compatible with
2733 a split (this would result in a word swap). */
2734 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2736 code
= GET_CODE (XEXP (from
, 0));
2737 reg
= XEXP (XEXP (from
, 0), 0);
2738 offset
= GET_MODE_SIZE (GET_MODE (from
));
2739 if (code
== POST_DEC
)
2742 if (code
== PRE_INC
)
2743 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2745 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2746 if (code
== POST_DEC
)
2747 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2751 /* Likewise for destination. */
2752 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2754 code
= GET_CODE (XEXP (to
, 0));
2755 reg
= XEXP (XEXP (to
, 0), 0);
2756 offset
= GET_MODE_SIZE (GET_MODE (to
));
2757 if (code
== POST_DEC
)
2760 if (code
== PRE_INC
)
2761 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2763 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2764 if (code
== POST_DEC
)
2765 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2769 /* The source and destination auto increment modes must be compatible
2770 with each other: same direction. */
2771 if ((autoinc_to
!= autoinc_from
2772 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2773 /* The destination address register must not be used within
2774 the source operand because the source address would change
2775 while doing the copy. */
2776 || (autoinc_to
!= CONST
2777 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2778 && !IS_STACK_PUSH (to
)))
2780 /* Must change the destination. */
2781 code
= GET_CODE (XEXP (to
, 0));
2782 reg
= XEXP (XEXP (to
, 0), 0);
2783 offset
= GET_MODE_SIZE (GET_MODE (to
));
2784 if (code
== PRE_DEC
|| code
== POST_DEC
)
2787 if (code
== PRE_DEC
|| code
== PRE_INC
)
2788 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2789 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2790 if (code
== POST_DEC
|| code
== POST_INC
)
2791 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2796 /* Likewise, the source address register must not be used within
2797 the destination operand. */
2798 if (autoinc_from
!= CONST
2799 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2800 && !IS_STACK_PUSH (to
))
2802 /* Must change the source. */
2803 code
= GET_CODE (XEXP (from
, 0));
2804 reg
= XEXP (XEXP (from
, 0), 0);
2805 offset
= GET_MODE_SIZE (GET_MODE (from
));
2806 if (code
== PRE_DEC
|| code
== POST_DEC
)
2809 if (code
== PRE_DEC
|| code
== PRE_INC
)
2810 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2811 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2812 if (code
== POST_DEC
|| code
== POST_INC
)
2813 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2819 if (GET_MODE_SIZE (mode
) == 8)
2821 else if (GET_MODE_SIZE (mode
) == 4)
2827 && IS_STACK_PUSH (to
)
2828 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2834 else if (mode
== HImode
)
2842 low_to
= m68hc11_gen_lowpart (mode
, to
);
2843 high_to
= m68hc11_gen_highpart (mode
, to
);
2845 low_from
= m68hc11_gen_lowpart (mode
, from
);
2846 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2848 if (INTVAL (from
) >= 0)
2849 high_from
= const0_rtx
;
2851 high_from
= constm1_rtx
;
2854 high_from
= m68hc11_gen_highpart (mode
, from
);
2858 high_from
= adjust_address (high_from
, mode
, offset
);
2859 low_from
= high_from
;
2862 /* When copying with a POST_INC mode, we must copy the
2863 high part and then the low part to guarantee a correct
2866 && GET_MODE_SIZE (mode
) >= 2
2867 && autoinc_from
!= autoinc_to
2868 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2877 low_from
= high_from
;
2882 m68hc11_split_move (low_to
, low_from
, scratch
);
2883 m68hc11_split_move (high_to
, high_from
, scratch
);
2885 else if (H_REG_P (to
) || H_REG_P (from
)
2886 || (low_from
== const0_rtx
2887 && high_from
== const0_rtx
2888 && ! push_operand (to
, GET_MODE (to
))
2889 && ! H_REG_P (scratch
))
2891 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2892 || m68hc11_small_indexed_indirect_p (from
,
2894 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2895 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2897 insn
= emit_move_insn (low_to
, low_from
);
2898 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2900 insn
= emit_move_insn (high_to
, high_from
);
2901 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2905 insn
= emit_move_insn (scratch
, low_from
);
2906 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2907 insn
= emit_move_insn (low_to
, scratch
);
2908 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2910 insn
= emit_move_insn (scratch
, high_from
);
2911 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2912 insn
= emit_move_insn (high_to
, scratch
);
2913 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2918 simplify_logical (mode
, code
, operand
, result
)
2919 enum machine_mode mode
;
2928 if (GET_CODE (operand
) != CONST_INT
)
2936 val
= INTVAL (operand
);
2940 if ((val
& mask
) == 0)
2942 if ((val
& mask
) == mask
)
2943 *result
= constm1_rtx
;
2947 if ((val
& mask
) == 0)
2948 *result
= const0_rtx
;
2949 if ((val
& mask
) == mask
)
2954 if ((val
& mask
) == 0)
2962 m68hc11_emit_logical (mode
, code
, operands
)
2963 enum machine_mode mode
;
2970 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2971 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2973 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2974 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2976 if (result
&& GET_CODE (result
) == CONST_INT
)
2978 if (!H_REG_P (operands
[0]) && operands
[3]
2979 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2981 emit_move_insn (operands
[3], result
);
2982 emit_move_insn (operands
[0], operands
[3]);
2986 emit_move_insn (operands
[0], result
);
2989 else if (operands
[1] != 0 && operands
[2] != 0)
2993 if (!H_REG_P (operands
[0]) && operands
[3])
2995 emit_move_insn (operands
[3], operands
[1]);
2996 emit_insn (gen_rtx (SET
, mode
,
2998 gen_rtx (code
, mode
,
2999 operands
[3], operands
[2])));
3000 insn
= emit_move_insn (operands
[0], operands
[3]);
3004 insn
= emit_insn (gen_rtx (SET
, mode
,
3006 gen_rtx (code
, mode
,
3007 operands
[0], operands
[2])));
3011 /* The logical operation is similar to a copy. */
3016 if (GET_CODE (operands
[1]) == CONST_INT
)
3021 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3023 emit_move_insn (operands
[3], src
);
3024 emit_move_insn (operands
[0], operands
[3]);
3028 emit_move_insn (operands
[0], src
);
3034 m68hc11_split_logical (mode
, code
, operands
)
3035 enum machine_mode mode
;
3042 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3043 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3044 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3046 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3048 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3050 if (INTVAL (operands
[1]) >= 0)
3051 high
[1] = const0_rtx
;
3053 high
[1] = constm1_rtx
;
3056 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3058 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3060 if (INTVAL (operands
[2]) >= 0)
3061 high
[2] = const0_rtx
;
3063 high
[2] = constm1_rtx
;
3066 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3068 low
[3] = operands
[3];
3069 high
[3] = operands
[3];
3072 m68hc11_split_logical (HImode
, code
, low
);
3073 m68hc11_split_logical (HImode
, code
, high
);
3077 m68hc11_emit_logical (mode
, code
, low
);
3078 m68hc11_emit_logical (mode
, code
, high
);
3082 /* Code generation. */
3085 m68hc11_output_swap (insn
, operands
)
3086 rtx insn ATTRIBUTE_UNUSED
;
3089 /* We have to be careful with the cc_status. An address register swap
3090 is generated for some comparison. The comparison is made with D
3091 but the branch really uses the address register. See the split
3092 pattern for compare. The xgdx/xgdy preserve the flags but after
3093 the exchange, the flags will reflect to the value of X and not D.
3094 Tell this by setting the cc_status according to the cc_prev_status. */
3095 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3097 if (cc_prev_status
.value1
!= 0
3098 && (D_REG_P (cc_prev_status
.value1
)
3099 || X_REG_P (cc_prev_status
.value1
)))
3101 cc_status
= cc_prev_status
;
3102 if (D_REG_P (cc_status
.value1
))
3103 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3106 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3112 output_asm_insn ("xgdx", operands
);
3116 if (cc_prev_status
.value1
!= 0
3117 && (D_REG_P (cc_prev_status
.value1
)
3118 || Y_REG_P (cc_prev_status
.value1
)))
3120 cc_status
= cc_prev_status
;
3121 if (D_REG_P (cc_status
.value1
))
3122 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3125 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3131 output_asm_insn ("xgdy", operands
);
3135 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3136 This is used to decide whether a move that set flags should be used
3139 next_insn_test_reg (insn
, reg
)
3145 insn
= next_nonnote_insn (insn
);
3146 if (GET_CODE (insn
) != INSN
)
3149 body
= PATTERN (insn
);
3150 if (sets_cc0_p (body
) != 1)
3153 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3159 /* Generate the code to move a 16-bit operand into another one. */
3162 m68hc11_gen_movhi (insn
, operands
)
3168 /* Move a register or memory to the same location.
3169 This is possible because such insn can appear
3170 in a non-optimizing mode. */
3171 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3173 cc_status
= cc_prev_status
;
3179 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3181 cc_status
= cc_prev_status
;
3182 switch (REGNO (operands
[1]))
3187 output_asm_insn ("psh%1", operands
);
3189 case HARD_SP_REGNUM
:
3190 output_asm_insn ("sts\t-2,sp", operands
);
3197 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3199 cc_status
= cc_prev_status
;
3200 switch (REGNO (operands
[0]))
3205 output_asm_insn ("pul%0", operands
);
3212 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3214 m68hc11_notice_keep_cc (operands
[0]);
3215 output_asm_insn ("tfr\t%1,%0", operands
);
3217 else if (H_REG_P (operands
[0]))
3219 if (SP_REG_P (operands
[0]))
3220 output_asm_insn ("lds\t%1", operands
);
3222 output_asm_insn ("ld%0\t%1", operands
);
3224 else if (H_REG_P (operands
[1]))
3226 if (SP_REG_P (operands
[1]))
3227 output_asm_insn ("sts\t%0", operands
);
3229 output_asm_insn ("st%1\t%0", operands
);
3233 rtx from
= operands
[1];
3234 rtx to
= operands
[0];
3236 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3237 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3238 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3239 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3245 ops
[0] = operands
[2];
3248 m68hc11_gen_movhi (insn
, ops
);
3250 ops
[1] = operands
[2];
3251 m68hc11_gen_movhi (insn
, ops
);
3255 /* !!!! SCz wrong here. */
3256 fatal_insn ("move insn not handled", insn
);
3261 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3263 output_asm_insn ("clr\t%h0", operands
);
3264 output_asm_insn ("clr\t%b0", operands
);
3268 m68hc11_notice_keep_cc (operands
[0]);
3269 output_asm_insn ("movw\t%1,%0", operands
);
3276 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3278 cc_status
= cc_prev_status
;
3279 switch (REGNO (operands
[0]))
3283 output_asm_insn ("pul%0", operands
);
3286 output_asm_insn ("pula", operands
);
3287 output_asm_insn ("pulb", operands
);
3294 /* Some moves to a hard register are special. Not all of them
3295 are really supported and we have to use a temporary
3296 location to provide them (either the stack of a temp var). */
3297 if (H_REG_P (operands
[0]))
3299 switch (REGNO (operands
[0]))
3302 if (X_REG_P (operands
[1]))
3304 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3306 m68hc11_output_swap (insn
, operands
);
3308 else if (next_insn_test_reg (insn
, operands
[0]))
3310 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3314 m68hc11_notice_keep_cc (operands
[0]);
3315 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3318 else if (Y_REG_P (operands
[1]))
3320 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3322 m68hc11_output_swap (insn
, operands
);
3326 /* %t means *ZTMP scratch register. */
3327 output_asm_insn ("sty\t%t1", operands
);
3328 output_asm_insn ("ldd\t%t1", operands
);
3331 else if (SP_REG_P (operands
[1]))
3336 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3337 output_asm_insn ("xgdx", operands
);
3338 output_asm_insn ("tsx", operands
);
3339 output_asm_insn ("xgdx", operands
);
3341 else if (IS_STACK_POP (operands
[1]))
3343 output_asm_insn ("pula\n\tpulb", operands
);
3345 else if (GET_CODE (operands
[1]) == CONST_INT
3346 && INTVAL (operands
[1]) == 0)
3348 output_asm_insn ("clra\n\tclrb", operands
);
3352 output_asm_insn ("ldd\t%1", operands
);
3357 if (D_REG_P (operands
[1]))
3359 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3361 m68hc11_output_swap (insn
, operands
);
3363 else if (next_insn_test_reg (insn
, operands
[0]))
3365 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3369 m68hc11_notice_keep_cc (operands
[0]);
3370 output_asm_insn ("pshb", operands
);
3371 output_asm_insn ("psha", operands
);
3372 output_asm_insn ("pulx", operands
);
3375 else if (Y_REG_P (operands
[1]))
3377 /* When both D and Y are dead, use the sequence xgdy, xgdx
3378 to move Y into X. The D and Y registers are modified. */
3379 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3380 && dead_register_here (insn
, d_reg
))
3382 output_asm_insn ("xgdy", operands
);
3383 output_asm_insn ("xgdx", operands
);
3388 output_asm_insn ("sty\t%t1", operands
);
3389 output_asm_insn ("ldx\t%t1", operands
);
3392 else if (SP_REG_P (operands
[1]))
3394 /* tsx, tsy preserve the flags */
3395 cc_status
= cc_prev_status
;
3396 output_asm_insn ("tsx", operands
);
3400 output_asm_insn ("ldx\t%1", operands
);
3405 if (D_REG_P (operands
[1]))
3407 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3409 m68hc11_output_swap (insn
, operands
);
3413 output_asm_insn ("std\t%t1", operands
);
3414 output_asm_insn ("ldy\t%t1", operands
);
3417 else if (X_REG_P (operands
[1]))
3419 /* When both D and X are dead, use the sequence xgdx, xgdy
3420 to move X into Y. The D and X registers are modified. */
3421 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3422 && dead_register_here (insn
, d_reg
))
3424 output_asm_insn ("xgdx", operands
);
3425 output_asm_insn ("xgdy", operands
);
3430 output_asm_insn ("stx\t%t1", operands
);
3431 output_asm_insn ("ldy\t%t1", operands
);
3434 else if (SP_REG_P (operands
[1]))
3436 /* tsx, tsy preserve the flags */
3437 cc_status
= cc_prev_status
;
3438 output_asm_insn ("tsy", operands
);
3442 output_asm_insn ("ldy\t%1", operands
);
3446 case HARD_SP_REGNUM
:
3447 if (D_REG_P (operands
[1]))
3449 m68hc11_notice_keep_cc (operands
[0]);
3450 output_asm_insn ("xgdx", operands
);
3451 output_asm_insn ("txs", operands
);
3452 output_asm_insn ("xgdx", operands
);
3454 else if (X_REG_P (operands
[1]))
3456 /* tys, txs preserve the flags */
3457 cc_status
= cc_prev_status
;
3458 output_asm_insn ("txs", operands
);
3460 else if (Y_REG_P (operands
[1]))
3462 /* tys, txs preserve the flags */
3463 cc_status
= cc_prev_status
;
3464 output_asm_insn ("tys", operands
);
3468 /* lds sets the flags but the des does not. */
3470 output_asm_insn ("lds\t%1", operands
);
3471 output_asm_insn ("des", operands
);
3476 fatal_insn ("invalid register in the move instruction", insn
);
3481 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3482 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3484 output_asm_insn ("sts\t%0", operands
);
3488 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3490 cc_status
= cc_prev_status
;
3491 switch (REGNO (operands
[1]))
3495 output_asm_insn ("psh%1", operands
);
3498 output_asm_insn ("pshb", operands
);
3499 output_asm_insn ("psha", operands
);
3507 /* Operand 1 must be a hard register. */
3508 if (!H_REG_P (operands
[1]))
3510 fatal_insn ("invalid operand in the instruction", insn
);
3513 reg
= REGNO (operands
[1]);
3517 output_asm_insn ("std\t%0", operands
);
3521 output_asm_insn ("stx\t%0", operands
);
3525 output_asm_insn ("sty\t%0", operands
);
3528 case HARD_SP_REGNUM
:
3532 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3534 output_asm_insn ("pshx", operands
);
3535 output_asm_insn ("tsx", operands
);
3536 output_asm_insn ("inx", operands
);
3537 output_asm_insn ("inx", operands
);
3538 output_asm_insn ("stx\t%0", operands
);
3539 output_asm_insn ("pulx", operands
);
3542 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3544 output_asm_insn ("sty\t%t0", operands
);
3545 output_asm_insn ("tsy", operands
);
3546 output_asm_insn ("sty\t%0", operands
);
3547 output_asm_insn ("ldy\t%t0", operands
);
3551 output_asm_insn ("stx\t%t0", operands
);
3552 output_asm_insn ("tsx", operands
);
3553 output_asm_insn ("stx\t%0", operands
);
3554 output_asm_insn ("ldx\t%t0", operands
);
3560 fatal_insn ("invalid register in the move instruction", insn
);
3566 m68hc11_gen_movqi (insn
, operands
)
3570 /* Move a register or memory to the same location.
3571 This is possible because such insn can appear
3572 in a non-optimizing mode. */
3573 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3575 cc_status
= cc_prev_status
;
3582 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3584 m68hc11_notice_keep_cc (operands
[0]);
3585 output_asm_insn ("tfr\t%1,%0", operands
);
3587 else if (H_REG_P (operands
[0]))
3589 if (Q_REG_P (operands
[0]))
3590 output_asm_insn ("lda%0\t%b1", operands
);
3591 else if (D_REG_P (operands
[0]))
3592 output_asm_insn ("ldab\t%b1", operands
);
3596 else if (H_REG_P (operands
[1]))
3598 if (Q_REG_P (operands
[1]))
3599 output_asm_insn ("sta%1\t%b0", operands
);
3600 else if (D_REG_P (operands
[1]))
3601 output_asm_insn ("stab\t%b0", operands
);
3607 rtx from
= operands
[1];
3608 rtx to
= operands
[0];
3610 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3611 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3612 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3613 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3619 ops
[0] = operands
[2];
3622 m68hc11_gen_movqi (insn
, ops
);
3624 ops
[1] = operands
[2];
3625 m68hc11_gen_movqi (insn
, ops
);
3629 /* !!!! SCz wrong here. */
3630 fatal_insn ("move insn not handled", insn
);
3635 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3637 output_asm_insn ("clr\t%b0", operands
);
3641 m68hc11_notice_keep_cc (operands
[0]);
3642 output_asm_insn ("movb\t%b1,%b0", operands
);
3650 if (H_REG_P (operands
[0]))
3652 switch (REGNO (operands
[0]))
3656 if (X_REG_P (operands
[1]))
3658 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3660 m68hc11_output_swap (insn
, operands
);
3664 output_asm_insn ("stx\t%t1", operands
);
3665 output_asm_insn ("ldab\t%T0", operands
);
3668 else if (Y_REG_P (operands
[1]))
3670 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3672 m68hc11_output_swap (insn
, operands
);
3676 output_asm_insn ("sty\t%t1", operands
);
3677 output_asm_insn ("ldab\t%T0", operands
);
3680 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3681 && !DA_REG_P (operands
[1]))
3683 output_asm_insn ("ldab\t%b1", operands
);
3685 else if (DA_REG_P (operands
[1]))
3687 output_asm_insn ("tab", operands
);
3691 cc_status
= cc_prev_status
;
3697 if (X_REG_P (operands
[1]))
3699 output_asm_insn ("stx\t%t1", operands
);
3700 output_asm_insn ("ldaa\t%T0", operands
);
3702 else if (Y_REG_P (operands
[1]))
3704 output_asm_insn ("sty\t%t1", operands
);
3705 output_asm_insn ("ldaa\t%T0", operands
);
3707 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3708 && !DA_REG_P (operands
[1]))
3710 output_asm_insn ("ldaa\t%b1", operands
);
3712 else if (!DA_REG_P (operands
[1]))
3714 output_asm_insn ("tba", operands
);
3718 cc_status
= cc_prev_status
;
3723 if (D_REG_P (operands
[1]))
3725 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3727 m68hc11_output_swap (insn
, operands
);
3731 output_asm_insn ("stab\t%T1", operands
);
3732 output_asm_insn ("ldx\t%t1", operands
);
3736 else if (Y_REG_P (operands
[1]))
3738 output_asm_insn ("sty\t%t0", operands
);
3739 output_asm_insn ("ldx\t%t0", operands
);
3741 else if (GET_CODE (operands
[1]) == CONST_INT
)
3743 output_asm_insn ("ldx\t%1", operands
);
3745 else if (dead_register_here (insn
, d_reg
))
3747 output_asm_insn ("ldab\t%b1", operands
);
3748 output_asm_insn ("xgdx", operands
);
3750 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3752 output_asm_insn ("xgdx", operands
);
3753 output_asm_insn ("ldab\t%b1", operands
);
3754 output_asm_insn ("xgdx", operands
);
3758 output_asm_insn ("pshb", operands
);
3759 output_asm_insn ("ldab\t%b1", operands
);
3760 output_asm_insn ("stab\t%T1", operands
);
3761 output_asm_insn ("ldx\t%t1", operands
);
3762 output_asm_insn ("pulb", operands
);
3768 if (D_REG_P (operands
[1]))
3770 output_asm_insn ("stab\t%T1", operands
);
3771 output_asm_insn ("ldy\t%t1", operands
);
3774 else if (X_REG_P (operands
[1]))
3776 output_asm_insn ("stx\t%t1", operands
);
3777 output_asm_insn ("ldy\t%t1", operands
);
3780 else if (GET_CODE (operands
[1]) == CONST_INT
)
3782 output_asm_insn ("ldy\t%1", operands
);
3784 else if (dead_register_here (insn
, d_reg
))
3786 output_asm_insn ("ldab\t%b1", operands
);
3787 output_asm_insn ("xgdy", operands
);
3789 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3791 output_asm_insn ("xgdy", operands
);
3792 output_asm_insn ("ldab\t%b1", operands
);
3793 output_asm_insn ("xgdy", operands
);
3797 output_asm_insn ("pshb", operands
);
3798 output_asm_insn ("ldab\t%b1", operands
);
3799 output_asm_insn ("stab\t%T1", operands
);
3800 output_asm_insn ("ldy\t%t1", operands
);
3801 output_asm_insn ("pulb", operands
);
3807 fatal_insn ("invalid register in the instruction", insn
);
3811 else if (H_REG_P (operands
[1]))
3813 switch (REGNO (operands
[1]))
3817 output_asm_insn ("stab\t%b0", operands
);
3821 output_asm_insn ("staa\t%b0", operands
);
3825 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3829 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3833 fatal_insn ("invalid register in the move instruction", insn
);
3840 fatal_insn ("operand 1 must be a hard register", insn
);
3844 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3845 The source and destination must be D or A and the shift must
3848 m68hc11_gen_rotate (code
, insn
, operands
)
3855 if (GET_CODE (operands
[2]) != CONST_INT
3856 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3857 fatal_insn ("invalid rotate insn", insn
);
3859 val
= INTVAL (operands
[2]);
3860 if (code
== ROTATERT
)
3861 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3863 if (GET_MODE (operands
[0]) != QImode
)
3866 /* Rotate by 8-bits if the shift is within [5..11]. */
3867 if (val
>= 5 && val
<= 11)
3870 output_asm_insn ("exg\ta,b", operands
);
3873 output_asm_insn ("psha", operands
);
3874 output_asm_insn ("tba", operands
);
3875 output_asm_insn ("pulb", operands
);
3880 /* If the shift is big, invert the rotation. */
3888 /* Set the carry to bit-15, but don't change D yet. */
3889 if (GET_MODE (operands
[0]) != QImode
)
3891 output_asm_insn ("asra", operands
);
3892 output_asm_insn ("rola", operands
);
3897 /* Rotate B first to move the carry to bit-0. */
3898 if (D_REG_P (operands
[0]))
3899 output_asm_insn ("rolb", operands
);
3901 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3902 output_asm_insn ("rola", operands
);
3907 /* Set the carry to bit-8 of D. */
3908 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3910 output_asm_insn ("tap", operands
);
3915 /* Rotate B first to move the carry to bit-7. */
3916 if (D_REG_P (operands
[0]))
3917 output_asm_insn ("rorb", operands
);
3919 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3920 output_asm_insn ("rora", operands
);
3927 /* Store in cc_status the expressions that the condition codes will
3928 describe after execution of an instruction whose pattern is EXP.
3929 Do not alter them if the instruction would not alter the cc's. */
3932 m68hc11_notice_update_cc (exp
, insn
)
3934 rtx insn ATTRIBUTE_UNUSED
;
3936 /* recognize SET insn's. */
3937 if (GET_CODE (exp
) == SET
)
3939 /* Jumps do not alter the cc's. */
3940 if (SET_DEST (exp
) == pc_rtx
)
3943 /* NOTE: most instructions don't affect the carry bit, but the
3944 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3945 the conditions.h header. */
3947 /* Function calls clobber the cc's. */
3948 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3953 /* Tests and compares set the cc's in predictable ways. */
3954 else if (SET_DEST (exp
) == cc0_rtx
)
3956 cc_status
.flags
= 0;
3957 cc_status
.value1
= XEXP (exp
, 0);
3958 cc_status
.value2
= XEXP (exp
, 1);
3962 /* All other instructions affect the condition codes. */
3963 cc_status
.flags
= 0;
3964 cc_status
.value1
= XEXP (exp
, 0);
3965 cc_status
.value2
= XEXP (exp
, 1);
3970 /* Default action if we haven't recognized something
3971 and returned earlier. */
3975 if (cc_status
.value2
!= 0)
3976 switch (GET_CODE (cc_status
.value2
))
3978 /* These logical operations can generate several insns.
3979 The flags are setup according to what is generated. */
3985 /* The (not ...) generates several 'com' instructions for
3986 non QImode. We have to invalidate the flags. */
3988 if (GET_MODE (cc_status
.value2
) != QImode
)
4000 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4001 cc_status
.flags
|= CC_NO_OVERFLOW
;
4004 /* The asl sets the overflow bit in such a way that this
4005 makes the flags unusable for a next compare insn. */
4009 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4010 cc_status
.flags
|= CC_NO_OVERFLOW
;
4013 /* A load/store instruction does not affect the carry. */
4018 cc_status
.flags
|= CC_NO_OVERFLOW
;
4024 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4026 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4027 cc_status
.value2
= 0;
4030 /* The current instruction does not affect the flags but changes
4031 the register 'reg'. See if the previous flags can be kept for the
4032 next instruction to avoid a comparison. */
4034 m68hc11_notice_keep_cc (reg
)
4038 || cc_prev_status
.value1
== 0
4039 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4040 || (cc_prev_status
.value2
4041 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4044 cc_status
= cc_prev_status
;
4049 /* Machine Specific Reorg. */
4051 /* Z register replacement:
4053 GCC treats the Z register as an index base address register like
4054 X or Y. In general, it uses it during reload to compute the address
4055 of some operand. This helps the reload pass to avoid to fall into the
4056 register spill failure.
4058 The Z register is in the A_REGS class. In the machine description,
4059 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4061 It can appear everywhere an X or Y register can appear, except for
4062 some templates in the clobber section (when a clobber of X or Y is asked).
4063 For a given instruction, the template must ensure that no more than
4064 2 'A' registers are used. Otherwise, the register replacement is not
4067 To replace the Z register, the algorithm is not terrific:
4068 1. Insns that do not use the Z register are not changed
4069 2. When a Z register is used, we scan forward the insns to see
4070 a potential register to use: either X or Y and sometimes D.
4071 We stop when a call, a label or a branch is seen, or when we
4072 detect that both X and Y are used (probably at different times, but it does
4074 3. The register that will be used for the replacement of Z is saved
4075 in a .page0 register or on the stack. If the first instruction that
4076 used Z, uses Z as an input, the value is loaded from another .page0
4077 register. The replacement register is pushed on the stack in the
4078 rare cases where a compare insn uses Z and we couldn't find if X/Y
4080 4. The Z register is replaced in all instructions until we reach
4081 the end of the Z-block, as detected by step 2.
4082 5. If we detect that Z is still alive, its value is saved.
4083 If the replacement register is alive, its old value is loaded.
4085 The Z register can be disabled with -ffixed-z.
4095 int must_restore_reg
;
4106 int save_before_last
;
4107 int z_loaded_with_sp
;
4112 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4113 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4114 static void m68hc11_z_replacement
PARAMS ((rtx
));
4115 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4117 int z_replacement_completed
= 0;
4119 /* Analyze the insn to find out which replacement register to use and
4120 the boundaries of the replacement.
4121 Returns 0 if we reached the last insn to be replaced, 1 if we can
4122 continue replacement in next insns. */
4125 m68hc11_check_z_replacement (insn
, info
)
4127 struct replace_info
*info
;
4129 int this_insn_uses_ix
;
4130 int this_insn_uses_iy
;
4131 int this_insn_uses_z
;
4132 int this_insn_uses_z_in_dst
;
4133 int this_insn_uses_d
;
4137 /* A call is said to clobber the Z register, we don't need
4138 to save the value of Z. We also don't need to restore
4139 the replacement register (unless it is used by the call). */
4140 if (GET_CODE (insn
) == CALL_INSN
)
4142 body
= PATTERN (insn
);
4144 info
->can_use_d
= 0;
4146 /* If the call is an indirect call with Z, we have to use the
4147 Y register because X can be used as an input (D+X).
4148 We also must not save Z nor restore Y. */
4149 if (reg_mentioned_p (z_reg
, body
))
4151 insn
= NEXT_INSN (insn
);
4154 info
->found_call
= 1;
4155 info
->must_restore_reg
= 0;
4156 info
->last
= NEXT_INSN (insn
);
4158 info
->need_save_z
= 0;
4161 if (GET_CODE (insn
) == CODE_LABEL
4162 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4165 if (GET_CODE (insn
) == JUMP_INSN
)
4167 if (reg_mentioned_p (z_reg
, insn
) == 0)
4170 info
->can_use_d
= 0;
4171 info
->must_save_reg
= 0;
4172 info
->must_restore_reg
= 0;
4173 info
->need_save_z
= 0;
4174 info
->last
= NEXT_INSN (insn
);
4177 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4182 /* Z register dies here. */
4183 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4185 body
= PATTERN (insn
);
4186 if (GET_CODE (body
) == SET
)
4188 rtx src
= XEXP (body
, 1);
4189 rtx dst
= XEXP (body
, 0);
4191 /* Condition code is set here. We have to restore the X/Y and
4192 save into Z before any test/compare insn because once we save/restore
4193 we can change the condition codes. When the compare insn uses Z and
4194 we can't use X/Y, the comparison is made with the *ZREG soft register
4195 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4198 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4199 || (GET_CODE (src
) == COMPARE
&&
4200 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4201 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4203 if (insn
== info
->first
)
4205 info
->must_load_z
= 0;
4206 info
->must_save_reg
= 0;
4207 info
->must_restore_reg
= 0;
4208 info
->need_save_z
= 0;
4209 info
->found_call
= 1;
4210 info
->regno
= SOFT_Z_REGNUM
;
4215 if (reg_mentioned_p (z_reg
, src
) == 0)
4217 info
->can_use_d
= 0;
4221 if (insn
!= info
->first
)
4224 /* Compare insn which uses Z. We have to save/restore the X/Y
4225 register without modifying the condition codes. For this
4226 we have to use a push/pop insn. */
4227 info
->must_push_reg
= 1;
4231 /* Z reg is set to something new. We don't need to load it. */
4234 if (!reg_mentioned_p (z_reg
, src
))
4236 /* Z reg is used before being set. Treat this as
4237 a new sequence of Z register replacement. */
4238 if (insn
!= info
->first
)
4242 info
->must_load_z
= 0;
4244 info
->z_set_count
++;
4245 info
->z_value
= src
;
4247 info
->z_loaded_with_sp
= 1;
4249 else if (reg_mentioned_p (z_reg
, dst
))
4250 info
->can_use_d
= 0;
4252 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4253 | reg_mentioned_p (d_reg
, dst
);
4254 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4255 | reg_mentioned_p (ix_reg
, dst
);
4256 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4257 | reg_mentioned_p (iy_reg
, dst
);
4258 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4260 /* If z is used as an address operand (like (MEM (reg z))),
4261 we can't replace it with d. */
4262 if (this_insn_uses_z
&& !Z_REG_P (src
)
4263 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4264 && Z_REG_P (XEXP (src
, 0))
4265 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4266 && insn
== info
->first
4267 && dead_register_here (insn
, d_reg
)))
4268 info
->can_use_d
= 0;
4270 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4271 if (TARGET_M6812
&& !z_dies_here
4272 && ((this_insn_uses_z
&& side_effects_p (src
))
4273 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4275 info
->need_save_z
= 1;
4276 info
->z_set_count
++;
4278 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4280 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4282 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4285 if (this_insn_uses_d
)
4286 info
->can_use_d
= 0;
4288 /* IX and IY are used at the same time, we have to restore
4289 the value of the scratch register before this insn. */
4290 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4295 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4296 info
->can_use_d
= 0;
4298 if (info
->x_used
== 0 && this_insn_uses_ix
)
4302 /* We have a (set (REG:HI X) (REG:HI Z)).
4303 Since we use Z as the replacement register, this insn
4304 is no longer necessary. We turn it into a note. We must
4305 not reload the old value of X. */
4306 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4310 info
->need_save_z
= 0;
4313 info
->must_save_reg
= 0;
4314 info
->must_restore_reg
= 0;
4315 info
->found_call
= 1;
4316 info
->can_use_d
= 0;
4317 PUT_CODE (insn
, NOTE
);
4318 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4319 NOTE_SOURCE_FILE (insn
) = 0;
4320 info
->last
= NEXT_INSN (insn
);
4325 && (rtx_equal_p (src
, z_reg
)
4326 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4330 info
->need_save_z
= 0;
4333 info
->last
= NEXT_INSN (insn
);
4334 info
->must_save_reg
= 0;
4335 info
->must_restore_reg
= 0;
4337 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4338 && !reg_mentioned_p (ix_reg
, src
))
4343 info
->need_save_z
= 0;
4347 info
->save_before_last
= 1;
4349 info
->must_restore_reg
= 0;
4350 info
->last
= NEXT_INSN (insn
);
4352 else if (info
->can_use_d
)
4354 info
->last
= NEXT_INSN (insn
);
4360 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4361 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4363 info
->need_save_z
= 0;
4365 info
->last
= NEXT_INSN (insn
);
4366 info
->regno
= HARD_X_REGNUM
;
4367 info
->must_save_reg
= 0;
4368 info
->must_restore_reg
= 0;
4371 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4373 info
->regno
= HARD_X_REGNUM
;
4374 info
->must_restore_reg
= 0;
4375 info
->must_save_reg
= 0;
4379 if (info
->y_used
== 0 && this_insn_uses_iy
)
4383 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4387 info
->need_save_z
= 0;
4390 info
->must_save_reg
= 0;
4391 info
->must_restore_reg
= 0;
4392 info
->found_call
= 1;
4393 info
->can_use_d
= 0;
4394 PUT_CODE (insn
, NOTE
);
4395 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4396 NOTE_SOURCE_FILE (insn
) = 0;
4397 info
->last
= NEXT_INSN (insn
);
4402 && (rtx_equal_p (src
, z_reg
)
4403 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4408 info
->need_save_z
= 0;
4410 info
->last
= NEXT_INSN (insn
);
4411 info
->must_save_reg
= 0;
4412 info
->must_restore_reg
= 0;
4414 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4415 && !reg_mentioned_p (iy_reg
, src
))
4420 info
->need_save_z
= 0;
4424 info
->save_before_last
= 1;
4426 info
->must_restore_reg
= 0;
4427 info
->last
= NEXT_INSN (insn
);
4429 else if (info
->can_use_d
)
4431 info
->last
= NEXT_INSN (insn
);
4438 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4439 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4441 info
->need_save_z
= 0;
4443 info
->last
= NEXT_INSN (insn
);
4444 info
->regno
= HARD_Y_REGNUM
;
4445 info
->must_save_reg
= 0;
4446 info
->must_restore_reg
= 0;
4449 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4451 info
->regno
= HARD_Y_REGNUM
;
4452 info
->must_restore_reg
= 0;
4453 info
->must_save_reg
= 0;
4459 info
->need_save_z
= 0;
4461 if (info
->last
== 0)
4462 info
->last
= NEXT_INSN (insn
);
4465 return info
->last
!= NULL_RTX
? 0 : 1;
4467 if (GET_CODE (body
) == PARALLEL
)
4470 char ix_clobber
= 0;
4471 char iy_clobber
= 0;
4473 this_insn_uses_iy
= 0;
4474 this_insn_uses_ix
= 0;
4475 this_insn_uses_z
= 0;
4477 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4480 int uses_ix
, uses_iy
, uses_z
;
4482 x
= XVECEXP (body
, 0, i
);
4484 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4485 info
->can_use_d
= 0;
4487 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4488 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4489 uses_z
= reg_mentioned_p (z_reg
, x
);
4490 if (GET_CODE (x
) == CLOBBER
)
4492 ix_clobber
|= uses_ix
;
4493 iy_clobber
|= uses_iy
;
4494 z_clobber
|= uses_z
;
4498 this_insn_uses_ix
|= uses_ix
;
4499 this_insn_uses_iy
|= uses_iy
;
4500 this_insn_uses_z
|= uses_z
;
4502 if (uses_z
&& GET_CODE (x
) == SET
)
4504 rtx dst
= XEXP (x
, 0);
4507 info
->z_set_count
++;
4509 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4510 info
->need_save_z
= 1;
4513 info
->need_save_z
= 0;
4517 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4518 this_insn_uses_ix
, this_insn_uses_iy
,
4519 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4522 if (this_insn_uses_z
)
4523 info
->can_use_d
= 0;
4525 if (z_clobber
&& info
->first
!= insn
)
4527 info
->need_save_z
= 0;
4531 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4533 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4535 info
->must_load_z
= 0;
4537 if (dead_register_here (insn
, d_reg
))
4539 info
->regno
= HARD_D_REGNUM
;
4540 info
->must_save_reg
= 0;
4541 info
->must_restore_reg
= 0;
4543 else if (dead_register_here (insn
, ix_reg
))
4545 info
->regno
= HARD_X_REGNUM
;
4546 info
->must_save_reg
= 0;
4547 info
->must_restore_reg
= 0;
4549 else if (dead_register_here (insn
, iy_reg
))
4551 info
->regno
= HARD_Y_REGNUM
;
4552 info
->must_save_reg
= 0;
4553 info
->must_restore_reg
= 0;
4555 if (info
->regno
>= 0)
4557 info
->last
= NEXT_INSN (insn
);
4560 if (this_insn_uses_ix
== 0)
4562 info
->regno
= HARD_X_REGNUM
;
4563 info
->must_save_reg
= 1;
4564 info
->must_restore_reg
= 1;
4566 else if (this_insn_uses_iy
== 0)
4568 info
->regno
= HARD_Y_REGNUM
;
4569 info
->must_save_reg
= 1;
4570 info
->must_restore_reg
= 1;
4574 info
->regno
= HARD_D_REGNUM
;
4575 info
->must_save_reg
= 1;
4576 info
->must_restore_reg
= 1;
4578 info
->last
= NEXT_INSN (insn
);
4582 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4583 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4585 if (this_insn_uses_z
)
4587 if (info
->y_used
== 0 && iy_clobber
)
4589 info
->regno
= HARD_Y_REGNUM
;
4590 info
->must_save_reg
= 0;
4591 info
->must_restore_reg
= 0;
4593 if (info
->first
!= insn
4594 && ((info
->y_used
&& ix_clobber
)
4595 || (info
->x_used
&& iy_clobber
)))
4598 info
->last
= NEXT_INSN (insn
);
4599 info
->save_before_last
= 1;
4603 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4605 if (this_insn_uses_z
)
4607 fatal_insn ("cannot do z-register replacement", insn
);
4611 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4618 if (iy_clobber
|| z_clobber
)
4620 info
->last
= NEXT_INSN (insn
);
4621 info
->save_before_last
= 1;
4626 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4633 if (ix_clobber
|| z_clobber
)
4635 info
->last
= NEXT_INSN (insn
);
4636 info
->save_before_last
= 1;
4643 info
->need_save_z
= 0;
4647 if (GET_CODE (body
) == CLOBBER
)
4650 /* IX and IY are used at the same time, we have to restore
4651 the value of the scratch register before this insn. */
4652 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4656 if (info
->x_used
== 0 && this_insn_uses_ix
)
4664 if (info
->y_used
== 0 && this_insn_uses_iy
)
4678 m68hc11_find_z_replacement (insn
, info
)
4680 struct replace_info
*info
;
4684 info
->replace_reg
= NULL_RTX
;
4685 info
->must_load_z
= 1;
4686 info
->need_save_z
= 1;
4687 info
->must_save_reg
= 1;
4688 info
->must_restore_reg
= 1;
4692 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4693 info
->found_call
= 0;
4697 info
->z_set_count
= 0;
4698 info
->z_value
= NULL_RTX
;
4699 info
->must_push_reg
= 0;
4700 info
->save_before_last
= 0;
4701 info
->z_loaded_with_sp
= 0;
4703 /* Scan the insn forward to find an address register that is not used.
4705 - the flow of the program changes,
4706 - when we detect that both X and Y are necessary,
4707 - when the Z register dies,
4708 - when the condition codes are set. */
4710 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4712 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4716 /* May be we can use Y or X if they contain the same value as Z.
4717 This happens very often after the reload. */
4718 if (info
->z_set_count
== 1)
4720 rtx p
= info
->first
;
4725 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4727 else if (info
->y_used
)
4729 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4731 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4734 info
->regno
= HARD_Y_REGNUM
;
4736 info
->regno
= HARD_X_REGNUM
;
4737 info
->must_load_z
= 0;
4738 info
->must_save_reg
= 0;
4739 info
->must_restore_reg
= 0;
4740 info
->found_call
= 1;
4743 if (info
->z_set_count
== 0)
4744 info
->need_save_z
= 0;
4747 info
->need_save_z
= 0;
4749 if (info
->last
== 0)
4752 if (info
->regno
>= 0)
4755 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4757 else if (info
->can_use_d
)
4759 reg
= HARD_D_REGNUM
;
4760 info
->replace_reg
= d_reg
;
4762 else if (info
->x_used
)
4764 reg
= HARD_Y_REGNUM
;
4765 info
->replace_reg
= iy_reg
;
4769 reg
= HARD_X_REGNUM
;
4770 info
->replace_reg
= ix_reg
;
4774 if (info
->must_save_reg
&& info
->must_restore_reg
)
4776 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4778 info
->must_save_reg
= 0;
4779 info
->must_restore_reg
= 0;
4784 /* The insn uses the Z register. Find a replacement register for it
4785 (either X or Y) and replace it in the insn and the next ones until
4786 the flow changes or the replacement register is used. Instructions
4787 are emited before and after the Z-block to preserve the value of
4788 Z and of the replacement register. */
4791 m68hc11_z_replacement (insn
)
4796 struct replace_info info
;
4798 /* Find trivial case where we only need to replace z with the
4799 equivalent soft register. */
4800 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4802 rtx body
= PATTERN (insn
);
4803 rtx src
= XEXP (body
, 1);
4804 rtx dst
= XEXP (body
, 0);
4806 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4808 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4811 else if (Z_REG_P (src
)
4812 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4814 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4817 else if (D_REG_P (dst
)
4818 && m68hc11_arith_operator (src
, GET_MODE (src
))
4819 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4821 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4824 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4825 && INTVAL (src
) == 0)
4827 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4828 /* Force it to be re-recognized. */
4829 INSN_CODE (insn
) = -1;
4834 m68hc11_find_z_replacement (insn
, &info
);
4836 replace_reg
= info
.replace_reg
;
4837 replace_reg_qi
= NULL_RTX
;
4839 /* Save the X register in a .page0 location. */
4840 if (info
.must_save_reg
&& !info
.must_push_reg
)
4844 if (info
.must_push_reg
&& 0)
4845 dst
= gen_rtx (MEM
, HImode
,
4846 gen_rtx (PRE_DEC
, HImode
,
4847 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4849 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4851 emit_insn_before (gen_movhi (dst
,
4852 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4854 if (info
.must_load_z
&& !info
.must_push_reg
)
4856 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4857 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4862 /* Replace all occurrence of Z by replace_reg.
4863 Stop when the last instruction to replace is reached.
4864 Also stop when we detect a change in the flow (but it's not
4865 necessary; just safeguard). */
4867 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4871 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4874 if (GET_CODE (insn
) != INSN
4875 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4878 body
= PATTERN (insn
);
4879 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4880 || GET_CODE (body
) == ASM_OPERANDS
4881 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4885 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4887 printf ("Reg mentioned here...:\n");
4892 /* Stack pointer was decremented by 2 due to the push.
4893 Correct that by adding 2 to the destination. */
4894 if (info
.must_push_reg
4895 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4899 src
= SET_SRC (body
);
4900 dst
= SET_DEST (body
);
4901 if (SP_REG_P (src
) && Z_REG_P (dst
))
4902 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4905 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4906 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4908 INSN_CODE (insn
) = -1;
4909 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4910 fatal_insn ("cannot do z-register replacement", insn
);
4913 /* Likewise for (REG:QI Z). */
4914 if (reg_mentioned_p (z_reg
, insn
))
4916 if (replace_reg_qi
== NULL_RTX
)
4917 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4918 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4921 /* If there is a REG_INC note on Z, replace it with a
4922 REG_INC note on the replacement register. This is necessary
4923 to make sure that the flow pass will identify the change
4924 and it will not remove a possible insn that saves Z. */
4925 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4927 if (REG_NOTE_KIND (note
) == REG_INC
4928 && GET_CODE (XEXP (note
, 0)) == REG
4929 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4931 XEXP (note
, 0) = replace_reg
;
4935 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4939 /* Save Z before restoring the old value. */
4940 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4942 rtx save_pos_insn
= insn
;
4944 /* If Z is clobber by the last insn, we have to save its value
4945 before the last instruction. */
4946 if (info
.save_before_last
)
4947 save_pos_insn
= PREV_INSN (save_pos_insn
);
4949 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4950 gen_rtx (REG
, HImode
, info
.regno
)),
4954 if (info
.must_push_reg
&& info
.last
)
4958 body
= PATTERN (info
.last
);
4959 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4961 gen_rtx (USE
, VOIDmode
,
4963 gen_rtx (USE
, VOIDmode
,
4964 gen_rtx (REG
, HImode
,
4966 PATTERN (info
.last
) = new_body
;
4968 /* Force recognition on insn since we changed it. */
4969 INSN_CODE (insn
) = -1;
4971 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4973 fatal_insn ("invalid Z register replacement for insn", insn
);
4975 insn
= NEXT_INSN (info
.last
);
4978 /* Restore replacement register unless it was died. */
4979 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4983 if (info
.must_push_reg
&& 0)
4984 dst
= gen_rtx (MEM
, HImode
,
4985 gen_rtx (POST_INC
, HImode
,
4986 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4988 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4990 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4997 /* Scan all the insn and re-affects some registers
4998 - The Z register (if it was used), is affected to X or Y depending
4999 on the instruction. */
5002 m68hc11_reassign_regs (first
)
5007 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5008 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5009 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5010 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5012 /* Scan all insns to replace Z by X or Y preserving the old value
5013 of X/Y and restoring it afterward. */
5015 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5019 if (GET_CODE (insn
) == CODE_LABEL
5020 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5023 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5026 body
= PATTERN (insn
);
5027 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5030 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5031 || GET_CODE (body
) == ASM_OPERANDS
5032 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5035 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5036 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5039 /* If Z appears in this insn, replace it in the current insn
5040 and the next ones until the flow changes or we have to
5041 restore back the replacement register. */
5043 if (reg_mentioned_p (z_reg
, body
))
5045 m68hc11_z_replacement (insn
);
5050 printf ("insn not handled by Z replacement:\n");
5059 m68hc11_reorg (first
)
5065 z_replacement_completed
= 0;
5066 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5068 /* Some RTX are shared at this point. This breaks the Z register
5069 replacement, unshare everything. */
5070 unshare_all_rtl_again (first
);
5072 /* Force a split of all splitable insn. This is necessary for the
5073 Z register replacement mechanism because we end up with basic insns. */
5074 split_all_insns_noflow ();
5077 z_replacement_completed
= 1;
5078 m68hc11_reassign_regs (first
);
5081 compute_bb_for_insn ();
5083 /* After some splitting, there are some oportunities for CSE pass.
5084 This happens quite often when 32-bit or above patterns are split. */
5085 if (optimize
> 0 && split_done
)
5087 reload_cse_regs (first
);
5090 /* Re-create the REG_DEAD notes. These notes are used in the machine
5091 description to use the best assembly directives. */
5094 /* Before recomputing the REG_DEAD notes, remove all of them.
5095 This is necessary because the reload_cse_regs() pass can
5096 have replaced some (MEM) with a register. In that case,
5097 the REG_DEAD that could exist for that register may become
5099 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5105 pnote
= ®_NOTES (insn
);
5108 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5109 *pnote
= XEXP (*pnote
, 1);
5111 pnote
= &XEXP (*pnote
, 1);
5116 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5119 z_replacement_completed
= 2;
5121 /* If optimizing, then go ahead and split insns that must be
5122 split after Z register replacement. This gives more opportunities
5123 for peephole (in particular for consecutives xgdx/xgdy). */
5125 split_all_insns_noflow ();
5127 /* Once insns are split after the z_replacement_completed == 2,
5128 we must not re-run the life_analysis. The xgdx/xgdy patterns
5129 are not recognized and the life_analysis pass removes some
5130 insns because it thinks some (SETs) are noops or made to dead
5131 stores (which is false due to the swap).
5133 Do a simple pass to eliminate the noop set that the final
5134 split could generate (because it was easier for split definition). */
5138 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5142 if (INSN_DELETED_P (insn
))
5144 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5147 /* Remove the (set (R) (R)) insns generated by some splits. */
5148 body
= PATTERN (insn
);
5149 if (GET_CODE (body
) == SET
5150 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5152 PUT_CODE (insn
, NOTE
);
5153 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5154 NOTE_SOURCE_FILE (insn
) = 0;
5162 /* Cost functions. */
5164 /* Cost of moving memory. */
5166 m68hc11_memory_move_cost (mode
, class, in
)
5167 enum machine_mode mode
;
5168 enum reg_class
class;
5169 int in ATTRIBUTE_UNUSED
;
5171 if (class <= H_REGS
&& class > NO_REGS
)
5173 if (GET_MODE_SIZE (mode
) <= 2)
5174 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5176 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5180 if (GET_MODE_SIZE (mode
) <= 2)
5181 return COSTS_N_INSNS (2);
5183 return COSTS_N_INSNS (4);
5188 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5189 Reload does not check the constraint of set insns when the two registers
5190 have a move cost of 2. Setting a higher cost will force reload to check
5193 m68hc11_register_move_cost (mode
, from
, to
)
5194 enum machine_mode mode
;
5195 enum reg_class from
;
5198 /* All costs are symmetric, so reduce cases by putting the
5199 lower number class as the destination. */
5202 enum reg_class tmp
= to
;
5203 to
= from
, from
= tmp
;
5206 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5207 else if (from
<= S_REGS
)
5208 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5210 return COSTS_N_INSNS (2);
5214 /* Provide the costs of an addressing mode that contains ADDR.
5215 If ADDR is not a valid address, its cost is irrelevant. */
5218 m68hc11_address_cost (addr
)
5223 switch (GET_CODE (addr
))
5226 /* Make the cost of hard registers and specially SP, FP small. */
5227 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5244 register rtx plus0
= XEXP (addr
, 0);
5245 register rtx plus1
= XEXP (addr
, 1);
5247 if (GET_CODE (plus0
) != REG
)
5250 switch (GET_CODE (plus1
))
5253 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5254 || INTVAL (plus1
) < m68hc11_min_offset
)
5256 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5260 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5282 if (SP_REG_P (XEXP (addr
, 0)))
5291 printf ("Address cost: %d for :", cost
);
5300 m68hc11_shift_cost (mode
, x
, shift
)
5301 enum machine_mode mode
;
5307 total
= rtx_cost (x
, SET
);
5309 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5310 else if (mode
== HImode
)
5311 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5312 else if (shift
== 8 || shift
== 16 || shift
== 32)
5313 total
+= m68hc11_cost
->shiftHI_const
[8];
5314 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5316 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5319 /* For SI and others, the cost is higher. */
5320 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5321 total
*= GET_MODE_SIZE (mode
) / 2;
5323 /* When optimizing for size, make shift more costly so that
5324 multiplications are preferred. */
5325 if (optimize_size
&& (shift
% 8) != 0)
5332 m68hc11_rtx_costs (x
, code
, outer_code
)
5335 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5337 enum machine_mode mode
= GET_MODE (x
);
5348 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5350 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5353 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5354 total
+= m68hc11_cost
->shift_var
;
5360 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5361 total
+= m68hc11_cost
->logical
;
5363 /* Logical instructions are byte instructions only. */
5364 total
*= GET_MODE_SIZE (mode
);
5369 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5370 total
+= m68hc11_cost
->add
;
5371 if (GET_MODE_SIZE (mode
) > 2)
5373 total
*= GET_MODE_SIZE (mode
) / 2;
5380 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5384 total
+= m68hc11_cost
->divQI
;
5388 total
+= m68hc11_cost
->divHI
;
5393 total
+= m68hc11_cost
->divSI
;
5399 /* mul instruction produces 16-bit result. */
5400 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5401 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5402 return m68hc11_cost
->multQI
5403 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5404 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5406 /* emul instruction produces 32-bit result for 68HC12. */
5407 if (TARGET_M6812
&& mode
== SImode
5408 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5409 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5410 return m68hc11_cost
->multHI
5411 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5412 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5414 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5418 total
+= m68hc11_cost
->multQI
;
5422 total
+= m68hc11_cost
->multHI
;
5427 total
+= m68hc11_cost
->multSI
;
5434 extra_cost
= COSTS_N_INSNS (2);
5441 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5444 return total
+ COSTS_N_INSNS (1);
5448 return total
+ COSTS_N_INSNS (2);
5452 return total
+ COSTS_N_INSNS (4);
5454 return total
+ COSTS_N_INSNS (8);
5457 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5458 return COSTS_N_INSNS (1);
5460 return COSTS_N_INSNS (1);
5463 return COSTS_N_INSNS (4);
5468 /* print_options - called at the start of the code generation for a
5471 extern char *asm_file_name
;
5474 #include <sys/types.h>
5483 extern int save_argc
;
5484 extern char **save_argv
;
5486 fprintf (out
, ";;; Command:\t");
5487 for (i
= 0; i
< save_argc
; i
++)
5489 fprintf (out
, "%s", save_argv
[i
]);
5490 if (i
+ 1 < save_argc
)
5493 fprintf (out
, "\n");
5495 a_time
= ctime (&c_time
);
5496 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5499 #define __VERSION__ "[unknown]"
5501 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5503 fprintf (out
, ";;; (META)compiled by CC.\n");
5508 m68hc11_asm_file_start (out
, main_file
)
5510 const char *main_file
;
5512 fprintf (out
, ";;;-----------------------------------------\n");
5513 fprintf (out
, ";;; Start MC68HC11 gcc assembly output\n");
5514 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5515 print_options (out
);
5516 fprintf (out
, ";;;-----------------------------------------\n");
5517 output_file_directive (out
, main_file
);
5522 m68hc11_asm_out_constructor (symbol
, priority
)
5526 default_ctor_section_asm_out_constructor (symbol
, priority
);
5527 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5531 m68hc11_asm_out_destructor (symbol
, priority
)
5535 default_dtor_section_asm_out_destructor (symbol
, priority
);
5536 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");