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
, rtx
, 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
;
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 m68hc11_hard_regno_rename_ok (reg1
, reg2
)
401 /* Don't accept renaming to Z register. We will replace it to
402 X,Y or D during machine reorg pass. */
403 if (reg2
== HARD_Z_REGNUM
)
406 /* Don't accept renaming D,X to Y register as the code will be bigger. */
407 if (TARGET_M6811
&& reg2
== HARD_Y_REGNUM
408 && (D_REGNO_P (reg1
) || X_REGNO_P (reg1
)))
415 preferred_reload_class (operand
, class)
417 enum reg_class
class;
419 enum machine_mode mode
;
421 mode
= GET_MODE (operand
);
425 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
428 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
429 return m68hc11_base_reg_class
;
431 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
432 || GET_CODE (operand
) == CONST_INT
))
434 /* S_REGS class must not be used. The movhi template does not
435 work to move a memory to a soft register.
436 Restrict to a hard reg. */
441 case D_OR_A_OR_S_REGS
:
447 case D_OR_SP_OR_S_REGS
:
448 class = D_OR_SP_REGS
;
450 case D_OR_Y_OR_S_REGS
:
453 case D_OR_X_OR_S_REGS
:
469 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
473 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
477 else if (class >= S_REGS
&& S_REG_P (operand
))
483 case D_OR_A_OR_S_REGS
:
489 case D_OR_SP_OR_S_REGS
:
490 class = D_OR_SP_REGS
;
492 case D_OR_Y_OR_S_REGS
:
495 case D_OR_X_OR_S_REGS
:
511 else if (class >= S_REGS
)
515 printf ("Class = %s for: ", reg_class_names
[class]);
523 printf (" => class=%s\n", reg_class_names
[class]);
531 /* Return 1 if the operand is a valid indexed addressing mode.
532 For 68hc11: n,r with n in [0..255] and r in A_REGS class
533 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
535 register_indirect_p (operand
, mode
, strict
)
537 enum machine_mode mode
;
542 switch (GET_CODE (operand
))
548 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
549 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
553 base
= XEXP (operand
, 0);
554 if (GET_CODE (base
) == MEM
)
557 offset
= XEXP (operand
, 1);
558 if (GET_CODE (offset
) == MEM
)
561 if (GET_CODE (base
) == REG
)
563 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
569 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
571 if (GET_CODE (offset
) == REG
)
573 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
579 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
584 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
590 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
597 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
598 a 68HC12 1-byte index addressing mode. */
600 m68hc11_small_indexed_indirect_p (operand
, mode
)
602 enum machine_mode mode
;
606 if (GET_CODE (operand
) == REG
&& reload_in_progress
607 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
608 && reg_equiv_memory_loc
[REGNO (operand
)])
610 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
611 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
614 if (GET_CODE (operand
) != MEM
)
617 operand
= XEXP (operand
, 0);
618 if (CONSTANT_ADDRESS_P (operand
))
621 if (PUSH_POP_ADDRESS_P (operand
))
624 if (!register_indirect_p (operand
, mode
, reload_completed
))
627 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
628 && (reload_completed
| reload_in_progress
))
630 base
= XEXP (operand
, 0);
631 offset
= XEXP (operand
, 1);
633 /* The offset can be a symbol address and this is too big
634 for the operand constraint. */
635 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
638 if (GET_CODE (base
) == CONST_INT
)
641 switch (GET_MODE_SIZE (mode
))
644 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
649 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
654 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
663 m68hc11_register_indirect_p (operand
, mode
)
665 enum machine_mode mode
;
667 if (GET_CODE (operand
) != MEM
)
670 operand
= XEXP (operand
, 0);
671 return register_indirect_p (operand
, mode
,
672 (reload_completed
| reload_in_progress
));
676 go_if_legitimate_address_internal (operand
, mode
, strict
)
678 enum machine_mode mode
;
681 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
683 /* Reject the global variables if they are too wide. This forces
684 a load of their address in a register and generates smaller code. */
685 if (GET_MODE_SIZE (mode
) == 8)
690 if (register_indirect_p (operand
, mode
, strict
))
694 if (PUSH_POP_ADDRESS_P (operand
))
698 if (symbolic_memory_operand (operand
, mode
))
706 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
708 enum machine_mode mode
;
715 printf ("Checking: ");
720 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
724 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
731 printf ("go_if_legitimate%s, ret 0: %d:",
732 (strict
? "_strict" : ""), mode
);
741 m68hc11_legitimize_address (operand
, old_operand
, mode
)
742 rtx
*operand ATTRIBUTE_UNUSED
;
743 rtx old_operand ATTRIBUTE_UNUSED
;
744 enum machine_mode mode ATTRIBUTE_UNUSED
;
751 m68hc11_reload_operands (operands
)
754 enum machine_mode mode
;
756 if (regs_inited
== 0)
759 mode
= GET_MODE (operands
[1]);
761 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
762 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
764 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
765 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
767 if (GET_CODE (base
) != REG
)
774 /* If the offset is out of range, we have to compute the address
775 with a separate add instruction. We try to do with with an 8-bit
776 add on the A register. This is possible only if the lowest part
777 of the offset (ie, big_offset % 256) is a valid constant offset
778 with respect to the mode. If it's not, we have to generate a
779 16-bit add on the D register. From:
781 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
785 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
786 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
787 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
788 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
790 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
791 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
794 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
797 rtx reg
= operands
[0];
799 int val
= INTVAL (big_offset
);
802 /* We use the 'operands[0]' as a scratch register to compute the
803 address. Make sure 'base' is in that register. */
804 if (!rtx_equal_p (base
, operands
[0]))
806 emit_move_insn (reg
, base
);
816 vh
= (val
>> 8) & 0x0FF;
820 /* Create the lowest part offset that still remains to be added.
821 If it's not a valid offset, do a 16-bit add. */
822 offset
= GEN_INT (vl
);
823 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
825 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
826 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
831 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
832 gen_rtx (PLUS
, HImode
, reg
,
833 GEN_INT (vh
<< 8))));
835 emit_move_insn (operands
[0],
836 gen_rtx (MEM
, GET_MODE (operands
[1]),
837 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
842 /* Use the normal gen_movhi pattern. */
847 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
850 enum machine_mode dmode
;
851 enum machine_mode smode
;
861 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
865 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
866 dmode
, 1, operands
[1], smode
);
867 equiv
= gen_rtx (code
, dmode
, operands
[1]);
871 ret
= emit_library_call_value (libcall
, NULL_RTX
,
873 operands
[1], smode
, operands
[2],
875 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
882 insns
= get_insns ();
884 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
887 /* Returns true if X is a PRE/POST increment decrement
888 (same as auto_inc_p() in rtlanal.c but do not take into
889 account the stack). */
891 m68hc11_auto_inc_p (x
)
894 return GET_CODE (x
) == PRE_DEC
895 || GET_CODE (x
) == POST_INC
896 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
900 /* Predicates for machine description. */
903 memory_reload_operand (operand
, mode
)
905 enum machine_mode mode ATTRIBUTE_UNUSED
;
907 return GET_CODE (operand
) == MEM
908 && GET_CODE (XEXP (operand
, 0)) == PLUS
909 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
910 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
911 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
912 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
916 tst_operand (operand
, mode
)
918 enum machine_mode mode
;
920 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
922 rtx addr
= XEXP (operand
, 0);
923 if (m68hc11_auto_inc_p (addr
))
926 return nonimmediate_operand (operand
, mode
);
930 cmp_operand (operand
, mode
)
932 enum machine_mode mode
;
934 if (GET_CODE (operand
) == MEM
)
936 rtx addr
= XEXP (operand
, 0);
937 if (m68hc11_auto_inc_p (addr
))
940 return general_operand (operand
, mode
);
944 non_push_operand (operand
, mode
)
946 enum machine_mode mode
;
948 if (general_operand (operand
, mode
) == 0)
951 if (push_operand (operand
, mode
) == 1)
957 reg_or_some_mem_operand (operand
, mode
)
959 enum machine_mode mode
;
961 if (GET_CODE (operand
) == MEM
)
963 rtx op
= XEXP (operand
, 0);
965 if (symbolic_memory_operand (op
, mode
))
968 if (IS_STACK_PUSH (operand
))
971 if (m68hc11_register_indirect_p (operand
, mode
))
977 return register_operand (operand
, mode
);
981 m68hc11_symbolic_p (operand
, mode
)
983 enum machine_mode mode
;
985 if (GET_CODE (operand
) == MEM
)
987 rtx op
= XEXP (operand
, 0);
989 if (symbolic_memory_operand (op
, mode
))
996 m68hc11_indirect_p (operand
, mode
)
998 enum machine_mode mode
;
1000 if (GET_CODE (operand
) == MEM
)
1002 rtx op
= XEXP (operand
, 0);
1004 if (symbolic_memory_operand (op
, mode
))
1007 if (reload_in_progress
)
1010 operand
= XEXP (operand
, 0);
1011 return register_indirect_p (operand
, mode
, reload_completed
);
1017 stack_register_operand (operand
, mode
)
1019 enum machine_mode mode ATTRIBUTE_UNUSED
;
1021 return SP_REG_P (operand
);
1025 d_register_operand (operand
, mode
)
1027 enum machine_mode mode ATTRIBUTE_UNUSED
;
1029 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1032 if (GET_CODE (operand
) == SUBREG
)
1033 operand
= XEXP (operand
, 0);
1035 return GET_CODE (operand
) == REG
1036 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1037 || REGNO (operand
) == HARD_D_REGNUM
1038 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1042 hard_addr_reg_operand (operand
, mode
)
1044 enum machine_mode mode ATTRIBUTE_UNUSED
;
1046 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1049 if (GET_CODE (operand
) == SUBREG
)
1050 operand
= XEXP (operand
, 0);
1052 return GET_CODE (operand
) == REG
1053 && (REGNO (operand
) == HARD_X_REGNUM
1054 || REGNO (operand
) == HARD_Y_REGNUM
1055 || REGNO (operand
) == HARD_Z_REGNUM
);
1059 hard_reg_operand (operand
, mode
)
1061 enum machine_mode mode
;
1063 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1066 if (GET_CODE (operand
) == SUBREG
)
1067 operand
= XEXP (operand
, 0);
1069 return GET_CODE (operand
) == REG
1070 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1071 || H_REGNO_P (REGNO (operand
)));
1075 memory_indexed_operand (operand
, mode
)
1077 enum machine_mode mode ATTRIBUTE_UNUSED
;
1079 if (GET_CODE (operand
) != MEM
)
1082 operand
= XEXP (operand
, 0);
1083 if (GET_CODE (operand
) == PLUS
)
1085 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1086 operand
= XEXP (operand
, 0);
1087 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1088 operand
= XEXP (operand
, 1);
1090 return GET_CODE (operand
) == REG
1091 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1092 || A_REGNO_P (REGNO (operand
)));
1096 push_pop_operand_p (operand
)
1099 if (GET_CODE (operand
) != MEM
)
1103 operand
= XEXP (operand
, 0);
1104 return PUSH_POP_ADDRESS_P (operand
);
1107 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1108 reference and a constant. */
1111 symbolic_memory_operand (op
, mode
)
1113 enum machine_mode mode
;
1115 switch (GET_CODE (op
))
1123 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1124 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1125 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1127 /* ??? This clause seems to be irrelevant. */
1129 return GET_MODE (op
) == mode
;
1132 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1133 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1141 m68hc11_eq_compare_operator (op
, mode
)
1143 enum machine_mode mode ATTRIBUTE_UNUSED
;
1145 return GET_CODE (op
) == EQ
|| GET_CODE (op
) == NE
;
1149 m68hc11_logical_operator (op
, mode
)
1151 enum machine_mode mode ATTRIBUTE_UNUSED
;
1153 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1157 m68hc11_arith_operator (op
, mode
)
1159 enum machine_mode mode ATTRIBUTE_UNUSED
;
1161 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1162 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1163 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1164 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1165 || GET_CODE (op
) == ROTATERT
;
1169 m68hc11_non_shift_operator (op
, mode
)
1171 enum machine_mode mode ATTRIBUTE_UNUSED
;
1173 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1174 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1177 /* Return true if op is a shift operator. */
1179 m68hc11_shift_operator (op
, mode
)
1181 enum machine_mode mode ATTRIBUTE_UNUSED
;
1183 return GET_CODE (op
) == ROTATE
|| GET_CODE (op
) == ROTATERT
1184 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ASHIFT
1185 || GET_CODE (op
) == ASHIFTRT
;
1189 m68hc11_unary_operator (op
, mode
)
1191 enum machine_mode mode ATTRIBUTE_UNUSED
;
1193 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1194 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1197 /* Emit the code to build the trampoline used to call a nested function.
1201 ldy #&CXT movw #&CXT,*_.d1
1202 sty *_.d1 jmp FNADDR
1207 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1212 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1215 if (*static_chain_reg
== '*')
1219 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1220 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1221 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1223 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1224 gen_rtx_CONST (QImode
,
1225 gen_rtx_SYMBOL_REF (Pmode
,
1226 static_chain_reg
)));
1227 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1229 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1233 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1234 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1235 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1236 gen_rtx_CONST (HImode
,
1237 gen_rtx_SYMBOL_REF (Pmode
,
1238 static_chain_reg
)));
1239 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1241 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1245 /* Declaration of types. */
1247 const struct attribute_spec m68hc11_attribute_table
[] =
1249 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1250 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1251 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1252 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1253 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1254 { NULL
, 0, 0, false, false, false, NULL
}
1257 /* Keep track of the symbol which has a `trap' attribute and which uses
1258 the `swi' calling convention. Since there is only one trap, we only
1259 record one such symbol. If there are several, a warning is reported. */
1260 static rtx trap_handler_symbol
= 0;
1262 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1263 arguments as in struct attribute_spec.handler. */
1265 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1268 tree args ATTRIBUTE_UNUSED
;
1269 int flags ATTRIBUTE_UNUSED
;
1272 if (TREE_CODE (*node
) != FUNCTION_TYPE
1273 && TREE_CODE (*node
) != METHOD_TYPE
1274 && TREE_CODE (*node
) != FIELD_DECL
1275 && TREE_CODE (*node
) != TYPE_DECL
)
1277 warning ("`%s' attribute only applies to functions",
1278 IDENTIFIER_POINTER (name
));
1279 *no_add_attrs
= true;
1285 /* We want to recognize trap handlers so that we handle calls to traps
1286 in a special manner (by issuing the trap). This information is stored
1287 in SYMBOL_REF_FLAG. */
1290 m68hc11_encode_section_info (decl
, rtl
, first
)
1293 int first ATTRIBUTE_UNUSED
;
1299 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1302 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1305 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1307 else if (lookup_attribute ("near", func_attr
) == NULL_TREE
)
1308 is_far
= TARGET_LONG_CALLS
!= 0;
1310 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1311 if (trap_handler
&& is_far
)
1313 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1318 if (trap_handler_symbol
!= 0)
1319 warning ("`trap' attribute is already used");
1321 trap_handler_symbol
= XEXP (rtl
, 0);
1323 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = is_far
;
1327 m68hc11_is_far_symbol (sym
)
1330 if (GET_CODE (sym
) == MEM
)
1331 sym
= XEXP (sym
, 0);
1333 return SYMBOL_REF_FLAG (sym
);
1337 m68hc11_is_trap_symbol (sym
)
1340 if (GET_CODE (sym
) == MEM
)
1341 sym
= XEXP (sym
, 0);
1343 return trap_handler_symbol
!= 0 && rtx_equal_p (trap_handler_symbol
, sym
);
1347 /* Argument support functions. */
1349 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1350 Arrays are passed by references and other types by value.
1352 SCz: I tried to pass DImode by reference but it seems that this
1353 does not work very well. */
1355 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1356 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1357 enum machine_mode mode ATTRIBUTE_UNUSED
;
1359 int named ATTRIBUTE_UNUSED
;
1361 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1362 /* Consider complex values as aggregates, so care for TCmode. */
1363 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1364 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1368 /* Define the offset between two registers, one to be eliminated, and the
1369 other its replacement, at the start of a routine. */
1371 m68hc11_initial_elimination_offset (from
, to
)
1380 /* For a trap handler, we must take into account the registers which
1381 are pushed on the stack during the trap (except the PC). */
1382 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1384 if (lookup_attribute ("far", func_attr
) != 0)
1385 current_function_far
= 1;
1386 else if (lookup_attribute ("near", func_attr
) != 0)
1387 current_function_far
= 0;
1389 current_function_far
= TARGET_LONG_CALLS
!= 0;
1391 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1392 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1395 /* For a function using 'call/rtc' we must take into account the
1396 page register which is pushed in the call. */
1397 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1402 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1404 /* 2 is for the saved frame.
1405 1 is for the 'sts' correction when creating the frame. */
1406 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1409 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1411 return m68hc11_sp_correction
;
1414 /* Push any 2 byte pseudo hard registers that we need to save. */
1415 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1417 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1423 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1425 return get_frame_size () + size
;
1428 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1435 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1436 for a call to a function whose data type is FNTYPE.
1437 For a library call, FNTYPE is 0. */
1440 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1441 CUMULATIVE_ARGS
*cum
;
1447 z_replacement_completed
= 0;
1451 /* For a library call, we must find out the type of the return value.
1452 When the return value is bigger than 4 bytes, it is returned in
1453 memory. In that case, the first argument of the library call is a
1454 pointer to the memory location. Because the first argument is passed in
1455 register D, we have to identify this, so that the first function
1456 parameter is not passed in D either. */
1462 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1465 /* If the library ends in 'di' or in 'df', we assume it's
1466 returning some DImode or some DFmode which are 64-bit wide. */
1467 name
= XSTR (libname
, 0);
1468 len
= strlen (name
);
1470 && ((name
[len
- 2] == 'd'
1471 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1472 || (name
[len
- 3] == 'd'
1473 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1475 /* We are in. Mark the first parameter register as already used. */
1482 ret_type
= TREE_TYPE (fntype
);
1484 if (ret_type
&& aggregate_value_p (ret_type
))
1491 /* Update the data in CUM to advance over an argument
1492 of mode MODE and data type TYPE.
1493 (TYPE is null for libcalls where that information may not be available.) */
1496 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1497 CUMULATIVE_ARGS
*cum
;
1498 enum machine_mode mode
;
1500 int named ATTRIBUTE_UNUSED
;
1502 if (mode
!= BLKmode
)
1504 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1507 cum
->words
= GET_MODE_SIZE (mode
);
1511 cum
->words
+= GET_MODE_SIZE (mode
);
1512 if (cum
->words
<= HARD_REG_SIZE
)
1518 cum
->words
+= int_size_in_bytes (type
);
1523 /* Define where to put the arguments to a function.
1524 Value is zero to push the argument on the stack,
1525 or a hard register in which to store the argument.
1527 MODE is the argument's machine mode.
1528 TYPE is the data type of the argument (as a tree).
1529 This is null for libcalls where that information may
1531 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1532 the preceding args and about the function being called.
1533 NAMED is nonzero if this argument is a named parameter
1534 (otherwise it is an extra parameter matching an ellipsis). */
1537 m68hc11_function_arg (cum
, mode
, type
, named
)
1538 const CUMULATIVE_ARGS
*cum
;
1539 enum machine_mode mode
;
1540 tree type ATTRIBUTE_UNUSED
;
1541 int named ATTRIBUTE_UNUSED
;
1543 if (cum
->words
!= 0)
1548 if (mode
!= BLKmode
)
1550 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1551 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1553 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1557 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1562 /* If defined, a C expression which determines whether, and in which direction,
1563 to pad out an argument with extra space. The value should be of type
1564 `enum direction': either `upward' to pad above the argument,
1565 `downward' to pad below, or `none' to inhibit padding.
1567 Structures are stored left shifted in their argument slot. */
1569 m68hc11_function_arg_padding (mode
, type
)
1570 enum machine_mode mode
;
1573 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1576 /* This is the default definition. */
1577 return (!BYTES_BIG_ENDIAN
1580 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1581 && int_size_in_bytes (type
) <
1582 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1583 PARM_BOUNDARY
) ? downward
: upward
));
1587 /* Function prologue and epilogue. */
1589 /* Emit a move after the reload pass has completed. This is used to
1590 emit the prologue and epilogue. */
1592 emit_move_after_reload (to
, from
, scratch
)
1593 rtx to
, from
, scratch
;
1597 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1599 insn
= emit_move_insn (to
, from
);
1603 emit_move_insn (scratch
, from
);
1604 insn
= emit_move_insn (to
, scratch
);
1607 /* Put a REG_INC note to tell the flow analysis that the instruction
1609 if (IS_STACK_PUSH (to
))
1611 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1612 XEXP (XEXP (to
, 0), 0),
1615 else if (IS_STACK_POP (from
))
1617 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1618 XEXP (XEXP (from
, 0), 0),
1622 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1623 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1624 The problem is that we are lying to gcc and use `txs' for x = sp
1625 (which is not really true because txs is really x = sp + 1). */
1626 else if (TARGET_M6811
&& SP_REG_P (from
))
1628 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1635 m68hc11_total_frame_size ()
1640 size
= get_frame_size ();
1641 if (current_function_interrupt
)
1643 size
+= 3 * HARD_REG_SIZE
;
1645 if (frame_pointer_needed
)
1646 size
+= HARD_REG_SIZE
;
1648 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1649 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1650 size
+= HARD_REG_SIZE
;
1656 m68hc11_output_function_epilogue (out
, size
)
1657 FILE *out ATTRIBUTE_UNUSED
;
1658 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1660 /* We catch the function epilogue generation to have a chance
1661 to clear the z_replacement_completed flag. */
1662 z_replacement_completed
= 0;
1673 if (reload_completed
!= 1)
1676 size
= get_frame_size ();
1680 /* Generate specific prologue for interrupt handlers. */
1681 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1682 current_function_interrupt
= lookup_attribute ("interrupt",
1683 func_attr
) != NULL_TREE
;
1684 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1685 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1686 current_function_far
= 1;
1687 else if (lookup_attribute ("near", func_attr
) != NULL_TREE
)
1688 current_function_far
= 0;
1690 current_function_far
= TARGET_LONG_CALLS
!= 0;
1692 /* Get the scratch register to build the frame and push registers.
1693 If the first argument is a 32-bit quantity, the D+X registers
1694 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1695 For 68HC12, this scratch register is not used. */
1696 if (current_function_args_info
.nregs
== 2)
1701 /* Save current stack frame. */
1702 if (frame_pointer_needed
)
1703 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1705 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1706 Other soft registers in page0 need not to be saved because they
1707 will be restored by C functions. For a trap handler, we don't
1708 need to preserve these registers because this is a synchronous call. */
1709 if (current_function_interrupt
)
1711 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1712 emit_move_after_reload (stack_push_word
,
1713 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1714 emit_move_after_reload (stack_push_word
,
1715 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1719 /* Allocate local variables. */
1720 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1722 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1723 stack_pointer_rtx
, GEN_INT (-size
)));
1725 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1729 insn
= gen_rtx_PARALLEL
1732 gen_rtx_SET (VOIDmode
,
1734 gen_rtx_PLUS (HImode
,
1737 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1744 /* Allocate by pushing scratch values. */
1745 for (i
= 2; i
<= size
; i
+= 2)
1746 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1749 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1750 stack_pointer_rtx
, GEN_INT (-1)));
1753 /* Create the frame pointer. */
1754 if (frame_pointer_needed
)
1755 emit_move_after_reload (hard_frame_pointer_rtx
,
1756 stack_pointer_rtx
, scratch
);
1758 /* Push any 2 byte pseudo hard registers that we need to save. */
1759 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1761 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1763 emit_move_after_reload (stack_push_word
,
1764 gen_rtx (REG
, HImode
, regno
), scratch
);
1777 if (reload_completed
!= 1)
1780 size
= get_frame_size ();
1782 /* If we are returning a value in two registers, we have to preserve the
1783 X register and use the Y register to restore the stack and the saved
1784 registers. Otherwise, use X because it's faster (and smaller). */
1785 if (current_function_return_rtx
== 0)
1787 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1788 return_size
= HARD_REG_SIZE
;
1790 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1792 if (return_size
> HARD_REG_SIZE
&& return_size
<= 2 * HARD_REG_SIZE
)
1797 /* Pop any 2 byte pseudo hard registers that we saved. */
1798 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1800 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1802 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1803 stack_pop_word
, scratch
);
1807 /* de-allocate auto variables */
1808 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1810 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1811 stack_pointer_rtx
, GEN_INT (size
)));
1813 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1817 insn
= gen_rtx_PARALLEL
1820 gen_rtx_SET (VOIDmode
,
1822 gen_rtx_PLUS (HImode
,
1825 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1832 for (i
= 2; i
<= size
; i
+= 2)
1833 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1835 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1836 stack_pointer_rtx
, GEN_INT (1)));
1839 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1840 if (current_function_interrupt
)
1842 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1843 stack_pop_word
, scratch
);
1844 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1845 stack_pop_word
, scratch
);
1846 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1849 /* Restore previous frame pointer. */
1850 if (frame_pointer_needed
)
1851 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1853 /* If the trap handler returns some value, copy the value
1854 in D, X onto the stack so that the rti will pop the return value
1856 else if (current_function_trap
&& return_size
!= 0)
1858 rtx addr_reg
= stack_pointer_rtx
;
1862 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1865 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1866 gen_rtx (PLUS
, HImode
, addr_reg
,
1867 GEN_INT (1))), d_reg
, 0);
1868 if (return_size
> HARD_REG_SIZE
)
1869 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1870 gen_rtx (PLUS
, HImode
, addr_reg
,
1871 GEN_INT (3))), ix_reg
, 0);
1874 emit_jump_insn (gen_return ());
1878 /* Low and High part extraction for 68HC11. These routines are
1879 similar to gen_lowpart and gen_highpart but they have been
1880 fixed to work for constants and 68HC11 specific registers. */
1883 m68hc11_gen_lowpart (mode
, x
)
1884 enum machine_mode mode
;
1887 /* We assume that the low part of an auto-inc mode is the same with
1888 the mode changed and that the caller split the larger mode in the
1890 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1892 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1895 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1896 floating-point constant. A CONST_DOUBLE is used whenever the
1897 constant requires more than one word in order to be adequately
1899 if (GET_CODE (x
) == CONST_DOUBLE
)
1903 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1907 if (GET_MODE (x
) == SFmode
)
1909 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1910 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1916 split_double (x
, &first
, &second
);
1920 return GEN_INT (l
[0]);
1922 return gen_int_mode (l
[0], HImode
);
1926 l
[0] = CONST_DOUBLE_LOW (x
);
1929 return GEN_INT (l
[0]);
1930 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1931 return gen_int_mode (l
[0], HImode
);
1936 if (mode
== QImode
&& D_REG_P (x
))
1937 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1939 /* gen_lowpart crashes when it is called with a SUBREG. */
1940 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1943 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1944 else if (mode
== HImode
)
1945 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1949 x
= gen_lowpart (mode
, x
);
1951 /* Return a different rtx to avoid to share it in several insns
1952 (when used by a split pattern). Sharing addresses within
1953 a MEM breaks the Z register replacement (and reloading). */
1954 if (GET_CODE (x
) == MEM
)
1960 m68hc11_gen_highpart (mode
, x
)
1961 enum machine_mode mode
;
1964 /* We assume that the high part of an auto-inc mode is the same with
1965 the mode changed and that the caller split the larger mode in the
1967 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1969 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1972 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1973 floating-point constant. A CONST_DOUBLE is used whenever the
1974 constant requires more than one word in order to be adequately
1976 if (GET_CODE (x
) == CONST_DOUBLE
)
1980 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1984 if (GET_MODE (x
) == SFmode
)
1986 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1987 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1993 split_double (x
, &first
, &second
);
1997 return GEN_INT (l
[1]);
1999 return gen_int_mode ((l
[1] >> 16), HImode
);
2003 l
[1] = CONST_DOUBLE_HIGH (x
);
2007 return GEN_INT (l
[1]);
2008 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
2009 return gen_int_mode ((l
[0] >> 16), HImode
);
2013 if (GET_CODE (x
) == CONST_INT
)
2015 HOST_WIDE_INT val
= INTVAL (x
);
2019 return gen_int_mode (val
>> 8, QImode
);
2021 else if (mode
== HImode
)
2023 return gen_int_mode (val
>> 16, HImode
);
2026 if (mode
== QImode
&& D_REG_P (x
))
2027 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
2029 /* There is no way in GCC to represent the upper part of a word register.
2030 To obtain the 8-bit upper part of a soft register, we change the
2031 reg into a mem rtx. This is possible because they are physically
2032 located in memory. There is no offset because we are big-endian. */
2033 if (mode
== QImode
&& S_REG_P (x
))
2037 /* Avoid the '*' for direct addressing mode when this
2038 addressing mode is disabled. */
2039 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
2040 return gen_rtx (MEM
, QImode
,
2041 gen_rtx (SYMBOL_REF
, Pmode
,
2042 ®_names
[REGNO (x
)][pos
]));
2045 /* gen_highpart crashes when it is called with a SUBREG. */
2046 if (GET_CODE (x
) == SUBREG
)
2048 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
2050 if (GET_CODE (x
) == REG
)
2052 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
2053 return gen_rtx (REG
, mode
, REGNO (x
));
2055 return gen_rtx_SUBREG (mode
, x
, 0);
2058 if (GET_CODE (x
) == MEM
)
2060 x
= change_address (x
, mode
, 0);
2062 /* Return a different rtx to avoid to share it in several insns
2063 (when used by a split pattern). Sharing addresses within
2064 a MEM breaks the Z register replacement (and reloading). */
2065 if (GET_CODE (x
) == MEM
)
2073 /* Obscure register manipulation. */
2075 /* Finds backward in the instructions to see if register 'reg' is
2076 dead. This is used when generating code to see if we can use 'reg'
2077 as a scratch register. This allows us to choose a better generation
2078 of code when we know that some register dies or can be clobbered. */
2081 dead_register_here (x
, reg
)
2089 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2093 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2094 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2100 if (GET_CODE (body
) == CALL_INSN
)
2102 if (GET_CODE (body
) == JUMP_INSN
)
2105 if (GET_CODE (body
) == SET
)
2107 rtx dst
= XEXP (body
, 0);
2109 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2111 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2114 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2117 else if (reg_mentioned_p (reg
, p
)
2118 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2122 /* Scan forward to see if the register is set in some insns and never
2124 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2128 if (GET_CODE (p
) == CODE_LABEL
2129 || GET_CODE (p
) == JUMP_INSN
2130 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2133 if (GET_CODE (p
) != INSN
)
2137 if (GET_CODE (body
) == SET
)
2139 rtx src
= XEXP (body
, 1);
2140 rtx dst
= XEXP (body
, 0);
2142 if (GET_CODE (dst
) == REG
2143 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2147 /* Register is used (may be in source or in dest). */
2148 if (reg_mentioned_p (reg
, p
)
2149 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2150 && reg_mentioned_p (x_reg
, p
)))
2153 return p
== 0 ? 1 : 0;
2157 /* Code generation operations called from machine description file. */
2159 /* Print the name of register 'regno' in the assembly file. */
2161 asm_print_register (file
, regno
)
2165 const char *name
= reg_names
[regno
];
2167 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2170 fprintf (file
, "%s", name
);
2173 /* A C compound statement to output to stdio stream STREAM the
2174 assembler syntax for an instruction operand X. X is an RTL
2177 CODE is a value that can be used to specify one of several ways
2178 of printing the operand. It is used when identical operands
2179 must be printed differently depending on the context. CODE
2180 comes from the `%' specification that was used to request
2181 printing of the operand. If the specification was just `%DIGIT'
2182 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2183 is the ASCII code for LTR.
2185 If X is a register, this macro should print the register's name.
2186 The names can be found in an array `reg_names' whose type is
2187 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2189 When the machine description has a specification `%PUNCT' (a `%'
2190 followed by a punctuation character), this macro is called with
2191 a null pointer for X and the punctuation character for CODE.
2193 The M68HC11 specific codes are:
2195 'b' for the low part of the operand.
2196 'h' for the high part of the operand
2197 The 'b' or 'h' modifiers have no effect if the operand has
2198 the QImode and is not a S_REG_P (soft register). If the
2199 operand is a hard register, these two modifiers have no effect.
2200 't' generate the temporary scratch register. The operand is
2202 'T' generate the low-part temporary scratch register. The operand is
2206 print_operand (file
, op
, letter
)
2213 asm_print_register (file
, SOFT_TMP_REGNUM
);
2216 else if (letter
== 'T')
2218 asm_print_register (file
, SOFT_TMP_REGNUM
);
2219 fprintf (file
, "+1");
2222 else if (letter
== '#')
2224 asm_fprintf (file
, "%0I");
2227 if (GET_CODE (op
) == REG
)
2229 if (letter
== 'b' && S_REG_P (op
))
2231 asm_print_register (file
, REGNO (op
));
2232 fprintf (file
, "+1");
2234 else if (letter
== 'b' && D_REG_P (op
))
2236 asm_print_register (file
, HARD_B_REGNUM
);
2240 asm_print_register (file
, REGNO (op
));
2245 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2248 asm_fprintf (file
, "%0I%%lo(");
2250 asm_fprintf (file
, "%0I%%hi(");
2252 output_addr_const (file
, op
);
2253 fprintf (file
, ")");
2257 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2258 are specified. If we already have a QImode, there is nothing to do. */
2259 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2263 op
= m68hc11_gen_lowpart (QImode
, op
);
2265 else if (letter
== 'h')
2267 op
= m68hc11_gen_highpart (QImode
, op
);
2271 if (GET_CODE (op
) == MEM
)
2273 rtx base
= XEXP (op
, 0);
2274 switch (GET_CODE (base
))
2279 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2280 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2289 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2290 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2291 fprintf (file
, "-");
2300 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2301 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2302 fprintf (file
, "+");
2311 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2312 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2319 output_address (base
);
2323 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2328 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2329 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2330 asm_fprintf (file
, "%I0x%lx", l
);
2332 else if (GET_CODE (op
) == CONST_DOUBLE
2333 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2337 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2338 sizeof (dstr
), 0, 1);
2339 asm_fprintf (file
, "%I0r%s", dstr
);
2343 int need_parenthesize
= 0;
2346 asm_fprintf (file
, "%0I");
2348 need_parenthesize
= must_parenthesize (op
);
2350 if (need_parenthesize
)
2351 fprintf (file
, "(");
2353 output_addr_const (file
, op
);
2354 if (need_parenthesize
)
2355 fprintf (file
, ")");
2359 /* Returns true if the operand 'op' must be printed with parenthesis
2360 arround it. This must be done only if there is a symbol whose name
2361 is a processor register. */
2363 must_parenthesize (op
)
2368 switch (GET_CODE (op
))
2371 name
= XSTR (op
, 0);
2372 /* Avoid a conflict between symbol name and a possible
2374 return (strcasecmp (name
, "a") == 0
2375 || strcasecmp (name
, "b") == 0
2376 || strcasecmp (name
, "d") == 0
2377 || strcasecmp (name
, "x") == 0
2378 || strcasecmp (name
, "y") == 0
2379 || strcasecmp (name
, "ix") == 0
2380 || strcasecmp (name
, "iy") == 0
2381 || strcasecmp (name
, "pc") == 0
2382 || strcasecmp (name
, "sp") == 0
2383 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2387 return must_parenthesize (XEXP (op
, 0))
2388 || must_parenthesize (XEXP (op
, 1));
2394 return must_parenthesize (XEXP (op
, 0));
2405 /* A C compound statement to output to stdio stream STREAM the
2406 assembler syntax for an instruction operand that is a memory
2407 reference whose address is ADDR. ADDR is an RTL expression. */
2410 print_operand_address (file
, addr
)
2416 int need_parenthesis
= 0;
2418 switch (GET_CODE (addr
))
2421 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2424 fprintf (file
, "0,");
2425 asm_print_register (file
, REGNO (addr
));
2429 base
= XEXP (addr
, 0);
2430 switch (GET_CODE (base
))
2435 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2436 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2445 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2446 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2447 fprintf (file
, "-");
2456 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2457 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2458 fprintf (file
, "+");
2467 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2468 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2475 need_parenthesis
= must_parenthesize (base
);
2476 if (need_parenthesis
)
2477 fprintf (file
, "(");
2479 output_addr_const (file
, base
);
2480 if (need_parenthesis
)
2481 fprintf (file
, ")");
2487 base
= XEXP (addr
, 0);
2488 offset
= XEXP (addr
, 1);
2489 if (!G_REG_P (base
) && G_REG_P (offset
))
2491 base
= XEXP (addr
, 1);
2492 offset
= XEXP (addr
, 0);
2494 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2496 need_parenthesis
= must_parenthesize (addr
);
2498 if (need_parenthesis
)
2499 fprintf (file
, "(");
2501 output_addr_const (file
, base
);
2502 fprintf (file
, "+");
2503 output_addr_const (file
, offset
);
2504 if (need_parenthesis
)
2505 fprintf (file
, ")");
2507 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2513 asm_print_register (file
, REGNO (offset
));
2514 fprintf (file
, ",");
2515 asm_print_register (file
, REGNO (base
));
2522 need_parenthesis
= must_parenthesize (offset
);
2523 if (need_parenthesis
)
2524 fprintf (file
, "(");
2526 output_addr_const (file
, offset
);
2527 if (need_parenthesis
)
2528 fprintf (file
, ")");
2529 fprintf (file
, ",");
2530 asm_print_register (file
, REGNO (base
));
2540 if (GET_CODE (addr
) == CONST_INT
2541 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2543 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2547 need_parenthesis
= must_parenthesize (addr
);
2548 if (need_parenthesis
)
2549 fprintf (file
, "(");
2551 output_addr_const (file
, addr
);
2552 if (need_parenthesis
)
2553 fprintf (file
, ")");
2560 /* Splitting of some instructions. */
2563 m68hc11_expand_compare (code
, op0
, op1
)
2569 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2573 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2574 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2575 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2582 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2584 rtx op0
, op1
, label
;
2588 switch (GET_MODE (op0
))
2592 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2593 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2594 gen_rtx_LABEL_REF (VOIDmode
, label
),
2596 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2600 /* SCz: from i386.c */
2603 /* Don't expand the comparison early, so that we get better code
2604 when jump or whoever decides to reverse the comparison. */
2609 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2610 &m68hc11_compare_op1
);
2612 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2613 m68hc11_compare_op0
, m68hc11_compare_op1
);
2614 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2615 gen_rtx_LABEL_REF (VOIDmode
, label
),
2617 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2619 use_fcomi
= ix86_use_fcomi_compare (code
);
2620 vec
= rtvec_alloc (3 + !use_fcomi
);
2621 RTVEC_ELT (vec
, 0) = tmp
;
2623 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2625 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2628 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2630 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2636 /* Expand SImode branch into multiple compare+branch. */
2638 rtx lo
[2], hi
[2], label2
;
2639 enum rtx_code code1
, code2
, code3
;
2641 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2646 code
= swap_condition (code
);
2648 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2649 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2650 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2651 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2653 /* Otherwise, if we are doing less-than, op1 is a constant and the
2654 low word is zero, then we can just examine the high word. */
2656 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2657 && (code
== LT
|| code
== LTU
))
2659 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2663 /* Otherwise, we need two or three jumps. */
2665 label2
= gen_label_rtx ();
2668 code2
= swap_condition (code
);
2669 code3
= unsigned_condition (code
);
2710 * if (hi(a) < hi(b)) goto true;
2711 * if (hi(a) > hi(b)) goto false;
2712 * if (lo(a) < lo(b)) goto true;
2716 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2718 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2720 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2723 emit_label (label2
);
2733 /* Return the increment/decrement mode of a MEM if it is such.
2734 Return CONST if it is anything else. */
2739 if (GET_CODE (x
) != MEM
)
2743 if (GET_CODE (x
) == PRE_INC
2744 || GET_CODE (x
) == PRE_DEC
2745 || GET_CODE (x
) == POST_INC
2746 || GET_CODE (x
) == POST_DEC
)
2747 return GET_CODE (x
);
2753 m68hc11_make_autoinc_notes (x
, data
)
2759 switch (GET_CODE (*x
))
2766 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2775 /* Split a DI, SI or HI move into several smaller move operations.
2776 The scratch register 'scratch' is used as a temporary to load
2777 store intermediate values. It must be a hard register. */
2779 m68hc11_split_move (to
, from
, scratch
)
2780 rtx to
, from
, scratch
;
2782 rtx low_to
, low_from
;
2783 rtx high_to
, high_from
;
2785 enum machine_mode mode
;
2787 int autoinc_from
= autoinc_mode (from
);
2788 int autoinc_to
= autoinc_mode (to
);
2790 mode
= GET_MODE (to
);
2792 /* If the TO and FROM contain autoinc modes that are not compatible
2793 together (one pop and the other a push), we must change one to
2794 an offsetable operand and generate an appropriate add at the end. */
2795 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2800 /* The source uses an autoinc mode which is not compatible with
2801 a split (this would result in a word swap). */
2802 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2804 code
= GET_CODE (XEXP (from
, 0));
2805 reg
= XEXP (XEXP (from
, 0), 0);
2806 offset
= GET_MODE_SIZE (GET_MODE (from
));
2807 if (code
== POST_DEC
)
2810 if (code
== PRE_INC
)
2811 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2813 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2814 if (code
== POST_DEC
)
2815 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2819 /* Likewise for destination. */
2820 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2822 code
= GET_CODE (XEXP (to
, 0));
2823 reg
= XEXP (XEXP (to
, 0), 0);
2824 offset
= GET_MODE_SIZE (GET_MODE (to
));
2825 if (code
== POST_DEC
)
2828 if (code
== PRE_INC
)
2829 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2831 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2832 if (code
== POST_DEC
)
2833 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2837 /* The source and destination auto increment modes must be compatible
2838 with each other: same direction. */
2839 if ((autoinc_to
!= autoinc_from
2840 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2841 /* The destination address register must not be used within
2842 the source operand because the source address would change
2843 while doing the copy. */
2844 || (autoinc_to
!= CONST
2845 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2846 && !IS_STACK_PUSH (to
)))
2848 /* Must change the destination. */
2849 code
= GET_CODE (XEXP (to
, 0));
2850 reg
= XEXP (XEXP (to
, 0), 0);
2851 offset
= GET_MODE_SIZE (GET_MODE (to
));
2852 if (code
== PRE_DEC
|| code
== POST_DEC
)
2855 if (code
== PRE_DEC
|| code
== PRE_INC
)
2856 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2857 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2858 if (code
== POST_DEC
|| code
== POST_INC
)
2859 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2864 /* Likewise, the source address register must not be used within
2865 the destination operand. */
2866 if (autoinc_from
!= CONST
2867 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2868 && !IS_STACK_PUSH (to
))
2870 /* Must change the source. */
2871 code
= GET_CODE (XEXP (from
, 0));
2872 reg
= XEXP (XEXP (from
, 0), 0);
2873 offset
= GET_MODE_SIZE (GET_MODE (from
));
2874 if (code
== PRE_DEC
|| code
== POST_DEC
)
2877 if (code
== PRE_DEC
|| code
== PRE_INC
)
2878 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2879 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2880 if (code
== POST_DEC
|| code
== POST_INC
)
2881 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2887 if (GET_MODE_SIZE (mode
) == 8)
2889 else if (GET_MODE_SIZE (mode
) == 4)
2895 && IS_STACK_PUSH (to
)
2896 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2902 else if (mode
== HImode
)
2910 low_to
= m68hc11_gen_lowpart (mode
, to
);
2911 high_to
= m68hc11_gen_highpart (mode
, to
);
2913 low_from
= m68hc11_gen_lowpart (mode
, from
);
2914 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2916 if (INTVAL (from
) >= 0)
2917 high_from
= const0_rtx
;
2919 high_from
= constm1_rtx
;
2922 high_from
= m68hc11_gen_highpart (mode
, from
);
2926 high_from
= adjust_address (high_from
, mode
, offset
);
2927 low_from
= high_from
;
2930 /* When copying with a POST_INC mode, we must copy the
2931 high part and then the low part to guarantee a correct
2934 && GET_MODE_SIZE (mode
) >= 2
2935 && autoinc_from
!= autoinc_to
2936 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2945 low_from
= high_from
;
2950 m68hc11_split_move (low_to
, low_from
, scratch
);
2951 m68hc11_split_move (high_to
, high_from
, scratch
);
2953 else if (H_REG_P (to
) || H_REG_P (from
)
2954 || (low_from
== const0_rtx
2955 && high_from
== const0_rtx
2956 && ! push_operand (to
, GET_MODE (to
))
2957 && ! H_REG_P (scratch
))
2959 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2960 || m68hc11_small_indexed_indirect_p (from
,
2962 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2963 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2965 insn
= emit_move_insn (low_to
, low_from
);
2966 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2968 insn
= emit_move_insn (high_to
, high_from
);
2969 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2973 insn
= emit_move_insn (scratch
, low_from
);
2974 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2975 insn
= emit_move_insn (low_to
, scratch
);
2976 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2978 insn
= emit_move_insn (scratch
, high_from
);
2979 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2980 insn
= emit_move_insn (high_to
, scratch
);
2981 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2986 simplify_logical (mode
, code
, operand
, result
)
2987 enum machine_mode mode
;
2996 if (GET_CODE (operand
) != CONST_INT
)
3004 val
= INTVAL (operand
);
3008 if ((val
& mask
) == 0)
3010 if ((val
& mask
) == mask
)
3011 *result
= constm1_rtx
;
3015 if ((val
& mask
) == 0)
3016 *result
= const0_rtx
;
3017 if ((val
& mask
) == mask
)
3022 if ((val
& mask
) == 0)
3030 m68hc11_emit_logical (mode
, code
, operands
)
3031 enum machine_mode mode
;
3038 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
3039 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
3041 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
3042 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
3044 if (result
&& GET_CODE (result
) == CONST_INT
)
3046 if (!H_REG_P (operands
[0]) && operands
[3]
3047 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
3049 emit_move_insn (operands
[3], result
);
3050 emit_move_insn (operands
[0], operands
[3]);
3054 emit_move_insn (operands
[0], result
);
3057 else if (operands
[1] != 0 && operands
[2] != 0)
3061 if (!H_REG_P (operands
[0]) && operands
[3])
3063 emit_move_insn (operands
[3], operands
[1]);
3064 emit_insn (gen_rtx (SET
, mode
,
3066 gen_rtx (code
, mode
,
3067 operands
[3], operands
[2])));
3068 insn
= emit_move_insn (operands
[0], operands
[3]);
3072 insn
= emit_insn (gen_rtx (SET
, mode
,
3074 gen_rtx (code
, mode
,
3075 operands
[0], operands
[2])));
3079 /* The logical operation is similar to a copy. */
3084 if (GET_CODE (operands
[1]) == CONST_INT
)
3089 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3091 emit_move_insn (operands
[3], src
);
3092 emit_move_insn (operands
[0], operands
[3]);
3096 emit_move_insn (operands
[0], src
);
3102 m68hc11_split_logical (mode
, code
, operands
)
3103 enum machine_mode mode
;
3110 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3111 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3112 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3114 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3116 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3118 if (INTVAL (operands
[1]) >= 0)
3119 high
[1] = const0_rtx
;
3121 high
[1] = constm1_rtx
;
3124 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3126 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3128 if (INTVAL (operands
[2]) >= 0)
3129 high
[2] = const0_rtx
;
3131 high
[2] = constm1_rtx
;
3134 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3136 low
[3] = operands
[3];
3137 high
[3] = operands
[3];
3140 m68hc11_split_logical (HImode
, code
, low
);
3141 m68hc11_split_logical (HImode
, code
, high
);
3145 m68hc11_emit_logical (mode
, code
, low
);
3146 m68hc11_emit_logical (mode
, code
, high
);
3150 /* Code generation. */
3153 m68hc11_output_swap (insn
, operands
)
3154 rtx insn ATTRIBUTE_UNUSED
;
3157 /* We have to be careful with the cc_status. An address register swap
3158 is generated for some comparison. The comparison is made with D
3159 but the branch really uses the address register. See the split
3160 pattern for compare. The xgdx/xgdy preserve the flags but after
3161 the exchange, the flags will reflect to the value of X and not D.
3162 Tell this by setting the cc_status according to the cc_prev_status. */
3163 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3165 if (cc_prev_status
.value1
!= 0
3166 && (D_REG_P (cc_prev_status
.value1
)
3167 || X_REG_P (cc_prev_status
.value1
)))
3169 cc_status
= cc_prev_status
;
3170 if (D_REG_P (cc_status
.value1
))
3171 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3174 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3180 output_asm_insn ("xgdx", operands
);
3184 if (cc_prev_status
.value1
!= 0
3185 && (D_REG_P (cc_prev_status
.value1
)
3186 || Y_REG_P (cc_prev_status
.value1
)))
3188 cc_status
= cc_prev_status
;
3189 if (D_REG_P (cc_status
.value1
))
3190 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3193 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3199 output_asm_insn ("xgdy", operands
);
3203 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3204 This is used to decide whether a move that set flags should be used
3207 next_insn_test_reg (insn
, reg
)
3213 insn
= next_nonnote_insn (insn
);
3214 if (GET_CODE (insn
) != INSN
)
3217 body
= PATTERN (insn
);
3218 if (sets_cc0_p (body
) != 1)
3221 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3227 /* Generate the code to move a 16-bit operand into another one. */
3230 m68hc11_gen_movhi (insn
, operands
)
3236 /* Move a register or memory to the same location.
3237 This is possible because such insn can appear
3238 in a non-optimizing mode. */
3239 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3241 cc_status
= cc_prev_status
;
3247 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3249 cc_status
= cc_prev_status
;
3250 switch (REGNO (operands
[1]))
3255 output_asm_insn ("psh%1", operands
);
3257 case HARD_SP_REGNUM
:
3258 output_asm_insn ("sts\t-2,sp", operands
);
3265 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3267 cc_status
= cc_prev_status
;
3268 switch (REGNO (operands
[0]))
3273 output_asm_insn ("pul%0", operands
);
3280 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3282 m68hc11_notice_keep_cc (operands
[0]);
3283 output_asm_insn ("tfr\t%1,%0", operands
);
3285 else if (H_REG_P (operands
[0]))
3287 if (SP_REG_P (operands
[0]))
3288 output_asm_insn ("lds\t%1", operands
);
3289 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3290 && !D_REG_P (operands
[0])
3291 && GET_CODE (operands
[1]) == CONST_INT
3292 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3293 && find_reg_note (insn
, REG_WAS_0
, 0))
3295 if (INTVAL (operands
[1]) == 1)
3296 output_asm_insn ("in%0", operands
);
3298 output_asm_insn ("de%0", operands
);
3301 output_asm_insn ("ld%0\t%1", operands
);
3303 else if (H_REG_P (operands
[1]))
3305 if (SP_REG_P (operands
[1]))
3306 output_asm_insn ("sts\t%0", operands
);
3308 output_asm_insn ("st%1\t%0", operands
);
3312 rtx from
= operands
[1];
3313 rtx to
= operands
[0];
3315 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3316 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3317 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3318 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3324 ops
[0] = operands
[2];
3327 m68hc11_gen_movhi (insn
, ops
);
3329 ops
[1] = operands
[2];
3330 m68hc11_gen_movhi (insn
, ops
);
3334 /* !!!! SCz wrong here. */
3335 fatal_insn ("move insn not handled", insn
);
3340 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3342 output_asm_insn ("clr\t%h0", operands
);
3343 output_asm_insn ("clr\t%b0", operands
);
3347 m68hc11_notice_keep_cc (operands
[0]);
3348 output_asm_insn ("movw\t%1,%0", operands
);
3355 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3357 cc_status
= cc_prev_status
;
3358 switch (REGNO (operands
[0]))
3362 output_asm_insn ("pul%0", operands
);
3365 output_asm_insn ("pula", operands
);
3366 output_asm_insn ("pulb", operands
);
3373 /* Some moves to a hard register are special. Not all of them
3374 are really supported and we have to use a temporary
3375 location to provide them (either the stack of a temp var). */
3376 if (H_REG_P (operands
[0]))
3378 switch (REGNO (operands
[0]))
3381 if (X_REG_P (operands
[1]))
3383 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3385 m68hc11_output_swap (insn
, operands
);
3387 else if (next_insn_test_reg (insn
, operands
[0]))
3389 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3393 m68hc11_notice_keep_cc (operands
[0]);
3394 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3397 else if (Y_REG_P (operands
[1]))
3399 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3401 m68hc11_output_swap (insn
, operands
);
3405 /* %t means *ZTMP scratch register. */
3406 output_asm_insn ("sty\t%t1", operands
);
3407 output_asm_insn ("ldd\t%t1", operands
);
3410 else if (SP_REG_P (operands
[1]))
3415 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3416 output_asm_insn ("xgdx", operands
);
3417 output_asm_insn ("tsx", operands
);
3418 output_asm_insn ("xgdx", operands
);
3420 else if (IS_STACK_POP (operands
[1]))
3422 output_asm_insn ("pula\n\tpulb", operands
);
3424 else if (GET_CODE (operands
[1]) == CONST_INT
3425 && INTVAL (operands
[1]) == 0)
3427 output_asm_insn ("clra\n\tclrb", operands
);
3431 output_asm_insn ("ldd\t%1", operands
);
3436 if (D_REG_P (operands
[1]))
3438 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3440 m68hc11_output_swap (insn
, operands
);
3442 else if (next_insn_test_reg (insn
, operands
[0]))
3444 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3448 m68hc11_notice_keep_cc (operands
[0]);
3449 output_asm_insn ("pshb", operands
);
3450 output_asm_insn ("psha", operands
);
3451 output_asm_insn ("pulx", operands
);
3454 else if (Y_REG_P (operands
[1]))
3456 /* When both D and Y are dead, use the sequence xgdy, xgdx
3457 to move Y into X. The D and Y registers are modified. */
3458 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3459 && dead_register_here (insn
, d_reg
))
3461 output_asm_insn ("xgdy", operands
);
3462 output_asm_insn ("xgdx", operands
);
3465 else if (!optimize_size
)
3467 output_asm_insn ("sty\t%t1", operands
);
3468 output_asm_insn ("ldx\t%t1", operands
);
3473 output_asm_insn ("pshy", operands
);
3474 output_asm_insn ("pulx", operands
);
3477 else if (SP_REG_P (operands
[1]))
3479 /* tsx, tsy preserve the flags */
3480 cc_status
= cc_prev_status
;
3481 output_asm_insn ("tsx", operands
);
3483 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3484 && GET_CODE (operands
[1]) == CONST_INT
3485 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3486 && find_reg_note (insn
, REG_WAS_0
, 0))
3488 if (INTVAL (operands
[1]) == 1)
3489 output_asm_insn ("in%0", operands
);
3491 output_asm_insn ("de%0", operands
);
3495 output_asm_insn ("ldx\t%1", operands
);
3500 if (D_REG_P (operands
[1]))
3502 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3504 m68hc11_output_swap (insn
, operands
);
3508 output_asm_insn ("std\t%t1", operands
);
3509 output_asm_insn ("ldy\t%t1", operands
);
3512 else if (X_REG_P (operands
[1]))
3514 /* When both D and X are dead, use the sequence xgdx, xgdy
3515 to move X into Y. The D and X registers are modified. */
3516 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3517 && dead_register_here (insn
, d_reg
))
3519 output_asm_insn ("xgdx", operands
);
3520 output_asm_insn ("xgdy", operands
);
3523 else if (!optimize_size
)
3525 output_asm_insn ("stx\t%t1", operands
);
3526 output_asm_insn ("ldy\t%t1", operands
);
3531 output_asm_insn ("pshx", operands
);
3532 output_asm_insn ("puly", operands
);
3535 else if (SP_REG_P (operands
[1]))
3537 /* tsx, tsy preserve the flags */
3538 cc_status
= cc_prev_status
;
3539 output_asm_insn ("tsy", operands
);
3541 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3542 && GET_CODE (operands
[1]) == CONST_INT
3543 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3544 && find_reg_note (insn
, REG_WAS_0
, 0))
3546 if (INTVAL (operands
[1]) == 1)
3547 output_asm_insn ("in%0", operands
);
3549 output_asm_insn ("de%0", operands
);
3553 output_asm_insn ("ldy\t%1", operands
);
3557 case HARD_SP_REGNUM
:
3558 if (D_REG_P (operands
[1]))
3560 m68hc11_notice_keep_cc (operands
[0]);
3561 output_asm_insn ("xgdx", operands
);
3562 output_asm_insn ("txs", operands
);
3563 output_asm_insn ("xgdx", operands
);
3565 else if (X_REG_P (operands
[1]))
3567 /* tys, txs preserve the flags */
3568 cc_status
= cc_prev_status
;
3569 output_asm_insn ("txs", operands
);
3571 else if (Y_REG_P (operands
[1]))
3573 /* tys, txs preserve the flags */
3574 cc_status
= cc_prev_status
;
3575 output_asm_insn ("tys", operands
);
3579 /* lds sets the flags but the des does not. */
3581 output_asm_insn ("lds\t%1", operands
);
3582 output_asm_insn ("des", operands
);
3587 fatal_insn ("invalid register in the move instruction", insn
);
3592 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3593 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3595 output_asm_insn ("sts\t%0", operands
);
3599 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3601 cc_status
= cc_prev_status
;
3602 switch (REGNO (operands
[1]))
3606 output_asm_insn ("psh%1", operands
);
3609 output_asm_insn ("pshb", operands
);
3610 output_asm_insn ("psha", operands
);
3618 /* Operand 1 must be a hard register. */
3619 if (!H_REG_P (operands
[1]))
3621 fatal_insn ("invalid operand in the instruction", insn
);
3624 reg
= REGNO (operands
[1]);
3628 output_asm_insn ("std\t%0", operands
);
3632 output_asm_insn ("stx\t%0", operands
);
3636 output_asm_insn ("sty\t%0", operands
);
3639 case HARD_SP_REGNUM
:
3643 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3645 output_asm_insn ("pshx", operands
);
3646 output_asm_insn ("tsx", operands
);
3647 output_asm_insn ("inx", operands
);
3648 output_asm_insn ("inx", operands
);
3649 output_asm_insn ("stx\t%0", operands
);
3650 output_asm_insn ("pulx", operands
);
3653 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3655 output_asm_insn ("sty\t%t0", operands
);
3656 output_asm_insn ("tsy", operands
);
3657 output_asm_insn ("sty\t%0", operands
);
3658 output_asm_insn ("ldy\t%t0", operands
);
3662 output_asm_insn ("stx\t%t0", operands
);
3663 output_asm_insn ("tsx", operands
);
3664 output_asm_insn ("stx\t%0", operands
);
3665 output_asm_insn ("ldx\t%t0", operands
);
3671 fatal_insn ("invalid register in the move instruction", insn
);
3677 m68hc11_gen_movqi (insn
, operands
)
3681 /* Move a register or memory to the same location.
3682 This is possible because such insn can appear
3683 in a non-optimizing mode. */
3684 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3686 cc_status
= cc_prev_status
;
3693 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3695 m68hc11_notice_keep_cc (operands
[0]);
3696 output_asm_insn ("tfr\t%1,%0", operands
);
3698 else if (H_REG_P (operands
[0]))
3700 if (Q_REG_P (operands
[0]))
3701 output_asm_insn ("lda%0\t%b1", operands
);
3702 else if (D_REG_P (operands
[0]))
3703 output_asm_insn ("ldab\t%b1", operands
);
3707 else if (H_REG_P (operands
[1]))
3709 if (Q_REG_P (operands
[1]))
3710 output_asm_insn ("sta%1\t%b0", operands
);
3711 else if (D_REG_P (operands
[1]))
3712 output_asm_insn ("stab\t%b0", operands
);
3718 rtx from
= operands
[1];
3719 rtx to
= operands
[0];
3721 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3722 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3723 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3724 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3730 ops
[0] = operands
[2];
3733 m68hc11_gen_movqi (insn
, ops
);
3735 ops
[1] = operands
[2];
3736 m68hc11_gen_movqi (insn
, ops
);
3740 /* !!!! SCz wrong here. */
3741 fatal_insn ("move insn not handled", insn
);
3746 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3748 output_asm_insn ("clr\t%b0", operands
);
3752 m68hc11_notice_keep_cc (operands
[0]);
3753 output_asm_insn ("movb\t%b1,%b0", operands
);
3761 if (H_REG_P (operands
[0]))
3763 switch (REGNO (operands
[0]))
3767 if (X_REG_P (operands
[1]))
3769 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3771 m68hc11_output_swap (insn
, operands
);
3775 output_asm_insn ("stx\t%t1", operands
);
3776 output_asm_insn ("ldab\t%T0", operands
);
3779 else if (Y_REG_P (operands
[1]))
3781 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3783 m68hc11_output_swap (insn
, operands
);
3787 output_asm_insn ("sty\t%t1", operands
);
3788 output_asm_insn ("ldab\t%T0", operands
);
3791 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3792 && GET_CODE (operands
[1]) == CONST_INT
3793 && (INTVAL (operands
[1]) == 1 || INTVAL (operands
[1]) == -1)
3794 && find_reg_note (insn
, REG_WAS_0
, 0))
3796 if (INTVAL (operands
[1]) == 1)
3797 output_asm_insn ("inc%b0", operands
);
3799 output_asm_insn ("dec%b0", operands
);
3801 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3802 && !DA_REG_P (operands
[1]))
3804 output_asm_insn ("ldab\t%b1", operands
);
3806 else if (DA_REG_P (operands
[1]))
3808 output_asm_insn ("tab", operands
);
3812 cc_status
= cc_prev_status
;
3818 if (X_REG_P (operands
[1]))
3820 output_asm_insn ("stx\t%t1", operands
);
3821 output_asm_insn ("ldaa\t%T0", operands
);
3823 else if (Y_REG_P (operands
[1]))
3825 output_asm_insn ("sty\t%t1", operands
);
3826 output_asm_insn ("ldaa\t%T0", operands
);
3828 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3829 && !DA_REG_P (operands
[1]))
3831 output_asm_insn ("ldaa\t%b1", operands
);
3833 else if (!DA_REG_P (operands
[1]))
3835 output_asm_insn ("tba", operands
);
3839 cc_status
= cc_prev_status
;
3844 if (D_REG_P (operands
[1]))
3846 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3848 m68hc11_output_swap (insn
, operands
);
3852 output_asm_insn ("stab\t%T1", operands
);
3853 output_asm_insn ("ldx\t%t1", operands
);
3857 else if (Y_REG_P (operands
[1]))
3859 output_asm_insn ("sty\t%t0", operands
);
3860 output_asm_insn ("ldx\t%t0", operands
);
3862 else if (GET_CODE (operands
[1]) == CONST_INT
)
3864 output_asm_insn ("ldx\t%1", operands
);
3866 else if (dead_register_here (insn
, d_reg
))
3868 output_asm_insn ("ldab\t%b1", operands
);
3869 output_asm_insn ("xgdx", operands
);
3871 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3873 output_asm_insn ("xgdx", operands
);
3874 output_asm_insn ("ldab\t%b1", operands
);
3875 output_asm_insn ("xgdx", operands
);
3879 output_asm_insn ("pshb", operands
);
3880 output_asm_insn ("ldab\t%b1", operands
);
3881 output_asm_insn ("stab\t%T1", operands
);
3882 output_asm_insn ("ldx\t%t1", operands
);
3883 output_asm_insn ("pulb", operands
);
3889 if (D_REG_P (operands
[1]))
3891 output_asm_insn ("stab\t%T1", operands
);
3892 output_asm_insn ("ldy\t%t1", operands
);
3895 else if (X_REG_P (operands
[1]))
3897 output_asm_insn ("stx\t%t1", operands
);
3898 output_asm_insn ("ldy\t%t1", operands
);
3901 else if (GET_CODE (operands
[1]) == CONST_INT
)
3903 output_asm_insn ("ldy\t%1", operands
);
3905 else if (dead_register_here (insn
, d_reg
))
3907 output_asm_insn ("ldab\t%b1", operands
);
3908 output_asm_insn ("xgdy", operands
);
3910 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3912 output_asm_insn ("xgdy", operands
);
3913 output_asm_insn ("ldab\t%b1", operands
);
3914 output_asm_insn ("xgdy", operands
);
3918 output_asm_insn ("pshb", operands
);
3919 output_asm_insn ("ldab\t%b1", operands
);
3920 output_asm_insn ("stab\t%T1", operands
);
3921 output_asm_insn ("ldy\t%t1", operands
);
3922 output_asm_insn ("pulb", operands
);
3928 fatal_insn ("invalid register in the instruction", insn
);
3932 else if (H_REG_P (operands
[1]))
3934 switch (REGNO (operands
[1]))
3938 output_asm_insn ("stab\t%b0", operands
);
3942 output_asm_insn ("staa\t%b0", operands
);
3946 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3950 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3954 fatal_insn ("invalid register in the move instruction", insn
);
3961 fatal_insn ("operand 1 must be a hard register", insn
);
3965 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3966 The source and destination must be D or A and the shift must
3969 m68hc11_gen_rotate (code
, insn
, operands
)
3976 if (GET_CODE (operands
[2]) != CONST_INT
3977 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3978 fatal_insn ("invalid rotate insn", insn
);
3980 val
= INTVAL (operands
[2]);
3981 if (code
== ROTATERT
)
3982 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3984 if (GET_MODE (operands
[0]) != QImode
)
3987 /* Rotate by 8-bits if the shift is within [5..11]. */
3988 if (val
>= 5 && val
<= 11)
3991 output_asm_insn ("exg\ta,b", operands
);
3994 output_asm_insn ("psha", operands
);
3995 output_asm_insn ("tba", operands
);
3996 output_asm_insn ("pulb", operands
);
4001 /* If the shift is big, invert the rotation. */
4011 /* Set the carry to bit-15, but don't change D yet. */
4012 if (GET_MODE (operands
[0]) != QImode
)
4014 output_asm_insn ("asra", operands
);
4015 output_asm_insn ("rola", operands
);
4018 /* Rotate B first to move the carry to bit-0. */
4019 if (D_REG_P (operands
[0]))
4020 output_asm_insn ("rolb", operands
);
4022 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
4023 output_asm_insn ("rola", operands
);
4030 /* Set the carry to bit-8 of D. */
4031 if (GET_MODE (operands
[0]) != QImode
)
4032 output_asm_insn ("tap", operands
);
4034 /* Rotate B first to move the carry to bit-7. */
4035 if (D_REG_P (operands
[0]))
4036 output_asm_insn ("rorb", operands
);
4038 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
4039 output_asm_insn ("rora", operands
);
4046 /* Store in cc_status the expressions that the condition codes will
4047 describe after execution of an instruction whose pattern is EXP.
4048 Do not alter them if the instruction would not alter the cc's. */
4051 m68hc11_notice_update_cc (exp
, insn
)
4053 rtx insn ATTRIBUTE_UNUSED
;
4055 /* recognize SET insn's. */
4056 if (GET_CODE (exp
) == SET
)
4058 /* Jumps do not alter the cc's. */
4059 if (SET_DEST (exp
) == pc_rtx
)
4062 /* NOTE: most instructions don't affect the carry bit, but the
4063 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
4064 the conditions.h header. */
4066 /* Function calls clobber the cc's. */
4067 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
4072 /* Tests and compares set the cc's in predictable ways. */
4073 else if (SET_DEST (exp
) == cc0_rtx
)
4075 cc_status
.flags
= 0;
4076 cc_status
.value1
= XEXP (exp
, 0);
4077 cc_status
.value2
= XEXP (exp
, 1);
4081 /* All other instructions affect the condition codes. */
4082 cc_status
.flags
= 0;
4083 cc_status
.value1
= XEXP (exp
, 0);
4084 cc_status
.value2
= XEXP (exp
, 1);
4089 /* Default action if we haven't recognized something
4090 and returned earlier. */
4094 if (cc_status
.value2
!= 0)
4095 switch (GET_CODE (cc_status
.value2
))
4097 /* These logical operations can generate several insns.
4098 The flags are setup according to what is generated. */
4104 /* The (not ...) generates several 'com' instructions for
4105 non QImode. We have to invalidate the flags. */
4107 if (GET_MODE (cc_status
.value2
) != QImode
)
4119 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4120 cc_status
.flags
|= CC_NO_OVERFLOW
;
4123 /* The asl sets the overflow bit in such a way that this
4124 makes the flags unusable for a next compare insn. */
4128 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4129 cc_status
.flags
|= CC_NO_OVERFLOW
;
4132 /* A load/store instruction does not affect the carry. */
4137 cc_status
.flags
|= CC_NO_OVERFLOW
;
4143 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4145 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4146 cc_status
.value2
= 0;
4149 /* The current instruction does not affect the flags but changes
4150 the register 'reg'. See if the previous flags can be kept for the
4151 next instruction to avoid a comparison. */
4153 m68hc11_notice_keep_cc (reg
)
4157 || cc_prev_status
.value1
== 0
4158 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4159 || (cc_prev_status
.value2
4160 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4163 cc_status
= cc_prev_status
;
4168 /* Machine Specific Reorg. */
4170 /* Z register replacement:
4172 GCC treats the Z register as an index base address register like
4173 X or Y. In general, it uses it during reload to compute the address
4174 of some operand. This helps the reload pass to avoid to fall into the
4175 register spill failure.
4177 The Z register is in the A_REGS class. In the machine description,
4178 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4180 It can appear everywhere an X or Y register can appear, except for
4181 some templates in the clobber section (when a clobber of X or Y is asked).
4182 For a given instruction, the template must ensure that no more than
4183 2 'A' registers are used. Otherwise, the register replacement is not
4186 To replace the Z register, the algorithm is not terrific:
4187 1. Insns that do not use the Z register are not changed
4188 2. When a Z register is used, we scan forward the insns to see
4189 a potential register to use: either X or Y and sometimes D.
4190 We stop when a call, a label or a branch is seen, or when we
4191 detect that both X and Y are used (probably at different times, but it does
4193 3. The register that will be used for the replacement of Z is saved
4194 in a .page0 register or on the stack. If the first instruction that
4195 used Z, uses Z as an input, the value is loaded from another .page0
4196 register. The replacement register is pushed on the stack in the
4197 rare cases where a compare insn uses Z and we couldn't find if X/Y
4199 4. The Z register is replaced in all instructions until we reach
4200 the end of the Z-block, as detected by step 2.
4201 5. If we detect that Z is still alive, its value is saved.
4202 If the replacement register is alive, its old value is loaded.
4204 The Z register can be disabled with -ffixed-z.
4214 int must_restore_reg
;
4225 int save_before_last
;
4226 int z_loaded_with_sp
;
4229 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4230 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4231 static void m68hc11_z_replacement
PARAMS ((rtx
));
4232 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4234 int z_replacement_completed
= 0;
4236 /* Analyze the insn to find out which replacement register to use and
4237 the boundaries of the replacement.
4238 Returns 0 if we reached the last insn to be replaced, 1 if we can
4239 continue replacement in next insns. */
4242 m68hc11_check_z_replacement (insn
, info
)
4244 struct replace_info
*info
;
4246 int this_insn_uses_ix
;
4247 int this_insn_uses_iy
;
4248 int this_insn_uses_z
;
4249 int this_insn_uses_z_in_dst
;
4250 int this_insn_uses_d
;
4254 /* A call is said to clobber the Z register, we don't need
4255 to save the value of Z. We also don't need to restore
4256 the replacement register (unless it is used by the call). */
4257 if (GET_CODE (insn
) == CALL_INSN
)
4259 body
= PATTERN (insn
);
4261 info
->can_use_d
= 0;
4263 /* If the call is an indirect call with Z, we have to use the
4264 Y register because X can be used as an input (D+X).
4265 We also must not save Z nor restore Y. */
4266 if (reg_mentioned_p (z_reg
, body
))
4268 insn
= NEXT_INSN (insn
);
4271 info
->found_call
= 1;
4272 info
->must_restore_reg
= 0;
4273 info
->last
= NEXT_INSN (insn
);
4275 info
->need_save_z
= 0;
4278 if (GET_CODE (insn
) == CODE_LABEL
4279 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4282 if (GET_CODE (insn
) == JUMP_INSN
)
4284 if (reg_mentioned_p (z_reg
, insn
) == 0)
4287 info
->can_use_d
= 0;
4288 info
->must_save_reg
= 0;
4289 info
->must_restore_reg
= 0;
4290 info
->need_save_z
= 0;
4291 info
->last
= NEXT_INSN (insn
);
4294 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4299 /* Z register dies here. */
4300 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4302 body
= PATTERN (insn
);
4303 if (GET_CODE (body
) == SET
)
4305 rtx src
= XEXP (body
, 1);
4306 rtx dst
= XEXP (body
, 0);
4308 /* Condition code is set here. We have to restore the X/Y and
4309 save into Z before any test/compare insn because once we save/restore
4310 we can change the condition codes. When the compare insn uses Z and
4311 we can't use X/Y, the comparison is made with the *ZREG soft register
4312 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4315 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4316 || (GET_CODE (src
) == COMPARE
&&
4317 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4318 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4320 if (insn
== info
->first
)
4322 info
->must_load_z
= 0;
4323 info
->must_save_reg
= 0;
4324 info
->must_restore_reg
= 0;
4325 info
->need_save_z
= 0;
4326 info
->found_call
= 1;
4327 info
->regno
= SOFT_Z_REGNUM
;
4328 info
->last
= NEXT_INSN (insn
);
4332 if (reg_mentioned_p (z_reg
, src
) == 0)
4334 info
->can_use_d
= 0;
4338 if (insn
!= info
->first
)
4341 /* Compare insn which uses Z. We have to save/restore the X/Y
4342 register without modifying the condition codes. For this
4343 we have to use a push/pop insn. */
4344 info
->must_push_reg
= 1;
4348 /* Z reg is set to something new. We don't need to load it. */
4351 if (!reg_mentioned_p (z_reg
, src
))
4353 /* Z reg is used before being set. Treat this as
4354 a new sequence of Z register replacement. */
4355 if (insn
!= info
->first
)
4359 info
->must_load_z
= 0;
4361 info
->z_set_count
++;
4362 info
->z_value
= src
;
4364 info
->z_loaded_with_sp
= 1;
4366 else if (reg_mentioned_p (z_reg
, dst
))
4367 info
->can_use_d
= 0;
4369 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4370 | reg_mentioned_p (d_reg
, dst
);
4371 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4372 | reg_mentioned_p (ix_reg
, dst
);
4373 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4374 | reg_mentioned_p (iy_reg
, dst
);
4375 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4377 /* If z is used as an address operand (like (MEM (reg z))),
4378 we can't replace it with d. */
4379 if (this_insn_uses_z
&& !Z_REG_P (src
)
4380 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4381 && Z_REG_P (XEXP (src
, 0))
4382 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4383 && insn
== info
->first
4384 && dead_register_here (insn
, d_reg
)))
4385 info
->can_use_d
= 0;
4387 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4388 if (TARGET_M6812
&& !z_dies_here
4389 && ((this_insn_uses_z
&& side_effects_p (src
))
4390 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4392 info
->need_save_z
= 1;
4393 info
->z_set_count
++;
4395 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4397 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4399 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4402 if (this_insn_uses_d
)
4403 info
->can_use_d
= 0;
4405 /* IX and IY are used at the same time, we have to restore
4406 the value of the scratch register before this insn. */
4407 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4412 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4413 info
->can_use_d
= 0;
4415 if (info
->x_used
== 0 && this_insn_uses_ix
)
4419 /* We have a (set (REG:HI X) (REG:HI Z)).
4420 Since we use Z as the replacement register, this insn
4421 is no longer necessary. We turn it into a note. We must
4422 not reload the old value of X. */
4423 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4427 info
->need_save_z
= 0;
4430 info
->must_save_reg
= 0;
4431 info
->must_restore_reg
= 0;
4432 info
->found_call
= 1;
4433 info
->can_use_d
= 0;
4434 PUT_CODE (insn
, NOTE
);
4435 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4436 NOTE_SOURCE_FILE (insn
) = 0;
4437 info
->last
= NEXT_INSN (insn
);
4442 && (rtx_equal_p (src
, z_reg
)
4443 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4447 info
->need_save_z
= 0;
4450 info
->last
= NEXT_INSN (insn
);
4451 info
->must_save_reg
= 0;
4452 info
->must_restore_reg
= 0;
4454 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4455 && !reg_mentioned_p (ix_reg
, src
))
4460 info
->need_save_z
= 0;
4462 else if (TARGET_M6812
&& side_effects_p (src
))
4465 info
->must_restore_reg
= 0;
4470 info
->save_before_last
= 1;
4472 info
->must_restore_reg
= 0;
4473 info
->last
= NEXT_INSN (insn
);
4475 else if (info
->can_use_d
)
4477 info
->last
= NEXT_INSN (insn
);
4483 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4484 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4486 info
->need_save_z
= 0;
4488 info
->last
= NEXT_INSN (insn
);
4489 info
->regno
= HARD_X_REGNUM
;
4490 info
->must_save_reg
= 0;
4491 info
->must_restore_reg
= 0;
4494 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4496 info
->regno
= HARD_X_REGNUM
;
4497 info
->must_restore_reg
= 0;
4498 info
->must_save_reg
= 0;
4502 if (info
->y_used
== 0 && this_insn_uses_iy
)
4506 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4510 info
->need_save_z
= 0;
4513 info
->must_save_reg
= 0;
4514 info
->must_restore_reg
= 0;
4515 info
->found_call
= 1;
4516 info
->can_use_d
= 0;
4517 PUT_CODE (insn
, NOTE
);
4518 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4519 NOTE_SOURCE_FILE (insn
) = 0;
4520 info
->last
= NEXT_INSN (insn
);
4525 && (rtx_equal_p (src
, z_reg
)
4526 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4531 info
->need_save_z
= 0;
4533 info
->last
= NEXT_INSN (insn
);
4534 info
->must_save_reg
= 0;
4535 info
->must_restore_reg
= 0;
4537 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4538 && !reg_mentioned_p (iy_reg
, src
))
4543 info
->need_save_z
= 0;
4545 else if (TARGET_M6812
&& side_effects_p (src
))
4548 info
->must_restore_reg
= 0;
4553 info
->save_before_last
= 1;
4555 info
->must_restore_reg
= 0;
4556 info
->last
= NEXT_INSN (insn
);
4558 else if (info
->can_use_d
)
4560 info
->last
= NEXT_INSN (insn
);
4567 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4568 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4570 info
->need_save_z
= 0;
4572 info
->last
= NEXT_INSN (insn
);
4573 info
->regno
= HARD_Y_REGNUM
;
4574 info
->must_save_reg
= 0;
4575 info
->must_restore_reg
= 0;
4578 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4580 info
->regno
= HARD_Y_REGNUM
;
4581 info
->must_restore_reg
= 0;
4582 info
->must_save_reg
= 0;
4588 info
->need_save_z
= 0;
4590 if (info
->last
== 0)
4591 info
->last
= NEXT_INSN (insn
);
4594 return info
->last
!= NULL_RTX
? 0 : 1;
4596 if (GET_CODE (body
) == PARALLEL
)
4599 char ix_clobber
= 0;
4600 char iy_clobber
= 0;
4602 this_insn_uses_iy
= 0;
4603 this_insn_uses_ix
= 0;
4604 this_insn_uses_z
= 0;
4606 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4609 int uses_ix
, uses_iy
, uses_z
;
4611 x
= XVECEXP (body
, 0, i
);
4613 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4614 info
->can_use_d
= 0;
4616 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4617 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4618 uses_z
= reg_mentioned_p (z_reg
, x
);
4619 if (GET_CODE (x
) == CLOBBER
)
4621 ix_clobber
|= uses_ix
;
4622 iy_clobber
|= uses_iy
;
4623 z_clobber
|= uses_z
;
4627 this_insn_uses_ix
|= uses_ix
;
4628 this_insn_uses_iy
|= uses_iy
;
4629 this_insn_uses_z
|= uses_z
;
4631 if (uses_z
&& GET_CODE (x
) == SET
)
4633 rtx dst
= XEXP (x
, 0);
4636 info
->z_set_count
++;
4638 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4639 info
->need_save_z
= 1;
4642 info
->need_save_z
= 0;
4646 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4647 this_insn_uses_ix
, this_insn_uses_iy
,
4648 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4651 if (this_insn_uses_z
)
4652 info
->can_use_d
= 0;
4654 if (z_clobber
&& info
->first
!= insn
)
4656 info
->need_save_z
= 0;
4660 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4662 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4664 info
->must_load_z
= 0;
4666 if (dead_register_here (insn
, d_reg
))
4668 info
->regno
= HARD_D_REGNUM
;
4669 info
->must_save_reg
= 0;
4670 info
->must_restore_reg
= 0;
4672 else if (dead_register_here (insn
, ix_reg
))
4674 info
->regno
= HARD_X_REGNUM
;
4675 info
->must_save_reg
= 0;
4676 info
->must_restore_reg
= 0;
4678 else if (dead_register_here (insn
, iy_reg
))
4680 info
->regno
= HARD_Y_REGNUM
;
4681 info
->must_save_reg
= 0;
4682 info
->must_restore_reg
= 0;
4684 if (info
->regno
>= 0)
4686 info
->last
= NEXT_INSN (insn
);
4689 if (this_insn_uses_ix
== 0)
4691 info
->regno
= HARD_X_REGNUM
;
4692 info
->must_save_reg
= 1;
4693 info
->must_restore_reg
= 1;
4695 else if (this_insn_uses_iy
== 0)
4697 info
->regno
= HARD_Y_REGNUM
;
4698 info
->must_save_reg
= 1;
4699 info
->must_restore_reg
= 1;
4703 info
->regno
= HARD_D_REGNUM
;
4704 info
->must_save_reg
= 1;
4705 info
->must_restore_reg
= 1;
4707 info
->last
= NEXT_INSN (insn
);
4711 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4712 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4714 if (this_insn_uses_z
)
4716 if (info
->y_used
== 0 && iy_clobber
)
4718 info
->regno
= HARD_Y_REGNUM
;
4719 info
->must_save_reg
= 0;
4720 info
->must_restore_reg
= 0;
4722 if (info
->first
!= insn
4723 && ((info
->y_used
&& ix_clobber
)
4724 || (info
->x_used
&& iy_clobber
)))
4727 info
->last
= NEXT_INSN (insn
);
4728 info
->save_before_last
= 1;
4732 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4734 if (this_insn_uses_z
)
4736 fatal_insn ("cannot do z-register replacement", insn
);
4740 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4747 if (iy_clobber
|| z_clobber
)
4749 info
->last
= NEXT_INSN (insn
);
4750 info
->save_before_last
= 1;
4755 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4762 if (ix_clobber
|| z_clobber
)
4764 info
->last
= NEXT_INSN (insn
);
4765 info
->save_before_last
= 1;
4772 info
->need_save_z
= 0;
4776 if (GET_CODE (body
) == CLOBBER
)
4779 /* IX and IY are used at the same time, we have to restore
4780 the value of the scratch register before this insn. */
4781 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4785 if (info
->x_used
== 0 && this_insn_uses_ix
)
4793 if (info
->y_used
== 0 && this_insn_uses_iy
)
4807 m68hc11_find_z_replacement (insn
, info
)
4809 struct replace_info
*info
;
4813 info
->replace_reg
= NULL_RTX
;
4814 info
->must_load_z
= 1;
4815 info
->need_save_z
= 1;
4816 info
->must_save_reg
= 1;
4817 info
->must_restore_reg
= 1;
4821 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4822 info
->found_call
= 0;
4826 info
->z_set_count
= 0;
4827 info
->z_value
= NULL_RTX
;
4828 info
->must_push_reg
= 0;
4829 info
->save_before_last
= 0;
4830 info
->z_loaded_with_sp
= 0;
4832 /* Scan the insn forward to find an address register that is not used.
4834 - the flow of the program changes,
4835 - when we detect that both X and Y are necessary,
4836 - when the Z register dies,
4837 - when the condition codes are set. */
4839 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4841 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4845 /* May be we can use Y or X if they contain the same value as Z.
4846 This happens very often after the reload. */
4847 if (info
->z_set_count
== 1)
4849 rtx p
= info
->first
;
4854 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4856 else if (info
->y_used
)
4858 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4860 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4863 info
->regno
= HARD_Y_REGNUM
;
4865 info
->regno
= HARD_X_REGNUM
;
4866 info
->must_load_z
= 0;
4867 info
->must_save_reg
= 0;
4868 info
->must_restore_reg
= 0;
4869 info
->found_call
= 1;
4872 if (info
->z_set_count
== 0)
4873 info
->need_save_z
= 0;
4876 info
->need_save_z
= 0;
4878 if (info
->last
== 0)
4881 if (info
->regno
>= 0)
4884 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4886 else if (info
->can_use_d
)
4888 reg
= HARD_D_REGNUM
;
4889 info
->replace_reg
= d_reg
;
4891 else if (info
->x_used
)
4893 reg
= HARD_Y_REGNUM
;
4894 info
->replace_reg
= iy_reg
;
4898 reg
= HARD_X_REGNUM
;
4899 info
->replace_reg
= ix_reg
;
4903 if (info
->must_save_reg
&& info
->must_restore_reg
)
4905 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4907 info
->must_save_reg
= 0;
4908 info
->must_restore_reg
= 0;
4913 /* The insn uses the Z register. Find a replacement register for it
4914 (either X or Y) and replace it in the insn and the next ones until
4915 the flow changes or the replacement register is used. Instructions
4916 are emited before and after the Z-block to preserve the value of
4917 Z and of the replacement register. */
4920 m68hc11_z_replacement (insn
)
4925 struct replace_info info
;
4927 /* Find trivial case where we only need to replace z with the
4928 equivalent soft register. */
4929 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4931 rtx body
= PATTERN (insn
);
4932 rtx src
= XEXP (body
, 1);
4933 rtx dst
= XEXP (body
, 0);
4935 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4937 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4940 else if (Z_REG_P (src
)
4941 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4943 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4946 else if (D_REG_P (dst
)
4947 && m68hc11_arith_operator (src
, GET_MODE (src
))
4948 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4950 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4953 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4954 && INTVAL (src
) == 0)
4956 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4957 /* Force it to be re-recognized. */
4958 INSN_CODE (insn
) = -1;
4963 m68hc11_find_z_replacement (insn
, &info
);
4965 replace_reg
= info
.replace_reg
;
4966 replace_reg_qi
= NULL_RTX
;
4968 /* Save the X register in a .page0 location. */
4969 if (info
.must_save_reg
&& !info
.must_push_reg
)
4973 if (info
.must_push_reg
&& 0)
4974 dst
= gen_rtx (MEM
, HImode
,
4975 gen_rtx (PRE_DEC
, HImode
,
4976 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4978 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4980 emit_insn_before (gen_movhi (dst
,
4981 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4983 if (info
.must_load_z
&& !info
.must_push_reg
)
4985 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4986 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4991 /* Replace all occurrence of Z by replace_reg.
4992 Stop when the last instruction to replace is reached.
4993 Also stop when we detect a change in the flow (but it's not
4994 necessary; just safeguard). */
4996 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
5000 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
5003 if (GET_CODE (insn
) != INSN
5004 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
5007 body
= PATTERN (insn
);
5008 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5009 || GET_CODE (body
) == ASM_OPERANDS
5010 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5014 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
5016 printf ("Reg mentioned here...:\n");
5021 /* Stack pointer was decremented by 2 due to the push.
5022 Correct that by adding 2 to the destination. */
5023 if (info
.must_push_reg
5024 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
5028 src
= SET_SRC (body
);
5029 dst
= SET_DEST (body
);
5030 if (SP_REG_P (src
) && Z_REG_P (dst
))
5031 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
5034 /* Replace any (REG:HI Z) occurrence by either X or Y. */
5035 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
5037 INSN_CODE (insn
) = -1;
5038 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
5039 fatal_insn ("cannot do z-register replacement", insn
);
5042 /* Likewise for (REG:QI Z). */
5043 if (reg_mentioned_p (z_reg
, insn
))
5045 if (replace_reg_qi
== NULL_RTX
)
5046 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
5047 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
5050 /* If there is a REG_INC note on Z, replace it with a
5051 REG_INC note on the replacement register. This is necessary
5052 to make sure that the flow pass will identify the change
5053 and it will not remove a possible insn that saves Z. */
5054 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
5056 if (REG_NOTE_KIND (note
) == REG_INC
5057 && GET_CODE (XEXP (note
, 0)) == REG
5058 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
5060 XEXP (note
, 0) = replace_reg
;
5064 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5068 /* Save Z before restoring the old value. */
5069 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
5071 rtx save_pos_insn
= insn
;
5073 /* If Z is clobber by the last insn, we have to save its value
5074 before the last instruction. */
5075 if (info
.save_before_last
)
5076 save_pos_insn
= PREV_INSN (save_pos_insn
);
5078 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
5079 gen_rtx (REG
, HImode
, info
.regno
)),
5083 if (info
.must_push_reg
&& info
.last
)
5087 body
= PATTERN (info
.last
);
5088 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
5090 gen_rtx (USE
, VOIDmode
,
5092 gen_rtx (USE
, VOIDmode
,
5093 gen_rtx (REG
, HImode
,
5095 PATTERN (info
.last
) = new_body
;
5097 /* Force recognition on insn since we changed it. */
5098 INSN_CODE (insn
) = -1;
5100 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
5102 fatal_insn ("invalid Z register replacement for insn", insn
);
5104 insn
= NEXT_INSN (info
.last
);
5107 /* Restore replacement register unless it was died. */
5108 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
5112 if (info
.must_push_reg
&& 0)
5113 dst
= gen_rtx (MEM
, HImode
,
5114 gen_rtx (POST_INC
, HImode
,
5115 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
5117 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
5119 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
5126 /* Scan all the insn and re-affects some registers
5127 - The Z register (if it was used), is affected to X or Y depending
5128 on the instruction. */
5131 m68hc11_reassign_regs (first
)
5136 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5137 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5138 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5139 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5141 /* Scan all insns to replace Z by X or Y preserving the old value
5142 of X/Y and restoring it afterward. */
5144 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5148 if (GET_CODE (insn
) == CODE_LABEL
5149 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5152 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5155 body
= PATTERN (insn
);
5156 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5159 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5160 || GET_CODE (body
) == ASM_OPERANDS
5161 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5164 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5165 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5168 /* If Z appears in this insn, replace it in the current insn
5169 and the next ones until the flow changes or we have to
5170 restore back the replacement register. */
5172 if (reg_mentioned_p (z_reg
, body
))
5174 m68hc11_z_replacement (insn
);
5179 printf ("insn not handled by Z replacement:\n");
5188 m68hc11_reorg (first
)
5194 z_replacement_completed
= 0;
5195 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5197 /* Some RTX are shared at this point. This breaks the Z register
5198 replacement, unshare everything. */
5199 unshare_all_rtl_again (first
);
5201 /* Force a split of all splitable insn. This is necessary for the
5202 Z register replacement mechanism because we end up with basic insns. */
5203 split_all_insns_noflow ();
5206 z_replacement_completed
= 1;
5207 m68hc11_reassign_regs (first
);
5210 compute_bb_for_insn ();
5212 /* After some splitting, there are some oportunities for CSE pass.
5213 This happens quite often when 32-bit or above patterns are split. */
5214 if (optimize
> 0 && split_done
)
5216 reload_cse_regs (first
);
5219 /* Re-create the REG_DEAD notes. These notes are used in the machine
5220 description to use the best assembly directives. */
5223 /* Before recomputing the REG_DEAD notes, remove all of them.
5224 This is necessary because the reload_cse_regs() pass can
5225 have replaced some (MEM) with a register. In that case,
5226 the REG_DEAD that could exist for that register may become
5228 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5234 pnote
= ®_NOTES (insn
);
5237 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5238 *pnote
= XEXP (*pnote
, 1);
5240 pnote
= &XEXP (*pnote
, 1);
5245 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5248 z_replacement_completed
= 2;
5250 /* If optimizing, then go ahead and split insns that must be
5251 split after Z register replacement. This gives more opportunities
5252 for peephole (in particular for consecutives xgdx/xgdy). */
5254 split_all_insns_noflow ();
5256 /* Once insns are split after the z_replacement_completed == 2,
5257 we must not re-run the life_analysis. The xgdx/xgdy patterns
5258 are not recognized and the life_analysis pass removes some
5259 insns because it thinks some (SETs) are noops or made to dead
5260 stores (which is false due to the swap).
5262 Do a simple pass to eliminate the noop set that the final
5263 split could generate (because it was easier for split definition). */
5267 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5271 if (INSN_DELETED_P (insn
))
5273 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5276 /* Remove the (set (R) (R)) insns generated by some splits. */
5277 body
= PATTERN (insn
);
5278 if (GET_CODE (body
) == SET
5279 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5281 PUT_CODE (insn
, NOTE
);
5282 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5283 NOTE_SOURCE_FILE (insn
) = 0;
5291 /* Cost functions. */
5293 /* Cost of moving memory. */
5295 m68hc11_memory_move_cost (mode
, class, in
)
5296 enum machine_mode mode
;
5297 enum reg_class
class;
5298 int in ATTRIBUTE_UNUSED
;
5300 if (class <= H_REGS
&& class > NO_REGS
)
5302 if (GET_MODE_SIZE (mode
) <= 2)
5303 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5305 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5309 if (GET_MODE_SIZE (mode
) <= 2)
5310 return COSTS_N_INSNS (3);
5312 return COSTS_N_INSNS (4);
5317 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5318 Reload does not check the constraint of set insns when the two registers
5319 have a move cost of 2. Setting a higher cost will force reload to check
5322 m68hc11_register_move_cost (mode
, from
, to
)
5323 enum machine_mode mode
;
5324 enum reg_class from
;
5327 /* All costs are symmetric, so reduce cases by putting the
5328 lower number class as the destination. */
5331 enum reg_class tmp
= to
;
5332 to
= from
, from
= tmp
;
5335 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5336 else if (from
<= S_REGS
)
5337 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5339 return COSTS_N_INSNS (2);
5343 /* Provide the costs of an addressing mode that contains ADDR.
5344 If ADDR is not a valid address, its cost is irrelevant. */
5347 m68hc11_address_cost (addr
)
5352 switch (GET_CODE (addr
))
5355 /* Make the cost of hard registers and specially SP, FP small. */
5356 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5373 register rtx plus0
= XEXP (addr
, 0);
5374 register rtx plus1
= XEXP (addr
, 1);
5376 if (GET_CODE (plus0
) != REG
)
5379 switch (GET_CODE (plus1
))
5382 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5383 || INTVAL (plus1
) < m68hc11_min_offset
)
5385 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5389 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5411 if (SP_REG_P (XEXP (addr
, 0)))
5420 printf ("Address cost: %d for :", cost
);
5429 m68hc11_shift_cost (mode
, x
, shift
)
5430 enum machine_mode mode
;
5436 total
= rtx_cost (x
, SET
);
5438 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5439 else if (mode
== HImode
)
5440 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5441 else if (shift
== 8 || shift
== 16 || shift
== 32)
5442 total
+= m68hc11_cost
->shiftHI_const
[8];
5443 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5445 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5448 /* For SI and others, the cost is higher. */
5449 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5450 total
*= GET_MODE_SIZE (mode
) / 2;
5452 /* When optimizing for size, make shift more costly so that
5453 multiplications are preferred. */
5454 if (optimize_size
&& (shift
% 8) != 0)
5461 m68hc11_rtx_costs_1 (x
, code
, outer_code
)
5464 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5466 enum machine_mode mode
= GET_MODE (x
);
5477 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5479 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5482 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5483 total
+= m68hc11_cost
->shift_var
;
5489 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5490 total
+= m68hc11_cost
->logical
;
5492 /* Logical instructions are byte instructions only. */
5493 total
*= GET_MODE_SIZE (mode
);
5498 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5499 total
+= m68hc11_cost
->add
;
5500 if (GET_MODE_SIZE (mode
) > 2)
5502 total
*= GET_MODE_SIZE (mode
) / 2;
5509 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5513 total
+= m68hc11_cost
->divQI
;
5517 total
+= m68hc11_cost
->divHI
;
5522 total
+= m68hc11_cost
->divSI
;
5528 /* mul instruction produces 16-bit result. */
5529 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5530 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5531 return m68hc11_cost
->multQI
5532 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5533 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5535 /* emul instruction produces 32-bit result for 68HC12. */
5536 if (TARGET_M6812
&& mode
== SImode
5537 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5538 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5539 return m68hc11_cost
->multHI
5540 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5541 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5543 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5547 total
+= m68hc11_cost
->multQI
;
5551 total
+= m68hc11_cost
->multHI
;
5556 total
+= m68hc11_cost
->multSI
;
5563 extra_cost
= COSTS_N_INSNS (2);
5570 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5573 return total
+ COSTS_N_INSNS (1);
5577 return total
+ COSTS_N_INSNS (2);
5581 return total
+ COSTS_N_INSNS (4);
5583 return total
+ COSTS_N_INSNS (8);
5586 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5587 return COSTS_N_INSNS (1);
5589 return COSTS_N_INSNS (1);
5592 return COSTS_N_INSNS (4);
5597 m68hc11_rtx_costs (x
, code
, outer_code
, total
)
5599 int code
, outer_code
;
5604 /* Constants are cheap. Moving them in registers must be avoided
5605 because most instructions do not handle two register operands. */
5611 /* Logical and arithmetic operations with a constant operand are
5612 better because they are not supported with two registers. */
5614 if (outer_code
== SET
&& x
== const0_rtx
)
5615 /* After reload, the reload_cse pass checks the cost to change
5616 a SET into a PLUS. Make const0 cheap then. */
5617 *total
= 1 - reload_completed
;
5622 if (outer_code
== SET
)
5623 *total
= 1 - reload_completed
;
5645 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5654 /* print_options - called at the start of the code generation for a
5657 extern char *asm_file_name
;
5660 #include <sys/types.h>
5669 extern int save_argc
;
5670 extern char **save_argv
;
5672 fprintf (out
, ";;; Command:\t");
5673 for (i
= 0; i
< save_argc
; i
++)
5675 fprintf (out
, "%s", save_argv
[i
]);
5676 if (i
+ 1 < save_argc
)
5679 fprintf (out
, "\n");
5681 a_time
= ctime (&c_time
);
5682 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5685 #define __VERSION__ "[unknown]"
5687 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5689 fprintf (out
, ";;; (META)compiled by CC.\n");
5694 m68hc11_asm_file_start (out
, main_file
)
5696 const char *main_file
;
5698 fprintf (out
, ";;;-----------------------------------------\n");
5699 fprintf (out
, ";;; Start %s gcc assembly output\n",
5702 : TARGET_M68S12
? "MC68HCS12" : "MC68HC12");
5703 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5704 print_options (out
);
5705 fprintf (out
, ";;;-----------------------------------------\n");
5706 output_file_directive (out
, main_file
);
5709 fprintf (out
, "\t.mode mshort\n");
5711 fprintf (out
, "\t.mode mlong\n");
5716 m68hc11_asm_out_constructor (symbol
, priority
)
5720 default_ctor_section_asm_out_constructor (symbol
, priority
);
5721 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5725 m68hc11_asm_out_destructor (symbol
, priority
)
5729 default_dtor_section_asm_out_destructor (symbol
, priority
);
5730 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5733 #include "gt-m68hc11.h"