1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@worldnet.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
23 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24 on gcc 2.6.3. I have used it as a starting point for this port.
25 However, this new port is a complete re-write. Its internal
26 design is completely different. The generated code is not
27 compatible with the gcc 2.6.3 port.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
42 #include "hard-reg-set.h"
44 #include "insn-config.h"
45 #include "conditions.h"
47 #include "insn-attr.h"
52 #include "basic-block.h"
56 static void print_options
PARAMS ((FILE *));
57 static void emit_move_after_reload
PARAMS ((rtx
, rtx
, rtx
));
58 static rtx simplify_logical
PARAMS ((enum machine_mode
, int, rtx
, rtx
*));
59 static void m68hc11_emit_logical
PARAMS ((enum machine_mode
, int, rtx
*));
60 static int go_if_legitimate_address_internal
PARAMS((rtx
, enum machine_mode
,
62 static int register_indirect_p
PARAMS((rtx
, enum machine_mode
, int));
63 static rtx m68hc11_expand_compare
PARAMS((enum rtx_code
, rtx
, rtx
));
64 static int must_parenthesize
PARAMS ((rtx
));
66 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
68 void create_regs_rtx
PARAMS ((void));
70 static void asm_print_register
PARAMS ((FILE *, int));
72 rtx m68hc11_soft_tmp_reg
;
74 /* Must be set to 1 to produce debug messages. */
77 extern FILE *asm_out_file
;
85 static int regs_inited
= 0;
88 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
89 int current_function_interrupt
;
91 /* Set to 1 by expand_prologue() when the function is a trap handler. */
92 int current_function_trap
;
94 /* Min offset that is valid for the indirect addressing mode. */
95 HOST_WIDE_INT m68hc11_min_offset
= 0;
97 /* Max offset that is valid for the indirect addressing mode. */
98 HOST_WIDE_INT m68hc11_max_offset
= 256;
100 /* The class value for base registers. */
101 enum reg_class m68hc11_base_reg_class
= A_REGS
;
103 /* The class value for index registers. This is NO_REGS for 68HC11. */
104 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
106 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
108 /* Tables that tell whether a given hard register is valid for
109 a base or an index register. It is filled at init time depending
110 on the target processor. */
111 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
112 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
114 /* A correction offset which is applied to the stack pointer.
115 This is 1 for 68HC11 and 0 for 68HC12. */
116 int m68hc11_sp_correction
;
118 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
119 rtx m68hc11_compare_op0
;
120 rtx m68hc11_compare_op1
;
123 /* Machine specific options */
125 const char *m68hc11_regparm_string
;
126 const char *m68hc11_reg_alloc_order
;
127 const char *m68hc11_soft_reg_count
;
129 static void m68hc11_add_gc_roots
PARAMS ((void));
131 static int nb_soft_regs
;
133 /* Flag defined in c-decl.c
135 Nonzero means don't recognize the non-ANSI builtin functions.
138 It is set by 'm68hc11_override_options' to ensure that bcmp() and
139 bzero() are not defined. Their prototype are wrong and they
140 conflict with newlib definition. Don't define as external to
141 avoid a link problem for f77. */
142 int flag_no_nonansi_builtin
;
145 m68hc11_override_options ()
147 m68hc11_add_gc_roots ();
149 flag_no_nonansi_builtin
= 1;
151 memset (m68hc11_reg_valid_for_index
, 0,
152 sizeof (m68hc11_reg_valid_for_index
));
153 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
155 /* Configure for a 68hc11 processor. */
158 /* If gcc was built for a 68hc12, invalidate that because
159 a -m68hc11 option was specified on the command line. */
160 if (TARGET_DEFAULT
!= MASK_M6811
)
161 target_flags
&= ~TARGET_DEFAULT
;
163 m68hc11_min_offset
= 0;
164 m68hc11_max_offset
= 256;
165 m68hc11_index_reg_class
= NO_REGS
;
166 m68hc11_base_reg_class
= A_REGS
;
167 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
168 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
169 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
170 m68hc11_sp_correction
= 1;
171 m68hc11_tmp_regs_class
= D_REGS
;
172 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
173 m68hc11_soft_reg_count
= "4";
176 /* Configure for a 68hc12 processor. */
179 m68hc11_min_offset
= 0;
180 m68hc11_max_offset
= 65536;
181 m68hc11_index_reg_class
= D_REGS
;
182 m68hc11_base_reg_class
= A_OR_SP_REGS
;
183 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
184 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
185 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
186 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
187 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
188 m68hc11_sp_correction
= 0;
189 m68hc11_tmp_regs_class
= TMP_REGS
;
190 target_flags
&= ~MASK_M6811
;
191 if (m68hc11_soft_reg_count
== 0)
192 m68hc11_soft_reg_count
= "2";
199 m68hc11_conditional_register_usage ()
202 int cnt
= atoi (m68hc11_soft_reg_count
);
206 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
207 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
210 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
213 call_used_regs
[i
] = 1;
218 /* Reload and register operations. */
220 static const char *reg_class_names
[] = REG_CLASS_NAMES
;
226 /* regs_inited = 1; */
227 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
228 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
229 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
230 da_reg
= gen_rtx (REG
, QImode
, HARD_A_REGNUM
);
231 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
233 stack_push_word
= gen_rtx (MEM
, HImode
,
234 gen_rtx (PRE_DEC
, HImode
,
235 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
236 stack_pop_word
= gen_rtx (MEM
, HImode
,
237 gen_rtx (POST_INC
, HImode
,
238 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
242 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
243 - 8 bit values are stored anywhere (except the SP register).
244 - 16 bit values can be stored in any register whose mode is 16
245 - 32 bit values can be stored in D, X registers or in a soft register
246 (except the last one because we need 2 soft registers)
247 - Values whose size is > 32 bit are not stored in real hard
248 registers. They may be stored in soft registers if there are
251 hard_regno_mode_ok (regno
, mode
)
253 enum machine_mode mode
;
255 switch (GET_MODE_SIZE (mode
))
258 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
261 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
264 return G_REGNO_P (regno
);
267 /* We have to accept a QImode in X or Y registers. Otherwise, the
268 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
269 in the insns. Reload fails if the insn rejects the register class 'a'
270 as well as if it accepts it. Patterns that failed were
271 zero_extend_qihi2 and iorqi3. */
273 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
281 limit_reload_class (mode
, class)
282 enum machine_mode mode
;
283 enum reg_class
class;
287 if (class == m68hc11_base_reg_class
|| class == SP_REGS
288 || class == Y_REGS
|| class == X_REGS
289 || class == X_OR_SP_REGS
|| class == Y_OR_S_REGS
290 || class == A_OR_SP_REGS
)
295 printf ("Forcing to A_REGS\n");
298 return m68hc11_base_reg_class
;
304 preferred_reload_class (operand
, class)
306 enum reg_class
class;
308 enum machine_mode mode
;
310 mode
= GET_MODE (operand
);
314 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
317 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
318 return m68hc11_base_reg_class
;
320 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
321 || GET_CODE (operand
) == CONST_INT
))
323 /* S_REGS class must not be used. The movhi template does not
324 work to move a memory to a soft register.
325 Restrict to a hard reg. */
330 case D_OR_A_OR_S_REGS
:
336 case D_OR_SP_OR_S_REGS
:
337 class = D_OR_SP_REGS
;
339 case D_OR_Y_OR_S_REGS
:
342 case D_OR_X_OR_S_REGS
:
358 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
362 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
366 else if (class >= S_REGS
&& S_REG_P (operand
))
372 case D_OR_A_OR_S_REGS
:
378 case D_OR_SP_OR_S_REGS
:
379 class = D_OR_SP_REGS
;
381 case D_OR_Y_OR_S_REGS
:
384 case D_OR_X_OR_S_REGS
:
400 else if (class >= S_REGS
)
404 printf ("Class = %s for: ", reg_class_names
[class]);
412 printf (" => class=%s\n", reg_class_names
[class]);
420 /* Return 1 if the operand is a valid indexed addressing mode.
421 For 68hc11: n,r with n in [0..255] and r in A_REGS class
422 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
424 register_indirect_p (operand
, mode
, strict
)
426 enum machine_mode mode
;
431 switch (GET_CODE (operand
))
437 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
438 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
442 base
= XEXP (operand
, 0);
443 if (GET_CODE (base
) == MEM
)
446 offset
= XEXP (operand
, 1);
447 if (GET_CODE (offset
) == MEM
)
450 if (GET_CODE (base
) == REG
)
452 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
458 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
460 if (GET_CODE (offset
) == REG
)
462 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
468 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
473 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
480 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
481 a 68HC12 1-byte index addressing mode. */
483 m68hc11_small_indexed_indirect_p (operand
, mode
)
485 enum machine_mode mode
;
489 if (GET_CODE (operand
) != MEM
)
492 operand
= XEXP (operand
, 0);
493 if (CONSTANT_ADDRESS_P (operand
))
496 if (PUSH_POP_ADDRESS_P (operand
))
499 if (!register_indirect_p (operand
, mode
,
500 (reload_completed
| reload_in_progress
)))
503 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
504 && (reload_completed
| reload_in_progress
))
506 base
= XEXP (operand
, 0);
507 offset
= XEXP (operand
, 1);
508 if (GET_CODE (base
) == CONST_INT
)
511 switch (GET_MODE_SIZE (mode
))
514 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
519 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
524 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
533 m68hc11_register_indirect_p (operand
, mode
)
535 enum machine_mode mode
;
537 if (GET_CODE (operand
) != MEM
)
540 operand
= XEXP (operand
, 0);
541 return register_indirect_p (operand
, mode
,
542 (reload_completed
| reload_in_progress
));
546 go_if_legitimate_address_internal (operand
, mode
, strict
)
548 enum machine_mode mode
;
551 if (CONSTANT_ADDRESS_P (operand
))
553 /* Reject the global variables if they are too wide. This forces
554 a load of their address in a register and generates smaller code. */
555 if (GET_MODE_SIZE (mode
) == 8)
560 if (register_indirect_p (operand
, mode
, strict
))
564 if (PUSH_POP_ADDRESS_P (operand
))
568 if (symbolic_memory_operand (operand
, mode
))
576 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
578 enum machine_mode mode
;
585 printf ("Checking: ");
590 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
594 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
601 printf ("go_if_legitimate%s, ret 0: %d:",
602 (strict
? "_strict" : ""), mode
);
611 m68hc11_legitimize_address (operand
, old_operand
, mode
)
612 rtx
*operand ATTRIBUTE_UNUSED
;
613 rtx old_operand ATTRIBUTE_UNUSED
;
614 enum machine_mode mode ATTRIBUTE_UNUSED
;
621 m68hc11_reload_operands (operands
)
624 enum machine_mode mode
;
626 if (regs_inited
== 0)
629 mode
= GET_MODE (operands
[1]);
631 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
632 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
634 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
635 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
637 if (GET_CODE (base
) != REG
)
644 /* If the offset is out of range, we have to compute the address
645 with a separate add instruction. We try to do with with an 8-bit
646 add on the A register. This is possible only if the lowest part
647 of the offset (ie, big_offset % 256) is a valid constant offset
648 with respect to the mode. If it's not, we have to generate a
649 16-bit add on the D register. From:
651 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
655 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
656 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
657 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
658 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
660 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
661 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
664 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
667 rtx reg
= operands
[0];
669 int val
= INTVAL (big_offset
);
672 /* We use the 'operands[0]' as a scratch register to compute the
673 address. Make sure 'base' is in that register. */
674 if (!rtx_equal_p (base
, operands
[0]))
676 emit_move_insn (reg
, base
);
686 vh
= (val
>> 8) & 0x0FF;
690 /* Create the lowest part offset that still remains to be added.
691 If it's not a valid offset, do a 16-bit add. */
692 offset
= gen_rtx (CONST_INT
, VOIDmode
, vl
);
693 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
695 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
696 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
701 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
702 gen_rtx (PLUS
, HImode
, reg
,
704 VOIDmode
, vh
<< 8))));
706 emit_move_insn (operands
[0],
707 gen_rtx (MEM
, GET_MODE (operands
[1]),
708 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
713 /* Use the normal gen_movhi pattern. */
718 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
721 enum machine_mode dmode
;
722 enum machine_mode smode
;
732 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
736 ret
= emit_library_call_value (libcall
, NULL_RTX
, 1, dmode
, 1,
738 equiv
= gen_rtx (code
, dmode
, operands
[1]);
742 ret
= emit_library_call_value (libcall
, operands
[0], 1, dmode
, 2,
743 operands
[1], smode
, operands
[2],
745 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
752 insns
= get_insns ();
754 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
757 /* Returns true if X is a PRE/POST increment decrement
758 (same as auto_inc_p() in rtlanal.c but do not take into
759 account the stack). */
761 m68hc11_auto_inc_p (x
)
764 return GET_CODE (x
) == PRE_DEC
765 || GET_CODE (x
) == POST_INC
766 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
770 /* Predicates for machine description. */
773 memory_reload_operand (operand
, mode
)
775 enum machine_mode mode ATTRIBUTE_UNUSED
;
777 return GET_CODE (operand
) == MEM
778 && GET_CODE (XEXP (operand
, 0)) == PLUS
779 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
780 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
781 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
782 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
786 tst_operand (operand
, mode
)
788 enum machine_mode mode
;
790 if (GET_CODE (operand
) == MEM
)
792 rtx addr
= XEXP (operand
, 0);
793 if (m68hc11_auto_inc_p (addr
))
796 return nonimmediate_operand (operand
, mode
);
800 cmp_operand (operand
, mode
)
802 enum machine_mode mode
;
804 if (GET_CODE (operand
) == MEM
)
806 rtx addr
= XEXP (operand
, 0);
807 if (m68hc11_auto_inc_p (addr
))
810 return general_operand (operand
, mode
);
814 non_push_operand (operand
, mode
)
816 enum machine_mode mode
;
818 if (general_operand (operand
, mode
) == 0)
821 if (push_operand (operand
, mode
) == 1)
827 reg_or_some_mem_operand (operand
, mode
)
829 enum machine_mode mode
;
831 if (GET_CODE (operand
) == MEM
)
833 rtx op
= XEXP (operand
, 0);
835 if (symbolic_memory_operand (op
, mode
))
838 if (IS_STACK_PUSH (operand
))
841 if (m68hc11_register_indirect_p (operand
, mode
))
847 return register_operand (operand
, mode
);
851 stack_register_operand (operand
, mode
)
853 enum machine_mode mode ATTRIBUTE_UNUSED
;
855 return SP_REG_P (operand
);
859 d_register_operand (operand
, mode
)
861 enum machine_mode mode ATTRIBUTE_UNUSED
;
863 if (GET_CODE (operand
) == SUBREG
)
864 operand
= XEXP (operand
, 0);
866 return GET_CODE (operand
) == REG
867 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
868 || REGNO (operand
) == HARD_D_REGNUM
);
872 hard_addr_reg_operand (operand
, mode
)
874 enum machine_mode mode ATTRIBUTE_UNUSED
;
876 if (GET_CODE (operand
) == SUBREG
)
877 operand
= XEXP (operand
, 0);
879 return GET_CODE (operand
) == REG
880 && (REGNO (operand
) == HARD_X_REGNUM
881 || REGNO (operand
) == HARD_Y_REGNUM
882 || REGNO (operand
) == HARD_Z_REGNUM
);
886 hard_reg_operand (operand
, mode
)
888 enum machine_mode mode ATTRIBUTE_UNUSED
;
890 if (GET_CODE (operand
) == SUBREG
)
891 operand
= XEXP (operand
, 0);
893 return GET_CODE (operand
) == REG
894 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
895 || H_REGNO_P (REGNO (operand
)));
899 memory_indexed_operand (operand
, mode
)
901 enum machine_mode mode ATTRIBUTE_UNUSED
;
903 if (GET_CODE (operand
) != MEM
)
906 operand
= XEXP (operand
, 0);
907 if (GET_CODE (operand
) == PLUS
)
909 if (GET_CODE (XEXP (operand
, 0)) == REG
)
910 operand
= XEXP (operand
, 0);
911 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
912 operand
= XEXP (operand
, 1);
914 return GET_CODE (operand
) == REG
915 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
916 || A_REGNO_P (REGNO (operand
)));
920 push_pop_operand_p (operand
)
923 if (GET_CODE (operand
) != MEM
)
927 operand
= XEXP (operand
, 0);
928 return PUSH_POP_ADDRESS_P (operand
);
931 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
932 reference and a constant. */
935 symbolic_memory_operand (op
, mode
)
937 enum machine_mode mode
;
939 switch (GET_CODE (op
))
946 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
947 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
948 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
950 /* ??? This clause seems to be irrelevant. */
952 return GET_MODE (op
) == mode
;
955 return symbolic_memory_operand (XEXP (op
, 0), mode
)
956 && symbolic_memory_operand (XEXP (op
, 1), mode
);
964 m68hc11_logical_operator (op
, mode
)
966 enum machine_mode mode ATTRIBUTE_UNUSED
;
968 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
972 m68hc11_arith_operator (op
, mode
)
974 enum machine_mode mode ATTRIBUTE_UNUSED
;
976 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
977 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
978 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
979 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
980 || GET_CODE (op
) == ROTATERT
;
984 m68hc11_non_shift_operator (op
, mode
)
986 enum machine_mode mode ATTRIBUTE_UNUSED
;
988 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
989 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
994 m68hc11_unary_operator (op
, mode
)
996 enum machine_mode mode ATTRIBUTE_UNUSED
;
998 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
999 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1006 m68hc11_block_profiler (out
, blockno
)
1007 FILE *out ATTRIBUTE_UNUSED
;
1008 int blockno ATTRIBUTE_UNUSED
;
1014 m68hc11_function_block_profiler (out
, block_or_label
)
1015 FILE *out ATTRIBUTE_UNUSED
;
1016 int block_or_label ATTRIBUTE_UNUSED
;
1021 /* Declaration of types. */
1023 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1024 with arguments ARGS is a valid machine specific attribute for DECL.
1025 The attributes in ATTRIBUTES have previously been assigned to DECL. */
1028 m68hc11_valid_decl_attribute_p (decl
, attributes
, identifier
, args
)
1029 tree decl ATTRIBUTE_UNUSED
;
1030 tree attributes ATTRIBUTE_UNUSED
;
1031 tree identifier ATTRIBUTE_UNUSED
;
1032 tree args ATTRIBUTE_UNUSED
;
1037 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1038 with arguments ARGS is a valid machine specific attribute for TYPE.
1039 The attributes in ATTRIBUTES have previously been assigned to TYPE. */
1042 m68hc11_valid_type_attribute_p (type
, attributes
, identifier
, args
)
1044 tree attributes ATTRIBUTE_UNUSED
;
1048 if (TREE_CODE (type
) != FUNCTION_TYPE
1049 && TREE_CODE (type
) != FIELD_DECL
&& TREE_CODE (type
) != TYPE_DECL
)
1052 if (TREE_CODE (type
) == FUNCTION_TYPE
)
1054 if (is_attribute_p ("interrupt", identifier
))
1055 return (args
== NULL_TREE
);
1056 if (is_attribute_p ("trap", identifier
))
1057 return (args
== NULL_TREE
);
1063 /* If defined, a C expression whose value is zero if the attributes on
1064 TYPE1 and TYPE2 are incompatible, one if they are compatible, and
1065 two if they are nearly compatible (which causes a warning to be
1069 m68hc11_comp_type_attributes (type1
, type2
)
1070 tree type1 ATTRIBUTE_UNUSED
;
1071 tree type2 ATTRIBUTE_UNUSED
;
1076 /* If defined, a C statement that assigns default attributes to newly
1080 m68hc11_set_default_type_attributes (type
)
1081 tree type ATTRIBUTE_UNUSED
;
1085 /* Define this macro if references to a symbol must be treated
1086 differently depending on something about the variable or function
1087 named by the symbol (such as what section it is in).
1089 For the 68HC11, we want to recognize trap handlers so that we
1090 handle calls to traps in a special manner (by issuing the trap).
1091 This information is stored in SYMBOL_REF_FLAG. */
1093 m68hc11_encode_section_info (decl
)
1100 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1103 rtl
= DECL_RTL (decl
);
1105 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1106 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1107 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1111 /* Argument support functions. */
1113 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1114 Arrays are passed by references and other types by value.
1116 SCz: I tried to pass DImode by reference but it seems that this
1117 does not work very well. */
1119 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1120 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1121 enum machine_mode mode ATTRIBUTE_UNUSED
;
1123 int named ATTRIBUTE_UNUSED
;
1125 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1126 /* Consider complex values as aggregates, so care for TCmode. */
1127 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1128 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1132 /* Define the offset between two registers, one to be eliminated, and the
1133 other its replacement, at the start of a routine. */
1135 m68hc11_initial_elimination_offset (from
, to
)
1144 /* For a trap handler, we must take into account the registers which
1145 are pushed on the stack during the trap (except the PC). */
1146 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1147 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1148 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1153 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1155 /* 2 is for the saved frame.
1156 1 is for the 'sts' correction when creating the frame. */
1157 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1160 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1165 /* Push any 2 byte pseudo hard registers that we need to save. */
1166 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1168 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1174 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1176 return get_frame_size () + size
;
1179 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1181 return size
- m68hc11_sp_correction
;
1186 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1187 for a call to a function whose data type is FNTYPE.
1188 For a library call, FNTYPE is 0. */
1191 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1192 CUMULATIVE_ARGS
*cum
;
1198 z_replacement_completed
= 0;
1202 /* For a library call, we must find out the type of the return value.
1203 When the return value is bigger than 4 bytes, it is returned in
1204 memory. In that case, the first argument of the library call is a
1205 pointer to the memory location. Because the first argument is passed in
1206 register D, we have to identify this, so that the first function
1207 parameter is not passed in D either. */
1213 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1216 /* If the library ends in 'di' or in 'df', we assume it's
1217 returning some DImode or some DFmode which are 64-bit wide. */
1218 name
= XSTR (libname
, 0);
1219 len
= strlen (name
);
1221 && ((name
[len
- 2] == 'd'
1222 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1223 || (name
[len
- 3] == 'd'
1224 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1226 /* We are in. Mark the first parameter register as already used. */
1233 ret_type
= TREE_TYPE (fntype
);
1235 if (ret_type
&& aggregate_value_p (ret_type
))
1242 /* Update the data in CUM to advance over an argument
1243 of mode MODE and data type TYPE.
1244 (TYPE is null for libcalls where that information may not be available.) */
1247 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1248 CUMULATIVE_ARGS
*cum
;
1249 enum machine_mode mode
;
1251 int named ATTRIBUTE_UNUSED
;
1253 if (mode
!= BLKmode
)
1255 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1258 cum
->words
= GET_MODE_SIZE (mode
);
1262 cum
->words
+= GET_MODE_SIZE (mode
);
1263 if (cum
->words
<= HARD_REG_SIZE
)
1269 cum
->words
+= int_size_in_bytes (type
);
1274 /* Define where to put the arguments to a function.
1275 Value is zero to push the argument on the stack,
1276 or a hard register in which to store the argument.
1278 MODE is the argument's machine mode.
1279 TYPE is the data type of the argument (as a tree).
1280 This is null for libcalls where that information may
1282 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1283 the preceding args and about the function being called.
1284 NAMED is nonzero if this argument is a named parameter
1285 (otherwise it is an extra parameter matching an ellipsis). */
1288 m68hc11_function_arg (cum
, mode
, type
, named
)
1289 const CUMULATIVE_ARGS
*cum
;
1290 enum machine_mode mode
;
1291 tree type ATTRIBUTE_UNUSED
;
1292 int named ATTRIBUTE_UNUSED
;
1294 if (cum
->words
!= 0)
1299 if (mode
!= BLKmode
)
1301 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1302 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1304 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1308 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1313 /* The "standard" implementation of va_start: just assign `nextarg' to
1316 m68hc11_expand_builtin_va_start (stdarg_p
, valist
, nextarg
)
1317 int stdarg_p ATTRIBUTE_UNUSED
;
1323 /* SCz: the default implementation in builtins.c adjust the
1324 nextarg using UNITS_PER_WORD. This works only with -mshort
1325 and fails when integers are 32-bit. Here is the correct way. */
1327 nextarg
= plus_constant (nextarg
, -INT_TYPE_SIZE
/ 8);
1329 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1330 make_tree (ptr_type_node
, nextarg
));
1331 TREE_SIDE_EFFECTS (t
) = 1;
1333 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1337 m68hc11_va_arg (valist
, type
)
1342 HOST_WIDE_INT align
;
1343 HOST_WIDE_INT rounded_size
;
1347 /* Compute the rounded size of the type. */
1348 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1349 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1353 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1355 if (pad_direction
== downward
)
1357 /* Small args are padded downward. */
1360 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1361 if (rounded_size
> align
)
1364 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1365 build_int_2 (rounded_size
- adj
, 0));
1368 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1369 addr
= copy_to_reg (addr
);
1371 /* Compute new value for AP. */
1372 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1373 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1374 build_int_2 (rounded_size
, 0)));
1375 TREE_SIDE_EFFECTS (t
) = 1;
1376 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1381 /* If defined, a C expression which determines whether, and in which direction,
1382 to pad out an argument with extra space. The value should be of type
1383 `enum direction': either `upward' to pad above the argument,
1384 `downward' to pad below, or `none' to inhibit padding.
1386 Structures are stored left shifted in their argument slot. */
1388 m68hc11_function_arg_padding (mode
, type
)
1389 enum machine_mode mode
;
1392 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1395 /* This is the default definition. */
1396 return (!BYTES_BIG_ENDIAN
1399 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1400 && int_size_in_bytes (type
) <
1401 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1402 PARM_BOUNDARY
) ? downward
: upward
));
1406 /* Function prologue and epilogue. */
1408 /* Emit a move after the reload pass has completed. This is used to
1409 emit the prologue and epilogue. */
1411 emit_move_after_reload (to
, from
, scratch
)
1412 rtx to
, from
, scratch
;
1416 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1418 insn
= emit_move_insn (to
, from
);
1422 emit_move_insn (scratch
, from
);
1423 insn
= emit_move_insn (to
, scratch
);
1426 /* Put a REG_INC note to tell the flow analysis that the instruction
1428 if (IS_STACK_PUSH (to
))
1430 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1431 XEXP (XEXP (to
, 0), 0),
1434 else if (IS_STACK_POP (from
))
1436 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1437 XEXP (XEXP (from
, 0), 0),
1443 m68hc11_total_frame_size ()
1448 size
= get_frame_size ();
1449 if (current_function_interrupt
)
1451 size
+= 3 * HARD_REG_SIZE
;
1453 if (frame_pointer_needed
)
1454 size
+= HARD_REG_SIZE
;
1456 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1457 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1458 size
+= HARD_REG_SIZE
;
1464 m68hc11_function_epilogue (out
, size
)
1465 FILE *out ATTRIBUTE_UNUSED
;
1466 int size ATTRIBUTE_UNUSED
;
1468 /* We catch the function epilogue generation to have a chance
1469 to clear the z_replacement_completed flag. */
1470 z_replacement_completed
= 0;
1481 if (reload_completed
!= 1)
1484 size
= get_frame_size ();
1488 /* Generate specific prologue for interrupt handlers. */
1489 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1490 current_function_interrupt
= lookup_attribute ("interrupt",
1491 func_attr
) != NULL_TREE
;
1492 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1494 /* Get the scratch register to build the frame and push registers.
1495 If the first argument is a 32-bit quantity, the D+X registers
1496 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1497 For 68HC12, this scratch register is not used. */
1498 if (current_function_args_info
.nregs
== 2)
1503 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1504 Other soft registers in page0 need not to be saved because they
1505 will be restored by C functions. For a trap handler, we don't
1506 need to preserve these registers because this is a synchronous call. */
1507 if (current_function_interrupt
)
1509 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1510 emit_move_after_reload (stack_push_word
,
1511 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1512 emit_move_after_reload (stack_push_word
,
1513 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1517 /* Save current stack frame. */
1518 if (frame_pointer_needed
)
1519 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1521 /* Allocate local variables. */
1522 if (TARGET_M6812
&& size
>= 2)
1524 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1525 stack_pointer_rtx
, GEN_INT (-size
)));
1531 insn
= gen_rtx_PARALLEL
1534 gen_rtx_SET (VOIDmode
,
1536 gen_rtx_PLUS (HImode
,
1539 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1546 /* Allocate by pushing scratch values. */
1547 for (i
= 2; i
<= size
; i
+= 2)
1548 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1551 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1552 stack_pointer_rtx
, GEN_INT (-1)));
1555 /* Create the frame pointer. */
1556 if (frame_pointer_needed
)
1557 emit_move_after_reload (hard_frame_pointer_rtx
,
1558 stack_pointer_rtx
, scratch
);
1560 /* Push any 2 byte pseudo hard registers that we need to save. */
1561 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1563 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1565 emit_move_after_reload (stack_push_word
,
1566 gen_rtx (REG
, HImode
, regno
), scratch
);
1579 if (reload_completed
!= 1)
1582 size
= get_frame_size ();
1584 /* If we are returning a value in two registers, we have to preserve the
1585 X register and use the Y register to restore the stack and the saved
1586 registers. Otherwise, use X because it's faster (and smaller). */
1587 if (current_function_return_rtx
== 0)
1589 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1590 return_size
= HARD_REG_SIZE
;
1592 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1594 if (return_size
> HARD_REG_SIZE
)
1599 /* Pop any 2 byte pseudo hard registers that we saved. */
1600 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1602 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1604 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1605 stack_pop_word
, scratch
);
1609 /* de-allocate auto variables */
1610 if (TARGET_M6812
&& size
>= 2)
1612 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1613 stack_pointer_rtx
, GEN_INT (size
)));
1619 insn
= gen_rtx_PARALLEL
1622 gen_rtx_SET (VOIDmode
,
1624 gen_rtx_PLUS (HImode
,
1627 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1634 for (i
= 2; i
<= size
; i
+= 2)
1635 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1637 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1638 stack_pointer_rtx
, GEN_INT (1)));
1641 /* Restore previous frame pointer. */
1642 if (frame_pointer_needed
)
1643 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1645 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1646 if (current_function_interrupt
)
1648 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1649 stack_pop_word
, scratch
);
1650 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1651 stack_pop_word
, scratch
);
1652 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1655 /* If the trap handler returns some value, copy the value
1656 in D, X onto the stack so that the rti will pop the return value
1658 else if (current_function_trap
&& return_size
!= 0)
1660 rtx addr_reg
= stack_pointer_rtx
;
1664 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1667 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1668 gen_rtx (PLUS
, HImode
, addr_reg
,
1669 GEN_INT (1))), d_reg
, 0);
1670 if (return_size
> HARD_REG_SIZE
)
1671 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1672 gen_rtx (PLUS
, HImode
, addr_reg
,
1673 GEN_INT (3))), ix_reg
, 0);
1676 emit_jump_insn (gen_return ());
1680 /* Low and High part extraction for 68HC11. These routines are
1681 similar to gen_lowpart and gen_highpart but they have been
1682 fixed to work for constants and 68HC11 specific registers. */
1685 m68hc11_gen_lowpart (mode
, x
)
1686 enum machine_mode mode
;
1689 /* We assume that the low part of an auto-inc mode is the same with
1690 the mode changed and that the caller split the larger mode in the
1692 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1694 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1697 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1698 floating-point constant. A CONST_DOUBLE is used whenever the
1699 constant requires more than one word in order to be adequately
1701 if (GET_CODE (x
) == CONST_DOUBLE
)
1705 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1709 if (GET_MODE (x
) == SFmode
)
1711 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1712 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1718 split_double (x
, &first
, &second
);
1722 return gen_rtx (CONST_INT
, VOIDmode
, l
[0]);
1724 return gen_rtx (CONST_INT
, VOIDmode
, l
[0] & 0x0ffff);
1728 l
[0] = CONST_DOUBLE_LOW (x
);
1731 return gen_rtx (CONST_INT
, VOIDmode
, l
[0]);
1732 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1733 return gen_rtx (CONST_INT
, VOIDmode
, l
[0] & 0x0FFFF);
1738 if (mode
== QImode
&& D_REG_P (x
))
1739 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1741 /* gen_lowpart crashes when it is called with a SUBREG. */
1742 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1745 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1746 else if (mode
== HImode
)
1747 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 1);
1751 x
= gen_lowpart (mode
, x
);
1753 /* Return a different rtx to avoid to share it in several insns
1754 (when used by a split pattern). Sharing addresses within
1755 a MEM breaks the Z register replacement (and reloading). */
1756 if (GET_CODE (x
) == MEM
)
1762 m68hc11_gen_highpart (mode
, x
)
1763 enum machine_mode mode
;
1766 /* We assume that the high part of an auto-inc mode is the same with
1767 the mode changed and that the caller split the larger mode in the
1769 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1771 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1774 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1775 floating-point constant. A CONST_DOUBLE is used whenever the
1776 constant requires more than one word in order to be adequately
1778 if (GET_CODE (x
) == CONST_DOUBLE
)
1782 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1786 if (GET_MODE (x
) == SFmode
)
1788 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1789 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1795 split_double (x
, &first
, &second
);
1799 return gen_rtx (CONST_INT
, VOIDmode
, l
[1]);
1801 return gen_rtx (CONST_INT
, VOIDmode
, (l
[1] >> 16) & 0x0ffff);
1805 l
[1] = CONST_DOUBLE_HIGH (x
);
1809 return gen_rtx (CONST_INT
, VOIDmode
, l
[1]);
1810 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1811 return gen_rtx (CONST_INT
, VOIDmode
, (l
[0] >> 16) & 0x0FFFF);
1815 if (GET_CODE (x
) == CONST_INT
)
1817 HOST_WIDE_INT val
= INTVAL (x
);
1821 return gen_rtx (CONST_INT
, VOIDmode
, val
>> 8);
1823 else if (mode
== HImode
)
1825 return gen_rtx (CONST_INT
, VOIDmode
, val
>> 16);
1828 if (mode
== QImode
&& D_REG_P (x
))
1829 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1831 /* There is no way in GCC to represent the upper part of a word register.
1832 To obtain the 8-bit upper part of a soft register, we change the
1833 reg into a mem rtx. This is possible because they are physically
1834 located in memory. There is no offset because we are big-endian. */
1835 if (mode
== QImode
&& S_REG_P (x
))
1839 /* For 68HC12, avoid the '*' for direct addressing mode. */
1840 pos
= TARGET_M6812
? 1 : 0;
1841 return gen_rtx (MEM
, QImode
,
1842 gen_rtx (SYMBOL_REF
, Pmode
,
1843 ®_names
[REGNO (x
)][pos
]));
1846 /* gen_highpart crashes when it is called with a SUBREG. */
1847 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1849 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
1851 x
= gen_highpart (mode
, x
);
1853 /* Return a different rtx to avoid to share it in several insns
1854 (when used by a split pattern). Sharing addresses within
1855 a MEM breaks the Z register replacement (and reloading). */
1856 if (GET_CODE (x
) == MEM
)
1862 /* Obscure register manipulation. */
1864 /* Finds backward in the instructions to see if register 'reg' is
1865 dead. This is used when generating code to see if we can use 'reg'
1866 as a scratch register. This allows us to choose a better generation
1867 of code when we know that some register dies or can be clobbered. */
1870 dead_register_here (x
, reg
)
1878 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
1882 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
1883 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
1889 if (GET_CODE (body
) == CALL_INSN
)
1891 if (GET_CODE (body
) == JUMP_INSN
)
1894 if (GET_CODE (body
) == SET
)
1896 rtx dst
= XEXP (body
, 0);
1898 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
1900 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
1903 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
1906 else if (reg_mentioned_p (reg
, p
)
1907 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
1911 /* Scan forward to see if the register is set in some insns and never
1913 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
1917 if (GET_CODE (p
) == CODE_LABEL
1918 || GET_CODE (p
) == JUMP_INSN
1919 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
1922 if (GET_CODE (p
) != INSN
)
1926 if (GET_CODE (body
) == SET
)
1928 rtx src
= XEXP (body
, 1);
1929 rtx dst
= XEXP (body
, 0);
1931 if (GET_CODE (dst
) == REG
1932 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
1936 /* Register is used (may be in source or in dest). */
1937 if (reg_mentioned_p (reg
, p
)
1938 || (x_reg
!= 0 && GET_MODE (p
) == SImode
1939 && reg_mentioned_p (x_reg
, p
)))
1942 return p
== 0 ? 1 : 0;
1946 /* Code generation operations called from machine description file. */
1948 /* Print the name of register 'regno' in the assembly file. */
1950 asm_print_register (file
, regno
)
1954 const char *name
= reg_names
[regno
];
1956 if (TARGET_M6812
&& name
[0] == '*')
1959 asm_fprintf (file
, "%s", name
);
1962 /* A C compound statement to output to stdio stream STREAM the
1963 assembler syntax for an instruction operand X. X is an RTL
1966 CODE is a value that can be used to specify one of several ways
1967 of printing the operand. It is used when identical operands
1968 must be printed differently depending on the context. CODE
1969 comes from the `%' specification that was used to request
1970 printing of the operand. If the specification was just `%DIGIT'
1971 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
1972 is the ASCII code for LTR.
1974 If X is a register, this macro should print the register's name.
1975 The names can be found in an array `reg_names' whose type is
1976 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
1978 When the machine description has a specification `%PUNCT' (a `%'
1979 followed by a punctuation character), this macro is called with
1980 a null pointer for X and the punctuation character for CODE.
1982 The M68HC11 specific codes are:
1984 'b' for the low part of the operand.
1985 'h' for the high part of the operand
1986 The 'b' or 'h' modifiers have no effect if the operand has
1987 the QImode and is not a S_REG_P (soft register). If the
1988 operand is a hard register, these two modifiers have no effect.
1989 't' generate the temporary scratch register. The operand is
1991 'T' generate the low-part temporary scratch register. The operand is
1995 print_operand (file
, op
, letter
)
2002 asm_print_register (file
, SOFT_TMP_REGNUM
);
2005 else if (letter
== 'T')
2007 asm_print_register (file
, SOFT_TMP_REGNUM
);
2008 asm_fprintf (file
, "+1");
2011 else if (letter
== '#')
2013 asm_fprintf (file
, "%0I");
2016 if (GET_CODE (op
) == REG
)
2018 if (letter
== 'b' && S_REG_P (op
))
2020 asm_print_register (file
, REGNO (op
));
2021 asm_fprintf (file
, "+1");
2025 asm_print_register (file
, REGNO (op
));
2030 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2033 asm_fprintf (file
, "%0I%%lo(");
2035 asm_fprintf (file
, "%0I%%hi(");
2037 output_addr_const (file
, op
);
2038 asm_fprintf (file
, ")");
2042 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2043 are specified. If we already have a QImode, there is nothing to do. */
2044 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2048 op
= m68hc11_gen_lowpart (QImode
, op
);
2050 else if (letter
== 'h')
2052 op
= m68hc11_gen_highpart (QImode
, op
);
2056 if (GET_CODE (op
) == MEM
)
2058 rtx base
= XEXP (op
, 0);
2059 switch (GET_CODE (base
))
2064 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2065 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2074 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2075 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2076 asm_fprintf (file
, "-");
2085 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2086 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2087 asm_fprintf (file
, "+");
2096 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2097 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2104 output_address (base
);
2108 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2111 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2112 ASM_OUTPUT_FLOAT_OPERAND (letter
, file
, r
);
2114 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == XFmode
)
2117 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2118 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file
, r
);
2120 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == DFmode
)
2123 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2124 ASM_OUTPUT_DOUBLE_OPERAND (file
, r
);
2129 asm_fprintf (file
, "%0I");
2130 output_addr_const (file
, op
);
2134 /* Returns true if the operand 'op' must be printed with parenthesis
2135 arround it. This must be done only if there is a symbol whose name
2136 is a processor register. */
2138 must_parenthesize (op
)
2143 switch (GET_CODE (op
))
2146 name
= XSTR (op
, 0);
2147 /* Avoid a conflict between symbol name and a possible
2149 return (strcasecmp (name
, "a") == 0
2150 || strcasecmp (name
, "b") == 0
2151 || strcasecmp (name
, "d") == 0
2152 || strcasecmp (name
, "x") == 0
2153 || strcasecmp (name
, "y") == 0
2154 || strcasecmp (name
, "pc") == 0
2155 || strcasecmp (name
, "sp") == 0
2156 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2160 return must_parenthesize (XEXP (op
, 0))
2161 || must_parenthesize (XEXP (op
, 1));
2167 return must_parenthesize (XEXP (op
, 0));
2178 /* A C compound statement to output to stdio stream STREAM the
2179 assembler syntax for an instruction operand that is a memory
2180 reference whose address is ADDR. ADDR is an RTL expression. */
2183 print_operand_address (file
, addr
)
2189 int need_parenthesis
= 0;
2191 switch (GET_CODE (addr
))
2194 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2197 asm_fprintf (file
, "0,");
2198 asm_print_register (file
, REGNO (addr
));
2202 base
= XEXP (addr
, 0);
2203 switch (GET_CODE (base
))
2208 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2209 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2218 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2219 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2220 asm_fprintf (file
, "-");
2229 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2230 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2231 asm_fprintf (file
, "+");
2240 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2241 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2248 need_parenthesis
= must_parenthesize (base
);
2249 if (need_parenthesis
)
2250 asm_fprintf (file
, "(");
2252 output_addr_const (file
, base
);
2253 if (need_parenthesis
)
2254 asm_fprintf (file
, ")");
2260 base
= XEXP (addr
, 0);
2261 offset
= XEXP (addr
, 1);
2262 if (!G_REG_P (base
) && G_REG_P (offset
))
2264 base
= XEXP (addr
, 1);
2265 offset
= XEXP (addr
, 0);
2267 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2269 need_parenthesis
= must_parenthesize (addr
);
2271 if (need_parenthesis
)
2272 asm_fprintf (file
, "(");
2274 output_addr_const (file
, base
);
2275 asm_fprintf (file
, "+");
2276 output_addr_const (file
, offset
);
2277 if (need_parenthesis
)
2278 asm_fprintf (file
, ")");
2280 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2286 asm_print_register (file
, REGNO (offset
));
2287 asm_fprintf (file
, ",");
2288 asm_print_register (file
, REGNO (base
));
2295 output_addr_const (file
, offset
);
2296 asm_fprintf (file
, ",");
2297 asm_print_register (file
, REGNO (base
));
2307 if (GET_CODE (addr
) == CONST_INT
2308 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2310 asm_fprintf (file
, "%d", INTVAL (addr
));
2314 need_parenthesis
= must_parenthesize (addr
);
2315 if (need_parenthesis
)
2316 asm_fprintf (file
, "(");
2318 output_addr_const (file
, addr
);
2319 if (need_parenthesis
)
2320 asm_fprintf (file
, ")");
2327 /* Splitting of some instructions. */
2330 m68hc11_expand_compare (code
, op0
, op1
)
2336 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2340 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2341 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2342 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2349 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2351 rtx op0
, op1
, label
;
2355 switch (GET_MODE (op0
))
2359 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2360 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2361 gen_rtx_LABEL_REF (VOIDmode
, label
),
2363 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2367 /* SCz: from i386.c */
2370 /* Don't expand the comparison early, so that we get better code
2371 when jump or whoever decides to reverse the comparison. */
2376 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2377 &m68hc11_compare_op1
);
2379 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2380 m68hc11_compare_op0
, m68hc11_compare_op1
);
2381 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2382 gen_rtx_LABEL_REF (VOIDmode
, label
),
2384 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2386 use_fcomi
= ix86_use_fcomi_compare (code
);
2387 vec
= rtvec_alloc (3 + !use_fcomi
);
2388 RTVEC_ELT (vec
, 0) = tmp
;
2390 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2392 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2395 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2397 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2403 /* Expand SImode branch into multiple compare+branch. */
2405 rtx lo
[2], hi
[2], label2
;
2406 enum rtx_code code1
, code2
, code3
;
2408 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2413 code
= swap_condition (code
);
2415 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2416 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2417 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2418 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2420 /* Otherwise, if we are doing less-than, op1 is a constant and the
2421 low word is zero, then we can just examine the high word. */
2423 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2424 && (code
== LT
|| code
== LTU
))
2426 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2430 /* Otherwise, we need two or three jumps. */
2432 label2
= gen_label_rtx ();
2435 code2
= swap_condition (code
);
2436 code3
= unsigned_condition (code
);
2477 * if (hi(a) < hi(b)) goto true;
2478 * if (hi(a) > hi(b)) goto false;
2479 * if (lo(a) < lo(b)) goto true;
2483 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2485 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2487 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2490 emit_label (label2
);
2501 /* Split a DI, SI or HI move into several smaller move operations.
2502 The scratch register 'scratch' is used as a temporary to load
2503 store intermediate values. It must be a hard register. */
2505 m68hc11_split_move (to
, from
, scratch
)
2506 rtx to
, from
, scratch
;
2508 rtx low_to
, low_from
;
2509 rtx high_to
, high_from
;
2510 enum machine_mode mode
;
2512 mode
= GET_MODE (to
);
2513 if (GET_MODE_SIZE (mode
) == 8)
2515 else if (GET_MODE_SIZE (mode
) == 4)
2520 low_to
= m68hc11_gen_lowpart (mode
, to
);
2521 high_to
= m68hc11_gen_highpart (mode
, to
);
2523 low_from
= m68hc11_gen_lowpart (mode
, from
);
2524 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2526 if (INTVAL (from
) >= 0)
2527 high_from
= const0_rtx
;
2529 high_from
= constm1_rtx
;
2532 high_from
= m68hc11_gen_highpart (mode
, from
);
2536 m68hc11_split_move (low_to
, low_from
, scratch
);
2537 m68hc11_split_move (high_to
, high_from
, scratch
);
2539 else if (H_REG_P (to
) || H_REG_P (from
)
2541 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2542 || m68hc11_small_indexed_indirect_p (from
,
2544 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2545 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2547 emit_move_insn (low_to
, low_from
);
2548 emit_move_insn (high_to
, high_from
);
2554 emit_move_insn (scratch
, low_from
);
2555 insn
= emit_move_insn (low_to
, scratch
);
2557 emit_move_insn (scratch
, high_from
);
2558 insn
= emit_move_insn (high_to
, scratch
);
2563 simplify_logical (mode
, code
, operand
, result
)
2564 enum machine_mode mode
;
2573 if (GET_CODE (operand
) != CONST_INT
)
2581 val
= INTVAL (operand
);
2585 if ((val
& mask
) == 0)
2587 if ((val
& mask
) == mask
)
2588 *result
= constm1_rtx
;
2592 if ((val
& mask
) == 0)
2593 *result
= const0_rtx
;
2594 if ((val
& mask
) == mask
)
2599 if ((val
& mask
) == 0)
2607 m68hc11_emit_logical (mode
, code
, operands
)
2608 enum machine_mode mode
;
2615 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2616 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2618 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2619 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2621 if (result
&& GET_CODE (result
) == CONST_INT
)
2623 if (!H_REG_P (operands
[0]) && operands
[3]
2624 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2626 emit_move_insn (operands
[3], result
);
2627 emit_move_insn (operands
[0], operands
[3]);
2631 emit_move_insn (operands
[0], result
);
2634 else if (operands
[1] != 0 && operands
[2] != 0)
2638 if (!H_REG_P (operands
[0]) && operands
[3])
2640 emit_move_insn (operands
[3], operands
[1]);
2641 emit_insn (gen_rtx (SET
, mode
,
2643 gen_rtx (code
, mode
,
2644 operands
[3], operands
[2])));
2645 insn
= emit_move_insn (operands
[0], operands
[3]);
2649 insn
= emit_insn (gen_rtx (SET
, mode
,
2651 gen_rtx (code
, mode
,
2652 operands
[0], operands
[2])));
2656 /* The logical operation is similar to a copy. */
2661 if (GET_CODE (operands
[1]) == CONST_INT
)
2666 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
2668 emit_move_insn (operands
[3], src
);
2669 emit_move_insn (operands
[0], operands
[3]);
2673 emit_move_insn (operands
[0], src
);
2679 m68hc11_split_logical (mode
, code
, operands
)
2680 enum machine_mode mode
;
2687 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
2688 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
2689 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
2691 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
2693 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
2695 if (INTVAL (operands
[1]) >= 0)
2696 high
[1] = const0_rtx
;
2698 high
[1] = constm1_rtx
;
2701 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
2703 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
2705 if (INTVAL (operands
[2]) >= 0)
2706 high
[2] = const0_rtx
;
2708 high
[2] = constm1_rtx
;
2711 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
2713 low
[3] = operands
[3];
2714 high
[3] = operands
[3];
2717 m68hc11_split_logical (HImode
, code
, low
);
2718 m68hc11_split_logical (HImode
, code
, high
);
2722 m68hc11_emit_logical (mode
, code
, low
);
2723 m68hc11_emit_logical (mode
, code
, high
);
2727 /* Code generation. */
2730 m68hc11_output_swap (insn
, operands
)
2731 rtx insn ATTRIBUTE_UNUSED
;
2734 /* We have to be careful with the cc_status. An address register swap
2735 is generated for some comparison. The comparison is made with D
2736 but the branch really uses the address register. See the split
2737 pattern for compare. The xgdx/xgdy preserve the flags but after
2738 the exchange, the flags will reflect to the value of X and not D.
2739 Tell this by setting the cc_status according to the cc_prev_status. */
2740 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
2742 if (cc_prev_status
.value1
!= 0
2743 && (D_REG_P (cc_prev_status
.value1
)
2744 || X_REG_P (cc_prev_status
.value1
)))
2746 cc_status
= cc_prev_status
;
2747 if (D_REG_P (cc_status
.value1
))
2748 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2751 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2757 output_asm_insn ("xgdx", operands
);
2761 if (cc_prev_status
.value1
!= 0
2762 && (D_REG_P (cc_prev_status
.value1
)
2763 || Y_REG_P (cc_prev_status
.value1
)))
2765 cc_status
= cc_prev_status
;
2766 if (D_REG_P (cc_status
.value1
))
2767 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2770 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2776 output_asm_insn ("xgdy", operands
);
2780 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2781 This is used to decide whether a move that set flags should be used
2784 next_insn_test_reg (insn
, reg
)
2790 insn
= next_nonnote_insn (insn
);
2791 if (GET_CODE (insn
) != INSN
)
2794 body
= PATTERN (insn
);
2795 if (sets_cc0_p (body
) != 1)
2798 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
2804 /* Generate the code to move a 16-bit operand into another one. */
2807 m68hc11_gen_movhi (insn
, operands
)
2813 /* Move a register or memory to the same location.
2814 This is possible because such insn can appear
2815 in a non-optimizing mode. */
2816 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
2818 cc_status
= cc_prev_status
;
2824 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
2826 switch (REGNO (operands
[1]))
2831 output_asm_insn ("psh%1", operands
);
2838 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
2840 switch (REGNO (operands
[0]))
2845 output_asm_insn ("pul%0", operands
);
2852 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
2854 output_asm_insn ("tfr\t%1,%0", operands
);
2856 else if (H_REG_P (operands
[0]))
2858 if (SP_REG_P (operands
[0]))
2859 output_asm_insn ("lds\t%1", operands
);
2861 output_asm_insn ("ld%0\t%1", operands
);
2863 else if (H_REG_P (operands
[1]))
2865 if (SP_REG_P (operands
[1]))
2866 output_asm_insn ("sts\t%0", operands
);
2868 output_asm_insn ("st%1\t%0", operands
);
2872 rtx from
= operands
[1];
2873 rtx to
= operands
[0];
2875 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
2876 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
2877 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
2878 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
2884 ops
[0] = operands
[2];
2887 m68hc11_gen_movhi (insn
, ops
);
2889 ops
[1] = operands
[2];
2890 m68hc11_gen_movhi (insn
, ops
);
2894 /* !!!! SCz wrong here. */
2899 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
2901 output_asm_insn ("clr\t%h0", operands
);
2902 output_asm_insn ("clr\t%b0", operands
);
2906 output_asm_insn ("movw\t%1,%0", operands
);
2913 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
2915 switch (REGNO (operands
[0]))
2919 output_asm_insn ("pul%0", operands
);
2922 output_asm_insn ("pula", operands
);
2923 output_asm_insn ("pulb", operands
);
2930 /* Some moves to a hard register are special. Not all of them
2931 are really supported and we have to use a temporary
2932 location to provide them (either the stack of a temp var). */
2933 if (H_REG_P (operands
[0]))
2935 switch (REGNO (operands
[0]))
2938 if (X_REG_P (operands
[1]))
2940 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
2942 m68hc11_output_swap (insn
, operands
);
2944 else if (next_insn_test_reg (insn
, operands
[0]))
2946 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
2950 cc_status
= cc_prev_status
;
2951 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
2954 else if (Y_REG_P (operands
[1]))
2956 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
2958 m68hc11_output_swap (insn
, operands
);
2962 /* %t means *ZTMP scratch register. */
2963 output_asm_insn ("sty\t%t1", operands
);
2964 output_asm_insn ("ldd\t%t1", operands
);
2967 else if (SP_REG_P (operands
[1]))
2972 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
2973 output_asm_insn ("xgdx", operands
);
2974 output_asm_insn ("tsx", operands
);
2975 output_asm_insn ("xgdx", operands
);
2977 else if (IS_STACK_POP (operands
[1]))
2979 output_asm_insn ("pula\n\tpulb", operands
);
2981 else if (GET_CODE (operands
[1]) == CONST_INT
2982 && INTVAL (operands
[1]) == 0)
2984 output_asm_insn ("clra\n\tclrb", operands
);
2988 output_asm_insn ("ldd\t%1", operands
);
2993 if (D_REG_P (operands
[1]))
2995 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
2997 m68hc11_output_swap (insn
, operands
);
2999 else if (next_insn_test_reg (insn
, operands
[0]))
3001 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3005 cc_status
= cc_prev_status
;
3006 output_asm_insn ("pshb", operands
);
3007 output_asm_insn ("psha", operands
);
3008 output_asm_insn ("pulx", operands
);
3011 else if (Y_REG_P (operands
[1]))
3013 output_asm_insn ("sty\t%t1", operands
);
3014 output_asm_insn ("ldx\t%t1", operands
);
3016 else if (SP_REG_P (operands
[1]))
3018 /* tsx, tsy preserve the flags */
3019 cc_status
= cc_prev_status
;
3020 output_asm_insn ("tsx", operands
);
3024 output_asm_insn ("ldx\t%1", operands
);
3029 if (D_REG_P (operands
[1]))
3031 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3033 m68hc11_output_swap (insn
, operands
);
3037 output_asm_insn ("std\t%t1", operands
);
3038 output_asm_insn ("ldy\t%t1", operands
);
3041 else if (X_REG_P (operands
[1]))
3043 output_asm_insn ("stx\t%t1", operands
);
3044 output_asm_insn ("ldy\t%t1", operands
);
3046 else if (SP_REG_P (operands
[1]))
3048 /* tsx, tsy preserve the flags */
3049 cc_status
= cc_prev_status
;
3050 output_asm_insn ("tsy", operands
);
3054 output_asm_insn ("ldy\t%1", operands
);
3058 case HARD_SP_REGNUM
:
3059 if (D_REG_P (operands
[1]))
3061 cc_status
= cc_prev_status
;
3062 output_asm_insn ("xgdx", operands
);
3063 output_asm_insn ("txs", operands
);
3064 output_asm_insn ("xgdx", operands
);
3066 else if (X_REG_P (operands
[1]))
3068 /* tys, txs preserve the flags */
3069 cc_status
= cc_prev_status
;
3070 output_asm_insn ("txs", operands
);
3072 else if (Y_REG_P (operands
[1]))
3074 /* tys, txs preserve the flags */
3075 cc_status
= cc_prev_status
;
3076 output_asm_insn ("tys", operands
);
3080 /* lds sets the flags but the des does not. */
3082 output_asm_insn ("lds\t%1", operands
);
3083 output_asm_insn ("des", operands
);
3088 fatal_insn ("Invalid register in the move instruction", insn
);
3093 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3094 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3096 output_asm_insn ("sts\t%0", operands
);
3100 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3102 switch (REGNO (operands
[1]))
3106 output_asm_insn ("psh%1", operands
);
3109 output_asm_insn ("pshb", operands
);
3110 output_asm_insn ("psha", operands
);
3118 /* Operand 1 must be a hard register. */
3119 if (!H_REG_P (operands
[1]))
3121 fatal_insn ("Invalid operand in the instruction", insn
);
3124 reg
= REGNO (operands
[1]);
3128 output_asm_insn ("std\t%0", operands
);
3132 output_asm_insn ("stx\t%0", operands
);
3136 output_asm_insn ("sty\t%0", operands
);
3139 case HARD_SP_REGNUM
:
3143 if (reg_mentioned_p (ix_reg
, operands
[0]))
3145 output_asm_insn ("sty\t%t0", operands
);
3146 output_asm_insn ("tsy", operands
);
3147 output_asm_insn ("sty\t%0", operands
);
3148 output_asm_insn ("ldy\t%t0", operands
);
3152 output_asm_insn ("stx\t%t0", operands
);
3153 output_asm_insn ("tsx", operands
);
3154 output_asm_insn ("stx\t%0", operands
);
3155 output_asm_insn ("ldx\t%t0", operands
);
3161 fatal_insn ("Invalid register in the move instruction", insn
);
3167 m68hc11_gen_movqi (insn
, operands
)
3171 /* Move a register or memory to the same location.
3172 This is possible because such insn can appear
3173 in a non-optimizing mode. */
3174 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3176 cc_status
= cc_prev_status
;
3183 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3185 output_asm_insn ("tfr\t%1,%0", operands
);
3187 else if (H_REG_P (operands
[0]))
3189 if (Q_REG_P (operands
[0]))
3190 output_asm_insn ("lda%0\t%1", operands
);
3191 else if (D_REG_P (operands
[0]))
3192 output_asm_insn ("ldab\t%1", operands
);
3194 output_asm_insn ("ld%0\t%1", operands
);
3196 else if (H_REG_P (operands
[1]))
3198 if (Q_REG_P (operands
[1]))
3199 output_asm_insn ("sta%1\t%0", operands
);
3200 else if (D_REG_P (operands
[1]))
3201 output_asm_insn ("staa\t%0", operands
);
3203 output_asm_insn ("st%1\t%0", operands
);
3207 rtx from
= operands
[1];
3208 rtx to
= operands
[0];
3210 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3211 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3212 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3213 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3219 ops
[0] = operands
[2];
3222 m68hc11_gen_movqi (insn
, ops
);
3224 ops
[1] = operands
[2];
3225 m68hc11_gen_movqi (insn
, ops
);
3229 /* !!!! SCz wrong here. */
3234 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3236 output_asm_insn ("clr\t%b0", operands
);
3240 output_asm_insn ("movb\t%1,%0", operands
);
3247 if (H_REG_P (operands
[0]))
3249 switch (REGNO (operands
[0]))
3253 if (X_REG_P (operands
[1]))
3255 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3257 m68hc11_output_swap (insn
, operands
);
3261 output_asm_insn ("stx\t%t1", operands
);
3262 output_asm_insn ("ldab\t%T0", operands
);
3265 else if (Y_REG_P (operands
[1]))
3267 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3269 m68hc11_output_swap (insn
, operands
);
3273 output_asm_insn ("sty\t%t1", operands
);
3274 output_asm_insn ("ldab\t%T0", operands
);
3277 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3278 && !DA_REG_P (operands
[1]))
3280 output_asm_insn ("ldab\t%b1", operands
);
3282 else if (DA_REG_P (operands
[1]))
3284 output_asm_insn ("tab", operands
);
3288 cc_status
= cc_prev_status
;
3294 if (X_REG_P (operands
[1]))
3296 output_asm_insn ("stx\t%t1", operands
);
3297 output_asm_insn ("ldaa\t%T0", operands
);
3299 else if (Y_REG_P (operands
[1]))
3301 output_asm_insn ("sty\t%t1", operands
);
3302 output_asm_insn ("ldaa\t%T0", operands
);
3304 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3305 && !DA_REG_P (operands
[1]))
3307 output_asm_insn ("ldaa\t%b1", operands
);
3309 else if (!DA_REG_P (operands
[1]))
3311 output_asm_insn ("tba", operands
);
3315 cc_status
= cc_prev_status
;
3320 if (D_REG_P (operands
[1]))
3322 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3324 m68hc11_output_swap (insn
, operands
);
3328 output_asm_insn ("stab\t%T1", operands
);
3329 output_asm_insn ("ldx\t%t1", operands
);
3333 else if (Y_REG_P (operands
[1]))
3335 output_asm_insn ("sty\t%t0", operands
);
3336 output_asm_insn ("ldx\t%t0", operands
);
3338 else if (GET_CODE (operands
[1]) == CONST_INT
)
3340 output_asm_insn ("ldx\t%1", operands
);
3342 else if (dead_register_here (insn
, d_reg
))
3344 output_asm_insn ("ldab\t%b1", operands
);
3345 output_asm_insn ("xgdx", operands
);
3347 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3349 output_asm_insn ("xgdx", operands
);
3350 output_asm_insn ("ldab\t%b1", operands
);
3351 output_asm_insn ("xgdx", operands
);
3355 output_asm_insn ("pshb", operands
);
3356 output_asm_insn ("ldab\t%b1", operands
);
3357 output_asm_insn ("stab\t%T1", operands
);
3358 output_asm_insn ("ldx\t%t1", operands
);
3359 output_asm_insn ("pulb", operands
);
3365 if (D_REG_P (operands
[1]))
3367 output_asm_insn ("stab\t%T1", operands
);
3368 output_asm_insn ("ldy\t%t1", operands
);
3371 else if (X_REG_P (operands
[1]))
3373 output_asm_insn ("stx\t%t1", operands
);
3374 output_asm_insn ("ldy\t%t1", operands
);
3377 else if (GET_CODE (operands
[1]) == CONST_INT
)
3379 output_asm_insn ("ldy\t%1", operands
);
3381 else if (dead_register_here (insn
, d_reg
))
3383 output_asm_insn ("ldab\t%b1", operands
);
3384 output_asm_insn ("xgdy", operands
);
3386 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3388 output_asm_insn ("xgdy", operands
);
3389 output_asm_insn ("ldab\t%b1", operands
);
3390 output_asm_insn ("xgdy", operands
);
3394 output_asm_insn ("pshb", operands
);
3395 output_asm_insn ("ldab\t%b1", operands
);
3396 output_asm_insn ("stab\t%T1", operands
);
3397 output_asm_insn ("ldy\t%t1", operands
);
3398 output_asm_insn ("pulb", operands
);
3404 fatal_insn ("Invalid register in the instruction", insn
);
3408 else if (H_REG_P (operands
[1]))
3410 switch (REGNO (operands
[1]))
3414 output_asm_insn ("stab\t%b0", operands
);
3418 output_asm_insn ("staa\t%b0", operands
);
3422 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3426 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3430 fatal_insn ("Invalid register in the move instruction", insn
);
3437 fatal_insn ("Operand 1 must be a hard register", insn
);
3441 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3442 The source and destination must be D or A and the shift must
3445 m68hc11_gen_rotate (code
, insn
, operands
)
3452 if (GET_CODE (operands
[2]) != CONST_INT
3453 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3454 fatal_insn ("Invalid rotate insn", insn
);
3456 val
= INTVAL (operands
[2]);
3457 if (code
== ROTATERT
)
3458 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3460 if (GET_MODE (operands
[0]) != QImode
)
3463 /* Rotate by 8-bits if the shift is within [5..11]. */
3464 if (val
>= 5 && val
<= 11)
3466 output_asm_insn ("psha", operands
);
3467 output_asm_insn ("tba", operands
);
3468 output_asm_insn ("pulb", operands
);
3472 /* If the shift is big, invert the rotation. */
3480 /* Set the carry to bit-15, but don't change D yet. */
3481 if (GET_MODE (operands
[0]) != QImode
)
3483 output_asm_insn ("asra", operands
);
3484 output_asm_insn ("rola", operands
);
3489 /* Rotate B first to move the carry to bit-0. */
3490 if (D_REG_P (operands
[0]))
3491 output_asm_insn ("rolb", operands
);
3493 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3494 output_asm_insn ("rola", operands
);
3499 /* Set the carry to bit-8 of D. */
3500 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3502 output_asm_insn ("tap", operands
);
3507 /* Rotate B first to move the carry to bit-7. */
3508 if (D_REG_P (operands
[0]))
3509 output_asm_insn ("rorb", operands
);
3511 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3512 output_asm_insn ("rora", operands
);
3519 /* Store in cc_status the expressions that the condition codes will
3520 describe after execution of an instruction whose pattern is EXP.
3521 Do not alter them if the instruction would not alter the cc's. */
3524 m68hc11_notice_update_cc (exp
, insn
)
3526 rtx insn ATTRIBUTE_UNUSED
;
3528 /* recognize SET insn's. */
3529 if (GET_CODE (exp
) == SET
)
3531 /* Jumps do not alter the cc's. */
3532 if (SET_DEST (exp
) == pc_rtx
)
3535 /* NOTE: most instructions don't affect the carry bit, but the
3536 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3537 the conditions.h header. */
3539 /* Function calls clobber the cc's. */
3540 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3545 /* Tests and compares set the cc's in predictable ways. */
3546 else if (SET_DEST (exp
) == cc0_rtx
)
3548 cc_status
.flags
= 0;
3549 cc_status
.value1
= XEXP (exp
, 0);
3550 cc_status
.value2
= XEXP (exp
, 1);
3554 /* All other instructions affect the condition codes. */
3555 cc_status
.flags
= 0;
3556 cc_status
.value1
= XEXP (exp
, 0);
3557 cc_status
.value2
= XEXP (exp
, 1);
3562 /* Default action if we haven't recognized something
3563 and returned earlier. */
3567 if (cc_status
.value2
!= 0)
3568 switch (GET_CODE (cc_status
.value2
))
3570 /* These logical operations can generate several insns.
3571 The flags are setup according to what is generated. */
3577 /* The (not ...) generates several 'com' instructions for
3578 non QImode. We have to invalidate the flags. */
3580 if (GET_MODE (cc_status
.value2
) != QImode
)
3592 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3593 cc_status
.flags
|= CC_NO_OVERFLOW
;
3596 /* The asl sets the overflow bit in such a way that this
3597 makes the flags unusable for a next compare insn. */
3601 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3602 cc_status
.flags
|= CC_NO_OVERFLOW
;
3605 /* A load/store instruction does not affect the carry. */
3610 cc_status
.flags
|= CC_NO_OVERFLOW
;
3616 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
3618 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
3619 cc_status
.value2
= 0;
3623 /* Machine Specific Reorg. */
3625 /* Z register replacement:
3627 GCC treats the Z register as an index base address register like
3628 X or Y. In general, it uses it during reload to compute the address
3629 of some operand. This helps the reload pass to avoid to fall into the
3630 register spill failure.
3632 The Z register is in the A_REGS class. In the machine description,
3633 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3635 It can appear everywhere an X or Y register can appear, except for
3636 some templates in the clobber section (when a clobber of X or Y is asked).
3637 For a given instruction, the template must ensure that no more than
3638 2 'A' registers are used. Otherwise, the register replacement is not
3641 To replace the Z register, the algorithm is not terrific:
3642 1. Insns that do not use the Z register are not changed
3643 2. When a Z register is used, we scan forward the insns to see
3644 a potential register to use: either X or Y and sometimes D.
3645 We stop when a call, a label or a branch is seen, or when we
3646 detect that both X and Y are used (probably at different times, but it does
3648 3. The register that will be used for the replacement of Z is saved
3649 in a .page0 register or on the stack. If the first instruction that
3650 used Z, uses Z as an input, the value is loaded from another .page0
3651 register. The replacement register is pushed on the stack in the
3652 rare cases where a compare insn uses Z and we couldn't find if X/Y
3654 4. The Z register is replaced in all instructions until we reach
3655 the end of the Z-block, as detected by step 2.
3656 5. If we detect that Z is still alive, its value is saved.
3657 If the replacement register is alive, its old value is loaded.
3659 The Z register can be disabled with -ffixed-z.
3669 int must_restore_reg
;
3680 int save_before_last
;
3681 int z_loaded_with_sp
;
3684 static rtx z_reg_qi
;
3686 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
3687 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
3688 static void m68hc11_z_replacement
PARAMS ((rtx
));
3689 static void m68hc11_reassign_regs
PARAMS ((rtx
));
3691 int z_replacement_completed
= 0;
3693 /* Analyze the insn to find out which replacement register to use and
3694 the boundaries of the replacement.
3695 Returns 0 if we reached the last insn to be replaced, 1 if we can
3696 continue replacement in next insns. */
3699 m68hc11_check_z_replacement (insn
, info
)
3701 struct replace_info
*info
;
3703 int this_insn_uses_ix
;
3704 int this_insn_uses_iy
;
3705 int this_insn_uses_z
;
3706 int this_insn_uses_d
;
3710 /* A call is said to clobber the Z register, we don't need
3711 to save the value of Z. We also don't need to restore
3712 the replacement register (unless it is used by the call). */
3713 if (GET_CODE (insn
) == CALL_INSN
)
3715 body
= PATTERN (insn
);
3717 info
->can_use_d
= 0;
3719 /* If the call is an indirect call with Z, we have to use the
3720 Y register because X can be used as an input (D+X).
3721 We also must not save Z nor restore Y. */
3722 if (reg_mentioned_p (z_reg
, body
))
3724 insn
= NEXT_INSN (insn
);
3727 info
->found_call
= 1;
3728 info
->must_restore_reg
= 0;
3729 info
->last
= NEXT_INSN (insn
);
3731 info
->need_save_z
= 0;
3734 if (GET_CODE (insn
) == CODE_LABEL
3735 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
3738 if (GET_CODE (insn
) == JUMP_INSN
)
3740 if (reg_mentioned_p (z_reg
, insn
) == 0)
3743 info
->can_use_d
= 0;
3744 info
->must_save_reg
= 0;
3745 info
->must_restore_reg
= 0;
3746 info
->need_save_z
= 0;
3747 info
->last
= NEXT_INSN (insn
);
3750 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
3755 /* Z register dies here. */
3756 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
3758 body
= PATTERN (insn
);
3759 if (GET_CODE (body
) == SET
)
3761 rtx src
= XEXP (body
, 1);
3762 rtx dst
= XEXP (body
, 0);
3764 /* Condition code is set here. We have to restore the X/Y and
3765 save into Z before any test/compare insn because once we save/restore
3766 we can change the condition codes. When the compare insn uses Z and
3767 we can't use X/Y, the comparison is made with the *ZREG soft register
3768 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3771 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
3772 || (GET_CODE (src
) == COMPARE
&&
3773 (rtx_equal_p (XEXP (src
, 0), z_reg
)
3774 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
3776 if (insn
== info
->first
)
3778 info
->must_load_z
= 0;
3779 info
->must_save_reg
= 0;
3780 info
->must_restore_reg
= 0;
3781 info
->need_save_z
= 0;
3782 info
->found_call
= 1;
3783 info
->regno
= SOFT_Z_REGNUM
;
3788 if (reg_mentioned_p (z_reg
, src
) == 0)
3790 info
->can_use_d
= 0;
3794 if (insn
!= info
->first
)
3797 /* Compare insn which uses Z. We have to save/restore the X/Y
3798 register without modifying the condition codes. For this
3799 we have to use a push/pop insn. */
3800 info
->must_push_reg
= 1;
3804 /* Z reg is set to something new. We don't need to load it. */
3807 if (!reg_mentioned_p (z_reg
, src
))
3809 if (insn
== info
->first
)
3811 info
->must_load_z
= 0;
3814 info
->z_set_count
++;
3815 info
->z_value
= src
;
3817 info
->z_loaded_with_sp
= 1;
3819 else if (reg_mentioned_p (z_reg
, dst
))
3820 info
->can_use_d
= 0;
3822 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
3823 | reg_mentioned_p (d_reg
, dst
);
3824 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
3825 | reg_mentioned_p (ix_reg
, dst
);
3826 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
3827 | reg_mentioned_p (iy_reg
, dst
);
3828 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
3830 /* If z is used as an address operand (like (MEM (reg z))),
3831 we can't replace it with d. */
3832 if (this_insn_uses_z
&& !Z_REG_P (src
))
3833 info
->can_use_d
= 0;
3834 this_insn_uses_z
|= reg_mentioned_p (z_reg
, dst
);
3836 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
3838 fatal_insn ("Registers IX, IY and Z used in the same INSN", insn
);
3841 if (this_insn_uses_d
)
3842 info
->can_use_d
= 0;
3844 /* IX and IY are used at the same time, we have to restore
3845 the value of the scratch register before this insn. */
3846 if (this_insn_uses_ix
&& this_insn_uses_iy
)
3851 if (info
->x_used
== 0 && this_insn_uses_ix
)
3855 /* We have a (set (REG:HI X) (REG:HI Z)).
3856 Since we use Z as the replacement register, this insn
3857 is no longer necessary. We turn it into a note. We must
3858 not reload the old value of X. */
3859 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
3863 info
->need_save_z
= 0;
3866 info
->must_save_reg
= 0;
3867 info
->must_restore_reg
= 0;
3868 info
->found_call
= 1;
3869 info
->can_use_d
= 0;
3870 PUT_CODE (insn
, NOTE
);
3871 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
3872 NOTE_SOURCE_FILE (insn
) = 0;
3873 info
->last
= NEXT_INSN (insn
);
3878 && (rtx_equal_p (src
, z_reg
)
3879 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
3883 info
->need_save_z
= 0;
3886 info
->last
= NEXT_INSN (insn
);
3887 info
->must_save_reg
= 0;
3888 info
->must_restore_reg
= 0;
3890 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
3891 && !reg_mentioned_p (ix_reg
, src
))
3896 info
->need_save_z
= 0;
3900 info
->save_before_last
= 1;
3902 info
->must_restore_reg
= 0;
3903 info
->last
= NEXT_INSN (insn
);
3905 else if (info
->can_use_d
)
3907 info
->last
= NEXT_INSN (insn
);
3913 if (z_dies_here
&& !reg_mentioned_p (src
, ix_reg
)
3914 && GET_CODE (src
) == REG
&& REGNO (src
) == HARD_X_REGNUM
)
3916 info
->need_save_z
= 0;
3918 info
->last
= NEXT_INSN (insn
);
3919 info
->regno
= HARD_X_REGNUM
;
3920 info
->must_save_reg
= 0;
3921 info
->must_restore_reg
= 0;
3925 if (info
->y_used
== 0 && this_insn_uses_iy
)
3929 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
3933 info
->need_save_z
= 0;
3936 info
->must_save_reg
= 0;
3937 info
->must_restore_reg
= 0;
3938 info
->found_call
= 1;
3939 info
->can_use_d
= 0;
3940 PUT_CODE (insn
, NOTE
);
3941 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
3942 NOTE_SOURCE_FILE (insn
) = 0;
3943 info
->last
= NEXT_INSN (insn
);
3948 && (rtx_equal_p (src
, z_reg
)
3949 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
3954 info
->need_save_z
= 0;
3956 info
->last
= NEXT_INSN (insn
);
3957 info
->must_save_reg
= 0;
3958 info
->must_restore_reg
= 0;
3960 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
3961 && !reg_mentioned_p (iy_reg
, src
))
3966 info
->need_save_z
= 0;
3970 info
->save_before_last
= 1;
3972 info
->must_restore_reg
= 0;
3973 info
->last
= NEXT_INSN (insn
);
3975 else if (info
->can_use_d
)
3977 info
->last
= NEXT_INSN (insn
);
3984 if (z_dies_here
&& !reg_mentioned_p (src
, iy_reg
)
3985 && GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Y_REGNUM
)
3987 info
->need_save_z
= 0;
3989 info
->last
= NEXT_INSN (insn
);
3990 info
->regno
= HARD_Y_REGNUM
;
3991 info
->must_save_reg
= 0;
3992 info
->must_restore_reg
= 0;
3998 info
->need_save_z
= 0;
4000 if (info
->last
== 0)
4001 info
->last
= NEXT_INSN (insn
);
4004 return info
->last
!= NULL_RTX
? 0 : 1;
4006 if (GET_CODE (body
) == PARALLEL
)
4009 char ix_clobber
= 0;
4010 char iy_clobber
= 0;
4012 this_insn_uses_iy
= 0;
4013 this_insn_uses_ix
= 0;
4014 this_insn_uses_z
= 0;
4016 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4019 int uses_ix
, uses_iy
, uses_z
;
4021 x
= XVECEXP (body
, 0, i
);
4023 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4024 info
->can_use_d
= 0;
4026 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4027 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4028 uses_z
= reg_mentioned_p (z_reg
, x
);
4029 if (GET_CODE (x
) == CLOBBER
)
4031 ix_clobber
|= uses_ix
;
4032 iy_clobber
|= uses_iy
;
4033 z_clobber
|= uses_z
;
4037 this_insn_uses_ix
|= uses_ix
;
4038 this_insn_uses_iy
|= uses_iy
;
4039 this_insn_uses_z
|= uses_z
;
4041 if (uses_z
&& GET_CODE (x
) == SET
)
4043 rtx dst
= XEXP (x
, 0);
4046 info
->z_set_count
++;
4049 info
->need_save_z
= 0;
4053 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4054 this_insn_uses_ix
, this_insn_uses_iy
,
4055 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4058 if (this_insn_uses_z
)
4059 info
->can_use_d
= 0;
4061 if (z_clobber
&& info
->first
!= insn
)
4063 info
->need_save_z
= 0;
4067 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4069 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4071 info
->must_load_z
= 0;
4073 if (dead_register_here (insn
, d_reg
))
4075 info
->regno
= HARD_D_REGNUM
;
4076 info
->must_save_reg
= 0;
4077 info
->must_restore_reg
= 0;
4079 else if (dead_register_here (insn
, ix_reg
))
4081 info
->regno
= HARD_X_REGNUM
;
4082 info
->must_save_reg
= 0;
4083 info
->must_restore_reg
= 0;
4085 else if (dead_register_here (insn
, iy_reg
))
4087 info
->regno
= HARD_Y_REGNUM
;
4088 info
->must_save_reg
= 0;
4089 info
->must_restore_reg
= 0;
4091 if (info
->regno
>= 0)
4093 info
->last
= NEXT_INSN (insn
);
4096 if (this_insn_uses_ix
== 0)
4098 info
->regno
= HARD_X_REGNUM
;
4099 info
->must_save_reg
= 1;
4100 info
->must_restore_reg
= 1;
4102 else if (this_insn_uses_iy
== 0)
4104 info
->regno
= HARD_Y_REGNUM
;
4105 info
->must_save_reg
= 1;
4106 info
->must_restore_reg
= 1;
4110 info
->regno
= HARD_D_REGNUM
;
4111 info
->must_save_reg
= 1;
4112 info
->must_restore_reg
= 1;
4114 info
->last
= NEXT_INSN (insn
);
4118 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4119 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4121 if (this_insn_uses_z
)
4123 if (info
->y_used
== 0 && iy_clobber
)
4125 info
->regno
= HARD_Y_REGNUM
;
4126 info
->must_save_reg
= 0;
4127 info
->must_restore_reg
= 0;
4129 info
->last
= NEXT_INSN (insn
);
4130 info
->save_before_last
= 1;
4134 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4136 if (this_insn_uses_z
)
4138 fatal_insn ("Cannot do z-register replacement", insn
);
4142 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4149 if (iy_clobber
|| z_clobber
)
4151 info
->last
= NEXT_INSN (insn
);
4152 info
->save_before_last
= 1;
4157 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4164 if (ix_clobber
|| z_clobber
)
4166 info
->last
= NEXT_INSN (insn
);
4167 info
->save_before_last
= 1;
4174 info
->need_save_z
= 0;
4178 if (GET_CODE (body
) == CLOBBER
)
4181 /* IX and IY are used at the same time, we have to restore
4182 the value of the scratch register before this insn. */
4183 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4187 if (info
->x_used
== 0 && this_insn_uses_ix
)
4195 if (info
->y_used
== 0 && this_insn_uses_iy
)
4209 m68hc11_find_z_replacement (insn
, info
)
4211 struct replace_info
*info
;
4215 info
->replace_reg
= NULL_RTX
;
4216 info
->must_load_z
= 1;
4217 info
->need_save_z
= 1;
4218 info
->must_save_reg
= 1;
4219 info
->must_restore_reg
= 1;
4223 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4224 info
->found_call
= 0;
4228 info
->z_set_count
= 0;
4229 info
->z_value
= NULL_RTX
;
4230 info
->must_push_reg
= 0;
4231 info
->save_before_last
= 0;
4232 info
->z_loaded_with_sp
= 0;
4234 /* Scan the insn forward to find an address register that is not used.
4236 - the flow of the program changes,
4237 - when we detect that both X and Y are necessary,
4238 - when the Z register dies,
4239 - when the condition codes are set. */
4241 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4243 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4247 /* May be we can use Y or X if they contain the same value as Z.
4248 This happens very often after the reload. */
4249 if (info
->z_set_count
== 1)
4251 rtx p
= info
->first
;
4256 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4258 else if (info
->y_used
)
4260 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4262 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4265 info
->regno
= HARD_Y_REGNUM
;
4267 info
->regno
= HARD_X_REGNUM
;
4268 info
->must_load_z
= 0;
4269 info
->must_save_reg
= 0;
4270 info
->must_restore_reg
= 0;
4271 info
->found_call
= 1;
4274 if (info
->z_set_count
== 0)
4275 info
->need_save_z
= 0;
4278 info
->need_save_z
= 0;
4280 if (info
->last
== 0)
4283 if (info
->regno
>= 0)
4286 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4288 else if (info
->can_use_d
)
4290 reg
= HARD_D_REGNUM
;
4291 info
->replace_reg
= d_reg
;
4293 else if (info
->x_used
)
4295 reg
= HARD_Y_REGNUM
;
4296 info
->replace_reg
= iy_reg
;
4300 reg
= HARD_X_REGNUM
;
4301 info
->replace_reg
= ix_reg
;
4305 if (info
->must_save_reg
&& info
->must_restore_reg
)
4307 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4309 info
->must_save_reg
= 0;
4310 info
->must_restore_reg
= 0;
4315 /* The insn uses the Z register. Find a replacement register for it
4316 (either X or Y) and replace it in the insn and the next ones until
4317 the flow changes or the replacement register is used. Instructions
4318 are emited before and after the Z-block to preserve the value of
4319 Z and of the replacement register. */
4322 m68hc11_z_replacement (insn
)
4327 struct replace_info info
;
4329 /* Find trivial case where we only need to replace z with the
4330 equivalent soft register. */
4331 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4333 rtx body
= PATTERN (insn
);
4334 rtx src
= XEXP (body
, 1);
4335 rtx dst
= XEXP (body
, 0);
4337 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4339 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4342 else if (Z_REG_P (src
)
4343 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4345 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4348 else if (D_REG_P (dst
)
4349 && m68hc11_arith_operator (src
, GET_MODE (src
))
4350 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4352 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4355 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4356 && INTVAL (src
) == 0)
4358 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4363 m68hc11_find_z_replacement (insn
, &info
);
4365 replace_reg
= info
.replace_reg
;
4366 replace_reg_qi
= NULL_RTX
;
4368 /* Save the X register in a .page0 location. */
4369 if (info
.must_save_reg
&& !info
.must_push_reg
)
4373 if (info
.must_push_reg
&& 0)
4374 dst
= gen_rtx (MEM
, HImode
,
4375 gen_rtx (PRE_DEC
, HImode
,
4376 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4378 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4380 emit_insn_before (gen_movhi (dst
,
4381 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4383 if (info
.must_load_z
&& !info
.must_push_reg
)
4385 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4386 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4391 /* Replace all occurence of Z by replace_reg.
4392 Stop when the last instruction to replace is reached.
4393 Also stop when we detect a change in the flow (but it's not
4394 necessary; just safeguard). */
4396 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4400 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4403 if (GET_CODE (insn
) != INSN
4404 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4407 body
= PATTERN (insn
);
4408 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4409 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4411 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4413 printf ("Reg mentioned here...:\n");
4418 /* Stack pointer was decremented by 2 due to the push.
4419 Correct that by adding 2 to the destination. */
4420 if (info
.must_push_reg
4421 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4425 src
= SET_SRC (body
);
4426 dst
= SET_DEST (body
);
4427 if (SP_REG_P (src
) && Z_REG_P (dst
))
4429 emit_insn_after (gen_addhi3 (dst
,
4432 VOIDmode
, 2)), insn
);
4436 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4437 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4439 INSN_CODE (insn
) = -1;
4440 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4441 fatal_insn ("Cannot do z-register replacement", insn
);
4444 /* Likewise for (REG:QI Z). */
4445 if (reg_mentioned_p (z_reg
, insn
))
4447 if (replace_reg_qi
== NULL_RTX
)
4448 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4449 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4452 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4456 /* Save Z before restoring the old value. */
4457 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4459 rtx save_pos_insn
= insn
;
4461 /* If Z is clobber by the last insn, we have to save its value
4462 before the last instruction. */
4463 if (info
.save_before_last
)
4464 save_pos_insn
= PREV_INSN (save_pos_insn
);
4466 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4467 gen_rtx (REG
, HImode
, info
.regno
)),
4471 if (info
.must_push_reg
&& info
.last
)
4475 body
= PATTERN (info
.last
);
4476 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4478 gen_rtx (USE
, VOIDmode
,
4480 gen_rtx (USE
, VOIDmode
,
4481 gen_rtx (REG
, HImode
,
4483 PATTERN (info
.last
) = new_body
;
4485 /* Force recognition on insn since we changed it. */
4486 INSN_CODE (insn
) = -1;
4488 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4490 fatal_insn ("Invalid Z register replacement for insn", insn
);
4492 insn
= NEXT_INSN (info
.last
);
4495 /* Restore replacement register unless it was died. */
4496 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4500 if (info
.must_push_reg
&& 0)
4501 dst
= gen_rtx (MEM
, HImode
,
4502 gen_rtx (POST_INC
, HImode
,
4503 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4505 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4507 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4514 /* Scan all the insn and re-affects some registers
4515 - The Z register (if it was used), is affected to X or Y depending
4516 on the instruction. */
4519 m68hc11_reassign_regs (first
)
4524 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
4525 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
4526 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
4527 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
4529 /* Scan all insns to replace Z by X or Y preserving the old value
4530 of X/Y and restoring it afterward. */
4532 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
4536 if (GET_CODE (insn
) == CODE_LABEL
4537 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
4540 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
4543 body
= PATTERN (insn
);
4544 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
4547 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
4548 || GET_CODE (body
) == ASM_OPERANDS
4549 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
4552 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4553 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4556 /* If Z appears in this insn, replace it in the current insn
4557 and the next ones until the flow changes or we have to
4558 restore back the replacement register. */
4560 if (reg_mentioned_p (z_reg
, body
))
4562 m68hc11_z_replacement (insn
);
4567 printf ("Insn not handled by Z replacement:\n");
4576 m68hc11_reorg (first
)
4581 z_replacement_completed
= 0;
4582 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
4584 /* Some RTX are shared at this point. This breaks the Z register
4585 replacement, unshare everything. */
4586 unshare_all_rtl_again (first
);
4588 /* Force a split of all splitable insn. This is necessary for the
4589 Z register replacement mechanism because we end up with basic insns. */
4590 split_all_insns (0);
4593 z_replacement_completed
= 1;
4594 m68hc11_reassign_regs (first
);
4596 /* After some splitting, there are some oportunities for CSE pass.
4597 This happens quite often when 32-bit or above patterns are split. */
4598 if (optimize
> 0 && split_done
)
4599 reload_cse_regs (first
);
4601 /* Re-create the REG_DEAD notes. These notes are used in the machine
4602 description to use the best assembly directives. */
4605 find_basic_blocks (first
, max_reg_num (), 0);
4606 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
4609 z_replacement_completed
= 2;
4611 /* If optimizing, then go ahead and split insns that must be
4612 split after Z register replacement. This gives more opportunities
4613 for peephole (in particular for consecutives xgdx/xgdy). */
4615 split_all_insns (0);
4617 /* Once insns are split after the z_replacement_completed == 2,
4618 we must not re-run the life_analysis. The xgdx/xgdy patterns
4619 are not recognized and the life_analysis pass removes some
4620 insns because it thinks some (SETs) are noops or made to dead
4621 stores (which is false due to the swap).
4623 Do a simple pass to eliminate the noop set that the final
4624 split could generate (because it was easier for split definition). */
4628 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
4632 if (INSN_DELETED_P (insn
))
4634 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
4637 /* Remove the (set (R) (R)) insns generated by some splits. */
4638 body
= PATTERN (insn
);
4639 if (GET_CODE (body
) == SET
4640 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
4642 PUT_CODE (insn
, NOTE
);
4643 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4644 NOTE_SOURCE_FILE (insn
) = 0;
4652 /* Cost functions. */
4654 #define COSTS_N_INSNS(N) ((N) * 4 - 2)
4656 /* Cost of moving memory. */
4658 m68hc11_memory_move_cost (mode
, class, in
)
4659 enum machine_mode mode
;
4660 enum reg_class
class;
4661 int in ATTRIBUTE_UNUSED
;
4663 if (class <= H_REGS
)
4665 if (GET_MODE_SIZE (mode
) <= 2)
4666 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
4668 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
4672 if (GET_MODE_SIZE (mode
) <= 2)
4673 return COSTS_N_INSNS (2);
4675 return COSTS_N_INSNS (4);
4680 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4681 Reload does not check the constraint of set insns when the two registers
4682 have a move cost of 2. Setting a higher cost will force reload to check
4685 m68hc11_register_move_cost (from
, to
)
4686 enum reg_class from
;
4689 if (from
>= S_REGS
&& to
>= S_REGS
)
4691 return COSTS_N_INSNS (3);
4693 if (from
<= S_REGS
&& to
<= S_REGS
)
4695 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
4697 return COSTS_N_INSNS (2);
4701 /* Provide the costs of an addressing mode that contains ADDR.
4702 If ADDR is not a valid address, its cost is irrelevant. */
4705 m68hc11_address_cost (addr
)
4710 switch (GET_CODE (addr
))
4713 /* Make the cost of hard registers and specially SP, FP small. */
4714 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
4731 register rtx plus0
= XEXP (addr
, 0);
4732 register rtx plus1
= XEXP (addr
, 1);
4734 if (GET_CODE (plus0
) != REG
)
4737 switch (GET_CODE (plus1
))
4740 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
4741 || INTVAL (plus1
) < m68hc11_min_offset
)
4743 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
4747 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
4769 if (SP_REG_P (XEXP (addr
, 0)))
4778 printf ("Address cost: %d for :", cost
);
4787 m68hc11_rtx_costs (x
, code
, outer_code
)
4789 enum rtx_code code
, outer_code
;
4791 enum machine_mode mode
= GET_MODE (x
);
4798 return m68hc11_address_cost (XEXP (x
, 0)) + 4;
4805 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
4807 int val
= INTVAL (XEXP (x
, 1));
4810 /* 8 or 16 shift instructions are fast.
4811 Others are proportional to the shift counter. */
4812 if (val
== 8 || val
== 16 || val
== -8 || val
== -16)
4816 cost
= COSTS_N_INSNS (val
+ 1);
4817 cost
+= rtx_cost (XEXP (x
, 0), outer_code
);
4818 if (GET_MODE_SIZE (mode
) >= 4 && val
)
4824 total
= rtx_cost (XEXP (x
, 0), outer_code
);
4825 if (GET_MODE_SIZE (mode
) >= 4)
4827 total
+= COSTS_N_INSNS (16);
4831 total
+= COSTS_N_INSNS (8);
4842 total
= rtx_cost (XEXP (x
, 0), outer_code
)
4843 + rtx_cost (XEXP (x
, 1), outer_code
);
4844 if (GET_MODE_SIZE (mode
) <= 2)
4846 total
+= COSTS_N_INSNS (2);
4850 total
+= COSTS_N_INSNS (4);
4856 if (mode
== QImode
|| mode
== HImode
)
4860 else if (mode
== SImode
)
4872 return TARGET_OP_TIME
? 10 : 2;
4876 return TARGET_OP_TIME
? 30 : 4;
4880 return TARGET_OP_TIME
? 100 : 20;
4886 extra_cost
= COSTS_N_INSNS (2);
4893 total
= rtx_cost (XEXP (x
, 0), outer_code
);
4896 return total
+ extra_cost
+ COSTS_N_INSNS (1);
4900 return total
+ extra_cost
+ COSTS_N_INSNS (2);
4904 return total
+ extra_cost
+ COSTS_N_INSNS (4);
4906 return total
+ extra_cost
+ COSTS_N_INSNS (8);
4909 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
4910 return COSTS_N_INSNS (1);
4912 return COSTS_N_INSNS (1);
4915 return COSTS_N_INSNS (4);
4920 /* print_options - called at the start of the code generation for a
4923 extern char *asm_file_name
;
4926 #include <sys/types.h>
4935 extern int save_argc
;
4936 extern char **save_argv
;
4938 fprintf (out
, ";;; Command:\t");
4939 for (i
= 0; i
< save_argc
; i
++)
4941 fprintf (out
, "%s", save_argv
[i
]);
4942 if (i
+ 1 < save_argc
)
4945 fprintf (out
, "\n");
4947 a_time
= ctime (&c_time
);
4948 fprintf (out
, ";;; Compiled:\t%s", a_time
);
4951 #define __VERSION__ "[unknown]"
4953 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
4955 fprintf (out
, ";;; (META)compiled by CC.\n");
4960 m68hc11_asm_file_start (out
, main_file
)
4964 fprintf (out
, ";;;-----------------------------------------\n");
4965 fprintf (out
, ";;; Start MC68HC11 gcc assembly output\n");
4966 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
4967 print_options (out
);
4968 fprintf (out
, ";;;-----------------------------------------\n");
4969 output_file_directive (out
, main_file
);
4974 m68hc11_add_gc_roots ()
4976 ggc_add_rtx_root (&m68hc11_soft_tmp_reg
, 1);
4977 ggc_add_rtx_root (&ix_reg
, 1);
4978 ggc_add_rtx_root (&iy_reg
, 1);
4979 ggc_add_rtx_root (&d_reg
, 1);
4980 ggc_add_rtx_root (&da_reg
, 1);
4981 ggc_add_rtx_root (&z_reg
, 1);
4982 ggc_add_rtx_root (&z_reg_qi
, 1);
4983 ggc_add_rtx_root (&stack_push_word
, 1);
4984 ggc_add_rtx_root (&stack_pop_word
, 1);