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_shift_cost
PARAMS ((enum machine_mode
, rtx
, int));
71 static int m68hc11_rtx_costs_1
PARAMS ((rtx
, enum rtx_code
, enum rtx_code
));
72 static bool m68hc11_rtx_costs
PARAMS ((rtx
, int, int, int *));
73 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
74 static tree m68hc11_handle_fntype_attribute
PARAMS ((tree
*, tree
, tree
, int, bool *));
75 const struct attribute_spec m68hc11_attribute_table
[];
77 void create_regs_rtx
PARAMS ((void));
79 static void asm_print_register
PARAMS ((FILE *, int));
80 static void m68hc11_output_function_epilogue
PARAMS ((FILE *, HOST_WIDE_INT
));
81 static void m68hc11_asm_out_constructor
PARAMS ((rtx
, int));
82 static void m68hc11_asm_out_destructor
PARAMS ((rtx
, int));
83 static void m68hc11_encode_section_info
PARAMS((tree
, int));
84 static int autoinc_mode
PARAMS((rtx
));
85 static int m68hc11_make_autoinc_notes
PARAMS((rtx
*, void *));
87 /* Must be set to 1 to produce debug messages. */
90 extern FILE *asm_out_file
;
95 rtx m68hc11_soft_tmp_reg
;
96 static GTY(()) rtx stack_push_word
;
97 static GTY(()) rtx stack_pop_word
;
98 static GTY(()) rtx z_reg
;
99 static GTY(()) rtx z_reg_qi
;
100 static int regs_inited
= 0;
102 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
103 int current_function_interrupt
;
105 /* Set to 1 by expand_prologue() when the function is a trap handler. */
106 int current_function_trap
;
108 /* Set to 1 when the current function is placed in 68HC12 banked
109 memory and must return with rtc. */
110 int current_function_far
;
112 /* Min offset that is valid for the indirect addressing mode. */
113 HOST_WIDE_INT m68hc11_min_offset
= 0;
115 /* Max offset that is valid for the indirect addressing mode. */
116 HOST_WIDE_INT m68hc11_max_offset
= 256;
118 /* The class value for base registers. */
119 enum reg_class m68hc11_base_reg_class
= A_REGS
;
121 /* The class value for index registers. This is NO_REGS for 68HC11. */
122 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
124 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
126 /* Tables that tell whether a given hard register is valid for
127 a base or an index register. It is filled at init time depending
128 on the target processor. */
129 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
130 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
132 /* A correction offset which is applied to the stack pointer.
133 This is 1 for 68HC11 and 0 for 68HC12. */
134 int m68hc11_sp_correction
;
136 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
137 rtx m68hc11_compare_op0
;
138 rtx m68hc11_compare_op1
;
141 const struct processor_costs
*m68hc11_cost
;
143 /* Costs for a 68HC11. */
144 static const struct processor_costs m6811_cost
= {
149 /* non-constant shift */
152 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
153 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
154 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
157 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
158 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
159 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
160 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
161 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
162 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
167 COSTS_N_INSNS (20 * 4),
169 COSTS_N_INSNS (20 * 16),
178 /* Costs for a 68HC12. */
179 static const struct processor_costs m6812_cost
= {
184 /* non-constant shift */
187 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
188 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
189 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
192 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
193 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
194 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
195 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
196 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
197 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
204 COSTS_N_INSNS (3 * 4),
213 /* Machine specific options */
215 const char *m68hc11_regparm_string
;
216 const char *m68hc11_reg_alloc_order
;
217 const char *m68hc11_soft_reg_count
;
219 static int nb_soft_regs
;
221 /* Initialize the GCC target structure. */
222 #undef TARGET_ATTRIBUTE_TABLE
223 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
225 #undef TARGET_ASM_ALIGNED_HI_OP
226 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
228 #undef TARGET_ASM_FUNCTION_EPILOGUE
229 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
231 #undef TARGET_ENCODE_SECTION_INFO
232 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
234 #undef TARGET_RTX_COSTS
235 #define TARGET_RTX_COSTS m68hc11_rtx_costs
237 struct gcc_target targetm
= TARGET_INITIALIZER
;
240 m68hc11_override_options ()
242 memset (m68hc11_reg_valid_for_index
, 0,
243 sizeof (m68hc11_reg_valid_for_index
));
244 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
246 /* Compilation with -fpic generates a wrong code. */
249 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
250 (flag_pic
> 1) ? "PIC" : "pic");
254 /* Configure for a 68hc11 processor. */
257 /* If gcc was built for a 68hc12, invalidate that because
258 a -m68hc11 option was specified on the command line. */
259 if (TARGET_DEFAULT
!= MASK_M6811
)
260 target_flags
&= ~TARGET_DEFAULT
;
263 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
264 m68hc11_cost
= &m6811_cost
;
265 m68hc11_min_offset
= 0;
266 m68hc11_max_offset
= 256;
267 m68hc11_index_reg_class
= NO_REGS
;
268 m68hc11_base_reg_class
= A_REGS
;
269 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
270 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
271 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
272 m68hc11_sp_correction
= 1;
273 m68hc11_tmp_regs_class
= D_REGS
;
274 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
275 m68hc11_soft_reg_count
= "4";
278 /* Configure for a 68hc12 processor. */
281 m68hc11_cost
= &m6812_cost
;
282 m68hc11_min_offset
= -65536;
283 m68hc11_max_offset
= 65536;
284 m68hc11_index_reg_class
= D_REGS
;
285 m68hc11_base_reg_class
= A_OR_SP_REGS
;
286 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
287 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
288 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
289 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
290 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
291 m68hc11_sp_correction
= 0;
292 m68hc11_tmp_regs_class
= TMP_REGS
;
293 target_flags
&= ~MASK_M6811
;
294 target_flags
|= MASK_NO_DIRECT_MODE
| MASK_MIN_MAX
;
295 if (m68hc11_soft_reg_count
== 0)
296 m68hc11_soft_reg_count
= "0";
298 if (TARGET_LONG_CALLS
)
299 current_function_far
= 1;
306 m68hc11_conditional_register_usage ()
309 int cnt
= atoi (m68hc11_soft_reg_count
);
313 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
314 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
317 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
320 call_used_regs
[i
] = 1;
323 /* For 68HC12, the Z register emulation is not necessary when the
324 frame pointer is not used. The frame pointer is eliminated and
325 replaced by the stack register (which is a BASE_REG_CLASS). */
326 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
328 fixed_regs
[HARD_Z_REGNUM
] = 1;
333 /* Reload and register operations. */
335 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
341 /* regs_inited = 1; */
342 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
343 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
344 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
345 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
347 stack_push_word
= gen_rtx (MEM
, HImode
,
348 gen_rtx (PRE_DEC
, HImode
,
349 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
350 stack_pop_word
= gen_rtx (MEM
, HImode
,
351 gen_rtx (POST_INC
, HImode
,
352 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
356 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
357 - 8 bit values are stored anywhere (except the SP register).
358 - 16 bit values can be stored in any register whose mode is 16
359 - 32 bit values can be stored in D, X registers or in a soft register
360 (except the last one because we need 2 soft registers)
361 - Values whose size is > 32 bit are not stored in real hard
362 registers. They may be stored in soft registers if there are
365 hard_regno_mode_ok (regno
, mode
)
367 enum machine_mode mode
;
369 switch (GET_MODE_SIZE (mode
))
372 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
375 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
378 return G_REGNO_P (regno
);
381 /* We have to accept a QImode in X or Y registers. Otherwise, the
382 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
383 in the insns. Reload fails if the insn rejects the register class 'a'
384 as well as if it accepts it. Patterns that failed were
385 zero_extend_qihi2 and iorqi3. */
387 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
395 preferred_reload_class (operand
, class)
397 enum reg_class
class;
399 enum machine_mode mode
;
401 mode
= GET_MODE (operand
);
405 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
408 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
409 return m68hc11_base_reg_class
;
411 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
412 || GET_CODE (operand
) == CONST_INT
))
414 /* S_REGS class must not be used. The movhi template does not
415 work to move a memory to a soft register.
416 Restrict to a hard reg. */
421 case D_OR_A_OR_S_REGS
:
427 case D_OR_SP_OR_S_REGS
:
428 class = D_OR_SP_REGS
;
430 case D_OR_Y_OR_S_REGS
:
433 case D_OR_X_OR_S_REGS
:
449 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
453 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
457 else if (class >= S_REGS
&& S_REG_P (operand
))
463 case D_OR_A_OR_S_REGS
:
469 case D_OR_SP_OR_S_REGS
:
470 class = D_OR_SP_REGS
;
472 case D_OR_Y_OR_S_REGS
:
475 case D_OR_X_OR_S_REGS
:
491 else if (class >= S_REGS
)
495 printf ("Class = %s for: ", reg_class_names
[class]);
503 printf (" => class=%s\n", reg_class_names
[class]);
511 /* Return 1 if the operand is a valid indexed addressing mode.
512 For 68hc11: n,r with n in [0..255] and r in A_REGS class
513 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
515 register_indirect_p (operand
, mode
, strict
)
517 enum machine_mode mode
;
522 switch (GET_CODE (operand
))
528 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
529 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
533 base
= XEXP (operand
, 0);
534 if (GET_CODE (base
) == MEM
)
537 offset
= XEXP (operand
, 1);
538 if (GET_CODE (offset
) == MEM
)
541 if (GET_CODE (base
) == REG
)
543 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
549 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
551 if (GET_CODE (offset
) == REG
)
553 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
559 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
564 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
570 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
577 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
578 a 68HC12 1-byte index addressing mode. */
580 m68hc11_small_indexed_indirect_p (operand
, mode
)
582 enum machine_mode mode
;
586 if (GET_CODE (operand
) == REG
&& reload_in_progress
587 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
588 && reg_equiv_memory_loc
[REGNO (operand
)])
590 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
591 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
594 if (GET_CODE (operand
) != MEM
)
597 operand
= XEXP (operand
, 0);
598 if (CONSTANT_ADDRESS_P (operand
))
601 if (PUSH_POP_ADDRESS_P (operand
))
604 if (!register_indirect_p (operand
, mode
, reload_completed
))
607 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
608 && (reload_completed
| reload_in_progress
))
610 base
= XEXP (operand
, 0);
611 offset
= XEXP (operand
, 1);
613 /* The offset can be a symbol address and this is too big
614 for the operand constraint. */
615 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
618 if (GET_CODE (base
) == CONST_INT
)
621 switch (GET_MODE_SIZE (mode
))
624 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
629 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
634 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
643 m68hc11_register_indirect_p (operand
, mode
)
645 enum machine_mode mode
;
647 if (GET_CODE (operand
) != MEM
)
650 operand
= XEXP (operand
, 0);
651 return register_indirect_p (operand
, mode
,
652 (reload_completed
| reload_in_progress
));
656 go_if_legitimate_address_internal (operand
, mode
, strict
)
658 enum machine_mode mode
;
661 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
663 /* Reject the global variables if they are too wide. This forces
664 a load of their address in a register and generates smaller code. */
665 if (GET_MODE_SIZE (mode
) == 8)
670 if (register_indirect_p (operand
, mode
, strict
))
674 if (PUSH_POP_ADDRESS_P (operand
))
678 if (symbolic_memory_operand (operand
, mode
))
686 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
688 enum machine_mode mode
;
695 printf ("Checking: ");
700 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
704 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
711 printf ("go_if_legitimate%s, ret 0: %d:",
712 (strict
? "_strict" : ""), mode
);
721 m68hc11_legitimize_address (operand
, old_operand
, mode
)
722 rtx
*operand ATTRIBUTE_UNUSED
;
723 rtx old_operand ATTRIBUTE_UNUSED
;
724 enum machine_mode mode ATTRIBUTE_UNUSED
;
731 m68hc11_reload_operands (operands
)
734 enum machine_mode mode
;
736 if (regs_inited
== 0)
739 mode
= GET_MODE (operands
[1]);
741 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
742 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
744 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
745 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
747 if (GET_CODE (base
) != REG
)
754 /* If the offset is out of range, we have to compute the address
755 with a separate add instruction. We try to do with with an 8-bit
756 add on the A register. This is possible only if the lowest part
757 of the offset (ie, big_offset % 256) is a valid constant offset
758 with respect to the mode. If it's not, we have to generate a
759 16-bit add on the D register. From:
761 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
765 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
766 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
767 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
768 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
770 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
771 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
774 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
777 rtx reg
= operands
[0];
779 int val
= INTVAL (big_offset
);
782 /* We use the 'operands[0]' as a scratch register to compute the
783 address. Make sure 'base' is in that register. */
784 if (!rtx_equal_p (base
, operands
[0]))
786 emit_move_insn (reg
, base
);
796 vh
= (val
>> 8) & 0x0FF;
800 /* Create the lowest part offset that still remains to be added.
801 If it's not a valid offset, do a 16-bit add. */
802 offset
= GEN_INT (vl
);
803 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
805 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
806 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
811 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
812 gen_rtx (PLUS
, HImode
, reg
,
813 GEN_INT (vh
<< 8))));
815 emit_move_insn (operands
[0],
816 gen_rtx (MEM
, GET_MODE (operands
[1]),
817 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
822 /* Use the normal gen_movhi pattern. */
827 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
830 enum machine_mode dmode
;
831 enum machine_mode smode
;
841 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
845 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
846 dmode
, 1, operands
[1], smode
);
847 equiv
= gen_rtx (code
, dmode
, operands
[1]);
851 ret
= emit_library_call_value (libcall
, NULL_RTX
,
853 operands
[1], smode
, operands
[2],
855 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
862 insns
= get_insns ();
864 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
867 /* Returns true if X is a PRE/POST increment decrement
868 (same as auto_inc_p() in rtlanal.c but do not take into
869 account the stack). */
871 m68hc11_auto_inc_p (x
)
874 return GET_CODE (x
) == PRE_DEC
875 || GET_CODE (x
) == POST_INC
876 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
880 /* Predicates for machine description. */
883 memory_reload_operand (operand
, mode
)
885 enum machine_mode mode ATTRIBUTE_UNUSED
;
887 return GET_CODE (operand
) == MEM
888 && GET_CODE (XEXP (operand
, 0)) == PLUS
889 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
890 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
891 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
892 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
896 tst_operand (operand
, mode
)
898 enum machine_mode mode
;
900 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
902 rtx addr
= XEXP (operand
, 0);
903 if (m68hc11_auto_inc_p (addr
))
906 return nonimmediate_operand (operand
, mode
);
910 cmp_operand (operand
, mode
)
912 enum machine_mode mode
;
914 if (GET_CODE (operand
) == MEM
)
916 rtx addr
= XEXP (operand
, 0);
917 if (m68hc11_auto_inc_p (addr
))
920 return general_operand (operand
, mode
);
924 non_push_operand (operand
, mode
)
926 enum machine_mode mode
;
928 if (general_operand (operand
, mode
) == 0)
931 if (push_operand (operand
, mode
) == 1)
937 reg_or_some_mem_operand (operand
, mode
)
939 enum machine_mode mode
;
941 if (GET_CODE (operand
) == MEM
)
943 rtx op
= XEXP (operand
, 0);
945 if (symbolic_memory_operand (op
, mode
))
948 if (IS_STACK_PUSH (operand
))
951 if (m68hc11_register_indirect_p (operand
, mode
))
957 return register_operand (operand
, mode
);
961 m68hc11_symbolic_p (operand
, mode
)
963 enum machine_mode mode
;
965 if (GET_CODE (operand
) == MEM
)
967 rtx op
= XEXP (operand
, 0);
969 if (symbolic_memory_operand (op
, mode
))
976 m68hc11_indirect_p (operand
, mode
)
978 enum machine_mode mode
;
980 if (GET_CODE (operand
) == MEM
)
982 rtx op
= XEXP (operand
, 0);
984 if (symbolic_memory_operand (op
, mode
))
987 if (reload_in_progress
)
990 operand
= XEXP (operand
, 0);
991 return register_indirect_p (operand
, mode
, reload_completed
);
997 stack_register_operand (operand
, mode
)
999 enum machine_mode mode ATTRIBUTE_UNUSED
;
1001 return SP_REG_P (operand
);
1005 d_register_operand (operand
, mode
)
1007 enum machine_mode mode ATTRIBUTE_UNUSED
;
1009 if (GET_CODE (operand
) == SUBREG
)
1010 operand
= XEXP (operand
, 0);
1012 return GET_CODE (operand
) == REG
1013 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1014 || REGNO (operand
) == HARD_D_REGNUM
1015 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1019 hard_addr_reg_operand (operand
, mode
)
1021 enum machine_mode mode ATTRIBUTE_UNUSED
;
1023 if (GET_CODE (operand
) == SUBREG
)
1024 operand
= XEXP (operand
, 0);
1026 return GET_CODE (operand
) == REG
1027 && (REGNO (operand
) == HARD_X_REGNUM
1028 || REGNO (operand
) == HARD_Y_REGNUM
1029 || REGNO (operand
) == HARD_Z_REGNUM
);
1033 hard_reg_operand (operand
, mode
)
1035 enum machine_mode mode ATTRIBUTE_UNUSED
;
1037 if (GET_CODE (operand
) == SUBREG
)
1038 operand
= XEXP (operand
, 0);
1040 return GET_CODE (operand
) == REG
1041 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1042 || H_REGNO_P (REGNO (operand
)));
1046 memory_indexed_operand (operand
, mode
)
1048 enum machine_mode mode ATTRIBUTE_UNUSED
;
1050 if (GET_CODE (operand
) != MEM
)
1053 operand
= XEXP (operand
, 0);
1054 if (GET_CODE (operand
) == PLUS
)
1056 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1057 operand
= XEXP (operand
, 0);
1058 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1059 operand
= XEXP (operand
, 1);
1061 return GET_CODE (operand
) == REG
1062 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1063 || A_REGNO_P (REGNO (operand
)));
1067 push_pop_operand_p (operand
)
1070 if (GET_CODE (operand
) != MEM
)
1074 operand
= XEXP (operand
, 0);
1075 return PUSH_POP_ADDRESS_P (operand
);
1078 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1079 reference and a constant. */
1082 symbolic_memory_operand (op
, mode
)
1084 enum machine_mode mode
;
1086 switch (GET_CODE (op
))
1094 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1095 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1096 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1098 /* ??? This clause seems to be irrelevant. */
1100 return GET_MODE (op
) == mode
;
1103 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1104 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1112 m68hc11_logical_operator (op
, mode
)
1114 enum machine_mode mode ATTRIBUTE_UNUSED
;
1116 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1120 m68hc11_arith_operator (op
, mode
)
1122 enum machine_mode mode ATTRIBUTE_UNUSED
;
1124 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1125 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1126 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1127 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1128 || GET_CODE (op
) == ROTATERT
;
1132 m68hc11_non_shift_operator (op
, mode
)
1134 enum machine_mode mode ATTRIBUTE_UNUSED
;
1136 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1137 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1142 m68hc11_unary_operator (op
, mode
)
1144 enum machine_mode mode ATTRIBUTE_UNUSED
;
1146 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1147 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1150 /* Emit the code to build the trampoline used to call a nested function.
1154 ldy #&CXT movw #&CXT,*_.d1
1155 sty *_.d1 jmp FNADDR
1160 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1165 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1168 if (*static_chain_reg
== '*')
1172 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1173 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1174 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1176 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1177 gen_rtx_CONST (QImode
,
1178 gen_rtx_SYMBOL_REF (Pmode
,
1179 static_chain_reg
)));
1180 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1182 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1186 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1187 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1188 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1189 gen_rtx_CONST (HImode
,
1190 gen_rtx_SYMBOL_REF (Pmode
,
1191 static_chain_reg
)));
1192 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1194 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1198 /* Declaration of types. */
1200 const struct attribute_spec m68hc11_attribute_table
[] =
1202 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1203 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1204 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1205 { NULL
, 0, 0, false, false, false, NULL
}
1208 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1209 arguments as in struct attribute_spec.handler. */
1211 m68hc11_handle_fntype_attribute (node
, name
, args
, flags
, no_add_attrs
)
1214 tree args ATTRIBUTE_UNUSED
;
1215 int flags ATTRIBUTE_UNUSED
;
1218 if (TREE_CODE (*node
) != FUNCTION_TYPE
1219 && TREE_CODE (*node
) != FIELD_DECL
1220 && TREE_CODE (*node
) != TYPE_DECL
)
1222 warning ("`%s' attribute only applies to functions",
1223 IDENTIFIER_POINTER (name
));
1224 *no_add_attrs
= true;
1230 /* We want to recognize trap handlers so that we handle calls to traps
1231 in a special manner (by issuing the trap). This information is stored
1232 in SYMBOL_REF_FLAG. */
1235 m68hc11_encode_section_info (decl
, first
)
1237 int first ATTRIBUTE_UNUSED
;
1243 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1246 rtl
= DECL_RTL (decl
);
1248 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1249 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1250 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1254 /* Argument support functions. */
1256 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1257 Arrays are passed by references and other types by value.
1259 SCz: I tried to pass DImode by reference but it seems that this
1260 does not work very well. */
1262 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1263 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1264 enum machine_mode mode ATTRIBUTE_UNUSED
;
1266 int named ATTRIBUTE_UNUSED
;
1268 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1269 /* Consider complex values as aggregates, so care for TCmode. */
1270 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1271 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1275 /* Define the offset between two registers, one to be eliminated, and the
1276 other its replacement, at the start of a routine. */
1278 m68hc11_initial_elimination_offset (from
, to
)
1287 /* For a trap handler, we must take into account the registers which
1288 are pushed on the stack during the trap (except the PC). */
1289 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1290 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1291 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1294 /* For a function using 'call/rtc' we must take into account the
1295 page register which is pushed in the call. */
1296 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1301 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1303 /* 2 is for the saved frame.
1304 1 is for the 'sts' correction when creating the frame. */
1305 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1308 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1310 return m68hc11_sp_correction
;
1313 /* Push any 2 byte pseudo hard registers that we need to save. */
1314 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1316 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1322 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1324 return get_frame_size () + size
;
1327 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1334 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1335 for a call to a function whose data type is FNTYPE.
1336 For a library call, FNTYPE is 0. */
1339 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1340 CUMULATIVE_ARGS
*cum
;
1346 z_replacement_completed
= 0;
1350 /* For a library call, we must find out the type of the return value.
1351 When the return value is bigger than 4 bytes, it is returned in
1352 memory. In that case, the first argument of the library call is a
1353 pointer to the memory location. Because the first argument is passed in
1354 register D, we have to identify this, so that the first function
1355 parameter is not passed in D either. */
1361 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1364 /* If the library ends in 'di' or in 'df', we assume it's
1365 returning some DImode or some DFmode which are 64-bit wide. */
1366 name
= XSTR (libname
, 0);
1367 len
= strlen (name
);
1369 && ((name
[len
- 2] == 'd'
1370 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1371 || (name
[len
- 3] == 'd'
1372 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1374 /* We are in. Mark the first parameter register as already used. */
1381 ret_type
= TREE_TYPE (fntype
);
1383 if (ret_type
&& aggregate_value_p (ret_type
))
1390 /* Update the data in CUM to advance over an argument
1391 of mode MODE and data type TYPE.
1392 (TYPE is null for libcalls where that information may not be available.) */
1395 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1396 CUMULATIVE_ARGS
*cum
;
1397 enum machine_mode mode
;
1399 int named ATTRIBUTE_UNUSED
;
1401 if (mode
!= BLKmode
)
1403 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1406 cum
->words
= GET_MODE_SIZE (mode
);
1410 cum
->words
+= GET_MODE_SIZE (mode
);
1411 if (cum
->words
<= HARD_REG_SIZE
)
1417 cum
->words
+= int_size_in_bytes (type
);
1422 /* Define where to put the arguments to a function.
1423 Value is zero to push the argument on the stack,
1424 or a hard register in which to store the argument.
1426 MODE is the argument's machine mode.
1427 TYPE is the data type of the argument (as a tree).
1428 This is null for libcalls where that information may
1430 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1431 the preceding args and about the function being called.
1432 NAMED is nonzero if this argument is a named parameter
1433 (otherwise it is an extra parameter matching an ellipsis). */
1436 m68hc11_function_arg (cum
, mode
, type
, named
)
1437 const CUMULATIVE_ARGS
*cum
;
1438 enum machine_mode mode
;
1439 tree type ATTRIBUTE_UNUSED
;
1440 int named ATTRIBUTE_UNUSED
;
1442 if (cum
->words
!= 0)
1447 if (mode
!= BLKmode
)
1449 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1450 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1452 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1456 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1462 m68hc11_va_arg (valist
, type
)
1467 HOST_WIDE_INT align
;
1468 HOST_WIDE_INT rounded_size
;
1472 /* Compute the rounded size of the type. */
1473 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1474 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1478 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1480 if (pad_direction
== downward
)
1482 /* Small args are padded downward. */
1485 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1486 if (rounded_size
> align
)
1489 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1490 build_int_2 (rounded_size
- adj
, 0));
1493 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1494 addr
= copy_to_reg (addr
);
1496 /* Compute new value for AP. */
1497 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1498 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1499 build_int_2 (rounded_size
, 0)));
1500 TREE_SIDE_EFFECTS (t
) = 1;
1501 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1506 /* If defined, a C expression which determines whether, and in which direction,
1507 to pad out an argument with extra space. The value should be of type
1508 `enum direction': either `upward' to pad above the argument,
1509 `downward' to pad below, or `none' to inhibit padding.
1511 Structures are stored left shifted in their argument slot. */
1513 m68hc11_function_arg_padding (mode
, type
)
1514 enum machine_mode mode
;
1517 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1520 /* This is the default definition. */
1521 return (!BYTES_BIG_ENDIAN
1524 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1525 && int_size_in_bytes (type
) <
1526 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1527 PARM_BOUNDARY
) ? downward
: upward
));
1531 /* Function prologue and epilogue. */
1533 /* Emit a move after the reload pass has completed. This is used to
1534 emit the prologue and epilogue. */
1536 emit_move_after_reload (to
, from
, scratch
)
1537 rtx to
, from
, scratch
;
1541 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1543 insn
= emit_move_insn (to
, from
);
1547 emit_move_insn (scratch
, from
);
1548 insn
= emit_move_insn (to
, scratch
);
1551 /* Put a REG_INC note to tell the flow analysis that the instruction
1553 if (IS_STACK_PUSH (to
))
1555 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1556 XEXP (XEXP (to
, 0), 0),
1559 else if (IS_STACK_POP (from
))
1561 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1562 XEXP (XEXP (from
, 0), 0),
1566 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1567 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1568 The problem is that we are lying to gcc and use `txs' for x = sp
1569 (which is not really true because txs is really x = sp + 1). */
1570 else if (TARGET_M6811
&& SP_REG_P (from
))
1572 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1579 m68hc11_total_frame_size ()
1584 size
= get_frame_size ();
1585 if (current_function_interrupt
)
1587 size
+= 3 * HARD_REG_SIZE
;
1589 if (frame_pointer_needed
)
1590 size
+= HARD_REG_SIZE
;
1592 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1593 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1594 size
+= HARD_REG_SIZE
;
1600 m68hc11_output_function_epilogue (out
, size
)
1601 FILE *out ATTRIBUTE_UNUSED
;
1602 HOST_WIDE_INT size ATTRIBUTE_UNUSED
;
1604 /* We catch the function epilogue generation to have a chance
1605 to clear the z_replacement_completed flag. */
1606 z_replacement_completed
= 0;
1617 if (reload_completed
!= 1)
1620 size
= get_frame_size ();
1624 /* Generate specific prologue for interrupt handlers. */
1625 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1626 current_function_interrupt
= lookup_attribute ("interrupt",
1627 func_attr
) != NULL_TREE
;
1628 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1630 /* Get the scratch register to build the frame and push registers.
1631 If the first argument is a 32-bit quantity, the D+X registers
1632 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1633 For 68HC12, this scratch register is not used. */
1634 if (current_function_args_info
.nregs
== 2)
1639 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1640 Other soft registers in page0 need not to be saved because they
1641 will be restored by C functions. For a trap handler, we don't
1642 need to preserve these registers because this is a synchronous call. */
1643 if (current_function_interrupt
)
1645 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1646 emit_move_after_reload (stack_push_word
,
1647 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1648 emit_move_after_reload (stack_push_word
,
1649 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1653 /* Save current stack frame. */
1654 if (frame_pointer_needed
)
1655 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1657 /* Allocate local variables. */
1658 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1660 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1661 stack_pointer_rtx
, GEN_INT (-size
)));
1663 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1667 insn
= gen_rtx_PARALLEL
1670 gen_rtx_SET (VOIDmode
,
1672 gen_rtx_PLUS (HImode
,
1675 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1682 /* Allocate by pushing scratch values. */
1683 for (i
= 2; i
<= size
; i
+= 2)
1684 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1687 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1688 stack_pointer_rtx
, GEN_INT (-1)));
1691 /* Create the frame pointer. */
1692 if (frame_pointer_needed
)
1693 emit_move_after_reload (hard_frame_pointer_rtx
,
1694 stack_pointer_rtx
, scratch
);
1696 /* Push any 2 byte pseudo hard registers that we need to save. */
1697 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1699 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1701 emit_move_after_reload (stack_push_word
,
1702 gen_rtx (REG
, HImode
, regno
), scratch
);
1715 if (reload_completed
!= 1)
1718 size
= get_frame_size ();
1720 /* If we are returning a value in two registers, we have to preserve the
1721 X register and use the Y register to restore the stack and the saved
1722 registers. Otherwise, use X because it's faster (and smaller). */
1723 if (current_function_return_rtx
== 0)
1725 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1726 return_size
= HARD_REG_SIZE
;
1728 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1730 if (return_size
> HARD_REG_SIZE
)
1735 /* Pop any 2 byte pseudo hard registers that we saved. */
1736 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1738 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1740 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1741 stack_pop_word
, scratch
);
1745 /* de-allocate auto variables */
1746 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1748 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1749 stack_pointer_rtx
, GEN_INT (size
)));
1751 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1755 insn
= gen_rtx_PARALLEL
1758 gen_rtx_SET (VOIDmode
,
1760 gen_rtx_PLUS (HImode
,
1763 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1770 for (i
= 2; i
<= size
; i
+= 2)
1771 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1773 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1774 stack_pointer_rtx
, GEN_INT (1)));
1777 /* Restore previous frame pointer. */
1778 if (frame_pointer_needed
)
1779 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1781 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1782 if (current_function_interrupt
)
1784 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1785 stack_pop_word
, scratch
);
1786 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1787 stack_pop_word
, scratch
);
1788 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1791 /* If the trap handler returns some value, copy the value
1792 in D, X onto the stack so that the rti will pop the return value
1794 else if (current_function_trap
&& return_size
!= 0)
1796 rtx addr_reg
= stack_pointer_rtx
;
1800 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1803 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1804 gen_rtx (PLUS
, HImode
, addr_reg
,
1805 GEN_INT (1))), d_reg
, 0);
1806 if (return_size
> HARD_REG_SIZE
)
1807 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1808 gen_rtx (PLUS
, HImode
, addr_reg
,
1809 GEN_INT (3))), ix_reg
, 0);
1812 emit_jump_insn (gen_return ());
1816 /* Low and High part extraction for 68HC11. These routines are
1817 similar to gen_lowpart and gen_highpart but they have been
1818 fixed to work for constants and 68HC11 specific registers. */
1821 m68hc11_gen_lowpart (mode
, x
)
1822 enum machine_mode mode
;
1825 /* We assume that the low part of an auto-inc mode is the same with
1826 the mode changed and that the caller split the larger mode in the
1828 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1830 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1833 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1834 floating-point constant. A CONST_DOUBLE is used whenever the
1835 constant requires more than one word in order to be adequately
1837 if (GET_CODE (x
) == CONST_DOUBLE
)
1841 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1845 if (GET_MODE (x
) == SFmode
)
1847 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1848 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1854 split_double (x
, &first
, &second
);
1858 return GEN_INT (l
[0]);
1860 return gen_int_mode (l
[0], HImode
);
1864 l
[0] = CONST_DOUBLE_LOW (x
);
1867 return GEN_INT (l
[0]);
1868 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1869 return gen_int_mode (l
[0], HImode
);
1874 if (mode
== QImode
&& D_REG_P (x
))
1875 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1877 /* gen_lowpart crashes when it is called with a SUBREG. */
1878 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1881 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1882 else if (mode
== HImode
)
1883 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1887 x
= gen_lowpart (mode
, x
);
1889 /* Return a different rtx to avoid to share it in several insns
1890 (when used by a split pattern). Sharing addresses within
1891 a MEM breaks the Z register replacement (and reloading). */
1892 if (GET_CODE (x
) == MEM
)
1898 m68hc11_gen_highpart (mode
, x
)
1899 enum machine_mode mode
;
1902 /* We assume that the high part of an auto-inc mode is the same with
1903 the mode changed and that the caller split the larger mode in the
1905 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1907 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1910 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1911 floating-point constant. A CONST_DOUBLE is used whenever the
1912 constant requires more than one word in order to be adequately
1914 if (GET_CODE (x
) == CONST_DOUBLE
)
1918 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1922 if (GET_MODE (x
) == SFmode
)
1924 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1925 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1931 split_double (x
, &first
, &second
);
1935 return GEN_INT (l
[1]);
1937 return gen_int_mode ((l
[1] >> 16), HImode
);
1941 l
[1] = CONST_DOUBLE_HIGH (x
);
1945 return GEN_INT (l
[1]);
1946 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1947 return gen_int_mode ((l
[0] >> 16), HImode
);
1951 if (GET_CODE (x
) == CONST_INT
)
1953 HOST_WIDE_INT val
= INTVAL (x
);
1957 return gen_int_mode (val
>> 8, QImode
);
1959 else if (mode
== HImode
)
1961 return gen_int_mode (val
>> 16, HImode
);
1964 if (mode
== QImode
&& D_REG_P (x
))
1965 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1967 /* There is no way in GCC to represent the upper part of a word register.
1968 To obtain the 8-bit upper part of a soft register, we change the
1969 reg into a mem rtx. This is possible because they are physically
1970 located in memory. There is no offset because we are big-endian. */
1971 if (mode
== QImode
&& S_REG_P (x
))
1975 /* Avoid the '*' for direct addressing mode when this
1976 addressing mode is disabled. */
1977 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
1978 return gen_rtx (MEM
, QImode
,
1979 gen_rtx (SYMBOL_REF
, Pmode
,
1980 ®_names
[REGNO (x
)][pos
]));
1983 /* gen_highpart crashes when it is called with a SUBREG. */
1984 if (GET_CODE (x
) == SUBREG
)
1986 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
1988 if (GET_CODE (x
) == REG
)
1990 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
1991 return gen_rtx (REG
, mode
, REGNO (x
));
1993 return gen_rtx_SUBREG (mode
, x
, 0);
1996 if (GET_CODE (x
) == MEM
)
1998 x
= change_address (x
, mode
, 0);
2000 /* Return a different rtx to avoid to share it in several insns
2001 (when used by a split pattern). Sharing addresses within
2002 a MEM breaks the Z register replacement (and reloading). */
2003 if (GET_CODE (x
) == MEM
)
2011 /* Obscure register manipulation. */
2013 /* Finds backward in the instructions to see if register 'reg' is
2014 dead. This is used when generating code to see if we can use 'reg'
2015 as a scratch register. This allows us to choose a better generation
2016 of code when we know that some register dies or can be clobbered. */
2019 dead_register_here (x
, reg
)
2027 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2031 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2032 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
2038 if (GET_CODE (body
) == CALL_INSN
)
2040 if (GET_CODE (body
) == JUMP_INSN
)
2043 if (GET_CODE (body
) == SET
)
2045 rtx dst
= XEXP (body
, 0);
2047 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2049 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2052 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2055 else if (reg_mentioned_p (reg
, p
)
2056 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2060 /* Scan forward to see if the register is set in some insns and never
2062 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2066 if (GET_CODE (p
) == CODE_LABEL
2067 || GET_CODE (p
) == JUMP_INSN
2068 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2071 if (GET_CODE (p
) != INSN
)
2075 if (GET_CODE (body
) == SET
)
2077 rtx src
= XEXP (body
, 1);
2078 rtx dst
= XEXP (body
, 0);
2080 if (GET_CODE (dst
) == REG
2081 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2085 /* Register is used (may be in source or in dest). */
2086 if (reg_mentioned_p (reg
, p
)
2087 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2088 && reg_mentioned_p (x_reg
, p
)))
2091 return p
== 0 ? 1 : 0;
2095 /* Code generation operations called from machine description file. */
2097 /* Print the name of register 'regno' in the assembly file. */
2099 asm_print_register (file
, regno
)
2103 const char *name
= reg_names
[regno
];
2105 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2108 fprintf (file
, "%s", name
);
2111 /* A C compound statement to output to stdio stream STREAM the
2112 assembler syntax for an instruction operand X. X is an RTL
2115 CODE is a value that can be used to specify one of several ways
2116 of printing the operand. It is used when identical operands
2117 must be printed differently depending on the context. CODE
2118 comes from the `%' specification that was used to request
2119 printing of the operand. If the specification was just `%DIGIT'
2120 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2121 is the ASCII code for LTR.
2123 If X is a register, this macro should print the register's name.
2124 The names can be found in an array `reg_names' whose type is
2125 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2127 When the machine description has a specification `%PUNCT' (a `%'
2128 followed by a punctuation character), this macro is called with
2129 a null pointer for X and the punctuation character for CODE.
2131 The M68HC11 specific codes are:
2133 'b' for the low part of the operand.
2134 'h' for the high part of the operand
2135 The 'b' or 'h' modifiers have no effect if the operand has
2136 the QImode and is not a S_REG_P (soft register). If the
2137 operand is a hard register, these two modifiers have no effect.
2138 't' generate the temporary scratch register. The operand is
2140 'T' generate the low-part temporary scratch register. The operand is
2144 print_operand (file
, op
, letter
)
2151 asm_print_register (file
, SOFT_TMP_REGNUM
);
2154 else if (letter
== 'T')
2156 asm_print_register (file
, SOFT_TMP_REGNUM
);
2157 fprintf (file
, "+1");
2160 else if (letter
== '#')
2162 asm_fprintf (file
, "%0I");
2165 if (GET_CODE (op
) == REG
)
2167 if (letter
== 'b' && S_REG_P (op
))
2169 asm_print_register (file
, REGNO (op
));
2170 fprintf (file
, "+1");
2174 asm_print_register (file
, REGNO (op
));
2179 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2182 asm_fprintf (file
, "%0I%%lo(");
2184 asm_fprintf (file
, "%0I%%hi(");
2186 output_addr_const (file
, op
);
2187 fprintf (file
, ")");
2191 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2192 are specified. If we already have a QImode, there is nothing to do. */
2193 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2197 op
= m68hc11_gen_lowpart (QImode
, op
);
2199 else if (letter
== 'h')
2201 op
= m68hc11_gen_highpart (QImode
, op
);
2205 if (GET_CODE (op
) == MEM
)
2207 rtx base
= XEXP (op
, 0);
2208 switch (GET_CODE (base
))
2213 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2214 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2223 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2224 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2225 fprintf (file
, "-");
2234 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2235 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2236 fprintf (file
, "+");
2245 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2246 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2253 output_address (base
);
2257 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2262 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2263 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2264 asm_fprintf (file
, "%I0x%lx", l
);
2266 else if (GET_CODE (op
) == CONST_DOUBLE
2267 && (GET_MODE (op
) == DFmode
|| GET_MODE (op
) == XFmode
))
2271 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2272 sizeof (dstr
), 0, 1);
2273 asm_fprintf (file
, "%I0r%s", dstr
);
2277 int need_parenthesize
= 0;
2280 asm_fprintf (file
, "%0I");
2282 need_parenthesize
= must_parenthesize (op
);
2284 if (need_parenthesize
)
2285 fprintf (file
, "(");
2287 output_addr_const (file
, op
);
2288 if (need_parenthesize
)
2289 fprintf (file
, ")");
2293 /* Returns true if the operand 'op' must be printed with parenthesis
2294 arround it. This must be done only if there is a symbol whose name
2295 is a processor register. */
2297 must_parenthesize (op
)
2302 switch (GET_CODE (op
))
2305 name
= XSTR (op
, 0);
2306 /* Avoid a conflict between symbol name and a possible
2308 return (strcasecmp (name
, "a") == 0
2309 || strcasecmp (name
, "b") == 0
2310 || strcasecmp (name
, "d") == 0
2311 || strcasecmp (name
, "x") == 0
2312 || strcasecmp (name
, "y") == 0
2313 || strcasecmp (name
, "ix") == 0
2314 || strcasecmp (name
, "iy") == 0
2315 || strcasecmp (name
, "pc") == 0
2316 || strcasecmp (name
, "sp") == 0
2317 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2321 return must_parenthesize (XEXP (op
, 0))
2322 || must_parenthesize (XEXP (op
, 1));
2328 return must_parenthesize (XEXP (op
, 0));
2339 /* A C compound statement to output to stdio stream STREAM the
2340 assembler syntax for an instruction operand that is a memory
2341 reference whose address is ADDR. ADDR is an RTL expression. */
2344 print_operand_address (file
, addr
)
2350 int need_parenthesis
= 0;
2352 switch (GET_CODE (addr
))
2355 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2358 fprintf (file
, "0,");
2359 asm_print_register (file
, REGNO (addr
));
2363 base
= XEXP (addr
, 0);
2364 switch (GET_CODE (base
))
2369 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2370 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2379 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2380 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2381 fprintf (file
, "-");
2390 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2391 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2392 fprintf (file
, "+");
2401 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2402 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2409 need_parenthesis
= must_parenthesize (base
);
2410 if (need_parenthesis
)
2411 fprintf (file
, "(");
2413 output_addr_const (file
, base
);
2414 if (need_parenthesis
)
2415 fprintf (file
, ")");
2421 base
= XEXP (addr
, 0);
2422 offset
= XEXP (addr
, 1);
2423 if (!G_REG_P (base
) && G_REG_P (offset
))
2425 base
= XEXP (addr
, 1);
2426 offset
= XEXP (addr
, 0);
2428 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2430 need_parenthesis
= must_parenthesize (addr
);
2432 if (need_parenthesis
)
2433 fprintf (file
, "(");
2435 output_addr_const (file
, base
);
2436 fprintf (file
, "+");
2437 output_addr_const (file
, offset
);
2438 if (need_parenthesis
)
2439 fprintf (file
, ")");
2441 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2447 asm_print_register (file
, REGNO (offset
));
2448 fprintf (file
, ",");
2449 asm_print_register (file
, REGNO (base
));
2456 need_parenthesis
= must_parenthesize (offset
);
2457 if (need_parenthesis
)
2458 fprintf (file
, "(");
2460 output_addr_const (file
, offset
);
2461 if (need_parenthesis
)
2462 fprintf (file
, ")");
2463 fprintf (file
, ",");
2464 asm_print_register (file
, REGNO (base
));
2474 if (GET_CODE (addr
) == CONST_INT
2475 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2477 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2481 need_parenthesis
= must_parenthesize (addr
);
2482 if (need_parenthesis
)
2483 fprintf (file
, "(");
2485 output_addr_const (file
, addr
);
2486 if (need_parenthesis
)
2487 fprintf (file
, ")");
2494 /* Splitting of some instructions. */
2497 m68hc11_expand_compare (code
, op0
, op1
)
2503 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2507 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2508 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2509 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2516 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2518 rtx op0
, op1
, label
;
2522 switch (GET_MODE (op0
))
2526 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2527 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2528 gen_rtx_LABEL_REF (VOIDmode
, label
),
2530 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2534 /* SCz: from i386.c */
2537 /* Don't expand the comparison early, so that we get better code
2538 when jump or whoever decides to reverse the comparison. */
2543 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2544 &m68hc11_compare_op1
);
2546 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2547 m68hc11_compare_op0
, m68hc11_compare_op1
);
2548 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2549 gen_rtx_LABEL_REF (VOIDmode
, label
),
2551 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2553 use_fcomi
= ix86_use_fcomi_compare (code
);
2554 vec
= rtvec_alloc (3 + !use_fcomi
);
2555 RTVEC_ELT (vec
, 0) = tmp
;
2557 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2559 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2562 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2564 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2570 /* Expand SImode branch into multiple compare+branch. */
2572 rtx lo
[2], hi
[2], label2
;
2573 enum rtx_code code1
, code2
, code3
;
2575 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2580 code
= swap_condition (code
);
2582 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2583 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2584 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2585 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2587 /* Otherwise, if we are doing less-than, op1 is a constant and the
2588 low word is zero, then we can just examine the high word. */
2590 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2591 && (code
== LT
|| code
== LTU
))
2593 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2597 /* Otherwise, we need two or three jumps. */
2599 label2
= gen_label_rtx ();
2602 code2
= swap_condition (code
);
2603 code3
= unsigned_condition (code
);
2644 * if (hi(a) < hi(b)) goto true;
2645 * if (hi(a) > hi(b)) goto false;
2646 * if (lo(a) < lo(b)) goto true;
2650 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2652 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2654 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2657 emit_label (label2
);
2667 /* Return the increment/decrement mode of a MEM if it is such.
2668 Return CONST if it is anything else. */
2673 if (GET_CODE (x
) != MEM
)
2677 if (GET_CODE (x
) == PRE_INC
2678 || GET_CODE (x
) == PRE_DEC
2679 || GET_CODE (x
) == POST_INC
2680 || GET_CODE (x
) == POST_DEC
)
2681 return GET_CODE (x
);
2687 m68hc11_make_autoinc_notes (x
, data
)
2693 switch (GET_CODE (*x
))
2700 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2709 /* Split a DI, SI or HI move into several smaller move operations.
2710 The scratch register 'scratch' is used as a temporary to load
2711 store intermediate values. It must be a hard register. */
2713 m68hc11_split_move (to
, from
, scratch
)
2714 rtx to
, from
, scratch
;
2716 rtx low_to
, low_from
;
2717 rtx high_to
, high_from
;
2719 enum machine_mode mode
;
2721 int autoinc_from
= autoinc_mode (from
);
2722 int autoinc_to
= autoinc_mode (to
);
2724 mode
= GET_MODE (to
);
2726 /* If the TO and FROM contain autoinc modes that are not compatible
2727 together (one pop and the other a push), we must change one to
2728 an offsetable operand and generate an appropriate add at the end. */
2729 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2734 /* The source uses an autoinc mode which is not compatible with
2735 a split (this would result in a word swap). */
2736 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2738 code
= GET_CODE (XEXP (from
, 0));
2739 reg
= XEXP (XEXP (from
, 0), 0);
2740 offset
= GET_MODE_SIZE (GET_MODE (from
));
2741 if (code
== POST_DEC
)
2744 if (code
== PRE_INC
)
2745 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2747 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2748 if (code
== POST_DEC
)
2749 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2753 /* Likewise for destination. */
2754 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2756 code
= GET_CODE (XEXP (to
, 0));
2757 reg
= XEXP (XEXP (to
, 0), 0);
2758 offset
= GET_MODE_SIZE (GET_MODE (to
));
2759 if (code
== POST_DEC
)
2762 if (code
== PRE_INC
)
2763 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2765 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2766 if (code
== POST_DEC
)
2767 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2771 /* The source and destination auto increment modes must be compatible
2772 with each other: same direction. */
2773 if ((autoinc_to
!= autoinc_from
2774 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2775 /* The destination address register must not be used within
2776 the source operand because the source address would change
2777 while doing the copy. */
2778 || (autoinc_to
!= CONST
2779 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2780 && !IS_STACK_PUSH (to
)))
2782 /* Must change the destination. */
2783 code
= GET_CODE (XEXP (to
, 0));
2784 reg
= XEXP (XEXP (to
, 0), 0);
2785 offset
= GET_MODE_SIZE (GET_MODE (to
));
2786 if (code
== PRE_DEC
|| code
== POST_DEC
)
2789 if (code
== PRE_DEC
|| code
== PRE_INC
)
2790 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2791 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2792 if (code
== POST_DEC
|| code
== POST_INC
)
2793 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2798 /* Likewise, the source address register must not be used within
2799 the destination operand. */
2800 if (autoinc_from
!= CONST
2801 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2802 && !IS_STACK_PUSH (to
))
2804 /* Must change the source. */
2805 code
= GET_CODE (XEXP (from
, 0));
2806 reg
= XEXP (XEXP (from
, 0), 0);
2807 offset
= GET_MODE_SIZE (GET_MODE (from
));
2808 if (code
== PRE_DEC
|| code
== POST_DEC
)
2811 if (code
== PRE_DEC
|| code
== PRE_INC
)
2812 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
|| code
== POST_INC
)
2815 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2821 if (GET_MODE_SIZE (mode
) == 8)
2823 else if (GET_MODE_SIZE (mode
) == 4)
2829 && IS_STACK_PUSH (to
)
2830 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2836 else if (mode
== HImode
)
2844 low_to
= m68hc11_gen_lowpart (mode
, to
);
2845 high_to
= m68hc11_gen_highpart (mode
, to
);
2847 low_from
= m68hc11_gen_lowpart (mode
, from
);
2848 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2850 if (INTVAL (from
) >= 0)
2851 high_from
= const0_rtx
;
2853 high_from
= constm1_rtx
;
2856 high_from
= m68hc11_gen_highpart (mode
, from
);
2860 high_from
= adjust_address (high_from
, mode
, offset
);
2861 low_from
= high_from
;
2864 /* When copying with a POST_INC mode, we must copy the
2865 high part and then the low part to guarantee a correct
2868 && GET_MODE_SIZE (mode
) >= 2
2869 && autoinc_from
!= autoinc_to
2870 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2879 low_from
= high_from
;
2884 m68hc11_split_move (low_to
, low_from
, scratch
);
2885 m68hc11_split_move (high_to
, high_from
, scratch
);
2887 else if (H_REG_P (to
) || H_REG_P (from
)
2888 || (low_from
== const0_rtx
2889 && high_from
== const0_rtx
2890 && ! push_operand (to
, GET_MODE (to
))
2891 && ! H_REG_P (scratch
))
2893 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2894 || m68hc11_small_indexed_indirect_p (from
,
2896 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2897 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2899 insn
= emit_move_insn (low_to
, low_from
);
2900 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2902 insn
= emit_move_insn (high_to
, high_from
);
2903 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2907 insn
= emit_move_insn (scratch
, low_from
);
2908 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2909 insn
= emit_move_insn (low_to
, scratch
);
2910 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2912 insn
= emit_move_insn (scratch
, high_from
);
2913 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2914 insn
= emit_move_insn (high_to
, scratch
);
2915 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2920 simplify_logical (mode
, code
, operand
, result
)
2921 enum machine_mode mode
;
2930 if (GET_CODE (operand
) != CONST_INT
)
2938 val
= INTVAL (operand
);
2942 if ((val
& mask
) == 0)
2944 if ((val
& mask
) == mask
)
2945 *result
= constm1_rtx
;
2949 if ((val
& mask
) == 0)
2950 *result
= const0_rtx
;
2951 if ((val
& mask
) == mask
)
2956 if ((val
& mask
) == 0)
2964 m68hc11_emit_logical (mode
, code
, operands
)
2965 enum machine_mode mode
;
2972 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2973 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2975 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2976 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2978 if (result
&& GET_CODE (result
) == CONST_INT
)
2980 if (!H_REG_P (operands
[0]) && operands
[3]
2981 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2983 emit_move_insn (operands
[3], result
);
2984 emit_move_insn (operands
[0], operands
[3]);
2988 emit_move_insn (operands
[0], result
);
2991 else if (operands
[1] != 0 && operands
[2] != 0)
2995 if (!H_REG_P (operands
[0]) && operands
[3])
2997 emit_move_insn (operands
[3], operands
[1]);
2998 emit_insn (gen_rtx (SET
, mode
,
3000 gen_rtx (code
, mode
,
3001 operands
[3], operands
[2])));
3002 insn
= emit_move_insn (operands
[0], operands
[3]);
3006 insn
= emit_insn (gen_rtx (SET
, mode
,
3008 gen_rtx (code
, mode
,
3009 operands
[0], operands
[2])));
3013 /* The logical operation is similar to a copy. */
3018 if (GET_CODE (operands
[1]) == CONST_INT
)
3023 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3025 emit_move_insn (operands
[3], src
);
3026 emit_move_insn (operands
[0], operands
[3]);
3030 emit_move_insn (operands
[0], src
);
3036 m68hc11_split_logical (mode
, code
, operands
)
3037 enum machine_mode mode
;
3044 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3045 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3046 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3048 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3050 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3052 if (INTVAL (operands
[1]) >= 0)
3053 high
[1] = const0_rtx
;
3055 high
[1] = constm1_rtx
;
3058 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3060 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3062 if (INTVAL (operands
[2]) >= 0)
3063 high
[2] = const0_rtx
;
3065 high
[2] = constm1_rtx
;
3068 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3070 low
[3] = operands
[3];
3071 high
[3] = operands
[3];
3074 m68hc11_split_logical (HImode
, code
, low
);
3075 m68hc11_split_logical (HImode
, code
, high
);
3079 m68hc11_emit_logical (mode
, code
, low
);
3080 m68hc11_emit_logical (mode
, code
, high
);
3084 /* Code generation. */
3087 m68hc11_output_swap (insn
, operands
)
3088 rtx insn ATTRIBUTE_UNUSED
;
3091 /* We have to be careful with the cc_status. An address register swap
3092 is generated for some comparison. The comparison is made with D
3093 but the branch really uses the address register. See the split
3094 pattern for compare. The xgdx/xgdy preserve the flags but after
3095 the exchange, the flags will reflect to the value of X and not D.
3096 Tell this by setting the cc_status according to the cc_prev_status. */
3097 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3099 if (cc_prev_status
.value1
!= 0
3100 && (D_REG_P (cc_prev_status
.value1
)
3101 || X_REG_P (cc_prev_status
.value1
)))
3103 cc_status
= cc_prev_status
;
3104 if (D_REG_P (cc_status
.value1
))
3105 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3108 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3114 output_asm_insn ("xgdx", operands
);
3118 if (cc_prev_status
.value1
!= 0
3119 && (D_REG_P (cc_prev_status
.value1
)
3120 || Y_REG_P (cc_prev_status
.value1
)))
3122 cc_status
= cc_prev_status
;
3123 if (D_REG_P (cc_status
.value1
))
3124 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3127 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3133 output_asm_insn ("xgdy", operands
);
3137 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3138 This is used to decide whether a move that set flags should be used
3141 next_insn_test_reg (insn
, reg
)
3147 insn
= next_nonnote_insn (insn
);
3148 if (GET_CODE (insn
) != INSN
)
3151 body
= PATTERN (insn
);
3152 if (sets_cc0_p (body
) != 1)
3155 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3161 /* Generate the code to move a 16-bit operand into another one. */
3164 m68hc11_gen_movhi (insn
, operands
)
3170 /* Move a register or memory to the same location.
3171 This is possible because such insn can appear
3172 in a non-optimizing mode. */
3173 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3175 cc_status
= cc_prev_status
;
3181 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3183 cc_status
= cc_prev_status
;
3184 switch (REGNO (operands
[1]))
3189 output_asm_insn ("psh%1", operands
);
3191 case HARD_SP_REGNUM
:
3192 output_asm_insn ("sts\t-2,sp", operands
);
3199 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3201 cc_status
= cc_prev_status
;
3202 switch (REGNO (operands
[0]))
3207 output_asm_insn ("pul%0", operands
);
3214 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3216 m68hc11_notice_keep_cc (operands
[0]);
3217 output_asm_insn ("tfr\t%1,%0", operands
);
3219 else if (H_REG_P (operands
[0]))
3221 if (SP_REG_P (operands
[0]))
3222 output_asm_insn ("lds\t%1", operands
);
3224 output_asm_insn ("ld%0\t%1", operands
);
3226 else if (H_REG_P (operands
[1]))
3228 if (SP_REG_P (operands
[1]))
3229 output_asm_insn ("sts\t%0", operands
);
3231 output_asm_insn ("st%1\t%0", operands
);
3235 rtx from
= operands
[1];
3236 rtx to
= operands
[0];
3238 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3239 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3240 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3241 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3247 ops
[0] = operands
[2];
3250 m68hc11_gen_movhi (insn
, ops
);
3252 ops
[1] = operands
[2];
3253 m68hc11_gen_movhi (insn
, ops
);
3257 /* !!!! SCz wrong here. */
3258 fatal_insn ("move insn not handled", insn
);
3263 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3265 output_asm_insn ("clr\t%h0", operands
);
3266 output_asm_insn ("clr\t%b0", operands
);
3270 m68hc11_notice_keep_cc (operands
[0]);
3271 output_asm_insn ("movw\t%1,%0", operands
);
3278 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3280 cc_status
= cc_prev_status
;
3281 switch (REGNO (operands
[0]))
3285 output_asm_insn ("pul%0", operands
);
3288 output_asm_insn ("pula", operands
);
3289 output_asm_insn ("pulb", operands
);
3296 /* Some moves to a hard register are special. Not all of them
3297 are really supported and we have to use a temporary
3298 location to provide them (either the stack of a temp var). */
3299 if (H_REG_P (operands
[0]))
3301 switch (REGNO (operands
[0]))
3304 if (X_REG_P (operands
[1]))
3306 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3308 m68hc11_output_swap (insn
, operands
);
3310 else if (next_insn_test_reg (insn
, operands
[0]))
3312 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3316 m68hc11_notice_keep_cc (operands
[0]);
3317 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3320 else if (Y_REG_P (operands
[1]))
3322 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3324 m68hc11_output_swap (insn
, operands
);
3328 /* %t means *ZTMP scratch register. */
3329 output_asm_insn ("sty\t%t1", operands
);
3330 output_asm_insn ("ldd\t%t1", operands
);
3333 else if (SP_REG_P (operands
[1]))
3338 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3339 output_asm_insn ("xgdx", operands
);
3340 output_asm_insn ("tsx", operands
);
3341 output_asm_insn ("xgdx", operands
);
3343 else if (IS_STACK_POP (operands
[1]))
3345 output_asm_insn ("pula\n\tpulb", operands
);
3347 else if (GET_CODE (operands
[1]) == CONST_INT
3348 && INTVAL (operands
[1]) == 0)
3350 output_asm_insn ("clra\n\tclrb", operands
);
3354 output_asm_insn ("ldd\t%1", operands
);
3359 if (D_REG_P (operands
[1]))
3361 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3363 m68hc11_output_swap (insn
, operands
);
3365 else if (next_insn_test_reg (insn
, operands
[0]))
3367 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3371 m68hc11_notice_keep_cc (operands
[0]);
3372 output_asm_insn ("pshb", operands
);
3373 output_asm_insn ("psha", operands
);
3374 output_asm_insn ("pulx", operands
);
3377 else if (Y_REG_P (operands
[1]))
3379 /* When both D and Y are dead, use the sequence xgdy, xgdx
3380 to move Y into X. The D and Y registers are modified. */
3381 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3382 && dead_register_here (insn
, d_reg
))
3384 output_asm_insn ("xgdy", operands
);
3385 output_asm_insn ("xgdx", operands
);
3390 output_asm_insn ("sty\t%t1", operands
);
3391 output_asm_insn ("ldx\t%t1", operands
);
3394 else if (SP_REG_P (operands
[1]))
3396 /* tsx, tsy preserve the flags */
3397 cc_status
= cc_prev_status
;
3398 output_asm_insn ("tsx", operands
);
3402 output_asm_insn ("ldx\t%1", operands
);
3407 if (D_REG_P (operands
[1]))
3409 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3411 m68hc11_output_swap (insn
, operands
);
3415 output_asm_insn ("std\t%t1", operands
);
3416 output_asm_insn ("ldy\t%t1", operands
);
3419 else if (X_REG_P (operands
[1]))
3421 /* When both D and X are dead, use the sequence xgdx, xgdy
3422 to move X into Y. The D and X registers are modified. */
3423 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3424 && dead_register_here (insn
, d_reg
))
3426 output_asm_insn ("xgdx", operands
);
3427 output_asm_insn ("xgdy", operands
);
3432 output_asm_insn ("stx\t%t1", operands
);
3433 output_asm_insn ("ldy\t%t1", operands
);
3436 else if (SP_REG_P (operands
[1]))
3438 /* tsx, tsy preserve the flags */
3439 cc_status
= cc_prev_status
;
3440 output_asm_insn ("tsy", operands
);
3444 output_asm_insn ("ldy\t%1", operands
);
3448 case HARD_SP_REGNUM
:
3449 if (D_REG_P (operands
[1]))
3451 m68hc11_notice_keep_cc (operands
[0]);
3452 output_asm_insn ("xgdx", operands
);
3453 output_asm_insn ("txs", operands
);
3454 output_asm_insn ("xgdx", operands
);
3456 else if (X_REG_P (operands
[1]))
3458 /* tys, txs preserve the flags */
3459 cc_status
= cc_prev_status
;
3460 output_asm_insn ("txs", operands
);
3462 else if (Y_REG_P (operands
[1]))
3464 /* tys, txs preserve the flags */
3465 cc_status
= cc_prev_status
;
3466 output_asm_insn ("tys", operands
);
3470 /* lds sets the flags but the des does not. */
3472 output_asm_insn ("lds\t%1", operands
);
3473 output_asm_insn ("des", operands
);
3478 fatal_insn ("invalid register in the move instruction", insn
);
3483 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3484 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3486 output_asm_insn ("sts\t%0", operands
);
3490 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3492 cc_status
= cc_prev_status
;
3493 switch (REGNO (operands
[1]))
3497 output_asm_insn ("psh%1", operands
);
3500 output_asm_insn ("pshb", operands
);
3501 output_asm_insn ("psha", operands
);
3509 /* Operand 1 must be a hard register. */
3510 if (!H_REG_P (operands
[1]))
3512 fatal_insn ("invalid operand in the instruction", insn
);
3515 reg
= REGNO (operands
[1]);
3519 output_asm_insn ("std\t%0", operands
);
3523 output_asm_insn ("stx\t%0", operands
);
3527 output_asm_insn ("sty\t%0", operands
);
3530 case HARD_SP_REGNUM
:
3534 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3536 output_asm_insn ("pshx", operands
);
3537 output_asm_insn ("tsx", operands
);
3538 output_asm_insn ("inx", operands
);
3539 output_asm_insn ("inx", operands
);
3540 output_asm_insn ("stx\t%0", operands
);
3541 output_asm_insn ("pulx", operands
);
3544 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3546 output_asm_insn ("sty\t%t0", operands
);
3547 output_asm_insn ("tsy", operands
);
3548 output_asm_insn ("sty\t%0", operands
);
3549 output_asm_insn ("ldy\t%t0", operands
);
3553 output_asm_insn ("stx\t%t0", operands
);
3554 output_asm_insn ("tsx", operands
);
3555 output_asm_insn ("stx\t%0", operands
);
3556 output_asm_insn ("ldx\t%t0", operands
);
3562 fatal_insn ("invalid register in the move instruction", insn
);
3568 m68hc11_gen_movqi (insn
, operands
)
3572 /* Move a register or memory to the same location.
3573 This is possible because such insn can appear
3574 in a non-optimizing mode. */
3575 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3577 cc_status
= cc_prev_status
;
3584 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3586 m68hc11_notice_keep_cc (operands
[0]);
3587 output_asm_insn ("tfr\t%1,%0", operands
);
3589 else if (H_REG_P (operands
[0]))
3591 if (Q_REG_P (operands
[0]))
3592 output_asm_insn ("lda%0\t%b1", operands
);
3593 else if (D_REG_P (operands
[0]))
3594 output_asm_insn ("ldab\t%b1", operands
);
3598 else if (H_REG_P (operands
[1]))
3600 if (Q_REG_P (operands
[1]))
3601 output_asm_insn ("sta%1\t%b0", operands
);
3602 else if (D_REG_P (operands
[1]))
3603 output_asm_insn ("stab\t%b0", operands
);
3609 rtx from
= operands
[1];
3610 rtx to
= operands
[0];
3612 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3613 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3614 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3615 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3621 ops
[0] = operands
[2];
3624 m68hc11_gen_movqi (insn
, ops
);
3626 ops
[1] = operands
[2];
3627 m68hc11_gen_movqi (insn
, ops
);
3631 /* !!!! SCz wrong here. */
3632 fatal_insn ("move insn not handled", insn
);
3637 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3639 output_asm_insn ("clr\t%b0", operands
);
3643 m68hc11_notice_keep_cc (operands
[0]);
3644 output_asm_insn ("movb\t%b1,%b0", operands
);
3652 if (H_REG_P (operands
[0]))
3654 switch (REGNO (operands
[0]))
3658 if (X_REG_P (operands
[1]))
3660 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3662 m68hc11_output_swap (insn
, operands
);
3666 output_asm_insn ("stx\t%t1", operands
);
3667 output_asm_insn ("ldab\t%T0", operands
);
3670 else if (Y_REG_P (operands
[1]))
3672 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3674 m68hc11_output_swap (insn
, operands
);
3678 output_asm_insn ("sty\t%t1", operands
);
3679 output_asm_insn ("ldab\t%T0", operands
);
3682 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3683 && !DA_REG_P (operands
[1]))
3685 output_asm_insn ("ldab\t%b1", operands
);
3687 else if (DA_REG_P (operands
[1]))
3689 output_asm_insn ("tab", operands
);
3693 cc_status
= cc_prev_status
;
3699 if (X_REG_P (operands
[1]))
3701 output_asm_insn ("stx\t%t1", operands
);
3702 output_asm_insn ("ldaa\t%T0", operands
);
3704 else if (Y_REG_P (operands
[1]))
3706 output_asm_insn ("sty\t%t1", operands
);
3707 output_asm_insn ("ldaa\t%T0", operands
);
3709 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3710 && !DA_REG_P (operands
[1]))
3712 output_asm_insn ("ldaa\t%b1", operands
);
3714 else if (!DA_REG_P (operands
[1]))
3716 output_asm_insn ("tba", operands
);
3720 cc_status
= cc_prev_status
;
3725 if (D_REG_P (operands
[1]))
3727 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3729 m68hc11_output_swap (insn
, operands
);
3733 output_asm_insn ("stab\t%T1", operands
);
3734 output_asm_insn ("ldx\t%t1", operands
);
3738 else if (Y_REG_P (operands
[1]))
3740 output_asm_insn ("sty\t%t0", operands
);
3741 output_asm_insn ("ldx\t%t0", operands
);
3743 else if (GET_CODE (operands
[1]) == CONST_INT
)
3745 output_asm_insn ("ldx\t%1", operands
);
3747 else if (dead_register_here (insn
, d_reg
))
3749 output_asm_insn ("ldab\t%b1", operands
);
3750 output_asm_insn ("xgdx", operands
);
3752 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3754 output_asm_insn ("xgdx", operands
);
3755 output_asm_insn ("ldab\t%b1", operands
);
3756 output_asm_insn ("xgdx", operands
);
3760 output_asm_insn ("pshb", operands
);
3761 output_asm_insn ("ldab\t%b1", operands
);
3762 output_asm_insn ("stab\t%T1", operands
);
3763 output_asm_insn ("ldx\t%t1", operands
);
3764 output_asm_insn ("pulb", operands
);
3770 if (D_REG_P (operands
[1]))
3772 output_asm_insn ("stab\t%T1", operands
);
3773 output_asm_insn ("ldy\t%t1", operands
);
3776 else if (X_REG_P (operands
[1]))
3778 output_asm_insn ("stx\t%t1", operands
);
3779 output_asm_insn ("ldy\t%t1", operands
);
3782 else if (GET_CODE (operands
[1]) == CONST_INT
)
3784 output_asm_insn ("ldy\t%1", operands
);
3786 else if (dead_register_here (insn
, d_reg
))
3788 output_asm_insn ("ldab\t%b1", operands
);
3789 output_asm_insn ("xgdy", operands
);
3791 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3793 output_asm_insn ("xgdy", operands
);
3794 output_asm_insn ("ldab\t%b1", operands
);
3795 output_asm_insn ("xgdy", operands
);
3799 output_asm_insn ("pshb", operands
);
3800 output_asm_insn ("ldab\t%b1", operands
);
3801 output_asm_insn ("stab\t%T1", operands
);
3802 output_asm_insn ("ldy\t%t1", operands
);
3803 output_asm_insn ("pulb", operands
);
3809 fatal_insn ("invalid register in the instruction", insn
);
3813 else if (H_REG_P (operands
[1]))
3815 switch (REGNO (operands
[1]))
3819 output_asm_insn ("stab\t%b0", operands
);
3823 output_asm_insn ("staa\t%b0", operands
);
3827 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3831 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3835 fatal_insn ("invalid register in the move instruction", insn
);
3842 fatal_insn ("operand 1 must be a hard register", insn
);
3846 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3847 The source and destination must be D or A and the shift must
3850 m68hc11_gen_rotate (code
, insn
, operands
)
3857 if (GET_CODE (operands
[2]) != CONST_INT
3858 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3859 fatal_insn ("invalid rotate insn", insn
);
3861 val
= INTVAL (operands
[2]);
3862 if (code
== ROTATERT
)
3863 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3865 if (GET_MODE (operands
[0]) != QImode
)
3868 /* Rotate by 8-bits if the shift is within [5..11]. */
3869 if (val
>= 5 && val
<= 11)
3872 output_asm_insn ("exg\ta,b", operands
);
3875 output_asm_insn ("psha", operands
);
3876 output_asm_insn ("tba", operands
);
3877 output_asm_insn ("pulb", operands
);
3882 /* If the shift is big, invert the rotation. */
3890 /* Set the carry to bit-15, but don't change D yet. */
3891 if (GET_MODE (operands
[0]) != QImode
)
3893 output_asm_insn ("asra", operands
);
3894 output_asm_insn ("rola", operands
);
3899 /* Rotate B first to move the carry to bit-0. */
3900 if (D_REG_P (operands
[0]))
3901 output_asm_insn ("rolb", operands
);
3903 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3904 output_asm_insn ("rola", operands
);
3909 /* Set the carry to bit-8 of D. */
3910 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3912 output_asm_insn ("tap", operands
);
3917 /* Rotate B first to move the carry to bit-7. */
3918 if (D_REG_P (operands
[0]))
3919 output_asm_insn ("rorb", operands
);
3921 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3922 output_asm_insn ("rora", operands
);
3929 /* Store in cc_status the expressions that the condition codes will
3930 describe after execution of an instruction whose pattern is EXP.
3931 Do not alter them if the instruction would not alter the cc's. */
3934 m68hc11_notice_update_cc (exp
, insn
)
3936 rtx insn ATTRIBUTE_UNUSED
;
3938 /* recognize SET insn's. */
3939 if (GET_CODE (exp
) == SET
)
3941 /* Jumps do not alter the cc's. */
3942 if (SET_DEST (exp
) == pc_rtx
)
3945 /* NOTE: most instructions don't affect the carry bit, but the
3946 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3947 the conditions.h header. */
3949 /* Function calls clobber the cc's. */
3950 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3955 /* Tests and compares set the cc's in predictable ways. */
3956 else if (SET_DEST (exp
) == cc0_rtx
)
3958 cc_status
.flags
= 0;
3959 cc_status
.value1
= XEXP (exp
, 0);
3960 cc_status
.value2
= XEXP (exp
, 1);
3964 /* All other instructions affect the condition codes. */
3965 cc_status
.flags
= 0;
3966 cc_status
.value1
= XEXP (exp
, 0);
3967 cc_status
.value2
= XEXP (exp
, 1);
3972 /* Default action if we haven't recognized something
3973 and returned earlier. */
3977 if (cc_status
.value2
!= 0)
3978 switch (GET_CODE (cc_status
.value2
))
3980 /* These logical operations can generate several insns.
3981 The flags are setup according to what is generated. */
3987 /* The (not ...) generates several 'com' instructions for
3988 non QImode. We have to invalidate the flags. */
3990 if (GET_MODE (cc_status
.value2
) != QImode
)
4002 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4003 cc_status
.flags
|= CC_NO_OVERFLOW
;
4006 /* The asl sets the overflow bit in such a way that this
4007 makes the flags unusable for a next compare insn. */
4011 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4012 cc_status
.flags
|= CC_NO_OVERFLOW
;
4015 /* A load/store instruction does not affect the carry. */
4020 cc_status
.flags
|= CC_NO_OVERFLOW
;
4026 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4028 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4029 cc_status
.value2
= 0;
4032 /* The current instruction does not affect the flags but changes
4033 the register 'reg'. See if the previous flags can be kept for the
4034 next instruction to avoid a comparison. */
4036 m68hc11_notice_keep_cc (reg
)
4040 || cc_prev_status
.value1
== 0
4041 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4042 || (cc_prev_status
.value2
4043 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4046 cc_status
= cc_prev_status
;
4051 /* Machine Specific Reorg. */
4053 /* Z register replacement:
4055 GCC treats the Z register as an index base address register like
4056 X or Y. In general, it uses it during reload to compute the address
4057 of some operand. This helps the reload pass to avoid to fall into the
4058 register spill failure.
4060 The Z register is in the A_REGS class. In the machine description,
4061 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4063 It can appear everywhere an X or Y register can appear, except for
4064 some templates in the clobber section (when a clobber of X or Y is asked).
4065 For a given instruction, the template must ensure that no more than
4066 2 'A' registers are used. Otherwise, the register replacement is not
4069 To replace the Z register, the algorithm is not terrific:
4070 1. Insns that do not use the Z register are not changed
4071 2. When a Z register is used, we scan forward the insns to see
4072 a potential register to use: either X or Y and sometimes D.
4073 We stop when a call, a label or a branch is seen, or when we
4074 detect that both X and Y are used (probably at different times, but it does
4076 3. The register that will be used for the replacement of Z is saved
4077 in a .page0 register or on the stack. If the first instruction that
4078 used Z, uses Z as an input, the value is loaded from another .page0
4079 register. The replacement register is pushed on the stack in the
4080 rare cases where a compare insn uses Z and we couldn't find if X/Y
4082 4. The Z register is replaced in all instructions until we reach
4083 the end of the Z-block, as detected by step 2.
4084 5. If we detect that Z is still alive, its value is saved.
4085 If the replacement register is alive, its old value is loaded.
4087 The Z register can be disabled with -ffixed-z.
4097 int must_restore_reg
;
4108 int save_before_last
;
4109 int z_loaded_with_sp
;
4112 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4113 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
4114 static void m68hc11_z_replacement
PARAMS ((rtx
));
4115 static void m68hc11_reassign_regs
PARAMS ((rtx
));
4117 int z_replacement_completed
= 0;
4119 /* Analyze the insn to find out which replacement register to use and
4120 the boundaries of the replacement.
4121 Returns 0 if we reached the last insn to be replaced, 1 if we can
4122 continue replacement in next insns. */
4125 m68hc11_check_z_replacement (insn
, info
)
4127 struct replace_info
*info
;
4129 int this_insn_uses_ix
;
4130 int this_insn_uses_iy
;
4131 int this_insn_uses_z
;
4132 int this_insn_uses_z_in_dst
;
4133 int this_insn_uses_d
;
4137 /* A call is said to clobber the Z register, we don't need
4138 to save the value of Z. We also don't need to restore
4139 the replacement register (unless it is used by the call). */
4140 if (GET_CODE (insn
) == CALL_INSN
)
4142 body
= PATTERN (insn
);
4144 info
->can_use_d
= 0;
4146 /* If the call is an indirect call with Z, we have to use the
4147 Y register because X can be used as an input (D+X).
4148 We also must not save Z nor restore Y. */
4149 if (reg_mentioned_p (z_reg
, body
))
4151 insn
= NEXT_INSN (insn
);
4154 info
->found_call
= 1;
4155 info
->must_restore_reg
= 0;
4156 info
->last
= NEXT_INSN (insn
);
4158 info
->need_save_z
= 0;
4161 if (GET_CODE (insn
) == CODE_LABEL
4162 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4165 if (GET_CODE (insn
) == JUMP_INSN
)
4167 if (reg_mentioned_p (z_reg
, insn
) == 0)
4170 info
->can_use_d
= 0;
4171 info
->must_save_reg
= 0;
4172 info
->must_restore_reg
= 0;
4173 info
->need_save_z
= 0;
4174 info
->last
= NEXT_INSN (insn
);
4177 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4182 /* Z register dies here. */
4183 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4185 body
= PATTERN (insn
);
4186 if (GET_CODE (body
) == SET
)
4188 rtx src
= XEXP (body
, 1);
4189 rtx dst
= XEXP (body
, 0);
4191 /* Condition code is set here. We have to restore the X/Y and
4192 save into Z before any test/compare insn because once we save/restore
4193 we can change the condition codes. When the compare insn uses Z and
4194 we can't use X/Y, the comparison is made with the *ZREG soft register
4195 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4198 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4199 || (GET_CODE (src
) == COMPARE
&&
4200 (rtx_equal_p (XEXP (src
, 0), z_reg
)
4201 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
4203 if (insn
== info
->first
)
4205 info
->must_load_z
= 0;
4206 info
->must_save_reg
= 0;
4207 info
->must_restore_reg
= 0;
4208 info
->need_save_z
= 0;
4209 info
->found_call
= 1;
4210 info
->regno
= SOFT_Z_REGNUM
;
4215 if (reg_mentioned_p (z_reg
, src
) == 0)
4217 info
->can_use_d
= 0;
4221 if (insn
!= info
->first
)
4224 /* Compare insn which uses Z. We have to save/restore the X/Y
4225 register without modifying the condition codes. For this
4226 we have to use a push/pop insn. */
4227 info
->must_push_reg
= 1;
4231 /* Z reg is set to something new. We don't need to load it. */
4234 if (!reg_mentioned_p (z_reg
, src
))
4236 /* Z reg is used before being set. Treat this as
4237 a new sequence of Z register replacement. */
4238 if (insn
!= info
->first
)
4242 info
->must_load_z
= 0;
4244 info
->z_set_count
++;
4245 info
->z_value
= src
;
4247 info
->z_loaded_with_sp
= 1;
4249 else if (reg_mentioned_p (z_reg
, dst
))
4250 info
->can_use_d
= 0;
4252 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4253 | reg_mentioned_p (d_reg
, dst
);
4254 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4255 | reg_mentioned_p (ix_reg
, dst
);
4256 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4257 | reg_mentioned_p (iy_reg
, dst
);
4258 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4260 /* If z is used as an address operand (like (MEM (reg z))),
4261 we can't replace it with d. */
4262 if (this_insn_uses_z
&& !Z_REG_P (src
)
4263 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4264 && Z_REG_P (XEXP (src
, 0))
4265 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4266 && insn
== info
->first
4267 && dead_register_here (insn
, d_reg
)))
4268 info
->can_use_d
= 0;
4270 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4271 if (TARGET_M6812
&& !z_dies_here
4272 && ((this_insn_uses_z
&& side_effects_p (src
))
4273 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4275 info
->need_save_z
= 1;
4276 info
->z_set_count
++;
4278 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4280 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4282 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4285 if (this_insn_uses_d
)
4286 info
->can_use_d
= 0;
4288 /* IX and IY are used at the same time, we have to restore
4289 the value of the scratch register before this insn. */
4290 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4295 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4296 info
->can_use_d
= 0;
4298 if (info
->x_used
== 0 && this_insn_uses_ix
)
4302 /* We have a (set (REG:HI X) (REG:HI Z)).
4303 Since we use Z as the replacement register, this insn
4304 is no longer necessary. We turn it into a note. We must
4305 not reload the old value of X. */
4306 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4310 info
->need_save_z
= 0;
4313 info
->must_save_reg
= 0;
4314 info
->must_restore_reg
= 0;
4315 info
->found_call
= 1;
4316 info
->can_use_d
= 0;
4317 PUT_CODE (insn
, NOTE
);
4318 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4319 NOTE_SOURCE_FILE (insn
) = 0;
4320 info
->last
= NEXT_INSN (insn
);
4325 && (rtx_equal_p (src
, z_reg
)
4326 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4330 info
->need_save_z
= 0;
4333 info
->last
= NEXT_INSN (insn
);
4334 info
->must_save_reg
= 0;
4335 info
->must_restore_reg
= 0;
4337 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4338 && !reg_mentioned_p (ix_reg
, src
))
4343 info
->need_save_z
= 0;
4345 else if (TARGET_M6812
&& side_effects_p (src
))
4348 info
->must_restore_reg
= 0;
4353 info
->save_before_last
= 1;
4355 info
->must_restore_reg
= 0;
4356 info
->last
= NEXT_INSN (insn
);
4358 else if (info
->can_use_d
)
4360 info
->last
= NEXT_INSN (insn
);
4366 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4367 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4369 info
->need_save_z
= 0;
4371 info
->last
= NEXT_INSN (insn
);
4372 info
->regno
= HARD_X_REGNUM
;
4373 info
->must_save_reg
= 0;
4374 info
->must_restore_reg
= 0;
4377 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4379 info
->regno
= HARD_X_REGNUM
;
4380 info
->must_restore_reg
= 0;
4381 info
->must_save_reg
= 0;
4385 if (info
->y_used
== 0 && this_insn_uses_iy
)
4389 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4393 info
->need_save_z
= 0;
4396 info
->must_save_reg
= 0;
4397 info
->must_restore_reg
= 0;
4398 info
->found_call
= 1;
4399 info
->can_use_d
= 0;
4400 PUT_CODE (insn
, NOTE
);
4401 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4402 NOTE_SOURCE_FILE (insn
) = 0;
4403 info
->last
= NEXT_INSN (insn
);
4408 && (rtx_equal_p (src
, z_reg
)
4409 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4414 info
->need_save_z
= 0;
4416 info
->last
= NEXT_INSN (insn
);
4417 info
->must_save_reg
= 0;
4418 info
->must_restore_reg
= 0;
4420 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4421 && !reg_mentioned_p (iy_reg
, src
))
4426 info
->need_save_z
= 0;
4428 else if (TARGET_M6812
&& side_effects_p (src
))
4431 info
->must_restore_reg
= 0;
4436 info
->save_before_last
= 1;
4438 info
->must_restore_reg
= 0;
4439 info
->last
= NEXT_INSN (insn
);
4441 else if (info
->can_use_d
)
4443 info
->last
= NEXT_INSN (insn
);
4450 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4451 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4453 info
->need_save_z
= 0;
4455 info
->last
= NEXT_INSN (insn
);
4456 info
->regno
= HARD_Y_REGNUM
;
4457 info
->must_save_reg
= 0;
4458 info
->must_restore_reg
= 0;
4461 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4463 info
->regno
= HARD_Y_REGNUM
;
4464 info
->must_restore_reg
= 0;
4465 info
->must_save_reg
= 0;
4471 info
->need_save_z
= 0;
4473 if (info
->last
== 0)
4474 info
->last
= NEXT_INSN (insn
);
4477 return info
->last
!= NULL_RTX
? 0 : 1;
4479 if (GET_CODE (body
) == PARALLEL
)
4482 char ix_clobber
= 0;
4483 char iy_clobber
= 0;
4485 this_insn_uses_iy
= 0;
4486 this_insn_uses_ix
= 0;
4487 this_insn_uses_z
= 0;
4489 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4492 int uses_ix
, uses_iy
, uses_z
;
4494 x
= XVECEXP (body
, 0, i
);
4496 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4497 info
->can_use_d
= 0;
4499 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4500 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4501 uses_z
= reg_mentioned_p (z_reg
, x
);
4502 if (GET_CODE (x
) == CLOBBER
)
4504 ix_clobber
|= uses_ix
;
4505 iy_clobber
|= uses_iy
;
4506 z_clobber
|= uses_z
;
4510 this_insn_uses_ix
|= uses_ix
;
4511 this_insn_uses_iy
|= uses_iy
;
4512 this_insn_uses_z
|= uses_z
;
4514 if (uses_z
&& GET_CODE (x
) == SET
)
4516 rtx dst
= XEXP (x
, 0);
4519 info
->z_set_count
++;
4521 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4522 info
->need_save_z
= 1;
4525 info
->need_save_z
= 0;
4529 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4530 this_insn_uses_ix
, this_insn_uses_iy
,
4531 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4534 if (this_insn_uses_z
)
4535 info
->can_use_d
= 0;
4537 if (z_clobber
&& info
->first
!= insn
)
4539 info
->need_save_z
= 0;
4543 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4545 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4547 info
->must_load_z
= 0;
4549 if (dead_register_here (insn
, d_reg
))
4551 info
->regno
= HARD_D_REGNUM
;
4552 info
->must_save_reg
= 0;
4553 info
->must_restore_reg
= 0;
4555 else if (dead_register_here (insn
, ix_reg
))
4557 info
->regno
= HARD_X_REGNUM
;
4558 info
->must_save_reg
= 0;
4559 info
->must_restore_reg
= 0;
4561 else if (dead_register_here (insn
, iy_reg
))
4563 info
->regno
= HARD_Y_REGNUM
;
4564 info
->must_save_reg
= 0;
4565 info
->must_restore_reg
= 0;
4567 if (info
->regno
>= 0)
4569 info
->last
= NEXT_INSN (insn
);
4572 if (this_insn_uses_ix
== 0)
4574 info
->regno
= HARD_X_REGNUM
;
4575 info
->must_save_reg
= 1;
4576 info
->must_restore_reg
= 1;
4578 else if (this_insn_uses_iy
== 0)
4580 info
->regno
= HARD_Y_REGNUM
;
4581 info
->must_save_reg
= 1;
4582 info
->must_restore_reg
= 1;
4586 info
->regno
= HARD_D_REGNUM
;
4587 info
->must_save_reg
= 1;
4588 info
->must_restore_reg
= 1;
4590 info
->last
= NEXT_INSN (insn
);
4594 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4595 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4597 if (this_insn_uses_z
)
4599 if (info
->y_used
== 0 && iy_clobber
)
4601 info
->regno
= HARD_Y_REGNUM
;
4602 info
->must_save_reg
= 0;
4603 info
->must_restore_reg
= 0;
4605 if (info
->first
!= insn
4606 && ((info
->y_used
&& ix_clobber
)
4607 || (info
->x_used
&& iy_clobber
)))
4610 info
->last
= NEXT_INSN (insn
);
4611 info
->save_before_last
= 1;
4615 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4617 if (this_insn_uses_z
)
4619 fatal_insn ("cannot do z-register replacement", insn
);
4623 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4630 if (iy_clobber
|| z_clobber
)
4632 info
->last
= NEXT_INSN (insn
);
4633 info
->save_before_last
= 1;
4638 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4645 if (ix_clobber
|| z_clobber
)
4647 info
->last
= NEXT_INSN (insn
);
4648 info
->save_before_last
= 1;
4655 info
->need_save_z
= 0;
4659 if (GET_CODE (body
) == CLOBBER
)
4662 /* IX and IY are used at the same time, we have to restore
4663 the value of the scratch register before this insn. */
4664 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4668 if (info
->x_used
== 0 && this_insn_uses_ix
)
4676 if (info
->y_used
== 0 && this_insn_uses_iy
)
4690 m68hc11_find_z_replacement (insn
, info
)
4692 struct replace_info
*info
;
4696 info
->replace_reg
= NULL_RTX
;
4697 info
->must_load_z
= 1;
4698 info
->need_save_z
= 1;
4699 info
->must_save_reg
= 1;
4700 info
->must_restore_reg
= 1;
4704 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4705 info
->found_call
= 0;
4709 info
->z_set_count
= 0;
4710 info
->z_value
= NULL_RTX
;
4711 info
->must_push_reg
= 0;
4712 info
->save_before_last
= 0;
4713 info
->z_loaded_with_sp
= 0;
4715 /* Scan the insn forward to find an address register that is not used.
4717 - the flow of the program changes,
4718 - when we detect that both X and Y are necessary,
4719 - when the Z register dies,
4720 - when the condition codes are set. */
4722 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4724 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4728 /* May be we can use Y or X if they contain the same value as Z.
4729 This happens very often after the reload. */
4730 if (info
->z_set_count
== 1)
4732 rtx p
= info
->first
;
4737 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4739 else if (info
->y_used
)
4741 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4743 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4746 info
->regno
= HARD_Y_REGNUM
;
4748 info
->regno
= HARD_X_REGNUM
;
4749 info
->must_load_z
= 0;
4750 info
->must_save_reg
= 0;
4751 info
->must_restore_reg
= 0;
4752 info
->found_call
= 1;
4755 if (info
->z_set_count
== 0)
4756 info
->need_save_z
= 0;
4759 info
->need_save_z
= 0;
4761 if (info
->last
== 0)
4764 if (info
->regno
>= 0)
4767 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4769 else if (info
->can_use_d
)
4771 reg
= HARD_D_REGNUM
;
4772 info
->replace_reg
= d_reg
;
4774 else if (info
->x_used
)
4776 reg
= HARD_Y_REGNUM
;
4777 info
->replace_reg
= iy_reg
;
4781 reg
= HARD_X_REGNUM
;
4782 info
->replace_reg
= ix_reg
;
4786 if (info
->must_save_reg
&& info
->must_restore_reg
)
4788 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4790 info
->must_save_reg
= 0;
4791 info
->must_restore_reg
= 0;
4796 /* The insn uses the Z register. Find a replacement register for it
4797 (either X or Y) and replace it in the insn and the next ones until
4798 the flow changes or the replacement register is used. Instructions
4799 are emited before and after the Z-block to preserve the value of
4800 Z and of the replacement register. */
4803 m68hc11_z_replacement (insn
)
4808 struct replace_info info
;
4810 /* Find trivial case where we only need to replace z with the
4811 equivalent soft register. */
4812 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4814 rtx body
= PATTERN (insn
);
4815 rtx src
= XEXP (body
, 1);
4816 rtx dst
= XEXP (body
, 0);
4818 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4820 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4823 else if (Z_REG_P (src
)
4824 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4826 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4829 else if (D_REG_P (dst
)
4830 && m68hc11_arith_operator (src
, GET_MODE (src
))
4831 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4833 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4836 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4837 && INTVAL (src
) == 0)
4839 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4840 /* Force it to be re-recognized. */
4841 INSN_CODE (insn
) = -1;
4846 m68hc11_find_z_replacement (insn
, &info
);
4848 replace_reg
= info
.replace_reg
;
4849 replace_reg_qi
= NULL_RTX
;
4851 /* Save the X register in a .page0 location. */
4852 if (info
.must_save_reg
&& !info
.must_push_reg
)
4856 if (info
.must_push_reg
&& 0)
4857 dst
= gen_rtx (MEM
, HImode
,
4858 gen_rtx (PRE_DEC
, HImode
,
4859 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4861 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4863 emit_insn_before (gen_movhi (dst
,
4864 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4866 if (info
.must_load_z
&& !info
.must_push_reg
)
4868 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4869 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4874 /* Replace all occurrence of Z by replace_reg.
4875 Stop when the last instruction to replace is reached.
4876 Also stop when we detect a change in the flow (but it's not
4877 necessary; just safeguard). */
4879 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4883 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4886 if (GET_CODE (insn
) != INSN
4887 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4890 body
= PATTERN (insn
);
4891 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4892 || GET_CODE (body
) == ASM_OPERANDS
4893 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4897 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4899 printf ("Reg mentioned here...:\n");
4904 /* Stack pointer was decremented by 2 due to the push.
4905 Correct that by adding 2 to the destination. */
4906 if (info
.must_push_reg
4907 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4911 src
= SET_SRC (body
);
4912 dst
= SET_DEST (body
);
4913 if (SP_REG_P (src
) && Z_REG_P (dst
))
4914 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4917 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4918 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4920 INSN_CODE (insn
) = -1;
4921 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4922 fatal_insn ("cannot do z-register replacement", insn
);
4925 /* Likewise for (REG:QI Z). */
4926 if (reg_mentioned_p (z_reg
, insn
))
4928 if (replace_reg_qi
== NULL_RTX
)
4929 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4930 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4933 /* If there is a REG_INC note on Z, replace it with a
4934 REG_INC note on the replacement register. This is necessary
4935 to make sure that the flow pass will identify the change
4936 and it will not remove a possible insn that saves Z. */
4937 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4939 if (REG_NOTE_KIND (note
) == REG_INC
4940 && GET_CODE (XEXP (note
, 0)) == REG
4941 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4943 XEXP (note
, 0) = replace_reg
;
4947 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4951 /* Save Z before restoring the old value. */
4952 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4954 rtx save_pos_insn
= insn
;
4956 /* If Z is clobber by the last insn, we have to save its value
4957 before the last instruction. */
4958 if (info
.save_before_last
)
4959 save_pos_insn
= PREV_INSN (save_pos_insn
);
4961 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4962 gen_rtx (REG
, HImode
, info
.regno
)),
4966 if (info
.must_push_reg
&& info
.last
)
4970 body
= PATTERN (info
.last
);
4971 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4973 gen_rtx (USE
, VOIDmode
,
4975 gen_rtx (USE
, VOIDmode
,
4976 gen_rtx (REG
, HImode
,
4978 PATTERN (info
.last
) = new_body
;
4980 /* Force recognition on insn since we changed it. */
4981 INSN_CODE (insn
) = -1;
4983 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4985 fatal_insn ("invalid Z register replacement for insn", insn
);
4987 insn
= NEXT_INSN (info
.last
);
4990 /* Restore replacement register unless it was died. */
4991 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4995 if (info
.must_push_reg
&& 0)
4996 dst
= gen_rtx (MEM
, HImode
,
4997 gen_rtx (POST_INC
, HImode
,
4998 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
5000 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
5002 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
5009 /* Scan all the insn and re-affects some registers
5010 - The Z register (if it was used), is affected to X or Y depending
5011 on the instruction. */
5014 m68hc11_reassign_regs (first
)
5019 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5020 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5021 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5022 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5024 /* Scan all insns to replace Z by X or Y preserving the old value
5025 of X/Y and restoring it afterward. */
5027 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5031 if (GET_CODE (insn
) == CODE_LABEL
5032 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5035 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5038 body
= PATTERN (insn
);
5039 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5042 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5043 || GET_CODE (body
) == ASM_OPERANDS
5044 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5047 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5048 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5051 /* If Z appears in this insn, replace it in the current insn
5052 and the next ones until the flow changes or we have to
5053 restore back the replacement register. */
5055 if (reg_mentioned_p (z_reg
, body
))
5057 m68hc11_z_replacement (insn
);
5062 printf ("insn not handled by Z replacement:\n");
5071 m68hc11_reorg (first
)
5077 z_replacement_completed
= 0;
5078 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5080 /* Some RTX are shared at this point. This breaks the Z register
5081 replacement, unshare everything. */
5082 unshare_all_rtl_again (first
);
5084 /* Force a split of all splitable insn. This is necessary for the
5085 Z register replacement mechanism because we end up with basic insns. */
5086 split_all_insns_noflow ();
5089 z_replacement_completed
= 1;
5090 m68hc11_reassign_regs (first
);
5093 compute_bb_for_insn ();
5095 /* After some splitting, there are some oportunities for CSE pass.
5096 This happens quite often when 32-bit or above patterns are split. */
5097 if (optimize
> 0 && split_done
)
5099 reload_cse_regs (first
);
5102 /* Re-create the REG_DEAD notes. These notes are used in the machine
5103 description to use the best assembly directives. */
5106 /* Before recomputing the REG_DEAD notes, remove all of them.
5107 This is necessary because the reload_cse_regs() pass can
5108 have replaced some (MEM) with a register. In that case,
5109 the REG_DEAD that could exist for that register may become
5111 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5117 pnote
= ®_NOTES (insn
);
5120 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5121 *pnote
= XEXP (*pnote
, 1);
5123 pnote
= &XEXP (*pnote
, 1);
5128 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5131 z_replacement_completed
= 2;
5133 /* If optimizing, then go ahead and split insns that must be
5134 split after Z register replacement. This gives more opportunities
5135 for peephole (in particular for consecutives xgdx/xgdy). */
5137 split_all_insns_noflow ();
5139 /* Once insns are split after the z_replacement_completed == 2,
5140 we must not re-run the life_analysis. The xgdx/xgdy patterns
5141 are not recognized and the life_analysis pass removes some
5142 insns because it thinks some (SETs) are noops or made to dead
5143 stores (which is false due to the swap).
5145 Do a simple pass to eliminate the noop set that the final
5146 split could generate (because it was easier for split definition). */
5150 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5154 if (INSN_DELETED_P (insn
))
5156 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
5159 /* Remove the (set (R) (R)) insns generated by some splits. */
5160 body
= PATTERN (insn
);
5161 if (GET_CODE (body
) == SET
5162 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5164 PUT_CODE (insn
, NOTE
);
5165 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5166 NOTE_SOURCE_FILE (insn
) = 0;
5174 /* Cost functions. */
5176 /* Cost of moving memory. */
5178 m68hc11_memory_move_cost (mode
, class, in
)
5179 enum machine_mode mode
;
5180 enum reg_class
class;
5181 int in ATTRIBUTE_UNUSED
;
5183 if (class <= H_REGS
&& class > NO_REGS
)
5185 if (GET_MODE_SIZE (mode
) <= 2)
5186 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5188 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5192 if (GET_MODE_SIZE (mode
) <= 2)
5193 return COSTS_N_INSNS (3);
5195 return COSTS_N_INSNS (4);
5200 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5201 Reload does not check the constraint of set insns when the two registers
5202 have a move cost of 2. Setting a higher cost will force reload to check
5205 m68hc11_register_move_cost (mode
, from
, to
)
5206 enum machine_mode mode
;
5207 enum reg_class from
;
5210 /* All costs are symmetric, so reduce cases by putting the
5211 lower number class as the destination. */
5214 enum reg_class tmp
= to
;
5215 to
= from
, from
= tmp
;
5218 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5219 else if (from
<= S_REGS
)
5220 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5222 return COSTS_N_INSNS (2);
5226 /* Provide the costs of an addressing mode that contains ADDR.
5227 If ADDR is not a valid address, its cost is irrelevant. */
5230 m68hc11_address_cost (addr
)
5235 switch (GET_CODE (addr
))
5238 /* Make the cost of hard registers and specially SP, FP small. */
5239 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5256 register rtx plus0
= XEXP (addr
, 0);
5257 register rtx plus1
= XEXP (addr
, 1);
5259 if (GET_CODE (plus0
) != REG
)
5262 switch (GET_CODE (plus1
))
5265 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5266 || INTVAL (plus1
) < m68hc11_min_offset
)
5268 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5272 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5294 if (SP_REG_P (XEXP (addr
, 0)))
5303 printf ("Address cost: %d for :", cost
);
5312 m68hc11_shift_cost (mode
, x
, shift
)
5313 enum machine_mode mode
;
5319 total
= rtx_cost (x
, SET
);
5321 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5322 else if (mode
== HImode
)
5323 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5324 else if (shift
== 8 || shift
== 16 || shift
== 32)
5325 total
+= m68hc11_cost
->shiftHI_const
[8];
5326 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5328 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5331 /* For SI and others, the cost is higher. */
5332 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5333 total
*= GET_MODE_SIZE (mode
) / 2;
5335 /* When optimizing for size, make shift more costly so that
5336 multiplications are preferred. */
5337 if (optimize_size
&& (shift
% 8) != 0)
5344 m68hc11_rtx_costs_1 (x
, code
, outer_code
)
5347 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5349 enum machine_mode mode
= GET_MODE (x
);
5360 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5362 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5365 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5366 total
+= m68hc11_cost
->shift_var
;
5372 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5373 total
+= m68hc11_cost
->logical
;
5375 /* Logical instructions are byte instructions only. */
5376 total
*= GET_MODE_SIZE (mode
);
5381 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5382 total
+= m68hc11_cost
->add
;
5383 if (GET_MODE_SIZE (mode
) > 2)
5385 total
*= GET_MODE_SIZE (mode
) / 2;
5392 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5396 total
+= m68hc11_cost
->divQI
;
5400 total
+= m68hc11_cost
->divHI
;
5405 total
+= m68hc11_cost
->divSI
;
5411 /* mul instruction produces 16-bit result. */
5412 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5413 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5414 return m68hc11_cost
->multQI
5415 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5416 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5418 /* emul instruction produces 32-bit result for 68HC12. */
5419 if (TARGET_M6812
&& mode
== SImode
5420 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5421 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5422 return m68hc11_cost
->multHI
5423 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5424 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5426 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5430 total
+= m68hc11_cost
->multQI
;
5434 total
+= m68hc11_cost
->multHI
;
5439 total
+= m68hc11_cost
->multSI
;
5446 extra_cost
= COSTS_N_INSNS (2);
5453 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5456 return total
+ COSTS_N_INSNS (1);
5460 return total
+ COSTS_N_INSNS (2);
5464 return total
+ COSTS_N_INSNS (4);
5466 return total
+ COSTS_N_INSNS (8);
5469 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5470 return COSTS_N_INSNS (1);
5472 return COSTS_N_INSNS (1);
5475 return COSTS_N_INSNS (4);
5480 m68hc11_rtx_costs (x
, code
, outer_code
, total
)
5482 int code
, outer_code
;
5487 /* Constants are cheap. Moving them in registers must be avoided
5488 because most instructions do not handle two register operands. */
5494 /* Logical and arithmetic operations with a constant operand are
5495 better because they are not supported with two registers. */
5497 if (outer_code
== SET
&& x
== const0_rtx
)
5498 /* After reload, the reload_cse pass checks the cost to change
5499 a SET into a PLUS. Make const0 cheap then. */
5500 *total
= 1 - reload_completed
;
5505 if (outer_code
== SET
)
5506 *total
= 1 - reload_completed
;
5528 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5537 /* print_options - called at the start of the code generation for a
5540 extern char *asm_file_name
;
5543 #include <sys/types.h>
5552 extern int save_argc
;
5553 extern char **save_argv
;
5555 fprintf (out
, ";;; Command:\t");
5556 for (i
= 0; i
< save_argc
; i
++)
5558 fprintf (out
, "%s", save_argv
[i
]);
5559 if (i
+ 1 < save_argc
)
5562 fprintf (out
, "\n");
5564 a_time
= ctime (&c_time
);
5565 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5568 #define __VERSION__ "[unknown]"
5570 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5572 fprintf (out
, ";;; (META)compiled by CC.\n");
5577 m68hc11_asm_file_start (out
, main_file
)
5579 const char *main_file
;
5581 fprintf (out
, ";;;-----------------------------------------\n");
5582 fprintf (out
, ";;; Start %s gcc assembly output\n",
5585 : TARGET_M68S12
? "MC68HCS12" : "MC68HC12");
5586 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5587 print_options (out
);
5588 fprintf (out
, ";;;-----------------------------------------\n");
5589 output_file_directive (out
, main_file
);
5592 fprintf (out
, "\t.mode mshort\n");
5594 fprintf (out
, "\t.mode mlong\n");
5599 m68hc11_asm_out_constructor (symbol
, priority
)
5603 default_ctor_section_asm_out_constructor (symbol
, priority
);
5604 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5608 m68hc11_asm_out_destructor (symbol
, priority
)
5612 default_dtor_section_asm_out_destructor (symbol
, priority
);
5613 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5616 #include "gt-m68hc11.h"