1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@nerim.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
23 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24 on gcc 2.6.3. I have used it as a starting point for this port.
25 However, this new port is a complete re-write. Its internal
26 design is completely different. The generated code is not
27 compatible with the gcc 2.6.3 port.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
38 #include "coretypes.h"
44 #include "hard-reg-set.h"
46 #include "insn-config.h"
47 #include "conditions.h"
49 #include "insn-attr.h"
54 #include "basic-block.h"
59 #include "target-def.h"
61 static void print_options
PARAMS ((FILE *));
62 static void emit_move_after_reload
PARAMS ((rtx
, rtx
, rtx
));
63 static rtx simplify_logical
PARAMS ((enum machine_mode
, int, rtx
, rtx
*));
64 static void m68hc11_emit_logical
PARAMS ((enum machine_mode
, int, rtx
*));
65 static int go_if_legitimate_address_internal
PARAMS((rtx
, enum machine_mode
,
67 static int register_indirect_p
PARAMS((rtx
, enum machine_mode
, int));
68 static rtx m68hc11_expand_compare
PARAMS((enum rtx_code
, rtx
, rtx
));
69 static int must_parenthesize
PARAMS ((rtx
));
70 static int m68hc11_address_cost
PARAMS ((rtx
));
71 static int m68hc11_shift_cost
PARAMS ((enum machine_mode
, rtx
, int));
72 static int m68hc11_rtx_costs_1
PARAMS ((rtx
, enum rtx_code
, enum rtx_code
));
73 static bool m68hc11_rtx_costs
PARAMS ((rtx
, int, int, int *));
74 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
75 static tree m68hc11_handle_fntype_attribute
PARAMS ((tree
*, tree
, tree
, int, bool *));
76 const struct attribute_spec m68hc11_attribute_table
[];
78 void create_regs_rtx
PARAMS ((void));
80 static void asm_print_register
PARAMS ((FILE *, int));
81 static void m68hc11_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
82 static void m68hc11_asm_out_constructor
PARAMS ((rtx
, int));
83 static void m68hc11_asm_out_destructor
PARAMS ((rtx
, int));
84 static void m68hc11_encode_section_info
PARAMS((tree
, int));
85 static int autoinc_mode
PARAMS((rtx
));
86 static int m68hc11_make_autoinc_notes
PARAMS((rtx
*, void *));
88 /* Must be set to 1 to produce debug messages. */
91 extern FILE *asm_out_file
;
96 rtx m68hc11_soft_tmp_reg
;
97 static GTY(()) rtx stack_push_word
;
98 static GTY(()) rtx stack_pop_word
;
99 static GTY(()) rtx z_reg
;
100 static GTY(()) rtx z_reg_qi
;
101 static int regs_inited
= 0;
103 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
104 int current_function_interrupt
;
106 /* Set to 1 by expand_prologue() when the function is a trap handler. */
107 int current_function_trap
;
109 /* Set to 1 when the current function is placed in 68HC12 banked
110 memory and must return with rtc. */
111 int current_function_far
;
113 /* Min offset that is valid for the indirect addressing mode. */
114 HOST_WIDE_INT m68hc11_min_offset
= 0;
116 /* Max offset that is valid for the indirect addressing mode. */
117 HOST_WIDE_INT m68hc11_max_offset
= 256;
119 /* The class value for base registers. */
120 enum reg_class m68hc11_base_reg_class
= A_REGS
;
122 /* The class value for index registers. This is NO_REGS for 68HC11. */
123 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
125 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
127 /* Tables that tell whether a given hard register is valid for
128 a base or an index register. It is filled at init time depending
129 on the target processor. */
130 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
131 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
133 /* A correction offset which is applied to the stack pointer.
134 This is 1 for 68HC11 and 0 for 68HC12. */
135 int m68hc11_sp_correction
;
137 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
138 rtx m68hc11_compare_op0
;
139 rtx m68hc11_compare_op1
;
142 const struct processor_costs
*m68hc11_cost
;
144 /* Costs for a 68HC11. */
145 static const struct processor_costs m6811_cost
= {
150 /* non-constant shift */
153 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
154 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
155 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
158 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
159 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
160 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
161 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
162 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
163 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
168 COSTS_N_INSNS (20 * 4),
170 COSTS_N_INSNS (20 * 16),
179 /* Costs for a 68HC12. */
180 static const struct processor_costs m6812_cost
= {
185 /* non-constant shift */
188 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
189 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
190 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
193 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
194 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
195 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
196 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
197 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
198 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
205 COSTS_N_INSNS (3 * 4),
214 /* Machine specific options */
216 const char *m68hc11_regparm_string
;
217 const char *m68hc11_reg_alloc_order
;
218 const char *m68hc11_soft_reg_count
;
220 static int nb_soft_regs
;
222 /* Initialize the GCC target structure. */
223 #undef TARGET_ATTRIBUTE_TABLE
224 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
226 #undef TARGET_ASM_ALIGNED_HI_OP
227 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
229 #undef TARGET_ASM_FUNCTION_EPILOGUE
230 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
232 #undef TARGET_ENCODE_SECTION_INFO
233 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
235 #undef TARGET_RTX_COSTS
236 #define TARGET_RTX_COSTS m68hc11_rtx_costs
237 #undef TARGET_ADDRESS_COST
238 #define TARGET_ADDRESS_COST m68hc11_address_cost
240 struct gcc_target targetm
= TARGET_INITIALIZER
;
243 m68hc11_override_options ()
245 memset (m68hc11_reg_valid_for_index
, 0,
246 sizeof (m68hc11_reg_valid_for_index
));
247 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
249 /* Compilation with -fpic generates a wrong code. */
252 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
253 (flag_pic
> 1) ? "PIC" : "pic");
257 /* Configure for a 68hc11 processor. */
260 /* If gcc was built for a 68hc12, invalidate that because
261 a -m68hc11 option was specified on the command line. */
262 if (TARGET_DEFAULT
!= MASK_M6811
)
263 target_flags
&= ~TARGET_DEFAULT
;
266 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
267 m68hc11_cost
= &m6811_cost
;
268 m68hc11_min_offset
= 0;
269 m68hc11_max_offset
= 256;
270 m68hc11_index_reg_class
= NO_REGS
;
271 m68hc11_base_reg_class
= A_REGS
;
272 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
273 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
274 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
275 m68hc11_sp_correction
= 1;
276 m68hc11_tmp_regs_class
= D_REGS
;
277 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
278 m68hc11_soft_reg_count
= "4";
281 /* Configure for a 68hc12 processor. */
284 m68hc11_cost
= &m6812_cost
;
285 m68hc11_min_offset
= -65536;
286 m68hc11_max_offset
= 65536;
287 m68hc11_index_reg_class
= D_REGS
;
288 m68hc11_base_reg_class
= A_OR_SP_REGS
;
289 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
290 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
291 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
292 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
293 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
294 m68hc11_sp_correction
= 0;
295 m68hc11_tmp_regs_class
= TMP_REGS
;
296 target_flags
&= ~MASK_M6811
;
297 target_flags
|= MASK_NO_DIRECT_MODE
| MASK_MIN_MAX
;
298 if (m68hc11_soft_reg_count
== 0)
299 m68hc11_soft_reg_count
= "0";
301 if (TARGET_LONG_CALLS
)
302 current_function_far
= 1;
309 m68hc11_conditional_register_usage ()
312 int cnt
= atoi (m68hc11_soft_reg_count
);
316 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
317 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
320 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
323 call_used_regs
[i
] = 1;
326 /* For 68HC12, the Z register emulation is not necessary when the
327 frame pointer is not used. The frame pointer is eliminated and
328 replaced by the stack register (which is a BASE_REG_CLASS). */
329 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
331 fixed_regs
[HARD_Z_REGNUM
] = 1;
336 /* Reload and register operations. */
338 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
344 /* regs_inited = 1; */
345 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
346 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
347 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
348 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
350 stack_push_word
= gen_rtx (MEM
, HImode
,
351 gen_rtx (PRE_DEC
, HImode
,
352 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
353 stack_pop_word
= gen_rtx (MEM
, HImode
,
354 gen_rtx (POST_INC
, HImode
,
355 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
359 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
360 - 8 bit values are stored anywhere (except the SP register).
361 - 16 bit values can be stored in any register whose mode is 16
362 - 32 bit values can be stored in D, X registers or in a soft register
363 (except the last one because we need 2 soft registers)
364 - Values whose size is > 32 bit are not stored in real hard
365 registers. They may be stored in soft registers if there are
368 hard_regno_mode_ok (regno
, mode
)
370 enum machine_mode mode
;
372 switch (GET_MODE_SIZE (mode
))
375 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
378 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
381 return G_REGNO_P (regno
);
384 /* We have to accept a QImode in X or Y registers. Otherwise, the
385 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
386 in the insns. Reload fails if the insn rejects the register class 'a'
387 as well as if it accepts it. Patterns that failed were
388 zero_extend_qihi2 and iorqi3. */
390 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
398 preferred_reload_class (operand
, class)
400 enum reg_class
class;
402 enum machine_mode mode
;
404 mode
= GET_MODE (operand
);
408 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
411 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
412 return m68hc11_base_reg_class
;
414 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
415 || GET_CODE (operand
) == CONST_INT
))
417 /* S_REGS class must not be used. The movhi template does not
418 work to move a memory to a soft register.
419 Restrict to a hard reg. */
424 case D_OR_A_OR_S_REGS
:
430 case D_OR_SP_OR_S_REGS
:
431 class = D_OR_SP_REGS
;
433 case D_OR_Y_OR_S_REGS
:
436 case D_OR_X_OR_S_REGS
:
452 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
456 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
460 else if (class >= S_REGS
&& S_REG_P (operand
))
466 case D_OR_A_OR_S_REGS
:
472 case D_OR_SP_OR_S_REGS
:
473 class = D_OR_SP_REGS
;
475 case D_OR_Y_OR_S_REGS
:
478 case D_OR_X_OR_S_REGS
:
494 else if (class >= S_REGS
)
498 printf ("Class = %s for: ", reg_class_names
[class]);
506 printf (" => class=%s\n", reg_class_names
[class]);
514 /* Return 1 if the operand is a valid indexed addressing mode.
515 For 68hc11: n,r with n in [0..255] and r in A_REGS class
516 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
518 register_indirect_p (operand
, mode
, strict
)
520 enum machine_mode mode
;
525 switch (GET_CODE (operand
))
531 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
532 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
536 base
= XEXP (operand
, 0);
537 if (GET_CODE (base
) == MEM
)
540 offset
= XEXP (operand
, 1);
541 if (GET_CODE (offset
) == MEM
)
544 if (GET_CODE (base
) == REG
)
546 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
552 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
554 if (GET_CODE (offset
) == REG
)
556 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
562 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
567 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
573 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
580 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
581 a 68HC12 1-byte index addressing mode. */
583 m68hc11_small_indexed_indirect_p (operand
, mode
)
585 enum machine_mode mode
;
589 if (GET_CODE (operand
) == REG
&& reload_in_progress
590 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
591 && reg_equiv_memory_loc
[REGNO (operand
)])
593 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
594 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
597 if (GET_CODE (operand
) != MEM
)
600 operand
= XEXP (operand
, 0);
601 if (CONSTANT_ADDRESS_P (operand
))
604 if (PUSH_POP_ADDRESS_P (operand
))
607 if (!register_indirect_p (operand
, mode
, reload_completed
))
610 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
611 && (reload_completed
| reload_in_progress
))
613 base
= XEXP (operand
, 0);
614 offset
= XEXP (operand
, 1);
616 /* The offset can be a symbol address and this is too big
617 for the operand constraint. */
618 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
621 if (GET_CODE (base
) == CONST_INT
)
624 switch (GET_MODE_SIZE (mode
))
627 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
632 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
637 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
646 m68hc11_register_indirect_p (operand
, mode
)
648 enum machine_mode mode
;
650 if (GET_CODE (operand
) != MEM
)
653 operand
= XEXP (operand
, 0);
654 return register_indirect_p (operand
, mode
,
655 (reload_completed
| reload_in_progress
));
659 go_if_legitimate_address_internal (operand
, mode
, strict
)
661 enum machine_mode mode
;
664 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
666 /* Reject the global variables if they are too wide. This forces
667 a load of their address in a register and generates smaller code. */
668 if (GET_MODE_SIZE (mode
) == 8)
673 if (register_indirect_p (operand
, mode
, strict
))
677 if (PUSH_POP_ADDRESS_P (operand
))
681 if (symbolic_memory_operand (operand
, mode
))
689 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
691 enum machine_mode mode
;
698 printf ("Checking: ");
703 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
707 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
714 printf ("go_if_legitimate%s, ret 0: %d:",
715 (strict
? "_strict" : ""), mode
);
724 m68hc11_legitimize_address (operand
, old_operand
, mode
)
725 rtx
*operand ATTRIBUTE_UNUSED
;
726 rtx old_operand ATTRIBUTE_UNUSED
;
727 enum machine_mode mode ATTRIBUTE_UNUSED
;
734 m68hc11_reload_operands (operands
)
737 enum machine_mode mode
;
739 if (regs_inited
== 0)
742 mode
= GET_MODE (operands
[1]);
744 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
745 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
747 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
748 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
750 if (GET_CODE (base
) != REG
)
757 /* If the offset is out of range, we have to compute the address
758 with a separate add instruction. We try to do with with an 8-bit
759 add on the A register. This is possible only if the lowest part
760 of the offset (ie, big_offset % 256) is a valid constant offset
761 with respect to the mode. If it's not, we have to generate a
762 16-bit add on the D register. From:
764 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
768 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
769 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
770 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
771 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
773 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
774 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
777 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
780 rtx reg
= operands
[0];
782 int val
= INTVAL (big_offset
);
785 /* We use the 'operands[0]' as a scratch register to compute the
786 address. Make sure 'base' is in that register. */
787 if (!rtx_equal_p (base
, operands
[0]))
789 emit_move_insn (reg
, base
);
799 vh
= (val
>> 8) & 0x0FF;
803 /* Create the lowest part offset that still remains to be added.
804 If it's not a valid offset, do a 16-bit add. */
805 offset
= GEN_INT (vl
);
806 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
808 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
809 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
814 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
815 gen_rtx (PLUS
, HImode
, reg
,
816 GEN_INT (vh
<< 8))));
818 emit_move_insn (operands
[0],
819 gen_rtx (MEM
, GET_MODE (operands
[1]),
820 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
825 /* Use the normal gen_movhi pattern. */
830 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
833 enum machine_mode dmode
;
834 enum machine_mode smode
;
844 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
848 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
849 dmode
, 1, operands
[1], smode
);
850 equiv
= gen_rtx (code
, dmode
, operands
[1]);
854 ret
= emit_library_call_value (libcall
, NULL_RTX
,
856 operands
[1], smode
, operands
[2],
858 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
865 insns
= get_insns ();
867 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
870 /* Returns true if X is a PRE/POST increment decrement
871 (same as auto_inc_p() in rtlanal.c but do not take into
872 account the stack). */
874 m68hc11_auto_inc_p (x
)
877 return GET_CODE (x
) == PRE_DEC
878 || GET_CODE (x
) == POST_INC
879 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
883 /* Predicates for machine description. */
886 memory_reload_operand (operand
, mode
)
888 enum machine_mode mode ATTRIBUTE_UNUSED
;
890 return GET_CODE (operand
) == MEM
891 && GET_CODE (XEXP (operand
, 0)) == PLUS
892 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
893 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
894 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
895 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
899 tst_operand (operand
, mode
)
901 enum machine_mode mode
;
903 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
905 rtx addr
= XEXP (operand
, 0);
906 if (m68hc11_auto_inc_p (addr
))
909 return nonimmediate_operand (operand
, mode
);
913 cmp_operand (operand
, mode
)
915 enum machine_mode mode
;
917 if (GET_CODE (operand
) == MEM
)
919 rtx addr
= XEXP (operand
, 0);
920 if (m68hc11_auto_inc_p (addr
))
923 return general_operand (operand
, mode
);
927 non_push_operand (operand
, mode
)
929 enum machine_mode mode
;
931 if (general_operand (operand
, mode
) == 0)
934 if (push_operand (operand
, mode
) == 1)
940 reg_or_some_mem_operand (operand
, mode
)
942 enum machine_mode mode
;
944 if (GET_CODE (operand
) == MEM
)
946 rtx op
= XEXP (operand
, 0);
948 if (symbolic_memory_operand (op
, mode
))
951 if (IS_STACK_PUSH (operand
))
954 if (m68hc11_register_indirect_p (operand
, mode
))
960 return register_operand (operand
, mode
);
964 m68hc11_symbolic_p (operand
, mode
)
966 enum machine_mode mode
;
968 if (GET_CODE (operand
) == MEM
)
970 rtx op
= XEXP (operand
, 0);
972 if (symbolic_memory_operand (op
, mode
))
979 m68hc11_indirect_p (operand
, mode
)
981 enum machine_mode mode
;
983 if (GET_CODE (operand
) == MEM
)
985 rtx op
= XEXP (operand
, 0);
987 if (symbolic_memory_operand (op
, mode
))
990 if (reload_in_progress
)
993 operand
= XEXP (operand
, 0);
994 return register_indirect_p (operand
, mode
, reload_completed
);
1000 stack_register_operand (operand
, mode
)
1002 enum machine_mode mode ATTRIBUTE_UNUSED
;
1004 return SP_REG_P (operand
);
1008 d_register_operand (operand
, mode
)
1010 enum machine_mode mode ATTRIBUTE_UNUSED
;
1012 if (GET_CODE (operand
) == SUBREG
)
1013 operand
= XEXP (operand
, 0);
1015 return GET_CODE (operand
) == REG
1016 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1017 || REGNO (operand
) == HARD_D_REGNUM
1018 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1022 hard_addr_reg_operand (operand
, mode
)
1024 enum machine_mode mode ATTRIBUTE_UNUSED
;
1026 if (GET_CODE (operand
) == SUBREG
)
1027 operand
= XEXP (operand
, 0);
1029 return GET_CODE (operand
) == REG
1030 && (REGNO (operand
) == HARD_X_REGNUM
1031 || REGNO (operand
) == HARD_Y_REGNUM
1032 || REGNO (operand
) == HARD_Z_REGNUM
);
1036 hard_reg_operand (operand
, mode
)
1038 enum machine_mode mode ATTRIBUTE_UNUSED
;
1040 if (GET_CODE (operand
) == SUBREG
)
1041 operand
= XEXP (operand
, 0);
1043 return GET_CODE (operand
) == REG
1044 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1045 || H_REGNO_P (REGNO (operand
)));
1049 memory_indexed_operand (operand
, mode
)
1051 enum machine_mode mode ATTRIBUTE_UNUSED
;
1053 if (GET_CODE (operand
) != MEM
)
1056 operand
= XEXP (operand
, 0);
1057 if (GET_CODE (operand
) == PLUS
)
1059 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1060 operand
= XEXP (operand
, 0);
1061 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1062 operand
= XEXP (operand
, 1);
1064 return GET_CODE (operand
) == REG
1065 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1066 || A_REGNO_P (REGNO (operand
)));
1070 push_pop_operand_p (operand
)
1073 if (GET_CODE (operand
) != MEM
)
1077 operand
= XEXP (operand
, 0);
1078 return PUSH_POP_ADDRESS_P (operand
);
1081 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1082 reference and a constant. */
1085 symbolic_memory_operand (op
, mode
)
1087 enum machine_mode mode
;
1089 switch (GET_CODE (op
))
1097 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1098 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1099 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1101 /* ??? This clause seems to be irrelevant. */
1103 return GET_MODE (op
) == mode
;
1106 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1107 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1115 m68hc11_logical_operator (op
, mode
)
1117 enum machine_mode mode ATTRIBUTE_UNUSED
;
1119 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1123 m68hc11_arith_operator (op
, mode
)
1125 enum machine_mode mode ATTRIBUTE_UNUSED
;
1127 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1128 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1129 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1130 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1131 || GET_CODE (op
) == ROTATERT
;
1135 m68hc11_non_shift_operator (op
, mode
)
1137 enum machine_mode mode ATTRIBUTE_UNUSED
;
1139 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1140 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1145 m68hc11_unary_operator (op
, mode
)
1147 enum machine_mode mode ATTRIBUTE_UNUSED
;
1149 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1150 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1153 /* Emit the code to build the trampoline used to call a nested function.
1157 ldy #&CXT movw #&CXT,*_.d1
1158 sty *_.d1 jmp FNADDR
1163 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1168 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1171 if (*static_chain_reg
== '*')
1175 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1176 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1177 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1179 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1180 gen_rtx_CONST (QImode
,
1181 gen_rtx_SYMBOL_REF (Pmode
,
1182 static_chain_reg
)));
1183 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1185 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1189 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1190 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1191 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1192 gen_rtx_CONST (HImode
,
1193 gen_rtx_SYMBOL_REF (Pmode
,
1194 static_chain_reg
)));
1195 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1197 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1201 /* Declaration of types. */
1203 const struct attribute_spec m68hc11_attribute_table
[] =
1205 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1206 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1207 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1208 { NULL
, 0, 0, false, false, false, NULL
}
1211 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1212 arguments as in struct attribute_spec.handler. */
1214 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1217 tree args ATTRIBUTE_UNUSED
;
1218 int flags ATTRIBUTE_UNUSED
;
1221 if (TREE_CODE (*node
) != FUNCTION_TYPE
1222 && TREE_CODE (*node
) != FIELD_DECL
1223 && TREE_CODE (*node
) != TYPE_DECL
)
1225 warning ("`%s' attribute only applies to functions",
1226 IDENTIFIER_POINTER (name
));
1227 *no_add_attrs
= true;
1233 /* We want to recognize trap handlers so that we handle calls to traps
1234 in a special manner (by issuing the trap). This information is stored
1235 in SYMBOL_REF_FLAG. */
1238 m68hc11_encode_section_info (decl
, first
)
1240 int first ATTRIBUTE_UNUSED
;
1246 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1249 rtl
= DECL_RTL (decl
);
1251 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1252 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1253 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1257 /* Argument support functions. */
1259 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1260 Arrays are passed by references and other types by value.
1262 SCz: I tried to pass DImode by reference but it seems that this
1263 does not work very well. */
1265 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1266 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1267 enum machine_mode mode ATTRIBUTE_UNUSED
;
1269 int named ATTRIBUTE_UNUSED
;
1271 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1272 /* Consider complex values as aggregates, so care for TCmode. */
1273 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1274 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1278 /* Define the offset between two registers, one to be eliminated, and the
1279 other its replacement, at the start of a routine. */
1281 m68hc11_initial_elimination_offset (from
, to
)
1290 /* For a trap handler, we must take into account the registers which
1291 are pushed on the stack during the trap (except the PC). */
1292 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1293 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1294 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1297 /* For a function using 'call/rtc' we must take into account the
1298 page register which is pushed in the call. */
1299 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1304 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1306 /* 2 is for the saved frame.
1307 1 is for the 'sts' correction when creating the frame. */
1308 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1311 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1313 return m68hc11_sp_correction
;
1316 /* Push any 2 byte pseudo hard registers that we need to save. */
1317 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1319 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1325 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1327 return get_frame_size () + size
;
1330 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1337 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1338 for a call to a function whose data type is FNTYPE.
1339 For a library call, FNTYPE is 0. */
1342 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1343 CUMULATIVE_ARGS
*cum
;
1349 z_replacement_completed
= 0;
1353 /* For a library call, we must find out the type of the return value.
1354 When the return value is bigger than 4 bytes, it is returned in
1355 memory. In that case, the first argument of the library call is a
1356 pointer to the memory location. Because the first argument is passed in
1357 register D, we have to identify this, so that the first function
1358 parameter is not passed in D either. */
1364 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1367 /* If the library ends in 'di' or in 'df', we assume it's
1368 returning some DImode or some DFmode which are 64-bit wide. */
1369 name
= XSTR (libname
, 0);
1370 len
= strlen (name
);
1372 && ((name
[len
- 2] == 'd'
1373 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1374 || (name
[len
- 3] == 'd'
1375 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1377 /* We are in. Mark the first parameter register as already used. */
1384 ret_type
= TREE_TYPE (fntype
);
1386 if (ret_type
&& aggregate_value_p (ret_type
))
1393 /* Update the data in CUM to advance over an argument
1394 of mode MODE and data type TYPE.
1395 (TYPE is null for libcalls where that information may not be available.) */
1398 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1399 CUMULATIVE_ARGS
*cum
;
1400 enum machine_mode mode
;
1402 int named ATTRIBUTE_UNUSED
;
1404 if (mode
!= BLKmode
)
1406 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1409 cum
->words
= GET_MODE_SIZE (mode
);
1413 cum
->words
+= GET_MODE_SIZE (mode
);
1414 if (cum
->words
<= HARD_REG_SIZE
)
1420 cum
->words
+= int_size_in_bytes (type
);
1425 /* Define where to put the arguments to a function.
1426 Value is zero to push the argument on the stack,
1427 or a hard register in which to store the argument.
1429 MODE is the argument's machine mode.
1430 TYPE is the data type of the argument (as a tree).
1431 This is null for libcalls where that information may
1433 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1434 the preceding args and about the function being called.
1435 NAMED is nonzero if this argument is a named parameter
1436 (otherwise it is an extra parameter matching an ellipsis). */
1439 m68hc11_function_arg (cum
, mode
, type
, named
)
1440 const CUMULATIVE_ARGS
*cum
;
1441 enum machine_mode mode
;
1442 tree type ATTRIBUTE_UNUSED
;
1443 int named ATTRIBUTE_UNUSED
;
1445 if (cum
->words
!= 0)
1450 if (mode
!= BLKmode
)
1452 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1453 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1455 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1459 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1465 m68hc11_va_arg (valist
, type
)
1470 HOST_WIDE_INT align
;
1471 HOST_WIDE_INT rounded_size
;
1475 /* Compute the rounded size of the type. */
1476 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1477 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1481 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1483 if (pad_direction
== downward
)
1485 /* Small args are padded downward. */
1488 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1489 if (rounded_size
> align
)
1492 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1493 build_int_2 (rounded_size
- adj
, 0));
1496 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1497 addr
= copy_to_reg (addr
);
1499 /* Compute new value for AP. */
1500 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1501 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1502 build_int_2 (rounded_size
, 0)));
1503 TREE_SIDE_EFFECTS (t
) = 1;
1504 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1509 /* If defined, a C expression which determines whether, and in which direction,
1510 to pad out an argument with extra space. The value should be of type
1511 `enum direction': either `upward' to pad above the argument,
1512 `downward' to pad below, or `none' to inhibit padding.
1514 Structures are stored left shifted in their argument slot. */
1516 m68hc11_function_arg_padding (mode
, type
)
1517 enum machine_mode mode
;
1520 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1523 /* This is the default definition. */
1524 return (!BYTES_BIG_ENDIAN
1527 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1528 && int_size_in_bytes (type
) <
1529 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1530 PARM_BOUNDARY
) ? downward
: upward
));
1534 /* Function prologue and epilogue. */
1536 /* Emit a move after the reload pass has completed. This is used to
1537 emit the prologue and epilogue. */
1539 emit_move_after_reload (to
, from
, scratch
)
1540 rtx to
, from
, scratch
;
1544 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1546 insn
= emit_move_insn (to
, from
);
1550 emit_move_insn (scratch
, from
);
1551 insn
= emit_move_insn (to
, scratch
);
1554 /* Put a REG_INC note to tell the flow analysis that the instruction
1556 if (IS_STACK_PUSH (to
))
1558 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1559 XEXP (XEXP (to
, 0), 0),
1562 else if (IS_STACK_POP (from
))
1564 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1565 XEXP (XEXP (from
, 0), 0),
1569 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1570 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1571 The problem is that we are lying to gcc and use `txs' for x = sp
1572 (which is not really true because txs is really x = sp + 1). */
1573 else if (TARGET_M6811
&& SP_REG_P (from
))
1575 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1582 m68hc11_total_frame_size ()
1587 size
= get_frame_size ();
1588 if (current_function_interrupt
)
1590 size
+= 3 * HARD_REG_SIZE
;
1592 if (frame_pointer_needed
)
1593 size
+= HARD_REG_SIZE
;
1595 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1596 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1597 size
+= HARD_REG_SIZE
;
1603 m68hc11_output_function_epilogue (out
, size
)
1604 FILE *out ATTRIBUTE_UNUSED
;
1605 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1607 /* We catch the function epilogue generation to have a chance
1608 to clear the z_replacement_completed flag. */
1609 z_replacement_completed
= 0;
1620 if (reload_completed
!= 1)
1623 size
= get_frame_size ();
1627 /* Generate specific prologue for interrupt handlers. */
1628 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1629 current_function_interrupt
= lookup_attribute ("interrupt",
1630 func_attr
) != NULL_TREE
;
1631 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1633 /* Get the scratch register to build the frame and push registers.
1634 If the first argument is a 32-bit quantity, the D+X registers
1635 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1636 For 68HC12, this scratch register is not used. */
1637 if (current_function_args_info
.nregs
== 2)
1642 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1643 Other soft registers in page0 need not to be saved because they
1644 will be restored by C functions. For a trap handler, we don't
1645 need to preserve these registers because this is a synchronous call. */
1646 if (current_function_interrupt
)
1648 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1649 emit_move_after_reload (stack_push_word
,
1650 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1651 emit_move_after_reload (stack_push_word
,
1652 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1656 /* Save current stack frame. */
1657 if (frame_pointer_needed
)
1658 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1660 /* Allocate local variables. */
1661 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1663 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1664 stack_pointer_rtx
, GEN_INT (-size
)));
1666 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1670 insn
= gen_rtx_PARALLEL
1673 gen_rtx_SET (VOIDmode
,
1675 gen_rtx_PLUS (HImode
,
1678 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1685 /* Allocate by pushing scratch values. */
1686 for (i
= 2; i
<= size
; i
+= 2)
1687 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1690 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1691 stack_pointer_rtx
, GEN_INT (-1)));
1694 /* Create the frame pointer. */
1695 if (frame_pointer_needed
)
1696 emit_move_after_reload (hard_frame_pointer_rtx
,
1697 stack_pointer_rtx
, scratch
);
1699 /* Push any 2 byte pseudo hard registers that we need to save. */
1700 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1702 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1704 emit_move_after_reload (stack_push_word
,
1705 gen_rtx (REG
, HImode
, regno
), scratch
);
1718 if (reload_completed
!= 1)
1721 size
= get_frame_size ();
1723 /* If we are returning a value in two registers, we have to preserve the
1724 X register and use the Y register to restore the stack and the saved
1725 registers. Otherwise, use X because it's faster (and smaller). */
1726 if (current_function_return_rtx
== 0)
1728 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1729 return_size
= HARD_REG_SIZE
;
1731 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1733 if (return_size
> HARD_REG_SIZE
)
1738 /* Pop any 2 byte pseudo hard registers that we saved. */
1739 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1741 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1743 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1744 stack_pop_word
, scratch
);
1748 /* de-allocate auto variables */
1749 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1751 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1752 stack_pointer_rtx
, GEN_INT (size
)));
1754 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1758 insn
= gen_rtx_PARALLEL
1761 gen_rtx_SET (VOIDmode
,
1763 gen_rtx_PLUS (HImode
,
1766 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1773 for (i
= 2; i
<= size
; i
+= 2)
1774 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1776 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1777 stack_pointer_rtx
, GEN_INT (1)));
1780 /* Restore previous frame pointer. */
1781 if (frame_pointer_needed
)
1782 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1784 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1785 if (current_function_interrupt
)
1787 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1788 stack_pop_word
, scratch
);
1789 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1790 stack_pop_word
, scratch
);
1791 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1794 /* If the trap handler returns some value, copy the value
1795 in D, X onto the stack so that the rti will pop the return value
1797 else if (current_function_trap
&& return_size
!= 0)
1799 rtx addr_reg
= stack_pointer_rtx
;
1803 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1806 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1807 gen_rtx (PLUS
, HImode
, addr_reg
,
1808 GEN_INT (1))), d_reg
, 0);
1809 if (return_size
> HARD_REG_SIZE
)
1810 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1811 gen_rtx (PLUS
, HImode
, addr_reg
,
1812 GEN_INT (3))), ix_reg
, 0);
1815 emit_jump_insn (gen_return ());
1819 /* Low and High part extraction for 68HC11. These routines are
1820 similar to gen_lowpart and gen_highpart but they have been
1821 fixed to work for constants and 68HC11 specific registers. */
1824 m68hc11_gen_lowpart (mode
, x
)
1825 enum machine_mode mode
;
1828 /* We assume that the low part of an auto-inc mode is the same with
1829 the mode changed and that the caller split the larger mode in the
1831 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1833 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1836 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1837 floating-point constant. A CONST_DOUBLE is used whenever the
1838 constant requires more than one word in order to be adequately
1840 if (GET_CODE (x
) == CONST_DOUBLE
)
1844 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1848 if (GET_MODE (x
) == SFmode
)
1850 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1851 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1857 split_double (x
, &first
, &second
);
1861 return GEN_INT (l
[0]);
1863 return gen_int_mode (l
[0], HImode
);
1867 l
[0] = CONST_DOUBLE_LOW (x
);
1870 return GEN_INT (l
[0]);
1871 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1872 return gen_int_mode (l
[0], HImode
);
1877 if (mode
== QImode
&& D_REG_P (x
))
1878 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1880 /* gen_lowpart crashes when it is called with a SUBREG. */
1881 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1884 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1885 else if (mode
== HImode
)
1886 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1890 x
= gen_lowpart (mode
, x
);
1892 /* Return a different rtx to avoid to share it in several insns
1893 (when used by a split pattern). Sharing addresses within
1894 a MEM breaks the Z register replacement (and reloading). */
1895 if (GET_CODE (x
) == MEM
)
1901 m68hc11_gen_highpart (mode
, x
)
1902 enum machine_mode mode
;
1905 /* We assume that the high part of an auto-inc mode is the same with
1906 the mode changed and that the caller split the larger mode in the
1908 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1910 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1913 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1914 floating-point constant. A CONST_DOUBLE is used whenever the
1915 constant requires more than one word in order to be adequately
1917 if (GET_CODE (x
) == CONST_DOUBLE
)
1921 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1925 if (GET_MODE (x
) == SFmode
)
1927 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1928 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1934 split_double (x
, &first
, &second
);
1938 return GEN_INT (l
[1]);
1940 return gen_int_mode ((l
[1] >> 16), HImode
);
1944 l
[1] = CONST_DOUBLE_HIGH (x
);
1948 return GEN_INT (l
[1]);
1949 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1950 return gen_int_mode ((l
[0] >> 16), HImode
);
1954 if (GET_CODE (x
) == CONST_INT
)
1956 HOST_WIDE_INT val
= INTVAL (x
);
1960 return gen_int_mode (val
>> 8, QImode
);
1962 else if (mode
== HImode
)
1964 return gen_int_mode (val
>> 16, HImode
);
1967 if (mode
== QImode
&& D_REG_P (x
))
1968 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1970 /* There is no way in GCC to represent the upper part of a word register.
1971 To obtain the 8-bit upper part of a soft register, we change the
1972 reg into a mem rtx. This is possible because they are physically
1973 located in memory. There is no offset because we are big-endian. */
1974 if (mode
== QImode
&& S_REG_P (x
))
1978 /* Avoid the '*' for direct addressing mode when this
1979 addressing mode is disabled. */
1980 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1981 return gen_rtx (MEM
, QImode
,
1982 gen_rtx (SYMBOL_REF
, Pmode
,
1983 ®_names
[REGNO (x
)][pos
]));
1986 /* gen_highpart crashes when it is called with a SUBREG. */
1987 if (GET_CODE (x
) == SUBREG
)
1989 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
1991 if (GET_CODE (x
) == REG
)
1993 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
1994 return gen_rtx (REG
, mode
, REGNO (x
));
1996 return gen_rtx_SUBREG (mode
, x
, 0);
1999 if (GET_CODE (x
) == MEM
)
2001 x
= change_address (x
, mode
, 0);
2003 /* Return a different rtx to avoid to share it in several insns
2004 (when used by a split pattern). Sharing addresses within
2005 a MEM breaks the Z register replacement (and reloading). */
2006 if (GET_CODE (x
) == MEM
)
2014 /* Obscure register manipulation. */
2016 /* Finds backward in the instructions to see if register 'reg' is
2017 dead. This is used when generating code to see if we can use 'reg'
2018 as a scratch register. This allows us to choose a better generation
2019 of code when we know that some register dies or can be clobbered. */
2022 dead_register_here (x
, reg
)
2030 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2034 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2035 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2041 if (GET_CODE (body
) == CALL_INSN
)
2043 if (GET_CODE (body
) == JUMP_INSN
)
2046 if (GET_CODE (body
) == SET
)
2048 rtx dst
= XEXP (body
, 0);
2050 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2052 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2055 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2058 else if (reg_mentioned_p (reg
, p
)
2059 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2063 /* Scan forward to see if the register is set in some insns and never
2065 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2069 if (GET_CODE (p
) == CODE_LABEL
2070 || GET_CODE (p
) == JUMP_INSN
2071 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2074 if (GET_CODE (p
) != INSN
)
2078 if (GET_CODE (body
) == SET
)
2080 rtx src
= XEXP (body
, 1);
2081 rtx dst
= XEXP (body
, 0);
2083 if (GET_CODE (dst
) == REG
2084 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2088 /* Register is used (may be in source or in dest). */
2089 if (reg_mentioned_p (reg
, p
)
2090 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2091 && reg_mentioned_p (x_reg
, p
)))
2094 return p
== 0 ? 1 : 0;
2098 /* Code generation operations called from machine description file. */
2100 /* Print the name of register 'regno' in the assembly file. */
2102 asm_print_register (file
, regno
)
2106 const char *name
= reg_names
[regno
];
2108 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2111 fprintf (file
, "%s", name
);
2114 /* A C compound statement to output to stdio stream STREAM the
2115 assembler syntax for an instruction operand X. X is an RTL
2118 CODE is a value that can be used to specify one of several ways
2119 of printing the operand. It is used when identical operands
2120 must be printed differently depending on the context. CODE
2121 comes from the `%' specification that was used to request
2122 printing of the operand. If the specification was just `%DIGIT'
2123 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2124 is the ASCII code for LTR.
2126 If X is a register, this macro should print the register's name.
2127 The names can be found in an array `reg_names' whose type is
2128 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2130 When the machine description has a specification `%PUNCT' (a `%'
2131 followed by a punctuation character), this macro is called with
2132 a null pointer for X and the punctuation character for CODE.
2134 The M68HC11 specific codes are:
2136 'b' for the low part of the operand.
2137 'h' for the high part of the operand
2138 The 'b' or 'h' modifiers have no effect if the operand has
2139 the QImode and is not a S_REG_P (soft register). If the
2140 operand is a hard register, these two modifiers have no effect.
2141 't' generate the temporary scratch register. The operand is
2143 'T' generate the low-part temporary scratch register. The operand is
2147 print_operand (file
, op
, letter
)
2154 asm_print_register (file
, SOFT_TMP_REGNUM
);
2157 else if (letter
== 'T')
2159 asm_print_register (file
, SOFT_TMP_REGNUM
);
2160 fprintf (file
, "+1");
2163 else if (letter
== '#')
2165 asm_fprintf (file
, "%0I");
2168 if (GET_CODE (op
) == REG
)
2170 if (letter
== 'b' && S_REG_P (op
))
2172 asm_print_register (file
, REGNO (op
));
2173 fprintf (file
, "+1");
2177 asm_print_register (file
, REGNO (op
));
2182 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2185 asm_fprintf (file
, "%0I%%lo(");
2187 asm_fprintf (file
, "%0I%%hi(");
2189 output_addr_const (file
, op
);
2190 fprintf (file
, ")");
2194 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2195 are specified. If we already have a QImode, there is nothing to do. */
2196 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2200 op
= m68hc11_gen_lowpart (QImode
, op
);
2202 else if (letter
== 'h')
2204 op
= m68hc11_gen_highpart (QImode
, op
);
2208 if (GET_CODE (op
) == MEM
)
2210 rtx base
= XEXP (op
, 0);
2211 switch (GET_CODE (base
))
2216 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2217 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2226 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2227 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2228 fprintf (file
, "-");
2237 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2238 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2239 fprintf (file
, "+");
2248 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2249 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2256 output_address (base
);
2260 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2265 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2266 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2267 asm_fprintf (file
, "%I0x%lx", l
);
2269 else if (GET_CODE (op
) == CONST_DOUBLE
2270 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2274 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2275 sizeof (dstr
), 0, 1);
2276 asm_fprintf (file
, "%I0r%s", dstr
);
2280 int need_parenthesize
= 0;
2283 asm_fprintf (file
, "%0I");
2285 need_parenthesize
= must_parenthesize (op
);
2287 if (need_parenthesize
)
2288 fprintf (file
, "(");
2290 output_addr_const (file
, op
);
2291 if (need_parenthesize
)
2292 fprintf (file
, ")");
2296 /* Returns true if the operand 'op' must be printed with parenthesis
2297 arround it. This must be done only if there is a symbol whose name
2298 is a processor register. */
2300 must_parenthesize (op
)
2305 switch (GET_CODE (op
))
2308 name
= XSTR (op
, 0);
2309 /* Avoid a conflict between symbol name and a possible
2311 return (strcasecmp (name
, "a") == 0
2312 || strcasecmp (name
, "b") == 0
2313 || strcasecmp (name
, "d") == 0
2314 || strcasecmp (name
, "x") == 0
2315 || strcasecmp (name
, "y") == 0
2316 || strcasecmp (name
, "ix") == 0
2317 || strcasecmp (name
, "iy") == 0
2318 || strcasecmp (name
, "pc") == 0
2319 || strcasecmp (name
, "sp") == 0
2320 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2324 return must_parenthesize (XEXP (op
, 0))
2325 || must_parenthesize (XEXP (op
, 1));
2331 return must_parenthesize (XEXP (op
, 0));
2342 /* A C compound statement to output to stdio stream STREAM the
2343 assembler syntax for an instruction operand that is a memory
2344 reference whose address is ADDR. ADDR is an RTL expression. */
2347 print_operand_address (file
, addr
)
2353 int need_parenthesis
= 0;
2355 switch (GET_CODE (addr
))
2358 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2361 fprintf (file
, "0,");
2362 asm_print_register (file
, REGNO (addr
));
2366 base
= XEXP (addr
, 0);
2367 switch (GET_CODE (base
))
2372 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2373 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2382 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2383 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2384 fprintf (file
, "-");
2393 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2394 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2395 fprintf (file
, "+");
2404 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2405 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2412 need_parenthesis
= must_parenthesize (base
);
2413 if (need_parenthesis
)
2414 fprintf (file
, "(");
2416 output_addr_const (file
, base
);
2417 if (need_parenthesis
)
2418 fprintf (file
, ")");
2424 base
= XEXP (addr
, 0);
2425 offset
= XEXP (addr
, 1);
2426 if (!G_REG_P (base
) && G_REG_P (offset
))
2428 base
= XEXP (addr
, 1);
2429 offset
= XEXP (addr
, 0);
2431 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2433 need_parenthesis
= must_parenthesize (addr
);
2435 if (need_parenthesis
)
2436 fprintf (file
, "(");
2438 output_addr_const (file
, base
);
2439 fprintf (file
, "+");
2440 output_addr_const (file
, offset
);
2441 if (need_parenthesis
)
2442 fprintf (file
, ")");
2444 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2450 asm_print_register (file
, REGNO (offset
));
2451 fprintf (file
, ",");
2452 asm_print_register (file
, REGNO (base
));
2459 need_parenthesis
= must_parenthesize (offset
);
2460 if (need_parenthesis
)
2461 fprintf (file
, "(");
2463 output_addr_const (file
, offset
);
2464 if (need_parenthesis
)
2465 fprintf (file
, ")");
2466 fprintf (file
, ",");
2467 asm_print_register (file
, REGNO (base
));
2477 if (GET_CODE (addr
) == CONST_INT
2478 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2480 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2484 need_parenthesis
= must_parenthesize (addr
);
2485 if (need_parenthesis
)
2486 fprintf (file
, "(");
2488 output_addr_const (file
, addr
);
2489 if (need_parenthesis
)
2490 fprintf (file
, ")");
2497 /* Splitting of some instructions. */
2500 m68hc11_expand_compare (code
, op0
, op1
)
2506 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2510 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2511 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2512 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2519 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2521 rtx op0
, op1
, label
;
2525 switch (GET_MODE (op0
))
2529 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2530 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2531 gen_rtx_LABEL_REF (VOIDmode
, label
),
2533 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2537 /* SCz: from i386.c */
2540 /* Don't expand the comparison early, so that we get better code
2541 when jump or whoever decides to reverse the comparison. */
2546 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2547 &m68hc11_compare_op1
);
2549 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2550 m68hc11_compare_op0
, m68hc11_compare_op1
);
2551 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2552 gen_rtx_LABEL_REF (VOIDmode
, label
),
2554 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2556 use_fcomi
= ix86_use_fcomi_compare (code
);
2557 vec
= rtvec_alloc (3 + !use_fcomi
);
2558 RTVEC_ELT (vec
, 0) = tmp
;
2560 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2562 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2565 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2567 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2573 /* Expand SImode branch into multiple compare+branch. */
2575 rtx lo
[2], hi
[2], label2
;
2576 enum rtx_code code1
, code2
, code3
;
2578 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2583 code
= swap_condition (code
);
2585 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2586 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2587 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2588 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2590 /* Otherwise, if we are doing less-than, op1 is a constant and the
2591 low word is zero, then we can just examine the high word. */
2593 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2594 && (code
== LT
|| code
== LTU
))
2596 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2600 /* Otherwise, we need two or three jumps. */
2602 label2
= gen_label_rtx ();
2605 code2
= swap_condition (code
);
2606 code3
= unsigned_condition (code
);
2647 * if (hi(a) < hi(b)) goto true;
2648 * if (hi(a) > hi(b)) goto false;
2649 * if (lo(a) < lo(b)) goto true;
2653 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2655 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2657 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2660 emit_label (label2
);
2670 /* Return the increment/decrement mode of a MEM if it is such.
2671 Return CONST if it is anything else. */
2676 if (GET_CODE (x
) != MEM
)
2680 if (GET_CODE (x
) == PRE_INC
2681 || GET_CODE (x
) == PRE_DEC
2682 || GET_CODE (x
) == POST_INC
2683 || GET_CODE (x
) == POST_DEC
)
2684 return GET_CODE (x
);
2690 m68hc11_make_autoinc_notes (x
, data
)
2696 switch (GET_CODE (*x
))
2703 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2712 /* Split a DI, SI or HI move into several smaller move operations.
2713 The scratch register 'scratch' is used as a temporary to load
2714 store intermediate values. It must be a hard register. */
2716 m68hc11_split_move (to
, from
, scratch
)
2717 rtx to
, from
, scratch
;
2719 rtx low_to
, low_from
;
2720 rtx high_to
, high_from
;
2722 enum machine_mode mode
;
2724 int autoinc_from
= autoinc_mode (from
);
2725 int autoinc_to
= autoinc_mode (to
);
2727 mode
= GET_MODE (to
);
2729 /* If the TO and FROM contain autoinc modes that are not compatible
2730 together (one pop and the other a push), we must change one to
2731 an offsetable operand and generate an appropriate add at the end. */
2732 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2737 /* The source uses an autoinc mode which is not compatible with
2738 a split (this would result in a word swap). */
2739 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2741 code
= GET_CODE (XEXP (from
, 0));
2742 reg
= XEXP (XEXP (from
, 0), 0);
2743 offset
= GET_MODE_SIZE (GET_MODE (from
));
2744 if (code
== POST_DEC
)
2747 if (code
== PRE_INC
)
2748 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2750 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2751 if (code
== POST_DEC
)
2752 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2756 /* Likewise for destination. */
2757 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2759 code
= GET_CODE (XEXP (to
, 0));
2760 reg
= XEXP (XEXP (to
, 0), 0);
2761 offset
= GET_MODE_SIZE (GET_MODE (to
));
2762 if (code
== POST_DEC
)
2765 if (code
== PRE_INC
)
2766 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2768 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2769 if (code
== POST_DEC
)
2770 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2774 /* The source and destination auto increment modes must be compatible
2775 with each other: same direction. */
2776 if ((autoinc_to
!= autoinc_from
2777 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2778 /* The destination address register must not be used within
2779 the source operand because the source address would change
2780 while doing the copy. */
2781 || (autoinc_to
!= CONST
2782 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2783 && !IS_STACK_PUSH (to
)))
2785 /* Must change the destination. */
2786 code
= GET_CODE (XEXP (to
, 0));
2787 reg
= XEXP (XEXP (to
, 0), 0);
2788 offset
= GET_MODE_SIZE (GET_MODE (to
));
2789 if (code
== PRE_DEC
|| code
== POST_DEC
)
2792 if (code
== PRE_DEC
|| code
== PRE_INC
)
2793 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2794 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2795 if (code
== POST_DEC
|| code
== POST_INC
)
2796 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2801 /* Likewise, the source address register must not be used within
2802 the destination operand. */
2803 if (autoinc_from
!= CONST
2804 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2805 && !IS_STACK_PUSH (to
))
2807 /* Must change the source. */
2808 code
= GET_CODE (XEXP (from
, 0));
2809 reg
= XEXP (XEXP (from
, 0), 0);
2810 offset
= GET_MODE_SIZE (GET_MODE (from
));
2811 if (code
== PRE_DEC
|| code
== POST_DEC
)
2814 if (code
== PRE_DEC
|| code
== PRE_INC
)
2815 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2816 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2817 if (code
== POST_DEC
|| code
== POST_INC
)
2818 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2824 if (GET_MODE_SIZE (mode
) == 8)
2826 else if (GET_MODE_SIZE (mode
) == 4)
2832 && IS_STACK_PUSH (to
)
2833 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2839 else if (mode
== HImode
)
2847 low_to
= m68hc11_gen_lowpart (mode
, to
);
2848 high_to
= m68hc11_gen_highpart (mode
, to
);
2850 low_from
= m68hc11_gen_lowpart (mode
, from
);
2851 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2853 if (INTVAL (from
) >= 0)
2854 high_from
= const0_rtx
;
2856 high_from
= constm1_rtx
;
2859 high_from
= m68hc11_gen_highpart (mode
, from
);
2863 high_from
= adjust_address (high_from
, mode
, offset
);
2864 low_from
= high_from
;
2867 /* When copying with a POST_INC mode, we must copy the
2868 high part and then the low part to guarantee a correct
2871 && GET_MODE_SIZE (mode
) >= 2
2872 && autoinc_from
!= autoinc_to
2873 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2882 low_from
= high_from
;
2887 m68hc11_split_move (low_to
, low_from
, scratch
);
2888 m68hc11_split_move (high_to
, high_from
, scratch
);
2890 else if (H_REG_P (to
) || H_REG_P (from
)
2891 || (low_from
== const0_rtx
2892 && high_from
== const0_rtx
2893 && ! push_operand (to
, GET_MODE (to
))
2894 && ! H_REG_P (scratch
))
2896 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2897 || m68hc11_small_indexed_indirect_p (from
,
2899 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2900 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2902 insn
= emit_move_insn (low_to
, low_from
);
2903 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2905 insn
= emit_move_insn (high_to
, high_from
);
2906 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2910 insn
= emit_move_insn (scratch
, low_from
);
2911 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2912 insn
= emit_move_insn (low_to
, scratch
);
2913 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2915 insn
= emit_move_insn (scratch
, high_from
);
2916 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2917 insn
= emit_move_insn (high_to
, scratch
);
2918 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2923 simplify_logical (mode
, code
, operand
, result
)
2924 enum machine_mode mode
;
2933 if (GET_CODE (operand
) != CONST_INT
)
2941 val
= INTVAL (operand
);
2945 if ((val
& mask
) == 0)
2947 if ((val
& mask
) == mask
)
2948 *result
= constm1_rtx
;
2952 if ((val
& mask
) == 0)
2953 *result
= const0_rtx
;
2954 if ((val
& mask
) == mask
)
2959 if ((val
& mask
) == 0)
2967 m68hc11_emit_logical (mode
, code
, operands
)
2968 enum machine_mode mode
;
2975 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2976 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2978 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2979 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2981 if (result
&& GET_CODE (result
) == CONST_INT
)
2983 if (!H_REG_P (operands
[0]) && operands
[3]
2984 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2986 emit_move_insn (operands
[3], result
);
2987 emit_move_insn (operands
[0], operands
[3]);
2991 emit_move_insn (operands
[0], result
);
2994 else if (operands
[1] != 0 && operands
[2] != 0)
2998 if (!H_REG_P (operands
[0]) && operands
[3])
3000 emit_move_insn (operands
[3], operands
[1]);
3001 emit_insn (gen_rtx (SET
, mode
,
3003 gen_rtx (code
, mode
,
3004 operands
[3], operands
[2])));
3005 insn
= emit_move_insn (operands
[0], operands
[3]);
3009 insn
= emit_insn (gen_rtx (SET
, mode
,
3011 gen_rtx (code
, mode
,
3012 operands
[0], operands
[2])));
3016 /* The logical operation is similar to a copy. */
3021 if (GET_CODE (operands
[1]) == CONST_INT
)
3026 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3028 emit_move_insn (operands
[3], src
);
3029 emit_move_insn (operands
[0], operands
[3]);
3033 emit_move_insn (operands
[0], src
);
3039 m68hc11_split_logical (mode
, code
, operands
)
3040 enum machine_mode mode
;
3047 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3048 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3049 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3051 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3053 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3055 if (INTVAL (operands
[1]) >= 0)
3056 high
[1] = const0_rtx
;
3058 high
[1] = constm1_rtx
;
3061 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3063 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3065 if (INTVAL (operands
[2]) >= 0)
3066 high
[2] = const0_rtx
;
3068 high
[2] = constm1_rtx
;
3071 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3073 low
[3] = operands
[3];
3074 high
[3] = operands
[3];
3077 m68hc11_split_logical (HImode
, code
, low
);
3078 m68hc11_split_logical (HImode
, code
, high
);
3082 m68hc11_emit_logical (mode
, code
, low
);
3083 m68hc11_emit_logical (mode
, code
, high
);
3087 /* Code generation. */
3090 m68hc11_output_swap (insn
, operands
)
3091 rtx insn ATTRIBUTE_UNUSED
;
3094 /* We have to be careful with the cc_status. An address register swap
3095 is generated for some comparison. The comparison is made with D
3096 but the branch really uses the address register. See the split
3097 pattern for compare. The xgdx/xgdy preserve the flags but after
3098 the exchange, the flags will reflect to the value of X and not D.
3099 Tell this by setting the cc_status according to the cc_prev_status. */
3100 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3102 if (cc_prev_status
.value1
!= 0
3103 && (D_REG_P (cc_prev_status
.value1
)
3104 || X_REG_P (cc_prev_status
.value1
)))
3106 cc_status
= cc_prev_status
;
3107 if (D_REG_P (cc_status
.value1
))
3108 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3111 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3117 output_asm_insn ("xgdx", operands
);
3121 if (cc_prev_status
.value1
!= 0
3122 && (D_REG_P (cc_prev_status
.value1
)
3123 || Y_REG_P (cc_prev_status
.value1
)))
3125 cc_status
= cc_prev_status
;
3126 if (D_REG_P (cc_status
.value1
))
3127 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3130 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3136 output_asm_insn ("xgdy", operands
);
3140 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3141 This is used to decide whether a move that set flags should be used
3144 next_insn_test_reg (insn
, reg
)
3150 insn
= next_nonnote_insn (insn
);
3151 if (GET_CODE (insn
) != INSN
)
3154 body
= PATTERN (insn
);
3155 if (sets_cc0_p (body
) != 1)
3158 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3164 /* Generate the code to move a 16-bit operand into another one. */
3167 m68hc11_gen_movhi (insn
, operands
)
3173 /* Move a register or memory to the same location.
3174 This is possible because such insn can appear
3175 in a non-optimizing mode. */
3176 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3178 cc_status
= cc_prev_status
;
3184 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3186 cc_status
= cc_prev_status
;
3187 switch (REGNO (operands
[1]))
3192 output_asm_insn ("psh%1", operands
);
3194 case HARD_SP_REGNUM
:
3195 output_asm_insn ("sts\t-2,sp", operands
);
3202 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3204 cc_status
= cc_prev_status
;
3205 switch (REGNO (operands
[0]))
3210 output_asm_insn ("pul%0", operands
);
3217 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3219 m68hc11_notice_keep_cc (operands
[0]);
3220 output_asm_insn ("tfr\t%1,%0", operands
);
3222 else if (H_REG_P (operands
[0]))
3224 if (SP_REG_P (operands
[0]))
3225 output_asm_insn ("lds\t%1", operands
);
3227 output_asm_insn ("ld%0\t%1", operands
);
3229 else if (H_REG_P (operands
[1]))
3231 if (SP_REG_P (operands
[1]))
3232 output_asm_insn ("sts\t%0", operands
);
3234 output_asm_insn ("st%1\t%0", operands
);
3238 rtx from
= operands
[1];
3239 rtx to
= operands
[0];
3241 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3242 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3243 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3244 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3250 ops
[0] = operands
[2];
3253 m68hc11_gen_movhi (insn
, ops
);
3255 ops
[1] = operands
[2];
3256 m68hc11_gen_movhi (insn
, ops
);
3260 /* !!!! SCz wrong here. */
3261 fatal_insn ("move insn not handled", insn
);
3266 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3268 output_asm_insn ("clr\t%h0", operands
);
3269 output_asm_insn ("clr\t%b0", operands
);
3273 m68hc11_notice_keep_cc (operands
[0]);
3274 output_asm_insn ("movw\t%1,%0", operands
);
3281 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3283 cc_status
= cc_prev_status
;
3284 switch (REGNO (operands
[0]))
3288 output_asm_insn ("pul%0", operands
);
3291 output_asm_insn ("pula", operands
);
3292 output_asm_insn ("pulb", operands
);
3299 /* Some moves to a hard register are special. Not all of them
3300 are really supported and we have to use a temporary
3301 location to provide them (either the stack of a temp var). */
3302 if (H_REG_P (operands
[0]))
3304 switch (REGNO (operands
[0]))
3307 if (X_REG_P (operands
[1]))
3309 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3311 m68hc11_output_swap (insn
, operands
);
3313 else if (next_insn_test_reg (insn
, operands
[0]))
3315 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3319 m68hc11_notice_keep_cc (operands
[0]);
3320 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3323 else if (Y_REG_P (operands
[1]))
3325 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3327 m68hc11_output_swap (insn
, operands
);
3331 /* %t means *ZTMP scratch register. */
3332 output_asm_insn ("sty\t%t1", operands
);
3333 output_asm_insn ("ldd\t%t1", operands
);
3336 else if (SP_REG_P (operands
[1]))
3341 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3342 output_asm_insn ("xgdx", operands
);
3343 output_asm_insn ("tsx", operands
);
3344 output_asm_insn ("xgdx", operands
);
3346 else if (IS_STACK_POP (operands
[1]))
3348 output_asm_insn ("pula\n\tpulb", operands
);
3350 else if (GET_CODE (operands
[1]) == CONST_INT
3351 && INTVAL (operands
[1]) == 0)
3353 output_asm_insn ("clra\n\tclrb", operands
);
3357 output_asm_insn ("ldd\t%1", operands
);
3362 if (D_REG_P (operands
[1]))
3364 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3366 m68hc11_output_swap (insn
, operands
);
3368 else if (next_insn_test_reg (insn
, operands
[0]))
3370 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3374 m68hc11_notice_keep_cc (operands
[0]);
3375 output_asm_insn ("pshb", operands
);
3376 output_asm_insn ("psha", operands
);
3377 output_asm_insn ("pulx", operands
);
3380 else if (Y_REG_P (operands
[1]))
3382 /* When both D and Y are dead, use the sequence xgdy, xgdx
3383 to move Y into X. The D and Y registers are modified. */
3384 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3385 && dead_register_here (insn
, d_reg
))
3387 output_asm_insn ("xgdy", operands
);
3388 output_asm_insn ("xgdx", operands
);
3393 output_asm_insn ("sty\t%t1", operands
);
3394 output_asm_insn ("ldx\t%t1", operands
);
3397 else if (SP_REG_P (operands
[1]))
3399 /* tsx, tsy preserve the flags */
3400 cc_status
= cc_prev_status
;
3401 output_asm_insn ("tsx", operands
);
3405 output_asm_insn ("ldx\t%1", operands
);
3410 if (D_REG_P (operands
[1]))
3412 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3414 m68hc11_output_swap (insn
, operands
);
3418 output_asm_insn ("std\t%t1", operands
);
3419 output_asm_insn ("ldy\t%t1", operands
);
3422 else if (X_REG_P (operands
[1]))
3424 /* When both D and X are dead, use the sequence xgdx, xgdy
3425 to move X into Y. The D and X registers are modified. */
3426 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3427 && dead_register_here (insn
, d_reg
))
3429 output_asm_insn ("xgdx", operands
);
3430 output_asm_insn ("xgdy", operands
);
3435 output_asm_insn ("stx\t%t1", operands
);
3436 output_asm_insn ("ldy\t%t1", operands
);
3439 else if (SP_REG_P (operands
[1]))
3441 /* tsx, tsy preserve the flags */
3442 cc_status
= cc_prev_status
;
3443 output_asm_insn ("tsy", operands
);
3447 output_asm_insn ("ldy\t%1", operands
);
3451 case HARD_SP_REGNUM
:
3452 if (D_REG_P (operands
[1]))
3454 m68hc11_notice_keep_cc (operands
[0]);
3455 output_asm_insn ("xgdx", operands
);
3456 output_asm_insn ("txs", operands
);
3457 output_asm_insn ("xgdx", operands
);
3459 else if (X_REG_P (operands
[1]))
3461 /* tys, txs preserve the flags */
3462 cc_status
= cc_prev_status
;
3463 output_asm_insn ("txs", operands
);
3465 else if (Y_REG_P (operands
[1]))
3467 /* tys, txs preserve the flags */
3468 cc_status
= cc_prev_status
;
3469 output_asm_insn ("tys", operands
);
3473 /* lds sets the flags but the des does not. */
3475 output_asm_insn ("lds\t%1", operands
);
3476 output_asm_insn ("des", operands
);
3481 fatal_insn ("invalid register in the move instruction", insn
);
3486 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3487 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3489 output_asm_insn ("sts\t%0", operands
);
3493 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3495 cc_status
= cc_prev_status
;
3496 switch (REGNO (operands
[1]))
3500 output_asm_insn ("psh%1", operands
);
3503 output_asm_insn ("pshb", operands
);
3504 output_asm_insn ("psha", operands
);
3512 /* Operand 1 must be a hard register. */
3513 if (!H_REG_P (operands
[1]))
3515 fatal_insn ("invalid operand in the instruction", insn
);
3518 reg
= REGNO (operands
[1]);
3522 output_asm_insn ("std\t%0", operands
);
3526 output_asm_insn ("stx\t%0", operands
);
3530 output_asm_insn ("sty\t%0", operands
);
3533 case HARD_SP_REGNUM
:
3537 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3539 output_asm_insn ("pshx", operands
);
3540 output_asm_insn ("tsx", operands
);
3541 output_asm_insn ("inx", operands
);
3542 output_asm_insn ("inx", operands
);
3543 output_asm_insn ("stx\t%0", operands
);
3544 output_asm_insn ("pulx", operands
);
3547 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3549 output_asm_insn ("sty\t%t0", operands
);
3550 output_asm_insn ("tsy", operands
);
3551 output_asm_insn ("sty\t%0", operands
);
3552 output_asm_insn ("ldy\t%t0", operands
);
3556 output_asm_insn ("stx\t%t0", operands
);
3557 output_asm_insn ("tsx", operands
);
3558 output_asm_insn ("stx\t%0", operands
);
3559 output_asm_insn ("ldx\t%t0", operands
);
3565 fatal_insn ("invalid register in the move instruction", insn
);
3571 m68hc11_gen_movqi (insn
, operands
)
3575 /* Move a register or memory to the same location.
3576 This is possible because such insn can appear
3577 in a non-optimizing mode. */
3578 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3580 cc_status
= cc_prev_status
;
3587 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3589 m68hc11_notice_keep_cc (operands
[0]);
3590 output_asm_insn ("tfr\t%1,%0", operands
);
3592 else if (H_REG_P (operands
[0]))
3594 if (Q_REG_P (operands
[0]))
3595 output_asm_insn ("lda%0\t%b1", operands
);
3596 else if (D_REG_P (operands
[0]))
3597 output_asm_insn ("ldab\t%b1", operands
);
3601 else if (H_REG_P (operands
[1]))
3603 if (Q_REG_P (operands
[1]))
3604 output_asm_insn ("sta%1\t%b0", operands
);
3605 else if (D_REG_P (operands
[1]))
3606 output_asm_insn ("stab\t%b0", operands
);
3612 rtx from
= operands
[1];
3613 rtx to
= operands
[0];
3615 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3616 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3617 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3618 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3624 ops
[0] = operands
[2];
3627 m68hc11_gen_movqi (insn
, ops
);
3629 ops
[1] = operands
[2];
3630 m68hc11_gen_movqi (insn
, ops
);
3634 /* !!!! SCz wrong here. */
3635 fatal_insn ("move insn not handled", insn
);
3640 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3642 output_asm_insn ("clr\t%b0", operands
);
3646 m68hc11_notice_keep_cc (operands
[0]);
3647 output_asm_insn ("movb\t%b1,%b0", operands
);
3655 if (H_REG_P (operands
[0]))
3657 switch (REGNO (operands
[0]))
3661 if (X_REG_P (operands
[1]))
3663 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3665 m68hc11_output_swap (insn
, operands
);
3669 output_asm_insn ("stx\t%t1", operands
);
3670 output_asm_insn ("ldab\t%T0", operands
);
3673 else if (Y_REG_P (operands
[1]))
3675 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3677 m68hc11_output_swap (insn
, operands
);
3681 output_asm_insn ("sty\t%t1", operands
);
3682 output_asm_insn ("ldab\t%T0", operands
);
3685 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3686 && !DA_REG_P (operands
[1]))
3688 output_asm_insn ("ldab\t%b1", operands
);
3690 else if (DA_REG_P (operands
[1]))
3692 output_asm_insn ("tab", operands
);
3696 cc_status
= cc_prev_status
;
3702 if (X_REG_P (operands
[1]))
3704 output_asm_insn ("stx\t%t1", operands
);
3705 output_asm_insn ("ldaa\t%T0", operands
);
3707 else if (Y_REG_P (operands
[1]))
3709 output_asm_insn ("sty\t%t1", operands
);
3710 output_asm_insn ("ldaa\t%T0", operands
);
3712 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3713 && !DA_REG_P (operands
[1]))
3715 output_asm_insn ("ldaa\t%b1", operands
);
3717 else if (!DA_REG_P (operands
[1]))
3719 output_asm_insn ("tba", operands
);
3723 cc_status
= cc_prev_status
;
3728 if (D_REG_P (operands
[1]))
3730 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3732 m68hc11_output_swap (insn
, operands
);
3736 output_asm_insn ("stab\t%T1", operands
);
3737 output_asm_insn ("ldx\t%t1", operands
);
3741 else if (Y_REG_P (operands
[1]))
3743 output_asm_insn ("sty\t%t0", operands
);
3744 output_asm_insn ("ldx\t%t0", operands
);
3746 else if (GET_CODE (operands
[1]) == CONST_INT
)
3748 output_asm_insn ("ldx\t%1", operands
);
3750 else if (dead_register_here (insn
, d_reg
))
3752 output_asm_insn ("ldab\t%b1", operands
);
3753 output_asm_insn ("xgdx", operands
);
3755 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3757 output_asm_insn ("xgdx", operands
);
3758 output_asm_insn ("ldab\t%b1", operands
);
3759 output_asm_insn ("xgdx", operands
);
3763 output_asm_insn ("pshb", operands
);
3764 output_asm_insn ("ldab\t%b1", operands
);
3765 output_asm_insn ("stab\t%T1", operands
);
3766 output_asm_insn ("ldx\t%t1", operands
);
3767 output_asm_insn ("pulb", operands
);
3773 if (D_REG_P (operands
[1]))
3775 output_asm_insn ("stab\t%T1", operands
);
3776 output_asm_insn ("ldy\t%t1", operands
);
3779 else if (X_REG_P (operands
[1]))
3781 output_asm_insn ("stx\t%t1", operands
);
3782 output_asm_insn ("ldy\t%t1", operands
);
3785 else if (GET_CODE (operands
[1]) == CONST_INT
)
3787 output_asm_insn ("ldy\t%1", operands
);
3789 else if (dead_register_here (insn
, d_reg
))
3791 output_asm_insn ("ldab\t%b1", operands
);
3792 output_asm_insn ("xgdy", operands
);
3794 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3796 output_asm_insn ("xgdy", operands
);
3797 output_asm_insn ("ldab\t%b1", operands
);
3798 output_asm_insn ("xgdy", operands
);
3802 output_asm_insn ("pshb", operands
);
3803 output_asm_insn ("ldab\t%b1", operands
);
3804 output_asm_insn ("stab\t%T1", operands
);
3805 output_asm_insn ("ldy\t%t1", operands
);
3806 output_asm_insn ("pulb", operands
);
3812 fatal_insn ("invalid register in the instruction", insn
);
3816 else if (H_REG_P (operands
[1]))
3818 switch (REGNO (operands
[1]))
3822 output_asm_insn ("stab\t%b0", operands
);
3826 output_asm_insn ("staa\t%b0", operands
);
3830 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3834 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3838 fatal_insn ("invalid register in the move instruction", insn
);
3845 fatal_insn ("operand 1 must be a hard register", insn
);
3849 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3850 The source and destination must be D or A and the shift must
3853 m68hc11_gen_rotate (code
, insn
, operands
)
3860 if (GET_CODE (operands
[2]) != CONST_INT
3861 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3862 fatal_insn ("invalid rotate insn", insn
);
3864 val
= INTVAL (operands
[2]);
3865 if (code
== ROTATERT
)
3866 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3868 if (GET_MODE (operands
[0]) != QImode
)
3871 /* Rotate by 8-bits if the shift is within [5..11]. */
3872 if (val
>= 5 && val
<= 11)
3875 output_asm_insn ("exg\ta,b", operands
);
3878 output_asm_insn ("psha", operands
);
3879 output_asm_insn ("tba", operands
);
3880 output_asm_insn ("pulb", operands
);
3885 /* If the shift is big, invert the rotation. */
3893 /* Set the carry to bit-15, but don't change D yet. */
3894 if (GET_MODE (operands
[0]) != QImode
)
3896 output_asm_insn ("asra", operands
);
3897 output_asm_insn ("rola", operands
);
3902 /* Rotate B first to move the carry to bit-0. */
3903 if (D_REG_P (operands
[0]))
3904 output_asm_insn ("rolb", operands
);
3906 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3907 output_asm_insn ("rola", operands
);
3912 /* Set the carry to bit-8 of D. */
3913 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3915 output_asm_insn ("tap", operands
);
3920 /* Rotate B first to move the carry to bit-7. */
3921 if (D_REG_P (operands
[0]))
3922 output_asm_insn ("rorb", operands
);
3924 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3925 output_asm_insn ("rora", operands
);
3932 /* Store in cc_status the expressions that the condition codes will
3933 describe after execution of an instruction whose pattern is EXP.
3934 Do not alter them if the instruction would not alter the cc's. */
3937 m68hc11_notice_update_cc (exp
, insn
)
3939 rtx insn ATTRIBUTE_UNUSED
;
3941 /* recognize SET insn's. */
3942 if (GET_CODE (exp
) == SET
)
3944 /* Jumps do not alter the cc's. */
3945 if (SET_DEST (exp
) == pc_rtx
)
3948 /* NOTE: most instructions don't affect the carry bit, but the
3949 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3950 the conditions.h header. */
3952 /* Function calls clobber the cc's. */
3953 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3958 /* Tests and compares set the cc's in predictable ways. */
3959 else if (SET_DEST (exp
) == cc0_rtx
)
3961 cc_status
.flags
= 0;
3962 cc_status
.value1
= XEXP (exp
, 0);
3963 cc_status
.value2
= XEXP (exp
, 1);
3967 /* All other instructions affect the condition codes. */
3968 cc_status
.flags
= 0;
3969 cc_status
.value1
= XEXP (exp
, 0);
3970 cc_status
.value2
= XEXP (exp
, 1);
3975 /* Default action if we haven't recognized something
3976 and returned earlier. */
3980 if (cc_status
.value2
!= 0)
3981 switch (GET_CODE (cc_status
.value2
))
3983 /* These logical operations can generate several insns.
3984 The flags are setup according to what is generated. */
3990 /* The (not ...) generates several 'com' instructions for
3991 non QImode. We have to invalidate the flags. */
3993 if (GET_MODE (cc_status
.value2
) != QImode
)
4005 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4006 cc_status
.flags
|= CC_NO_OVERFLOW
;
4009 /* The asl sets the overflow bit in such a way that this
4010 makes the flags unusable for a next compare insn. */
4014 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4015 cc_status
.flags
|= CC_NO_OVERFLOW
;
4018 /* A load/store instruction does not affect the carry. */
4023 cc_status
.flags
|= CC_NO_OVERFLOW
;
4029 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4031 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4032 cc_status
.value2
= 0;
4035 /* The current instruction does not affect the flags but changes
4036 the register 'reg'. See if the previous flags can be kept for the
4037 next instruction to avoid a comparison. */
4039 m68hc11_notice_keep_cc (reg
)
4043 || cc_prev_status
.value1
== 0
4044 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4045 || (cc_prev_status
.value2
4046 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4049 cc_status
= cc_prev_status
;
4054 /* Machine Specific Reorg. */
4056 /* Z register replacement:
4058 GCC treats the Z register as an index base address register like
4059 X or Y. In general, it uses it during reload to compute the address
4060 of some operand. This helps the reload pass to avoid to fall into the
4061 register spill failure.
4063 The Z register is in the A_REGS class. In the machine description,
4064 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4066 It can appear everywhere an X or Y register can appear, except for
4067 some templates in the clobber section (when a clobber of X or Y is asked).
4068 For a given instruction, the template must ensure that no more than
4069 2 'A' registers are used. Otherwise, the register replacement is not
4072 To replace the Z register, the algorithm is not terrific:
4073 1. Insns that do not use the Z register are not changed
4074 2. When a Z register is used, we scan forward the insns to see
4075 a potential register to use: either X or Y and sometimes D.
4076 We stop when a call, a label or a branch is seen, or when we
4077 detect that both X and Y are used (probably at different times, but it does
4079 3. The register that will be used for the replacement of Z is saved
4080 in a .page0 register or on the stack. If the first instruction that
4081 used Z, uses Z as an input, the value is loaded from another .page0
4082 register. The replacement register is pushed on the stack in the
4083 rare cases where a compare insn uses Z and we couldn't find if X/Y
4085 4. The Z register is replaced in all instructions until we reach
4086 the end of the Z-block, as detected by step 2.
4087 5. If we detect that Z is still alive, its value is saved.
4088 If the replacement register is alive, its old value is loaded.
4090 The Z register can be disabled with -ffixed-z.
4100 int must_restore_reg
;
4111 int save_before_last
;
4112 int z_loaded_with_sp
;
4115 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4116 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4117 static void m68hc11_z_replacement
PARAMS ((rtx
));
4118 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4120 int z_replacement_completed
= 0;
4122 /* Analyze the insn to find out which replacement register to use and
4123 the boundaries of the replacement.
4124 Returns 0 if we reached the last insn to be replaced, 1 if we can
4125 continue replacement in next insns. */
4128 m68hc11_check_z_replacement (insn
, info
)
4130 struct replace_info
*info
;
4132 int this_insn_uses_ix
;
4133 int this_insn_uses_iy
;
4134 int this_insn_uses_z
;
4135 int this_insn_uses_z_in_dst
;
4136 int this_insn_uses_d
;
4140 /* A call is said to clobber the Z register, we don't need
4141 to save the value of Z. We also don't need to restore
4142 the replacement register (unless it is used by the call). */
4143 if (GET_CODE (insn
) == CALL_INSN
)
4145 body
= PATTERN (insn
);
4147 info
->can_use_d
= 0;
4149 /* If the call is an indirect call with Z, we have to use the
4150 Y register because X can be used as an input (D+X).
4151 We also must not save Z nor restore Y. */
4152 if (reg_mentioned_p (z_reg
, body
))
4154 insn
= NEXT_INSN (insn
);
4157 info
->found_call
= 1;
4158 info
->must_restore_reg
= 0;
4159 info
->last
= NEXT_INSN (insn
);
4161 info
->need_save_z
= 0;
4164 if (GET_CODE (insn
) == CODE_LABEL
4165 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4168 if (GET_CODE (insn
) == JUMP_INSN
)
4170 if (reg_mentioned_p (z_reg
, insn
) == 0)
4173 info
->can_use_d
= 0;
4174 info
->must_save_reg
= 0;
4175 info
->must_restore_reg
= 0;
4176 info
->need_save_z
= 0;
4177 info
->last
= NEXT_INSN (insn
);
4180 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4185 /* Z register dies here. */
4186 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4188 body
= PATTERN (insn
);
4189 if (GET_CODE (body
) == SET
)
4191 rtx src
= XEXP (body
, 1);
4192 rtx dst
= XEXP (body
, 0);
4194 /* Condition code is set here. We have to restore the X/Y and
4195 save into Z before any test/compare insn because once we save/restore
4196 we can change the condition codes. When the compare insn uses Z and
4197 we can't use X/Y, the comparison is made with the *ZREG soft register
4198 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4201 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4202 || (GET_CODE (src
) == COMPARE
&&
4203 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4204 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4206 if (insn
== info
->first
)
4208 info
->must_load_z
= 0;
4209 info
->must_save_reg
= 0;
4210 info
->must_restore_reg
= 0;
4211 info
->need_save_z
= 0;
4212 info
->found_call
= 1;
4213 info
->regno
= SOFT_Z_REGNUM
;
4218 if (reg_mentioned_p (z_reg
, src
) == 0)
4220 info
->can_use_d
= 0;
4224 if (insn
!= info
->first
)
4227 /* Compare insn which uses Z. We have to save/restore the X/Y
4228 register without modifying the condition codes. For this
4229 we have to use a push/pop insn. */
4230 info
->must_push_reg
= 1;
4234 /* Z reg is set to something new. We don't need to load it. */
4237 if (!reg_mentioned_p (z_reg
, src
))
4239 /* Z reg is used before being set. Treat this as
4240 a new sequence of Z register replacement. */
4241 if (insn
!= info
->first
)
4245 info
->must_load_z
= 0;
4247 info
->z_set_count
++;
4248 info
->z_value
= src
;
4250 info
->z_loaded_with_sp
= 1;
4252 else if (reg_mentioned_p (z_reg
, dst
))
4253 info
->can_use_d
= 0;
4255 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4256 | reg_mentioned_p (d_reg
, dst
);
4257 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4258 | reg_mentioned_p (ix_reg
, dst
);
4259 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4260 | reg_mentioned_p (iy_reg
, dst
);
4261 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4263 /* If z is used as an address operand (like (MEM (reg z))),
4264 we can't replace it with d. */
4265 if (this_insn_uses_z
&& !Z_REG_P (src
)
4266 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4267 && Z_REG_P (XEXP (src
, 0))
4268 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4269 && insn
== info
->first
4270 && dead_register_here (insn
, d_reg
)))
4271 info
->can_use_d
= 0;
4273 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4274 if (TARGET_M6812
&& !z_dies_here
4275 && ((this_insn_uses_z
&& side_effects_p (src
))
4276 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4278 info
->need_save_z
= 1;
4279 info
->z_set_count
++;
4281 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4283 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4285 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4288 if (this_insn_uses_d
)
4289 info
->can_use_d
= 0;
4291 /* IX and IY are used at the same time, we have to restore
4292 the value of the scratch register before this insn. */
4293 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4298 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4299 info
->can_use_d
= 0;
4301 if (info
->x_used
== 0 && this_insn_uses_ix
)
4305 /* We have a (set (REG:HI X) (REG:HI Z)).
4306 Since we use Z as the replacement register, this insn
4307 is no longer necessary. We turn it into a note. We must
4308 not reload the old value of X. */
4309 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4313 info
->need_save_z
= 0;
4316 info
->must_save_reg
= 0;
4317 info
->must_restore_reg
= 0;
4318 info
->found_call
= 1;
4319 info
->can_use_d
= 0;
4320 PUT_CODE (insn
, NOTE
);
4321 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4322 NOTE_SOURCE_FILE (insn
) = 0;
4323 info
->last
= NEXT_INSN (insn
);
4328 && (rtx_equal_p (src
, z_reg
)
4329 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4333 info
->need_save_z
= 0;
4336 info
->last
= NEXT_INSN (insn
);
4337 info
->must_save_reg
= 0;
4338 info
->must_restore_reg
= 0;
4340 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4341 && !reg_mentioned_p (ix_reg
, src
))
4346 info
->need_save_z
= 0;
4348 else if (TARGET_M6812
&& side_effects_p (src
))
4351 info
->must_restore_reg
= 0;
4356 info
->save_before_last
= 1;
4358 info
->must_restore_reg
= 0;
4359 info
->last
= NEXT_INSN (insn
);
4361 else if (info
->can_use_d
)
4363 info
->last
= NEXT_INSN (insn
);
4369 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4370 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4372 info
->need_save_z
= 0;
4374 info
->last
= NEXT_INSN (insn
);
4375 info
->regno
= HARD_X_REGNUM
;
4376 info
->must_save_reg
= 0;
4377 info
->must_restore_reg
= 0;
4380 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4382 info
->regno
= HARD_X_REGNUM
;
4383 info
->must_restore_reg
= 0;
4384 info
->must_save_reg
= 0;
4388 if (info
->y_used
== 0 && this_insn_uses_iy
)
4392 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4396 info
->need_save_z
= 0;
4399 info
->must_save_reg
= 0;
4400 info
->must_restore_reg
= 0;
4401 info
->found_call
= 1;
4402 info
->can_use_d
= 0;
4403 PUT_CODE (insn
, NOTE
);
4404 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4405 NOTE_SOURCE_FILE (insn
) = 0;
4406 info
->last
= NEXT_INSN (insn
);
4411 && (rtx_equal_p (src
, z_reg
)
4412 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4417 info
->need_save_z
= 0;
4419 info
->last
= NEXT_INSN (insn
);
4420 info
->must_save_reg
= 0;
4421 info
->must_restore_reg
= 0;
4423 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4424 && !reg_mentioned_p (iy_reg
, src
))
4429 info
->need_save_z
= 0;
4431 else if (TARGET_M6812
&& side_effects_p (src
))
4434 info
->must_restore_reg
= 0;
4439 info
->save_before_last
= 1;
4441 info
->must_restore_reg
= 0;
4442 info
->last
= NEXT_INSN (insn
);
4444 else if (info
->can_use_d
)
4446 info
->last
= NEXT_INSN (insn
);
4453 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4454 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4456 info
->need_save_z
= 0;
4458 info
->last
= NEXT_INSN (insn
);
4459 info
->regno
= HARD_Y_REGNUM
;
4460 info
->must_save_reg
= 0;
4461 info
->must_restore_reg
= 0;
4464 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4466 info
->regno
= HARD_Y_REGNUM
;
4467 info
->must_restore_reg
= 0;
4468 info
->must_save_reg
= 0;
4474 info
->need_save_z
= 0;
4476 if (info
->last
== 0)
4477 info
->last
= NEXT_INSN (insn
);
4480 return info
->last
!= NULL_RTX
? 0 : 1;
4482 if (GET_CODE (body
) == PARALLEL
)
4485 char ix_clobber
= 0;
4486 char iy_clobber
= 0;
4488 this_insn_uses_iy
= 0;
4489 this_insn_uses_ix
= 0;
4490 this_insn_uses_z
= 0;
4492 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4495 int uses_ix
, uses_iy
, uses_z
;
4497 x
= XVECEXP (body
, 0, i
);
4499 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4500 info
->can_use_d
= 0;
4502 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4503 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4504 uses_z
= reg_mentioned_p (z_reg
, x
);
4505 if (GET_CODE (x
) == CLOBBER
)
4507 ix_clobber
|= uses_ix
;
4508 iy_clobber
|= uses_iy
;
4509 z_clobber
|= uses_z
;
4513 this_insn_uses_ix
|= uses_ix
;
4514 this_insn_uses_iy
|= uses_iy
;
4515 this_insn_uses_z
|= uses_z
;
4517 if (uses_z
&& GET_CODE (x
) == SET
)
4519 rtx dst
= XEXP (x
, 0);
4522 info
->z_set_count
++;
4524 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4525 info
->need_save_z
= 1;
4528 info
->need_save_z
= 0;
4532 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4533 this_insn_uses_ix
, this_insn_uses_iy
,
4534 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4537 if (this_insn_uses_z
)
4538 info
->can_use_d
= 0;
4540 if (z_clobber
&& info
->first
!= insn
)
4542 info
->need_save_z
= 0;
4546 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4548 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4550 info
->must_load_z
= 0;
4552 if (dead_register_here (insn
, d_reg
))
4554 info
->regno
= HARD_D_REGNUM
;
4555 info
->must_save_reg
= 0;
4556 info
->must_restore_reg
= 0;
4558 else if (dead_register_here (insn
, ix_reg
))
4560 info
->regno
= HARD_X_REGNUM
;
4561 info
->must_save_reg
= 0;
4562 info
->must_restore_reg
= 0;
4564 else if (dead_register_here (insn
, iy_reg
))
4566 info
->regno
= HARD_Y_REGNUM
;
4567 info
->must_save_reg
= 0;
4568 info
->must_restore_reg
= 0;
4570 if (info
->regno
>= 0)
4572 info
->last
= NEXT_INSN (insn
);
4575 if (this_insn_uses_ix
== 0)
4577 info
->regno
= HARD_X_REGNUM
;
4578 info
->must_save_reg
= 1;
4579 info
->must_restore_reg
= 1;
4581 else if (this_insn_uses_iy
== 0)
4583 info
->regno
= HARD_Y_REGNUM
;
4584 info
->must_save_reg
= 1;
4585 info
->must_restore_reg
= 1;
4589 info
->regno
= HARD_D_REGNUM
;
4590 info
->must_save_reg
= 1;
4591 info
->must_restore_reg
= 1;
4593 info
->last
= NEXT_INSN (insn
);
4597 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4598 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4600 if (this_insn_uses_z
)
4602 if (info
->y_used
== 0 && iy_clobber
)
4604 info
->regno
= HARD_Y_REGNUM
;
4605 info
->must_save_reg
= 0;
4606 info
->must_restore_reg
= 0;
4608 if (info
->first
!= insn
4609 && ((info
->y_used
&& ix_clobber
)
4610 || (info
->x_used
&& iy_clobber
)))
4613 info
->last
= NEXT_INSN (insn
);
4614 info
->save_before_last
= 1;
4618 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4620 if (this_insn_uses_z
)
4622 fatal_insn ("cannot do z-register replacement", insn
);
4626 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4633 if (iy_clobber
|| z_clobber
)
4635 info
->last
= NEXT_INSN (insn
);
4636 info
->save_before_last
= 1;
4641 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4648 if (ix_clobber
|| z_clobber
)
4650 info
->last
= NEXT_INSN (insn
);
4651 info
->save_before_last
= 1;
4658 info
->need_save_z
= 0;
4662 if (GET_CODE (body
) == CLOBBER
)
4665 /* IX and IY are used at the same time, we have to restore
4666 the value of the scratch register before this insn. */
4667 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4671 if (info
->x_used
== 0 && this_insn_uses_ix
)
4679 if (info
->y_used
== 0 && this_insn_uses_iy
)
4693 m68hc11_find_z_replacement (insn
, info
)
4695 struct replace_info
*info
;
4699 info
->replace_reg
= NULL_RTX
;
4700 info
->must_load_z
= 1;
4701 info
->need_save_z
= 1;
4702 info
->must_save_reg
= 1;
4703 info
->must_restore_reg
= 1;
4707 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4708 info
->found_call
= 0;
4712 info
->z_set_count
= 0;
4713 info
->z_value
= NULL_RTX
;
4714 info
->must_push_reg
= 0;
4715 info
->save_before_last
= 0;
4716 info
->z_loaded_with_sp
= 0;
4718 /* Scan the insn forward to find an address register that is not used.
4720 - the flow of the program changes,
4721 - when we detect that both X and Y are necessary,
4722 - when the Z register dies,
4723 - when the condition codes are set. */
4725 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4727 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4731 /* May be we can use Y or X if they contain the same value as Z.
4732 This happens very often after the reload. */
4733 if (info
->z_set_count
== 1)
4735 rtx p
= info
->first
;
4740 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4742 else if (info
->y_used
)
4744 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4746 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4749 info
->regno
= HARD_Y_REGNUM
;
4751 info
->regno
= HARD_X_REGNUM
;
4752 info
->must_load_z
= 0;
4753 info
->must_save_reg
= 0;
4754 info
->must_restore_reg
= 0;
4755 info
->found_call
= 1;
4758 if (info
->z_set_count
== 0)
4759 info
->need_save_z
= 0;
4762 info
->need_save_z
= 0;
4764 if (info
->last
== 0)
4767 if (info
->regno
>= 0)
4770 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4772 else if (info
->can_use_d
)
4774 reg
= HARD_D_REGNUM
;
4775 info
->replace_reg
= d_reg
;
4777 else if (info
->x_used
)
4779 reg
= HARD_Y_REGNUM
;
4780 info
->replace_reg
= iy_reg
;
4784 reg
= HARD_X_REGNUM
;
4785 info
->replace_reg
= ix_reg
;
4789 if (info
->must_save_reg
&& info
->must_restore_reg
)
4791 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4793 info
->must_save_reg
= 0;
4794 info
->must_restore_reg
= 0;
4799 /* The insn uses the Z register. Find a replacement register for it
4800 (either X or Y) and replace it in the insn and the next ones until
4801 the flow changes or the replacement register is used. Instructions
4802 are emited before and after the Z-block to preserve the value of
4803 Z and of the replacement register. */
4806 m68hc11_z_replacement (insn
)
4811 struct replace_info info
;
4813 /* Find trivial case where we only need to replace z with the
4814 equivalent soft register. */
4815 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4817 rtx body
= PATTERN (insn
);
4818 rtx src
= XEXP (body
, 1);
4819 rtx dst
= XEXP (body
, 0);
4821 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4823 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4826 else if (Z_REG_P (src
)
4827 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4829 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4832 else if (D_REG_P (dst
)
4833 && m68hc11_arith_operator (src
, GET_MODE (src
))
4834 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4836 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4839 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4840 && INTVAL (src
) == 0)
4842 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4843 /* Force it to be re-recognized. */
4844 INSN_CODE (insn
) = -1;
4849 m68hc11_find_z_replacement (insn
, &info
);
4851 replace_reg
= info
.replace_reg
;
4852 replace_reg_qi
= NULL_RTX
;
4854 /* Save the X register in a .page0 location. */
4855 if (info
.must_save_reg
&& !info
.must_push_reg
)
4859 if (info
.must_push_reg
&& 0)
4860 dst
= gen_rtx (MEM
, HImode
,
4861 gen_rtx (PRE_DEC
, HImode
,
4862 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4864 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4866 emit_insn_before (gen_movhi (dst
,
4867 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4869 if (info
.must_load_z
&& !info
.must_push_reg
)
4871 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4872 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4877 /* Replace all occurrence of Z by replace_reg.
4878 Stop when the last instruction to replace is reached.
4879 Also stop when we detect a change in the flow (but it's not
4880 necessary; just safeguard). */
4882 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4886 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4889 if (GET_CODE (insn
) != INSN
4890 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4893 body
= PATTERN (insn
);
4894 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4895 || GET_CODE (body
) == ASM_OPERANDS
4896 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4900 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4902 printf ("Reg mentioned here...:\n");
4907 /* Stack pointer was decremented by 2 due to the push.
4908 Correct that by adding 2 to the destination. */
4909 if (info
.must_push_reg
4910 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4914 src
= SET_SRC (body
);
4915 dst
= SET_DEST (body
);
4916 if (SP_REG_P (src
) && Z_REG_P (dst
))
4917 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4920 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4921 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4923 INSN_CODE (insn
) = -1;
4924 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4925 fatal_insn ("cannot do z-register replacement", insn
);
4928 /* Likewise for (REG:QI Z). */
4929 if (reg_mentioned_p (z_reg
, insn
))
4931 if (replace_reg_qi
== NULL_RTX
)
4932 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4933 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4936 /* If there is a REG_INC note on Z, replace it with a
4937 REG_INC note on the replacement register. This is necessary
4938 to make sure that the flow pass will identify the change
4939 and it will not remove a possible insn that saves Z. */
4940 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4942 if (REG_NOTE_KIND (note
) == REG_INC
4943 && GET_CODE (XEXP (note
, 0)) == REG
4944 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4946 XEXP (note
, 0) = replace_reg
;
4950 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4954 /* Save Z before restoring the old value. */
4955 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4957 rtx save_pos_insn
= insn
;
4959 /* If Z is clobber by the last insn, we have to save its value
4960 before the last instruction. */
4961 if (info
.save_before_last
)
4962 save_pos_insn
= PREV_INSN (save_pos_insn
);
4964 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4965 gen_rtx (REG
, HImode
, info
.regno
)),
4969 if (info
.must_push_reg
&& info
.last
)
4973 body
= PATTERN (info
.last
);
4974 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4976 gen_rtx (USE
, VOIDmode
,
4978 gen_rtx (USE
, VOIDmode
,
4979 gen_rtx (REG
, HImode
,
4981 PATTERN (info
.last
) = new_body
;
4983 /* Force recognition on insn since we changed it. */
4984 INSN_CODE (insn
) = -1;
4986 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4988 fatal_insn ("invalid Z register replacement for insn", insn
);
4990 insn
= NEXT_INSN (info
.last
);
4993 /* Restore replacement register unless it was died. */
4994 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4998 if (info
.must_push_reg
&& 0)
4999 dst
= gen_rtx (MEM
, HImode
,
5000 gen_rtx (POST_INC
, HImode
,
5001 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
5003 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
5005 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
5012 /* Scan all the insn and re-affects some registers
5013 - The Z register (if it was used), is affected to X or Y depending
5014 on the instruction. */
5017 m68hc11_reassign_regs (first
)
5022 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5023 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5024 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5025 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5027 /* Scan all insns to replace Z by X or Y preserving the old value
5028 of X/Y and restoring it afterward. */
5030 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5034 if (GET_CODE (insn
) == CODE_LABEL
5035 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5038 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5041 body
= PATTERN (insn
);
5042 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5045 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5046 || GET_CODE (body
) == ASM_OPERANDS
5047 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5050 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5051 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5054 /* If Z appears in this insn, replace it in the current insn
5055 and the next ones until the flow changes or we have to
5056 restore back the replacement register. */
5058 if (reg_mentioned_p (z_reg
, body
))
5060 m68hc11_z_replacement (insn
);
5065 printf ("insn not handled by Z replacement:\n");
5074 m68hc11_reorg (first
)
5080 z_replacement_completed
= 0;
5081 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5083 /* Some RTX are shared at this point. This breaks the Z register
5084 replacement, unshare everything. */
5085 unshare_all_rtl_again (first
);
5087 /* Force a split of all splitable insn. This is necessary for the
5088 Z register replacement mechanism because we end up with basic insns. */
5089 split_all_insns_noflow ();
5092 z_replacement_completed
= 1;
5093 m68hc11_reassign_regs (first
);
5096 compute_bb_for_insn ();
5098 /* After some splitting, there are some oportunities for CSE pass.
5099 This happens quite often when 32-bit or above patterns are split. */
5100 if (optimize
> 0 && split_done
)
5102 reload_cse_regs (first
);
5105 /* Re-create the REG_DEAD notes. These notes are used in the machine
5106 description to use the best assembly directives. */
5109 /* Before recomputing the REG_DEAD notes, remove all of them.
5110 This is necessary because the reload_cse_regs() pass can
5111 have replaced some (MEM) with a register. In that case,
5112 the REG_DEAD that could exist for that register may become
5114 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5120 pnote
= ®_NOTES (insn
);
5123 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5124 *pnote
= XEXP (*pnote
, 1);
5126 pnote
= &XEXP (*pnote
, 1);
5131 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5134 z_replacement_completed
= 2;
5136 /* If optimizing, then go ahead and split insns that must be
5137 split after Z register replacement. This gives more opportunities
5138 for peephole (in particular for consecutives xgdx/xgdy). */
5140 split_all_insns_noflow ();
5142 /* Once insns are split after the z_replacement_completed == 2,
5143 we must not re-run the life_analysis. The xgdx/xgdy patterns
5144 are not recognized and the life_analysis pass removes some
5145 insns because it thinks some (SETs) are noops or made to dead
5146 stores (which is false due to the swap).
5148 Do a simple pass to eliminate the noop set that the final
5149 split could generate (because it was easier for split definition). */
5153 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5157 if (INSN_DELETED_P (insn
))
5159 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5162 /* Remove the (set (R) (R)) insns generated by some splits. */
5163 body
= PATTERN (insn
);
5164 if (GET_CODE (body
) == SET
5165 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5167 PUT_CODE (insn
, NOTE
);
5168 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5169 NOTE_SOURCE_FILE (insn
) = 0;
5177 /* Cost functions. */
5179 /* Cost of moving memory. */
5181 m68hc11_memory_move_cost (mode
, class, in
)
5182 enum machine_mode mode
;
5183 enum reg_class
class;
5184 int in ATTRIBUTE_UNUSED
;
5186 if (class <= H_REGS
&& class > NO_REGS
)
5188 if (GET_MODE_SIZE (mode
) <= 2)
5189 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5191 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5195 if (GET_MODE_SIZE (mode
) <= 2)
5196 return COSTS_N_INSNS (3);
5198 return COSTS_N_INSNS (4);
5203 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5204 Reload does not check the constraint of set insns when the two registers
5205 have a move cost of 2. Setting a higher cost will force reload to check
5208 m68hc11_register_move_cost (mode
, from
, to
)
5209 enum machine_mode mode
;
5210 enum reg_class from
;
5213 /* All costs are symmetric, so reduce cases by putting the
5214 lower number class as the destination. */
5217 enum reg_class tmp
= to
;
5218 to
= from
, from
= tmp
;
5221 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5222 else if (from
<= S_REGS
)
5223 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5225 return COSTS_N_INSNS (2);
5229 /* Provide the costs of an addressing mode that contains ADDR.
5230 If ADDR is not a valid address, its cost is irrelevant. */
5233 m68hc11_address_cost (addr
)
5238 switch (GET_CODE (addr
))
5241 /* Make the cost of hard registers and specially SP, FP small. */
5242 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5259 register rtx plus0
= XEXP (addr
, 0);
5260 register rtx plus1
= XEXP (addr
, 1);
5262 if (GET_CODE (plus0
) != REG
)
5265 switch (GET_CODE (plus1
))
5268 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5269 || INTVAL (plus1
) < m68hc11_min_offset
)
5271 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5275 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5297 if (SP_REG_P (XEXP (addr
, 0)))
5306 printf ("Address cost: %d for :", cost
);
5315 m68hc11_shift_cost (mode
, x
, shift
)
5316 enum machine_mode mode
;
5322 total
= rtx_cost (x
, SET
);
5324 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5325 else if (mode
== HImode
)
5326 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5327 else if (shift
== 8 || shift
== 16 || shift
== 32)
5328 total
+= m68hc11_cost
->shiftHI_const
[8];
5329 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5331 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5334 /* For SI and others, the cost is higher. */
5335 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5336 total
*= GET_MODE_SIZE (mode
) / 2;
5338 /* When optimizing for size, make shift more costly so that
5339 multiplications are preferred. */
5340 if (optimize_size
&& (shift
% 8) != 0)
5347 m68hc11_rtx_costs_1 (x
, code
, outer_code
)
5350 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5352 enum machine_mode mode
= GET_MODE (x
);
5363 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5365 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5368 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5369 total
+= m68hc11_cost
->shift_var
;
5375 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5376 total
+= m68hc11_cost
->logical
;
5378 /* Logical instructions are byte instructions only. */
5379 total
*= GET_MODE_SIZE (mode
);
5384 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5385 total
+= m68hc11_cost
->add
;
5386 if (GET_MODE_SIZE (mode
) > 2)
5388 total
*= GET_MODE_SIZE (mode
) / 2;
5395 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5399 total
+= m68hc11_cost
->divQI
;
5403 total
+= m68hc11_cost
->divHI
;
5408 total
+= m68hc11_cost
->divSI
;
5414 /* mul instruction produces 16-bit result. */
5415 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5416 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5417 return m68hc11_cost
->multQI
5418 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5419 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5421 /* emul instruction produces 32-bit result for 68HC12. */
5422 if (TARGET_M6812
&& mode
== SImode
5423 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5424 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5425 return m68hc11_cost
->multHI
5426 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5427 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5429 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5433 total
+= m68hc11_cost
->multQI
;
5437 total
+= m68hc11_cost
->multHI
;
5442 total
+= m68hc11_cost
->multSI
;
5449 extra_cost
= COSTS_N_INSNS (2);
5456 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5459 return total
+ COSTS_N_INSNS (1);
5463 return total
+ COSTS_N_INSNS (2);
5467 return total
+ COSTS_N_INSNS (4);
5469 return total
+ COSTS_N_INSNS (8);
5472 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5473 return COSTS_N_INSNS (1);
5475 return COSTS_N_INSNS (1);
5478 return COSTS_N_INSNS (4);
5483 m68hc11_rtx_costs (x
, code
, outer_code
, total
)
5485 int code
, outer_code
;
5490 /* Constants are cheap. Moving them in registers must be avoided
5491 because most instructions do not handle two register operands. */
5497 /* Logical and arithmetic operations with a constant operand are
5498 better because they are not supported with two registers. */
5500 if (outer_code
== SET
&& x
== const0_rtx
)
5501 /* After reload, the reload_cse pass checks the cost to change
5502 a SET into a PLUS. Make const0 cheap then. */
5503 *total
= 1 - reload_completed
;
5508 if (outer_code
== SET
)
5509 *total
= 1 - reload_completed
;
5531 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5540 /* print_options - called at the start of the code generation for a
5543 extern char *asm_file_name
;
5546 #include <sys/types.h>
5555 extern int save_argc
;
5556 extern char **save_argv
;
5558 fprintf (out
, ";;; Command:\t");
5559 for (i
= 0; i
< save_argc
; i
++)
5561 fprintf (out
, "%s", save_argv
[i
]);
5562 if (i
+ 1 < save_argc
)
5565 fprintf (out
, "\n");
5567 a_time
= ctime (&c_time
);
5568 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5571 #define __VERSION__ "[unknown]"
5573 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5575 fprintf (out
, ";;; (META)compiled by CC.\n");
5580 m68hc11_asm_file_start (out
, main_file
)
5582 const char *main_file
;
5584 fprintf (out
, ";;;-----------------------------------------\n");
5585 fprintf (out
, ";;; Start %s gcc assembly output\n",
5588 : TARGET_M68S12
? "MC68HCS12" : "MC68HC12");
5589 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5590 print_options (out
);
5591 fprintf (out
, ";;;-----------------------------------------\n");
5592 output_file_directive (out
, main_file
);
5595 fprintf (out
, "\t.mode mshort\n");
5597 fprintf (out
, "\t.mode mlong\n");
5602 m68hc11_asm_out_constructor (symbol
, priority
)
5606 default_ctor_section_asm_out_constructor (symbol
, priority
);
5607 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5611 m68hc11_asm_out_destructor (symbol
, priority
)
5615 default_dtor_section_asm_out_destructor (symbol
, priority
);
5616 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5619 #include "gt-m68hc11.h"