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 #include "target-def.h"
58 static void print_options
PARAMS ((FILE *));
59 static void emit_move_after_reload
PARAMS ((rtx
, rtx
, rtx
));
60 static rtx simplify_logical
PARAMS ((enum machine_mode
, int, rtx
, rtx
*));
61 static void m68hc11_emit_logical
PARAMS ((enum machine_mode
, int, rtx
*));
62 static int go_if_legitimate_address_internal
PARAMS((rtx
, enum machine_mode
,
64 static int register_indirect_p
PARAMS((rtx
, enum machine_mode
, int));
65 static rtx m68hc11_expand_compare
PARAMS((enum rtx_code
, rtx
, rtx
));
66 static int must_parenthesize
PARAMS ((rtx
));
67 static int m68hc11_shift_cost
PARAMS ((enum machine_mode
, rtx
, int));
68 static int m68hc11_auto_inc_p
PARAMS ((rtx
));
69 static int m68hc11_valid_type_attribute_p
PARAMS((tree
, tree
,
72 void create_regs_rtx
PARAMS ((void));
74 static void asm_print_register
PARAMS ((FILE *, int));
76 rtx m68hc11_soft_tmp_reg
;
78 /* Must be set to 1 to produce debug messages. */
81 extern FILE *asm_out_file
;
89 static int regs_inited
= 0;
92 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
93 int current_function_interrupt
;
95 /* Set to 1 by expand_prologue() when the function is a trap handler. */
96 int current_function_trap
;
98 /* Min offset that is valid for the indirect addressing mode. */
99 HOST_WIDE_INT m68hc11_min_offset
= 0;
101 /* Max offset that is valid for the indirect addressing mode. */
102 HOST_WIDE_INT m68hc11_max_offset
= 256;
104 /* The class value for base registers. */
105 enum reg_class m68hc11_base_reg_class
= A_REGS
;
107 /* The class value for index registers. This is NO_REGS for 68HC11. */
108 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
110 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
112 /* Tables that tell whether a given hard register is valid for
113 a base or an index register. It is filled at init time depending
114 on the target processor. */
115 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
116 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
118 /* A correction offset which is applied to the stack pointer.
119 This is 1 for 68HC11 and 0 for 68HC12. */
120 int m68hc11_sp_correction
;
122 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
123 rtx m68hc11_compare_op0
;
124 rtx m68hc11_compare_op1
;
127 struct processor_costs
*m68hc11_cost
;
129 /* Costs for a 68HC11. */
130 struct processor_costs m6811_cost
= {
135 /* non-constant shift */
138 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
139 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
140 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
143 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
144 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
145 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
146 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
147 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
148 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
153 COSTS_N_INSNS (20 * 4),
155 COSTS_N_INSNS (20 * 16),
164 /* Costs for a 68HC12. */
165 struct processor_costs m6812_cost
= {
170 /* non-constant shift */
173 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
174 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
175 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
178 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
179 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
180 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
181 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
182 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
183 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
190 COSTS_N_INSNS (3 * 4),
199 /* Machine specific options */
201 const char *m68hc11_regparm_string
;
202 const char *m68hc11_reg_alloc_order
;
203 const char *m68hc11_soft_reg_count
;
205 static void m68hc11_add_gc_roots
PARAMS ((void));
207 static int nb_soft_regs
;
209 /* Initialize the GCC target structure. */
210 #undef TARGET_VALID_TYPE_ATTRIBUTE
211 #define TARGET_VALID_TYPE_ATTRIBUTE m68hc11_valid_type_attribute_p
213 struct gcc_target target
= TARGET_INITIALIZER
;
216 m68hc11_override_options ()
218 m68hc11_add_gc_roots ();
220 memset (m68hc11_reg_valid_for_index
, 0,
221 sizeof (m68hc11_reg_valid_for_index
));
222 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
224 /* Compilation with -fpic generates a wrong code. */
227 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
228 (flag_pic
> 1) ? "PIC" : "pic");
232 /* Configure for a 68hc11 processor. */
235 /* If gcc was built for a 68hc12, invalidate that because
236 a -m68hc11 option was specified on the command line. */
237 if (TARGET_DEFAULT
!= MASK_M6811
)
238 target_flags
&= ~TARGET_DEFAULT
;
240 m68hc11_cost
= &m6811_cost
;
241 m68hc11_min_offset
= 0;
242 m68hc11_max_offset
= 256;
243 m68hc11_index_reg_class
= NO_REGS
;
244 m68hc11_base_reg_class
= A_REGS
;
245 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
246 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
247 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
248 m68hc11_sp_correction
= 1;
249 m68hc11_tmp_regs_class
= D_REGS
;
250 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
251 m68hc11_soft_reg_count
= "4";
254 /* Configure for a 68hc12 processor. */
257 m68hc11_cost
= &m6812_cost
;
258 m68hc11_min_offset
= -65536;
259 m68hc11_max_offset
= 65536;
260 m68hc11_index_reg_class
= D_REGS
;
261 m68hc11_base_reg_class
= A_OR_SP_REGS
;
262 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
263 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
264 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
265 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
266 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
267 m68hc11_sp_correction
= 0;
268 m68hc11_tmp_regs_class
= TMP_REGS
;
269 target_flags
&= ~MASK_M6811
;
270 if (m68hc11_soft_reg_count
== 0)
271 m68hc11_soft_reg_count
= "2";
278 m68hc11_conditional_register_usage ()
281 int cnt
= atoi (m68hc11_soft_reg_count
);
285 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
286 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
289 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
292 call_used_regs
[i
] = 1;
297 /* Reload and register operations. */
299 static const char *reg_class_names
[] = REG_CLASS_NAMES
;
305 /* regs_inited = 1; */
306 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
307 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
308 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
309 da_reg
= gen_rtx (REG
, QImode
, HARD_A_REGNUM
);
310 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
312 stack_push_word
= gen_rtx (MEM
, HImode
,
313 gen_rtx (PRE_DEC
, HImode
,
314 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
315 stack_pop_word
= gen_rtx (MEM
, HImode
,
316 gen_rtx (POST_INC
, HImode
,
317 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
321 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
322 - 8 bit values are stored anywhere (except the SP register).
323 - 16 bit values can be stored in any register whose mode is 16
324 - 32 bit values can be stored in D, X registers or in a soft register
325 (except the last one because we need 2 soft registers)
326 - Values whose size is > 32 bit are not stored in real hard
327 registers. They may be stored in soft registers if there are
330 hard_regno_mode_ok (regno
, mode
)
332 enum machine_mode mode
;
334 switch (GET_MODE_SIZE (mode
))
337 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
340 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
343 return G_REGNO_P (regno
);
346 /* We have to accept a QImode in X or Y registers. Otherwise, the
347 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
348 in the insns. Reload fails if the insn rejects the register class 'a'
349 as well as if it accepts it. Patterns that failed were
350 zero_extend_qihi2 and iorqi3. */
352 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
360 preferred_reload_class (operand
, class)
362 enum reg_class
class;
364 enum machine_mode mode
;
366 mode
= GET_MODE (operand
);
370 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
373 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
374 return m68hc11_base_reg_class
;
376 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
377 || GET_CODE (operand
) == CONST_INT
))
379 /* S_REGS class must not be used. The movhi template does not
380 work to move a memory to a soft register.
381 Restrict to a hard reg. */
386 case D_OR_A_OR_S_REGS
:
392 case D_OR_SP_OR_S_REGS
:
393 class = D_OR_SP_REGS
;
395 case D_OR_Y_OR_S_REGS
:
398 case D_OR_X_OR_S_REGS
:
414 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
418 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
422 else if (class >= S_REGS
&& S_REG_P (operand
))
428 case D_OR_A_OR_S_REGS
:
434 case D_OR_SP_OR_S_REGS
:
435 class = D_OR_SP_REGS
;
437 case D_OR_Y_OR_S_REGS
:
440 case D_OR_X_OR_S_REGS
:
456 else if (class >= S_REGS
)
460 printf ("Class = %s for: ", reg_class_names
[class]);
468 printf (" => class=%s\n", reg_class_names
[class]);
476 /* Return 1 if the operand is a valid indexed addressing mode.
477 For 68hc11: n,r with n in [0..255] and r in A_REGS class
478 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
480 register_indirect_p (operand
, mode
, strict
)
482 enum machine_mode mode
;
487 switch (GET_CODE (operand
))
493 if (TARGET_M6812
&& TARGET_AUTO_INC_DEC
)
494 return register_indirect_p (XEXP (operand
, 0), mode
, strict
);
498 base
= XEXP (operand
, 0);
499 if (GET_CODE (base
) == MEM
)
502 offset
= XEXP (operand
, 1);
503 if (GET_CODE (offset
) == MEM
)
506 if (GET_CODE (base
) == REG
)
508 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
514 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), strict
);
516 if (GET_CODE (offset
) == REG
)
518 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
524 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), strict
);
529 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), strict
);
536 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
537 a 68HC12 1-byte index addressing mode. */
539 m68hc11_small_indexed_indirect_p (operand
, mode
)
541 enum machine_mode mode
;
545 if (GET_CODE (operand
) != MEM
)
548 operand
= XEXP (operand
, 0);
549 if (CONSTANT_ADDRESS_P (operand
))
552 if (PUSH_POP_ADDRESS_P (operand
))
555 if (!register_indirect_p (operand
, mode
,
556 (reload_completed
| reload_in_progress
)))
559 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
560 && (reload_completed
| reload_in_progress
))
562 base
= XEXP (operand
, 0);
563 offset
= XEXP (operand
, 1);
564 if (GET_CODE (base
) == CONST_INT
)
567 switch (GET_MODE_SIZE (mode
))
570 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
575 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
580 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
589 m68hc11_register_indirect_p (operand
, mode
)
591 enum machine_mode mode
;
593 if (GET_CODE (operand
) != MEM
)
596 operand
= XEXP (operand
, 0);
597 return register_indirect_p (operand
, mode
,
598 (reload_completed
| reload_in_progress
));
602 go_if_legitimate_address_internal (operand
, mode
, strict
)
604 enum machine_mode mode
;
607 if (CONSTANT_ADDRESS_P (operand
))
609 /* Reject the global variables if they are too wide. This forces
610 a load of their address in a register and generates smaller code. */
611 if (GET_MODE_SIZE (mode
) == 8)
616 if (register_indirect_p (operand
, mode
, strict
))
620 if (PUSH_POP_ADDRESS_P (operand
))
624 if (symbolic_memory_operand (operand
, mode
))
632 m68hc11_go_if_legitimate_address (operand
, mode
, strict
)
634 enum machine_mode mode
;
641 printf ("Checking: ");
646 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
650 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
657 printf ("go_if_legitimate%s, ret 0: %d:",
658 (strict
? "_strict" : ""), mode
);
667 m68hc11_legitimize_address (operand
, old_operand
, mode
)
668 rtx
*operand ATTRIBUTE_UNUSED
;
669 rtx old_operand ATTRIBUTE_UNUSED
;
670 enum machine_mode mode ATTRIBUTE_UNUSED
;
677 m68hc11_reload_operands (operands
)
680 enum machine_mode mode
;
682 if (regs_inited
== 0)
685 mode
= GET_MODE (operands
[1]);
687 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
688 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
690 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
691 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
693 if (GET_CODE (base
) != REG
)
700 /* If the offset is out of range, we have to compute the address
701 with a separate add instruction. We try to do with with an 8-bit
702 add on the A register. This is possible only if the lowest part
703 of the offset (ie, big_offset % 256) is a valid constant offset
704 with respect to the mode. If it's not, we have to generate a
705 16-bit add on the D register. From:
707 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
711 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
712 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
713 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
714 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
716 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
717 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
720 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
723 rtx reg
= operands
[0];
725 int val
= INTVAL (big_offset
);
728 /* We use the 'operands[0]' as a scratch register to compute the
729 address. Make sure 'base' is in that register. */
730 if (!rtx_equal_p (base
, operands
[0]))
732 emit_move_insn (reg
, base
);
742 vh
= (val
>> 8) & 0x0FF;
746 /* Create the lowest part offset that still remains to be added.
747 If it's not a valid offset, do a 16-bit add. */
748 offset
= gen_rtx (CONST_INT
, VOIDmode
, vl
);
749 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
751 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
752 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
757 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
758 gen_rtx (PLUS
, HImode
, reg
,
760 VOIDmode
, vh
<< 8))));
762 emit_move_insn (operands
[0],
763 gen_rtx (MEM
, GET_MODE (operands
[1]),
764 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
769 /* Use the normal gen_movhi pattern. */
774 m68hc11_emit_libcall (name
, code
, dmode
, smode
, noperands
, operands
)
777 enum machine_mode dmode
;
778 enum machine_mode smode
;
788 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
792 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
793 dmode
, 1, operands
[1], smode
);
794 equiv
= gen_rtx (code
, dmode
, operands
[1]);
798 ret
= emit_library_call_value (libcall
, NULL_RTX
,
800 operands
[1], smode
, operands
[2],
802 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
809 insns
= get_insns ();
811 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
814 /* Returns true if X is a PRE/POST increment decrement
815 (same as auto_inc_p() in rtlanal.c but do not take into
816 account the stack). */
818 m68hc11_auto_inc_p (x
)
821 return GET_CODE (x
) == PRE_DEC
822 || GET_CODE (x
) == POST_INC
823 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
827 /* Predicates for machine description. */
830 memory_reload_operand (operand
, mode
)
832 enum machine_mode mode ATTRIBUTE_UNUSED
;
834 return GET_CODE (operand
) == MEM
835 && GET_CODE (XEXP (operand
, 0)) == PLUS
836 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
837 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
838 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
839 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
843 tst_operand (operand
, mode
)
845 enum machine_mode mode
;
847 if (GET_CODE (operand
) == MEM
)
849 rtx addr
= XEXP (operand
, 0);
850 if (m68hc11_auto_inc_p (addr
))
853 return nonimmediate_operand (operand
, mode
);
857 cmp_operand (operand
, mode
)
859 enum machine_mode mode
;
861 if (GET_CODE (operand
) == MEM
)
863 rtx addr
= XEXP (operand
, 0);
864 if (m68hc11_auto_inc_p (addr
))
867 return general_operand (operand
, mode
);
871 non_push_operand (operand
, mode
)
873 enum machine_mode mode
;
875 if (general_operand (operand
, mode
) == 0)
878 if (push_operand (operand
, mode
) == 1)
884 reg_or_some_mem_operand (operand
, mode
)
886 enum machine_mode mode
;
888 if (GET_CODE (operand
) == MEM
)
890 rtx op
= XEXP (operand
, 0);
892 if (symbolic_memory_operand (op
, mode
))
895 if (IS_STACK_PUSH (operand
))
898 if (m68hc11_register_indirect_p (operand
, mode
))
904 return register_operand (operand
, mode
);
908 stack_register_operand (operand
, mode
)
910 enum machine_mode mode ATTRIBUTE_UNUSED
;
912 return SP_REG_P (operand
);
916 d_register_operand (operand
, mode
)
918 enum machine_mode mode ATTRIBUTE_UNUSED
;
920 if (GET_CODE (operand
) == SUBREG
)
921 operand
= XEXP (operand
, 0);
923 return GET_CODE (operand
) == REG
924 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
925 || REGNO (operand
) == HARD_D_REGNUM
);
929 hard_addr_reg_operand (operand
, mode
)
931 enum machine_mode mode ATTRIBUTE_UNUSED
;
933 if (GET_CODE (operand
) == SUBREG
)
934 operand
= XEXP (operand
, 0);
936 return GET_CODE (operand
) == REG
937 && (REGNO (operand
) == HARD_X_REGNUM
938 || REGNO (operand
) == HARD_Y_REGNUM
939 || REGNO (operand
) == HARD_Z_REGNUM
);
943 hard_reg_operand (operand
, mode
)
945 enum machine_mode mode ATTRIBUTE_UNUSED
;
947 if (GET_CODE (operand
) == SUBREG
)
948 operand
= XEXP (operand
, 0);
950 return GET_CODE (operand
) == REG
951 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
952 || H_REGNO_P (REGNO (operand
)));
956 memory_indexed_operand (operand
, mode
)
958 enum machine_mode mode ATTRIBUTE_UNUSED
;
960 if (GET_CODE (operand
) != MEM
)
963 operand
= XEXP (operand
, 0);
964 if (GET_CODE (operand
) == PLUS
)
966 if (GET_CODE (XEXP (operand
, 0)) == REG
)
967 operand
= XEXP (operand
, 0);
968 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
969 operand
= XEXP (operand
, 1);
971 return GET_CODE (operand
) == REG
972 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
973 || A_REGNO_P (REGNO (operand
)));
977 push_pop_operand_p (operand
)
980 if (GET_CODE (operand
) != MEM
)
984 operand
= XEXP (operand
, 0);
985 return PUSH_POP_ADDRESS_P (operand
);
988 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
989 reference and a constant. */
992 symbolic_memory_operand (op
, mode
)
994 enum machine_mode mode
;
996 switch (GET_CODE (op
))
1003 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1004 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1005 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1007 /* ??? This clause seems to be irrelevant. */
1009 return GET_MODE (op
) == mode
;
1012 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1013 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1021 m68hc11_logical_operator (op
, mode
)
1023 enum machine_mode mode ATTRIBUTE_UNUSED
;
1025 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1029 m68hc11_arith_operator (op
, mode
)
1031 enum machine_mode mode ATTRIBUTE_UNUSED
;
1033 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1034 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1035 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1036 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1037 || GET_CODE (op
) == ROTATERT
;
1041 m68hc11_non_shift_operator (op
, mode
)
1043 enum machine_mode mode ATTRIBUTE_UNUSED
;
1045 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1046 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1051 m68hc11_unary_operator (op
, mode
)
1053 enum machine_mode mode ATTRIBUTE_UNUSED
;
1055 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1056 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1063 m68hc11_block_profiler (out
, blockno
)
1064 FILE *out ATTRIBUTE_UNUSED
;
1065 int blockno ATTRIBUTE_UNUSED
;
1071 m68hc11_function_block_profiler (out
, block_or_label
)
1072 FILE *out ATTRIBUTE_UNUSED
;
1073 int block_or_label ATTRIBUTE_UNUSED
;
1078 /* Emit the code to build the trampoline used to call a nested function.
1082 ldy #&CXT movw #&CXT,*_.d1
1083 sty *_.d1 jmp FNADDR
1088 m68hc11_initialize_trampoline (tramp
, fnaddr
, cxt
)
1093 char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1096 if (*static_chain_reg
== '*')
1100 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1101 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1102 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1104 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1105 gen_rtx_CONST (QImode
,
1106 gen_rtx_SYMBOL_REF (Pmode
,
1107 static_chain_reg
)));
1108 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1110 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1114 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1115 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1116 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1117 gen_rtx_CONST (HImode
,
1118 gen_rtx_SYMBOL_REF (Pmode
,
1119 static_chain_reg
)));
1120 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1122 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1126 /* Declaration of types. */
1128 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1129 with arguments ARGS is a valid machine specific attribute for TYPE.
1130 The attributes in ATTRIBUTES have previously been assigned to TYPE. */
1133 m68hc11_valid_type_attribute_p (type
, attributes
, identifier
, args
)
1135 tree attributes ATTRIBUTE_UNUSED
;
1139 if (TREE_CODE (type
) != FUNCTION_TYPE
1140 && TREE_CODE (type
) != FIELD_DECL
&& TREE_CODE (type
) != TYPE_DECL
)
1143 if (TREE_CODE (type
) == FUNCTION_TYPE
)
1145 if (is_attribute_p ("interrupt", identifier
))
1146 return (args
== NULL_TREE
);
1147 if (is_attribute_p ("trap", identifier
))
1148 return (args
== NULL_TREE
);
1154 /* If defined, a C expression whose value is zero if the attributes on
1155 TYPE1 and TYPE2 are incompatible, one if they are compatible, and
1156 two if they are nearly compatible (which causes a warning to be
1160 m68hc11_comp_type_attributes (type1
, type2
)
1161 tree type1 ATTRIBUTE_UNUSED
;
1162 tree type2 ATTRIBUTE_UNUSED
;
1167 /* If defined, a C statement that assigns default attributes to newly
1171 m68hc11_set_default_type_attributes (type
)
1172 tree type ATTRIBUTE_UNUSED
;
1176 /* Define this macro if references to a symbol must be treated
1177 differently depending on something about the variable or function
1178 named by the symbol (such as what section it is in).
1180 For the 68HC11, we want to recognize trap handlers so that we
1181 handle calls to traps in a special manner (by issuing the trap).
1182 This information is stored in SYMBOL_REF_FLAG. */
1184 m68hc11_encode_section_info (decl
)
1191 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1194 rtl
= DECL_RTL (decl
);
1196 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1197 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1198 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = trap_handler
;
1202 /* Argument support functions. */
1204 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1205 Arrays are passed by references and other types by value.
1207 SCz: I tried to pass DImode by reference but it seems that this
1208 does not work very well. */
1210 m68hc11_function_arg_pass_by_reference (cum
, mode
, type
, named
)
1211 const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
;
1212 enum machine_mode mode ATTRIBUTE_UNUSED
;
1214 int named ATTRIBUTE_UNUSED
;
1216 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1217 /* Consider complex values as aggregates, so care for TCmode. */
1218 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1219 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1223 /* Define the offset between two registers, one to be eliminated, and the
1224 other its replacement, at the start of a routine. */
1226 m68hc11_initial_elimination_offset (from
, to
)
1235 /* For a trap handler, we must take into account the registers which
1236 are pushed on the stack during the trap (except the PC). */
1237 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1238 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1239 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1244 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1246 /* 2 is for the saved frame.
1247 1 is for the 'sts' correction when creating the frame. */
1248 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1251 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1256 /* Push any 2 byte pseudo hard registers that we need to save. */
1257 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1259 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1265 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1267 return get_frame_size () + size
;
1270 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1272 return size
- m68hc11_sp_correction
;
1277 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1278 for a call to a function whose data type is FNTYPE.
1279 For a library call, FNTYPE is 0. */
1282 m68hc11_init_cumulative_args (cum
, fntype
, libname
)
1283 CUMULATIVE_ARGS
*cum
;
1289 z_replacement_completed
= 0;
1293 /* For a library call, we must find out the type of the return value.
1294 When the return value is bigger than 4 bytes, it is returned in
1295 memory. In that case, the first argument of the library call is a
1296 pointer to the memory location. Because the first argument is passed in
1297 register D, we have to identify this, so that the first function
1298 parameter is not passed in D either. */
1304 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1307 /* If the library ends in 'di' or in 'df', we assume it's
1308 returning some DImode or some DFmode which are 64-bit wide. */
1309 name
= XSTR (libname
, 0);
1310 len
= strlen (name
);
1312 && ((name
[len
- 2] == 'd'
1313 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1314 || (name
[len
- 3] == 'd'
1315 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1317 /* We are in. Mark the first parameter register as already used. */
1324 ret_type
= TREE_TYPE (fntype
);
1326 if (ret_type
&& aggregate_value_p (ret_type
))
1333 /* Update the data in CUM to advance over an argument
1334 of mode MODE and data type TYPE.
1335 (TYPE is null for libcalls where that information may not be available.) */
1338 m68hc11_function_arg_advance (cum
, mode
, type
, named
)
1339 CUMULATIVE_ARGS
*cum
;
1340 enum machine_mode mode
;
1342 int named ATTRIBUTE_UNUSED
;
1344 if (mode
!= BLKmode
)
1346 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1349 cum
->words
= GET_MODE_SIZE (mode
);
1353 cum
->words
+= GET_MODE_SIZE (mode
);
1354 if (cum
->words
<= HARD_REG_SIZE
)
1360 cum
->words
+= int_size_in_bytes (type
);
1365 /* Define where to put the arguments to a function.
1366 Value is zero to push the argument on the stack,
1367 or a hard register in which to store the argument.
1369 MODE is the argument's machine mode.
1370 TYPE is the data type of the argument (as a tree).
1371 This is null for libcalls where that information may
1373 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1374 the preceding args and about the function being called.
1375 NAMED is nonzero if this argument is a named parameter
1376 (otherwise it is an extra parameter matching an ellipsis). */
1379 m68hc11_function_arg (cum
, mode
, type
, named
)
1380 const CUMULATIVE_ARGS
*cum
;
1381 enum machine_mode mode
;
1382 tree type ATTRIBUTE_UNUSED
;
1383 int named ATTRIBUTE_UNUSED
;
1385 if (cum
->words
!= 0)
1390 if (mode
!= BLKmode
)
1392 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1393 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1395 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1399 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1404 /* The "standard" implementation of va_start: just assign `nextarg' to
1407 m68hc11_expand_builtin_va_start (stdarg_p
, valist
, nextarg
)
1408 int stdarg_p ATTRIBUTE_UNUSED
;
1414 /* SCz: the default implementation in builtins.c adjust the
1415 nextarg using UNITS_PER_WORD. This works only with -mshort
1416 and fails when integers are 32-bit. Here is the correct way. */
1418 nextarg
= plus_constant (nextarg
, -INT_TYPE_SIZE
/ 8);
1420 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1421 make_tree (ptr_type_node
, nextarg
));
1422 TREE_SIDE_EFFECTS (t
) = 1;
1424 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1428 m68hc11_va_arg (valist
, type
)
1433 HOST_WIDE_INT align
;
1434 HOST_WIDE_INT rounded_size
;
1438 /* Compute the rounded size of the type. */
1439 align
= PARM_BOUNDARY
/ BITS_PER_UNIT
;
1440 rounded_size
= (((int_size_in_bytes (type
) + align
- 1) / align
) * align
);
1444 pad_direction
= m68hc11_function_arg_padding (TYPE_MODE (type
), type
);
1446 if (pad_direction
== downward
)
1448 /* Small args are padded downward. */
1451 adj
= TREE_INT_CST_LOW (TYPE_SIZE (type
)) / BITS_PER_UNIT
;
1452 if (rounded_size
> align
)
1455 addr_tree
= build (PLUS_EXPR
, TREE_TYPE (addr_tree
), addr_tree
,
1456 build_int_2 (rounded_size
- adj
, 0));
1459 addr
= expand_expr (addr_tree
, NULL_RTX
, Pmode
, EXPAND_NORMAL
);
1460 addr
= copy_to_reg (addr
);
1462 /* Compute new value for AP. */
1463 t
= build (MODIFY_EXPR
, TREE_TYPE (valist
), valist
,
1464 build (PLUS_EXPR
, TREE_TYPE (valist
), valist
,
1465 build_int_2 (rounded_size
, 0)));
1466 TREE_SIDE_EFFECTS (t
) = 1;
1467 expand_expr (t
, const0_rtx
, VOIDmode
, EXPAND_NORMAL
);
1472 /* If defined, a C expression which determines whether, and in which direction,
1473 to pad out an argument with extra space. The value should be of type
1474 `enum direction': either `upward' to pad above the argument,
1475 `downward' to pad below, or `none' to inhibit padding.
1477 Structures are stored left shifted in their argument slot. */
1479 m68hc11_function_arg_padding (mode
, type
)
1480 enum machine_mode mode
;
1483 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1486 /* This is the default definition. */
1487 return (!BYTES_BIG_ENDIAN
1490 ? (type
&& TREE_CODE (TYPE_SIZE (type
)) == INTEGER_CST
1491 && int_size_in_bytes (type
) <
1492 (PARM_BOUNDARY
/ BITS_PER_UNIT
)) : GET_MODE_BITSIZE (mode
) <
1493 PARM_BOUNDARY
) ? downward
: upward
));
1497 /* Function prologue and epilogue. */
1499 /* Emit a move after the reload pass has completed. This is used to
1500 emit the prologue and epilogue. */
1502 emit_move_after_reload (to
, from
, scratch
)
1503 rtx to
, from
, scratch
;
1507 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1509 insn
= emit_move_insn (to
, from
);
1513 emit_move_insn (scratch
, from
);
1514 insn
= emit_move_insn (to
, scratch
);
1517 /* Put a REG_INC note to tell the flow analysis that the instruction
1519 if (IS_STACK_PUSH (to
))
1521 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1522 XEXP (XEXP (to
, 0), 0),
1525 else if (IS_STACK_POP (from
))
1527 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1528 XEXP (XEXP (from
, 0), 0),
1534 m68hc11_total_frame_size ()
1539 size
= get_frame_size ();
1540 if (current_function_interrupt
)
1542 size
+= 3 * HARD_REG_SIZE
;
1544 if (frame_pointer_needed
)
1545 size
+= HARD_REG_SIZE
;
1547 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1548 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1549 size
+= HARD_REG_SIZE
;
1555 m68hc11_function_epilogue (out
, size
)
1556 FILE *out ATTRIBUTE_UNUSED
;
1557 int size ATTRIBUTE_UNUSED
;
1559 /* We catch the function epilogue generation to have a chance
1560 to clear the z_replacement_completed flag. */
1561 z_replacement_completed
= 0;
1572 if (reload_completed
!= 1)
1575 size
= get_frame_size ();
1579 /* Generate specific prologue for interrupt handlers. */
1580 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1581 current_function_interrupt
= lookup_attribute ("interrupt",
1582 func_attr
) != NULL_TREE
;
1583 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1585 /* Get the scratch register to build the frame and push registers.
1586 If the first argument is a 32-bit quantity, the D+X registers
1587 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1588 For 68HC12, this scratch register is not used. */
1589 if (current_function_args_info
.nregs
== 2)
1594 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1595 Other soft registers in page0 need not to be saved because they
1596 will be restored by C functions. For a trap handler, we don't
1597 need to preserve these registers because this is a synchronous call. */
1598 if (current_function_interrupt
)
1600 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1601 emit_move_after_reload (stack_push_word
,
1602 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1603 emit_move_after_reload (stack_push_word
,
1604 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1608 /* Save current stack frame. */
1609 if (frame_pointer_needed
)
1610 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1612 /* Allocate local variables. */
1613 if (TARGET_M6812
&& size
>= 2)
1615 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1616 stack_pointer_rtx
, GEN_INT (-size
)));
1622 insn
= gen_rtx_PARALLEL
1625 gen_rtx_SET (VOIDmode
,
1627 gen_rtx_PLUS (HImode
,
1630 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1637 /* Allocate by pushing scratch values. */
1638 for (i
= 2; i
<= size
; i
+= 2)
1639 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1642 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1643 stack_pointer_rtx
, GEN_INT (-1)));
1646 /* Create the frame pointer. */
1647 if (frame_pointer_needed
)
1648 emit_move_after_reload (hard_frame_pointer_rtx
,
1649 stack_pointer_rtx
, scratch
);
1651 /* Push any 2 byte pseudo hard registers that we need to save. */
1652 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1654 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1656 emit_move_after_reload (stack_push_word
,
1657 gen_rtx (REG
, HImode
, regno
), scratch
);
1670 if (reload_completed
!= 1)
1673 size
= get_frame_size ();
1675 /* If we are returning a value in two registers, we have to preserve the
1676 X register and use the Y register to restore the stack and the saved
1677 registers. Otherwise, use X because it's faster (and smaller). */
1678 if (current_function_return_rtx
== 0)
1680 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1681 return_size
= HARD_REG_SIZE
;
1683 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1685 if (return_size
> HARD_REG_SIZE
)
1690 /* Pop any 2 byte pseudo hard registers that we saved. */
1691 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1693 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1695 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1696 stack_pop_word
, scratch
);
1700 /* de-allocate auto variables */
1701 if (TARGET_M6812
&& size
>= 2)
1703 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1704 stack_pointer_rtx
, GEN_INT (size
)));
1710 insn
= gen_rtx_PARALLEL
1713 gen_rtx_SET (VOIDmode
,
1715 gen_rtx_PLUS (HImode
,
1718 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1725 for (i
= 2; i
<= size
; i
+= 2)
1726 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1728 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1729 stack_pointer_rtx
, GEN_INT (1)));
1732 /* Restore previous frame pointer. */
1733 if (frame_pointer_needed
)
1734 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1736 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1737 if (current_function_interrupt
)
1739 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1740 stack_pop_word
, scratch
);
1741 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1742 stack_pop_word
, scratch
);
1743 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1746 /* If the trap handler returns some value, copy the value
1747 in D, X onto the stack so that the rti will pop the return value
1749 else if (current_function_trap
&& return_size
!= 0)
1751 rtx addr_reg
= stack_pointer_rtx
;
1755 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1758 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1759 gen_rtx (PLUS
, HImode
, addr_reg
,
1760 GEN_INT (1))), d_reg
, 0);
1761 if (return_size
> HARD_REG_SIZE
)
1762 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1763 gen_rtx (PLUS
, HImode
, addr_reg
,
1764 GEN_INT (3))), ix_reg
, 0);
1767 emit_jump_insn (gen_return ());
1771 /* Low and High part extraction for 68HC11. These routines are
1772 similar to gen_lowpart and gen_highpart but they have been
1773 fixed to work for constants and 68HC11 specific registers. */
1776 m68hc11_gen_lowpart (mode
, x
)
1777 enum machine_mode mode
;
1780 /* We assume that the low part of an auto-inc mode is the same with
1781 the mode changed and that the caller split the larger mode in the
1783 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1785 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1788 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1789 floating-point constant. A CONST_DOUBLE is used whenever the
1790 constant requires more than one word in order to be adequately
1792 if (GET_CODE (x
) == CONST_DOUBLE
)
1796 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1800 if (GET_MODE (x
) == SFmode
)
1802 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1803 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1809 split_double (x
, &first
, &second
);
1813 return gen_rtx (CONST_INT
, VOIDmode
, l
[0]);
1815 return gen_rtx (CONST_INT
, VOIDmode
,
1816 trunc_int_for_mode (l
[0], HImode
));
1820 l
[0] = CONST_DOUBLE_LOW (x
);
1823 return gen_rtx (CONST_INT
, VOIDmode
, l
[0]);
1824 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1825 return gen_rtx (CONST_INT
, VOIDmode
,
1826 trunc_int_for_mode (l
[0], HImode
));
1831 if (mode
== QImode
&& D_REG_P (x
))
1832 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1834 /* gen_lowpart crashes when it is called with a SUBREG. */
1835 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1838 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1839 else if (mode
== HImode
)
1840 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1844 x
= gen_lowpart (mode
, x
);
1846 /* Return a different rtx to avoid to share it in several insns
1847 (when used by a split pattern). Sharing addresses within
1848 a MEM breaks the Z register replacement (and reloading). */
1849 if (GET_CODE (x
) == MEM
)
1855 m68hc11_gen_highpart (mode
, x
)
1856 enum machine_mode mode
;
1859 /* We assume that the high part of an auto-inc mode is the same with
1860 the mode changed and that the caller split the larger mode in the
1862 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1864 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1867 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1868 floating-point constant. A CONST_DOUBLE is used whenever the
1869 constant requires more than one word in order to be adequately
1871 if (GET_CODE (x
) == CONST_DOUBLE
)
1875 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1879 if (GET_MODE (x
) == SFmode
)
1881 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1882 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1888 split_double (x
, &first
, &second
);
1892 return gen_rtx (CONST_INT
, VOIDmode
, l
[1]);
1894 return gen_rtx (CONST_INT
, VOIDmode
,
1895 trunc_int_for_mode ((l
[1] >> 16), HImode
));
1899 l
[1] = CONST_DOUBLE_HIGH (x
);
1903 return gen_rtx (CONST_INT
, VOIDmode
, l
[1]);
1904 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1905 return gen_rtx (CONST_INT
, VOIDmode
,
1906 trunc_int_for_mode ((l
[0] >> 16), HImode
));
1910 if (GET_CODE (x
) == CONST_INT
)
1912 HOST_WIDE_INT val
= INTVAL (x
);
1916 return gen_rtx (CONST_INT
, VOIDmode
,
1917 trunc_int_for_mode (val
>> 8, QImode
));
1919 else if (mode
== HImode
)
1921 return gen_rtx (CONST_INT
, VOIDmode
,
1922 trunc_int_for_mode (val
>> 16, HImode
));
1925 if (mode
== QImode
&& D_REG_P (x
))
1926 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
1928 /* There is no way in GCC to represent the upper part of a word register.
1929 To obtain the 8-bit upper part of a soft register, we change the
1930 reg into a mem rtx. This is possible because they are physically
1931 located in memory. There is no offset because we are big-endian. */
1932 if (mode
== QImode
&& S_REG_P (x
))
1936 /* For 68HC12, avoid the '*' for direct addressing mode. */
1937 pos
= TARGET_M6812
? 1 : 0;
1938 return gen_rtx (MEM
, QImode
,
1939 gen_rtx (SYMBOL_REF
, Pmode
,
1940 ®_names
[REGNO (x
)][pos
]));
1943 /* gen_highpart crashes when it is called with a SUBREG. */
1944 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1946 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
1948 x
= gen_highpart (mode
, x
);
1950 /* Return a different rtx to avoid to share it in several insns
1951 (when used by a split pattern). Sharing addresses within
1952 a MEM breaks the Z register replacement (and reloading). */
1953 if (GET_CODE (x
) == MEM
)
1959 /* Obscure register manipulation. */
1961 /* Finds backward in the instructions to see if register 'reg' is
1962 dead. This is used when generating code to see if we can use 'reg'
1963 as a scratch register. This allows us to choose a better generation
1964 of code when we know that some register dies or can be clobbered. */
1967 dead_register_here (x
, reg
)
1975 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
1979 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
1980 if (GET_RTX_CLASS (GET_CODE (p
)) == 'i')
1986 if (GET_CODE (body
) == CALL_INSN
)
1988 if (GET_CODE (body
) == JUMP_INSN
)
1991 if (GET_CODE (body
) == SET
)
1993 rtx dst
= XEXP (body
, 0);
1995 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
1997 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2000 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2003 else if (reg_mentioned_p (reg
, p
)
2004 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2008 /* Scan forward to see if the register is set in some insns and never
2010 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2014 if (GET_CODE (p
) == CODE_LABEL
2015 || GET_CODE (p
) == JUMP_INSN
2016 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2019 if (GET_CODE (p
) != INSN
)
2023 if (GET_CODE (body
) == SET
)
2025 rtx src
= XEXP (body
, 1);
2026 rtx dst
= XEXP (body
, 0);
2028 if (GET_CODE (dst
) == REG
2029 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2033 /* Register is used (may be in source or in dest). */
2034 if (reg_mentioned_p (reg
, p
)
2035 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2036 && reg_mentioned_p (x_reg
, p
)))
2039 return p
== 0 ? 1 : 0;
2043 /* Code generation operations called from machine description file. */
2045 /* Print the name of register 'regno' in the assembly file. */
2047 asm_print_register (file
, regno
)
2051 const char *name
= reg_names
[regno
];
2053 if (TARGET_M6812
&& name
[0] == '*')
2056 asm_fprintf (file
, "%s", name
);
2059 /* A C compound statement to output to stdio stream STREAM the
2060 assembler syntax for an instruction operand X. X is an RTL
2063 CODE is a value that can be used to specify one of several ways
2064 of printing the operand. It is used when identical operands
2065 must be printed differently depending on the context. CODE
2066 comes from the `%' specification that was used to request
2067 printing of the operand. If the specification was just `%DIGIT'
2068 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2069 is the ASCII code for LTR.
2071 If X is a register, this macro should print the register's name.
2072 The names can be found in an array `reg_names' whose type is
2073 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2075 When the machine description has a specification `%PUNCT' (a `%'
2076 followed by a punctuation character), this macro is called with
2077 a null pointer for X and the punctuation character for CODE.
2079 The M68HC11 specific codes are:
2081 'b' for the low part of the operand.
2082 'h' for the high part of the operand
2083 The 'b' or 'h' modifiers have no effect if the operand has
2084 the QImode and is not a S_REG_P (soft register). If the
2085 operand is a hard register, these two modifiers have no effect.
2086 't' generate the temporary scratch register. The operand is
2088 'T' generate the low-part temporary scratch register. The operand is
2092 print_operand (file
, op
, letter
)
2099 asm_print_register (file
, SOFT_TMP_REGNUM
);
2102 else if (letter
== 'T')
2104 asm_print_register (file
, SOFT_TMP_REGNUM
);
2105 asm_fprintf (file
, "+1");
2108 else if (letter
== '#')
2110 asm_fprintf (file
, "%0I");
2113 if (GET_CODE (op
) == REG
)
2115 if (letter
== 'b' && S_REG_P (op
))
2117 asm_print_register (file
, REGNO (op
));
2118 asm_fprintf (file
, "+1");
2122 asm_print_register (file
, REGNO (op
));
2127 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2130 asm_fprintf (file
, "%0I%%lo(");
2132 asm_fprintf (file
, "%0I%%hi(");
2134 output_addr_const (file
, op
);
2135 asm_fprintf (file
, ")");
2139 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2140 are specified. If we already have a QImode, there is nothing to do. */
2141 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2145 op
= m68hc11_gen_lowpart (QImode
, op
);
2147 else if (letter
== 'h')
2149 op
= m68hc11_gen_highpart (QImode
, op
);
2153 if (GET_CODE (op
) == MEM
)
2155 rtx base
= XEXP (op
, 0);
2156 switch (GET_CODE (base
))
2161 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2162 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2171 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2172 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2173 asm_fprintf (file
, "-");
2182 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2183 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2184 asm_fprintf (file
, "+");
2193 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2194 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2201 output_address (base
);
2205 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2208 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2209 ASM_OUTPUT_FLOAT_OPERAND (letter
, file
, r
);
2211 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == XFmode
)
2214 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2215 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file
, r
);
2217 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == DFmode
)
2220 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2221 ASM_OUTPUT_DOUBLE_OPERAND (file
, r
);
2225 int need_parenthesize
= 0;
2228 asm_fprintf (file
, "%0I");
2230 need_parenthesize
= must_parenthesize (op
);
2232 if (need_parenthesize
)
2233 asm_fprintf (file
, "(");
2235 output_addr_const (file
, op
);
2236 if (need_parenthesize
)
2237 asm_fprintf (file
, ")");
2241 /* Returns true if the operand 'op' must be printed with parenthesis
2242 arround it. This must be done only if there is a symbol whose name
2243 is a processor register. */
2245 must_parenthesize (op
)
2250 switch (GET_CODE (op
))
2253 name
= XSTR (op
, 0);
2254 /* Avoid a conflict between symbol name and a possible
2256 return (strcasecmp (name
, "a") == 0
2257 || strcasecmp (name
, "b") == 0
2258 || strcasecmp (name
, "d") == 0
2259 || strcasecmp (name
, "x") == 0
2260 || strcasecmp (name
, "y") == 0
2261 || strcasecmp (name
, "pc") == 0
2262 || strcasecmp (name
, "sp") == 0
2263 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2267 return must_parenthesize (XEXP (op
, 0))
2268 || must_parenthesize (XEXP (op
, 1));
2274 return must_parenthesize (XEXP (op
, 0));
2285 /* A C compound statement to output to stdio stream STREAM the
2286 assembler syntax for an instruction operand that is a memory
2287 reference whose address is ADDR. ADDR is an RTL expression. */
2290 print_operand_address (file
, addr
)
2296 int need_parenthesis
= 0;
2298 switch (GET_CODE (addr
))
2301 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2304 asm_fprintf (file
, "0,");
2305 asm_print_register (file
, REGNO (addr
));
2309 base
= XEXP (addr
, 0);
2310 switch (GET_CODE (base
))
2315 asm_fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2316 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2325 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2326 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2327 asm_fprintf (file
, "-");
2336 asm_fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2337 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2338 asm_fprintf (file
, "+");
2347 asm_fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2348 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2355 need_parenthesis
= must_parenthesize (base
);
2356 if (need_parenthesis
)
2357 asm_fprintf (file
, "(");
2359 output_addr_const (file
, base
);
2360 if (need_parenthesis
)
2361 asm_fprintf (file
, ")");
2367 base
= XEXP (addr
, 0);
2368 offset
= XEXP (addr
, 1);
2369 if (!G_REG_P (base
) && G_REG_P (offset
))
2371 base
= XEXP (addr
, 1);
2372 offset
= XEXP (addr
, 0);
2374 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2376 need_parenthesis
= must_parenthesize (addr
);
2378 if (need_parenthesis
)
2379 asm_fprintf (file
, "(");
2381 output_addr_const (file
, base
);
2382 asm_fprintf (file
, "+");
2383 output_addr_const (file
, offset
);
2384 if (need_parenthesis
)
2385 asm_fprintf (file
, ")");
2387 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2393 asm_print_register (file
, REGNO (offset
));
2394 asm_fprintf (file
, ",");
2395 asm_print_register (file
, REGNO (base
));
2402 output_addr_const (file
, offset
);
2403 asm_fprintf (file
, ",");
2404 asm_print_register (file
, REGNO (base
));
2414 if (GET_CODE (addr
) == CONST_INT
2415 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2417 asm_fprintf (file
, "%d", INTVAL (addr
));
2421 need_parenthesis
= must_parenthesize (addr
);
2422 if (need_parenthesis
)
2423 asm_fprintf (file
, "(");
2425 output_addr_const (file
, addr
);
2426 if (need_parenthesis
)
2427 asm_fprintf (file
, ")");
2434 /* Splitting of some instructions. */
2437 m68hc11_expand_compare (code
, op0
, op1
)
2443 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2447 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2448 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2449 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2456 m68hc11_expand_compare_and_branch (code
, op0
, op1
, label
)
2458 rtx op0
, op1
, label
;
2462 switch (GET_MODE (op0
))
2466 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2467 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2468 gen_rtx_LABEL_REF (VOIDmode
, label
),
2470 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2474 /* SCz: from i386.c */
2477 /* Don't expand the comparison early, so that we get better code
2478 when jump or whoever decides to reverse the comparison. */
2483 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2484 &m68hc11_compare_op1
);
2486 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2487 m68hc11_compare_op0
, m68hc11_compare_op1
);
2488 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2489 gen_rtx_LABEL_REF (VOIDmode
, label
),
2491 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2493 use_fcomi
= ix86_use_fcomi_compare (code
);
2494 vec
= rtvec_alloc (3 + !use_fcomi
);
2495 RTVEC_ELT (vec
, 0) = tmp
;
2497 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2499 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2502 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2504 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2510 /* Expand SImode branch into multiple compare+branch. */
2512 rtx lo
[2], hi
[2], label2
;
2513 enum rtx_code code1
, code2
, code3
;
2515 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2520 code
= swap_condition (code
);
2522 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2523 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2524 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2525 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2527 /* Otherwise, if we are doing less-than, op1 is a constant and the
2528 low word is zero, then we can just examine the high word. */
2530 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2531 && (code
== LT
|| code
== LTU
))
2533 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2537 /* Otherwise, we need two or three jumps. */
2539 label2
= gen_label_rtx ();
2542 code2
= swap_condition (code
);
2543 code3
= unsigned_condition (code
);
2584 * if (hi(a) < hi(b)) goto true;
2585 * if (hi(a) > hi(b)) goto false;
2586 * if (lo(a) < lo(b)) goto true;
2590 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2592 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2594 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2597 emit_label (label2
);
2608 /* Split a DI, SI or HI move into several smaller move operations.
2609 The scratch register 'scratch' is used as a temporary to load
2610 store intermediate values. It must be a hard register. */
2612 m68hc11_split_move (to
, from
, scratch
)
2613 rtx to
, from
, scratch
;
2615 rtx low_to
, low_from
;
2616 rtx high_to
, high_from
;
2617 enum machine_mode mode
;
2620 mode
= GET_MODE (to
);
2621 if (GET_MODE_SIZE (mode
) == 8)
2623 else if (GET_MODE_SIZE (mode
) == 4)
2629 && IS_STACK_PUSH (to
)
2630 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2636 else if (mode
== HImode
)
2644 low_to
= m68hc11_gen_lowpart (mode
, to
);
2645 high_to
= m68hc11_gen_highpart (mode
, to
);
2647 low_from
= m68hc11_gen_lowpart (mode
, from
);
2648 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2650 if (INTVAL (from
) >= 0)
2651 high_from
= const0_rtx
;
2653 high_from
= constm1_rtx
;
2656 high_from
= m68hc11_gen_highpart (mode
, from
);
2660 high_from
= adj_offsettable_operand (high_from
, offset
);
2661 low_from
= high_from
;
2665 m68hc11_split_move (low_to
, low_from
, scratch
);
2666 m68hc11_split_move (high_to
, high_from
, scratch
);
2668 else if (H_REG_P (to
) || H_REG_P (from
)
2670 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2671 || m68hc11_small_indexed_indirect_p (from
,
2673 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2674 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2676 emit_move_insn (low_to
, low_from
);
2677 emit_move_insn (high_to
, high_from
);
2683 emit_move_insn (scratch
, low_from
);
2684 insn
= emit_move_insn (low_to
, scratch
);
2686 emit_move_insn (scratch
, high_from
);
2687 insn
= emit_move_insn (high_to
, scratch
);
2692 simplify_logical (mode
, code
, operand
, result
)
2693 enum machine_mode mode
;
2702 if (GET_CODE (operand
) != CONST_INT
)
2710 val
= INTVAL (operand
);
2714 if ((val
& mask
) == 0)
2716 if ((val
& mask
) == mask
)
2717 *result
= constm1_rtx
;
2721 if ((val
& mask
) == 0)
2722 *result
= const0_rtx
;
2723 if ((val
& mask
) == mask
)
2728 if ((val
& mask
) == 0)
2736 m68hc11_emit_logical (mode
, code
, operands
)
2737 enum machine_mode mode
;
2744 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
2745 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
2747 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
2748 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
2750 if (result
&& GET_CODE (result
) == CONST_INT
)
2752 if (!H_REG_P (operands
[0]) && operands
[3]
2753 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
2755 emit_move_insn (operands
[3], result
);
2756 emit_move_insn (operands
[0], operands
[3]);
2760 emit_move_insn (operands
[0], result
);
2763 else if (operands
[1] != 0 && operands
[2] != 0)
2767 if (!H_REG_P (operands
[0]) && operands
[3])
2769 emit_move_insn (operands
[3], operands
[1]);
2770 emit_insn (gen_rtx (SET
, mode
,
2772 gen_rtx (code
, mode
,
2773 operands
[3], operands
[2])));
2774 insn
= emit_move_insn (operands
[0], operands
[3]);
2778 insn
= emit_insn (gen_rtx (SET
, mode
,
2780 gen_rtx (code
, mode
,
2781 operands
[0], operands
[2])));
2785 /* The logical operation is similar to a copy. */
2790 if (GET_CODE (operands
[1]) == CONST_INT
)
2795 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
2797 emit_move_insn (operands
[3], src
);
2798 emit_move_insn (operands
[0], operands
[3]);
2802 emit_move_insn (operands
[0], src
);
2808 m68hc11_split_logical (mode
, code
, operands
)
2809 enum machine_mode mode
;
2816 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
2817 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
2818 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
2820 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
2822 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
2824 if (INTVAL (operands
[1]) >= 0)
2825 high
[1] = const0_rtx
;
2827 high
[1] = constm1_rtx
;
2830 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
2832 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
2834 if (INTVAL (operands
[2]) >= 0)
2835 high
[2] = const0_rtx
;
2837 high
[2] = constm1_rtx
;
2840 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
2842 low
[3] = operands
[3];
2843 high
[3] = operands
[3];
2846 m68hc11_split_logical (HImode
, code
, low
);
2847 m68hc11_split_logical (HImode
, code
, high
);
2851 m68hc11_emit_logical (mode
, code
, low
);
2852 m68hc11_emit_logical (mode
, code
, high
);
2856 /* Code generation. */
2859 m68hc11_output_swap (insn
, operands
)
2860 rtx insn ATTRIBUTE_UNUSED
;
2863 /* We have to be careful with the cc_status. An address register swap
2864 is generated for some comparison. The comparison is made with D
2865 but the branch really uses the address register. See the split
2866 pattern for compare. The xgdx/xgdy preserve the flags but after
2867 the exchange, the flags will reflect to the value of X and not D.
2868 Tell this by setting the cc_status according to the cc_prev_status. */
2869 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
2871 if (cc_prev_status
.value1
!= 0
2872 && (D_REG_P (cc_prev_status
.value1
)
2873 || X_REG_P (cc_prev_status
.value1
)))
2875 cc_status
= cc_prev_status
;
2876 if (D_REG_P (cc_status
.value1
))
2877 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2880 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2886 output_asm_insn ("xgdx", operands
);
2890 if (cc_prev_status
.value1
!= 0
2891 && (D_REG_P (cc_prev_status
.value1
)
2892 || Y_REG_P (cc_prev_status
.value1
)))
2894 cc_status
= cc_prev_status
;
2895 if (D_REG_P (cc_status
.value1
))
2896 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2899 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
2905 output_asm_insn ("xgdy", operands
);
2909 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2910 This is used to decide whether a move that set flags should be used
2913 next_insn_test_reg (insn
, reg
)
2919 insn
= next_nonnote_insn (insn
);
2920 if (GET_CODE (insn
) != INSN
)
2923 body
= PATTERN (insn
);
2924 if (sets_cc0_p (body
) != 1)
2927 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
2933 /* Generate the code to move a 16-bit operand into another one. */
2936 m68hc11_gen_movhi (insn
, operands
)
2942 /* Move a register or memory to the same location.
2943 This is possible because such insn can appear
2944 in a non-optimizing mode. */
2945 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
2947 cc_status
= cc_prev_status
;
2953 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
2955 cc_status
= cc_prev_status
;
2956 switch (REGNO (operands
[1]))
2961 output_asm_insn ("psh%1", operands
);
2968 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
2970 cc_status
= cc_prev_status
;
2971 switch (REGNO (operands
[0]))
2976 output_asm_insn ("pul%0", operands
);
2983 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
2985 m68hc11_notice_keep_cc (operands
[0]);
2986 output_asm_insn ("tfr\t%1,%0", operands
);
2988 else if (H_REG_P (operands
[0]))
2990 if (SP_REG_P (operands
[0]))
2991 output_asm_insn ("lds\t%1", operands
);
2993 output_asm_insn ("ld%0\t%1", operands
);
2995 else if (H_REG_P (operands
[1]))
2997 if (SP_REG_P (operands
[1]))
2998 output_asm_insn ("sts\t%0", operands
);
3000 output_asm_insn ("st%1\t%0", operands
);
3004 rtx from
= operands
[1];
3005 rtx to
= operands
[0];
3007 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3008 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3009 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3010 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3016 ops
[0] = operands
[2];
3019 m68hc11_gen_movhi (insn
, ops
);
3021 ops
[1] = operands
[2];
3022 m68hc11_gen_movhi (insn
, ops
);
3026 /* !!!! SCz wrong here. */
3027 fatal_insn ("Move insn not handled", insn
);
3032 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3034 output_asm_insn ("clr\t%h0", operands
);
3035 output_asm_insn ("clr\t%b0", operands
);
3039 m68hc11_notice_keep_cc (operands
[0]);
3040 output_asm_insn ("movw\t%1,%0", operands
);
3047 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3049 cc_status
= cc_prev_status
;
3050 switch (REGNO (operands
[0]))
3054 output_asm_insn ("pul%0", operands
);
3057 output_asm_insn ("pula", operands
);
3058 output_asm_insn ("pulb", operands
);
3065 /* Some moves to a hard register are special. Not all of them
3066 are really supported and we have to use a temporary
3067 location to provide them (either the stack of a temp var). */
3068 if (H_REG_P (operands
[0]))
3070 switch (REGNO (operands
[0]))
3073 if (X_REG_P (operands
[1]))
3075 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3077 m68hc11_output_swap (insn
, operands
);
3079 else if (next_insn_test_reg (insn
, operands
[0]))
3081 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3085 m68hc11_notice_keep_cc (operands
[0]);
3086 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3089 else if (Y_REG_P (operands
[1]))
3091 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3093 m68hc11_output_swap (insn
, operands
);
3097 /* %t means *ZTMP scratch register. */
3098 output_asm_insn ("sty\t%t1", operands
);
3099 output_asm_insn ("ldd\t%t1", operands
);
3102 else if (SP_REG_P (operands
[1]))
3107 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3108 output_asm_insn ("xgdx", operands
);
3109 output_asm_insn ("tsx", operands
);
3110 output_asm_insn ("xgdx", operands
);
3112 else if (IS_STACK_POP (operands
[1]))
3114 output_asm_insn ("pula\n\tpulb", operands
);
3116 else if (GET_CODE (operands
[1]) == CONST_INT
3117 && INTVAL (operands
[1]) == 0)
3119 output_asm_insn ("clra\n\tclrb", operands
);
3123 output_asm_insn ("ldd\t%1", operands
);
3128 if (D_REG_P (operands
[1]))
3130 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3132 m68hc11_output_swap (insn
, operands
);
3134 else if (next_insn_test_reg (insn
, operands
[0]))
3136 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3140 m68hc11_notice_keep_cc (operands
[0]);
3141 output_asm_insn ("pshb", operands
);
3142 output_asm_insn ("psha", operands
);
3143 output_asm_insn ("pulx", operands
);
3146 else if (Y_REG_P (operands
[1]))
3148 /* When both D and Y are dead, use the sequence xgdy, xgdx
3149 to move Y into X. The D and Y registers are modified. */
3150 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3151 && dead_register_here (insn
, d_reg
))
3153 output_asm_insn ("xgdy", operands
);
3154 output_asm_insn ("xgdx", operands
);
3159 output_asm_insn ("sty\t%t1", operands
);
3160 output_asm_insn ("ldx\t%t1", operands
);
3163 else if (SP_REG_P (operands
[1]))
3165 /* tsx, tsy preserve the flags */
3166 cc_status
= cc_prev_status
;
3167 output_asm_insn ("tsx", operands
);
3171 output_asm_insn ("ldx\t%1", operands
);
3176 if (D_REG_P (operands
[1]))
3178 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3180 m68hc11_output_swap (insn
, operands
);
3184 output_asm_insn ("std\t%t1", operands
);
3185 output_asm_insn ("ldy\t%t1", operands
);
3188 else if (X_REG_P (operands
[1]))
3190 /* When both D and X are dead, use the sequence xgdx, xgdy
3191 to move X into Y. The D and X registers are modified. */
3192 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3193 && dead_register_here (insn
, d_reg
))
3195 output_asm_insn ("xgdx", operands
);
3196 output_asm_insn ("xgdy", operands
);
3201 output_asm_insn ("stx\t%t1", operands
);
3202 output_asm_insn ("ldy\t%t1", operands
);
3205 else if (SP_REG_P (operands
[1]))
3207 /* tsx, tsy preserve the flags */
3208 cc_status
= cc_prev_status
;
3209 output_asm_insn ("tsy", operands
);
3213 output_asm_insn ("ldy\t%1", operands
);
3217 case HARD_SP_REGNUM
:
3218 if (D_REG_P (operands
[1]))
3220 m68hc11_notice_keep_cc (operands
[0]);
3221 output_asm_insn ("xgdx", operands
);
3222 output_asm_insn ("txs", operands
);
3223 output_asm_insn ("xgdx", operands
);
3225 else if (X_REG_P (operands
[1]))
3227 /* tys, txs preserve the flags */
3228 cc_status
= cc_prev_status
;
3229 output_asm_insn ("txs", operands
);
3231 else if (Y_REG_P (operands
[1]))
3233 /* tys, txs preserve the flags */
3234 cc_status
= cc_prev_status
;
3235 output_asm_insn ("tys", operands
);
3239 /* lds sets the flags but the des does not. */
3241 output_asm_insn ("lds\t%1", operands
);
3242 output_asm_insn ("des", operands
);
3247 fatal_insn ("Invalid register in the move instruction", insn
);
3252 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3253 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3255 output_asm_insn ("sts\t%0", operands
);
3259 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3261 cc_status
= cc_prev_status
;
3262 switch (REGNO (operands
[1]))
3266 output_asm_insn ("psh%1", operands
);
3269 output_asm_insn ("pshb", operands
);
3270 output_asm_insn ("psha", operands
);
3278 /* Operand 1 must be a hard register. */
3279 if (!H_REG_P (operands
[1]))
3281 fatal_insn ("Invalid operand in the instruction", insn
);
3284 reg
= REGNO (operands
[1]);
3288 output_asm_insn ("std\t%0", operands
);
3292 output_asm_insn ("stx\t%0", operands
);
3296 output_asm_insn ("sty\t%0", operands
);
3299 case HARD_SP_REGNUM
:
3303 if (reg_mentioned_p (ix_reg
, operands
[0]))
3305 output_asm_insn ("sty\t%t0", operands
);
3306 output_asm_insn ("tsy", operands
);
3307 output_asm_insn ("sty\t%0", operands
);
3308 output_asm_insn ("ldy\t%t0", operands
);
3312 output_asm_insn ("stx\t%t0", operands
);
3313 output_asm_insn ("tsx", operands
);
3314 output_asm_insn ("stx\t%0", operands
);
3315 output_asm_insn ("ldx\t%t0", operands
);
3321 fatal_insn ("Invalid register in the move instruction", insn
);
3327 m68hc11_gen_movqi (insn
, operands
)
3331 /* Move a register or memory to the same location.
3332 This is possible because such insn can appear
3333 in a non-optimizing mode. */
3334 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3336 cc_status
= cc_prev_status
;
3343 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3345 m68hc11_notice_keep_cc (operands
[0]);
3346 output_asm_insn ("tfr\t%1,%0", operands
);
3348 else if (H_REG_P (operands
[0]))
3350 if (Q_REG_P (operands
[0]))
3351 output_asm_insn ("lda%0\t%b1", operands
);
3352 else if (D_REG_P (operands
[0]))
3353 output_asm_insn ("ldab\t%b1", operands
);
3357 else if (H_REG_P (operands
[1]))
3359 if (Q_REG_P (operands
[1]))
3360 output_asm_insn ("sta%1\t%b0", operands
);
3361 else if (D_REG_P (operands
[1]))
3362 output_asm_insn ("stab\t%b0", operands
);
3368 rtx from
= operands
[1];
3369 rtx to
= operands
[0];
3371 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3372 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3373 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3374 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3380 ops
[0] = operands
[2];
3383 m68hc11_gen_movqi (insn
, ops
);
3385 ops
[1] = operands
[2];
3386 m68hc11_gen_movqi (insn
, ops
);
3390 /* !!!! SCz wrong here. */
3391 fatal_insn ("Move insn not handled", insn
);
3396 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3398 output_asm_insn ("clr\t%b0", operands
);
3402 m68hc11_notice_keep_cc (operands
[0]);
3403 output_asm_insn ("movb\t%b1,%b0", operands
);
3411 if (H_REG_P (operands
[0]))
3413 switch (REGNO (operands
[0]))
3417 if (X_REG_P (operands
[1]))
3419 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3421 m68hc11_output_swap (insn
, operands
);
3425 output_asm_insn ("stx\t%t1", operands
);
3426 output_asm_insn ("ldab\t%T0", operands
);
3429 else if (Y_REG_P (operands
[1]))
3431 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3433 m68hc11_output_swap (insn
, operands
);
3437 output_asm_insn ("sty\t%t1", operands
);
3438 output_asm_insn ("ldab\t%T0", operands
);
3441 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3442 && !DA_REG_P (operands
[1]))
3444 output_asm_insn ("ldab\t%b1", operands
);
3446 else if (DA_REG_P (operands
[1]))
3448 output_asm_insn ("tab", operands
);
3452 cc_status
= cc_prev_status
;
3458 if (X_REG_P (operands
[1]))
3460 output_asm_insn ("stx\t%t1", operands
);
3461 output_asm_insn ("ldaa\t%T0", operands
);
3463 else if (Y_REG_P (operands
[1]))
3465 output_asm_insn ("sty\t%t1", operands
);
3466 output_asm_insn ("ldaa\t%T0", operands
);
3468 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3469 && !DA_REG_P (operands
[1]))
3471 output_asm_insn ("ldaa\t%b1", operands
);
3473 else if (!DA_REG_P (operands
[1]))
3475 output_asm_insn ("tba", operands
);
3479 cc_status
= cc_prev_status
;
3484 if (D_REG_P (operands
[1]))
3486 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3488 m68hc11_output_swap (insn
, operands
);
3492 output_asm_insn ("stab\t%T1", operands
);
3493 output_asm_insn ("ldx\t%t1", operands
);
3497 else if (Y_REG_P (operands
[1]))
3499 output_asm_insn ("sty\t%t0", operands
);
3500 output_asm_insn ("ldx\t%t0", operands
);
3502 else if (GET_CODE (operands
[1]) == CONST_INT
)
3504 output_asm_insn ("ldx\t%1", operands
);
3506 else if (dead_register_here (insn
, d_reg
))
3508 output_asm_insn ("ldab\t%b1", operands
);
3509 output_asm_insn ("xgdx", operands
);
3511 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3513 output_asm_insn ("xgdx", operands
);
3514 output_asm_insn ("ldab\t%b1", operands
);
3515 output_asm_insn ("xgdx", operands
);
3519 output_asm_insn ("pshb", operands
);
3520 output_asm_insn ("ldab\t%b1", operands
);
3521 output_asm_insn ("stab\t%T1", operands
);
3522 output_asm_insn ("ldx\t%t1", operands
);
3523 output_asm_insn ("pulb", operands
);
3529 if (D_REG_P (operands
[1]))
3531 output_asm_insn ("stab\t%T1", operands
);
3532 output_asm_insn ("ldy\t%t1", operands
);
3535 else if (X_REG_P (operands
[1]))
3537 output_asm_insn ("stx\t%t1", operands
);
3538 output_asm_insn ("ldy\t%t1", operands
);
3541 else if (GET_CODE (operands
[1]) == CONST_INT
)
3543 output_asm_insn ("ldy\t%1", operands
);
3545 else if (dead_register_here (insn
, d_reg
))
3547 output_asm_insn ("ldab\t%b1", operands
);
3548 output_asm_insn ("xgdy", operands
);
3550 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3552 output_asm_insn ("xgdy", operands
);
3553 output_asm_insn ("ldab\t%b1", operands
);
3554 output_asm_insn ("xgdy", operands
);
3558 output_asm_insn ("pshb", operands
);
3559 output_asm_insn ("ldab\t%b1", operands
);
3560 output_asm_insn ("stab\t%T1", operands
);
3561 output_asm_insn ("ldy\t%t1", operands
);
3562 output_asm_insn ("pulb", operands
);
3568 fatal_insn ("Invalid register in the instruction", insn
);
3572 else if (H_REG_P (operands
[1]))
3574 switch (REGNO (operands
[1]))
3578 output_asm_insn ("stab\t%b0", operands
);
3582 output_asm_insn ("staa\t%b0", operands
);
3586 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3590 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3594 fatal_insn ("Invalid register in the move instruction", insn
);
3601 fatal_insn ("Operand 1 must be a hard register", insn
);
3605 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3606 The source and destination must be D or A and the shift must
3609 m68hc11_gen_rotate (code
, insn
, operands
)
3616 if (GET_CODE (operands
[2]) != CONST_INT
3617 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3618 fatal_insn ("Invalid rotate insn", insn
);
3620 val
= INTVAL (operands
[2]);
3621 if (code
== ROTATERT
)
3622 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3624 if (GET_MODE (operands
[0]) != QImode
)
3627 /* Rotate by 8-bits if the shift is within [5..11]. */
3628 if (val
>= 5 && val
<= 11)
3630 output_asm_insn ("psha", operands
);
3631 output_asm_insn ("tba", operands
);
3632 output_asm_insn ("pulb", operands
);
3636 /* If the shift is big, invert the rotation. */
3644 /* Set the carry to bit-15, but don't change D yet. */
3645 if (GET_MODE (operands
[0]) != QImode
)
3647 output_asm_insn ("asra", operands
);
3648 output_asm_insn ("rola", operands
);
3653 /* Rotate B first to move the carry to bit-0. */
3654 if (D_REG_P (operands
[0]))
3655 output_asm_insn ("rolb", operands
);
3657 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3658 output_asm_insn ("rola", operands
);
3663 /* Set the carry to bit-8 of D. */
3664 if (val
!= 0 && GET_MODE (operands
[0]) != QImode
)
3666 output_asm_insn ("tap", operands
);
3671 /* Rotate B first to move the carry to bit-7. */
3672 if (D_REG_P (operands
[0]))
3673 output_asm_insn ("rorb", operands
);
3675 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3676 output_asm_insn ("rora", operands
);
3683 /* Store in cc_status the expressions that the condition codes will
3684 describe after execution of an instruction whose pattern is EXP.
3685 Do not alter them if the instruction would not alter the cc's. */
3688 m68hc11_notice_update_cc (exp
, insn
)
3690 rtx insn ATTRIBUTE_UNUSED
;
3692 /* recognize SET insn's. */
3693 if (GET_CODE (exp
) == SET
)
3695 /* Jumps do not alter the cc's. */
3696 if (SET_DEST (exp
) == pc_rtx
)
3699 /* NOTE: most instructions don't affect the carry bit, but the
3700 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3701 the conditions.h header. */
3703 /* Function calls clobber the cc's. */
3704 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
3709 /* Tests and compares set the cc's in predictable ways. */
3710 else if (SET_DEST (exp
) == cc0_rtx
)
3712 cc_status
.flags
= 0;
3713 cc_status
.value1
= XEXP (exp
, 0);
3714 cc_status
.value2
= XEXP (exp
, 1);
3718 /* All other instructions affect the condition codes. */
3719 cc_status
.flags
= 0;
3720 cc_status
.value1
= XEXP (exp
, 0);
3721 cc_status
.value2
= XEXP (exp
, 1);
3726 /* Default action if we haven't recognized something
3727 and returned earlier. */
3731 if (cc_status
.value2
!= 0)
3732 switch (GET_CODE (cc_status
.value2
))
3734 /* These logical operations can generate several insns.
3735 The flags are setup according to what is generated. */
3741 /* The (not ...) generates several 'com' instructions for
3742 non QImode. We have to invalidate the flags. */
3744 if (GET_MODE (cc_status
.value2
) != QImode
)
3756 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3757 cc_status
.flags
|= CC_NO_OVERFLOW
;
3760 /* The asl sets the overflow bit in such a way that this
3761 makes the flags unusable for a next compare insn. */
3765 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
3766 cc_status
.flags
|= CC_NO_OVERFLOW
;
3769 /* A load/store instruction does not affect the carry. */
3774 cc_status
.flags
|= CC_NO_OVERFLOW
;
3780 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
3782 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
3783 cc_status
.value2
= 0;
3786 /* The current instruction does not affect the flags but changes
3787 the register 'reg'. See if the previous flags can be kept for the
3788 next instruction to avoid a comparison. */
3790 m68hc11_notice_keep_cc (reg
)
3794 || cc_prev_status
.value1
== 0
3795 || rtx_equal_p (reg
, cc_prev_status
.value1
)
3796 || (cc_prev_status
.value2
3797 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
3800 cc_status
= cc_prev_status
;
3805 /* Machine Specific Reorg. */
3807 /* Z register replacement:
3809 GCC treats the Z register as an index base address register like
3810 X or Y. In general, it uses it during reload to compute the address
3811 of some operand. This helps the reload pass to avoid to fall into the
3812 register spill failure.
3814 The Z register is in the A_REGS class. In the machine description,
3815 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3817 It can appear everywhere an X or Y register can appear, except for
3818 some templates in the clobber section (when a clobber of X or Y is asked).
3819 For a given instruction, the template must ensure that no more than
3820 2 'A' registers are used. Otherwise, the register replacement is not
3823 To replace the Z register, the algorithm is not terrific:
3824 1. Insns that do not use the Z register are not changed
3825 2. When a Z register is used, we scan forward the insns to see
3826 a potential register to use: either X or Y and sometimes D.
3827 We stop when a call, a label or a branch is seen, or when we
3828 detect that both X and Y are used (probably at different times, but it does
3830 3. The register that will be used for the replacement of Z is saved
3831 in a .page0 register or on the stack. If the first instruction that
3832 used Z, uses Z as an input, the value is loaded from another .page0
3833 register. The replacement register is pushed on the stack in the
3834 rare cases where a compare insn uses Z and we couldn't find if X/Y
3836 4. The Z register is replaced in all instructions until we reach
3837 the end of the Z-block, as detected by step 2.
3838 5. If we detect that Z is still alive, its value is saved.
3839 If the replacement register is alive, its old value is loaded.
3841 The Z register can be disabled with -ffixed-z.
3851 int must_restore_reg
;
3862 int save_before_last
;
3863 int z_loaded_with_sp
;
3866 static rtx z_reg_qi
;
3868 static int m68hc11_check_z_replacement
PARAMS ((rtx
, struct replace_info
*));
3869 static void m68hc11_find_z_replacement
PARAMS ((rtx
, struct replace_info
*));
3870 static void m68hc11_z_replacement
PARAMS ((rtx
));
3871 static void m68hc11_reassign_regs
PARAMS ((rtx
));
3873 int z_replacement_completed
= 0;
3875 /* Analyze the insn to find out which replacement register to use and
3876 the boundaries of the replacement.
3877 Returns 0 if we reached the last insn to be replaced, 1 if we can
3878 continue replacement in next insns. */
3881 m68hc11_check_z_replacement (insn
, info
)
3883 struct replace_info
*info
;
3885 int this_insn_uses_ix
;
3886 int this_insn_uses_iy
;
3887 int this_insn_uses_z
;
3888 int this_insn_uses_z_in_dst
;
3889 int this_insn_uses_d
;
3893 /* A call is said to clobber the Z register, we don't need
3894 to save the value of Z. We also don't need to restore
3895 the replacement register (unless it is used by the call). */
3896 if (GET_CODE (insn
) == CALL_INSN
)
3898 body
= PATTERN (insn
);
3900 info
->can_use_d
= 0;
3902 /* If the call is an indirect call with Z, we have to use the
3903 Y register because X can be used as an input (D+X).
3904 We also must not save Z nor restore Y. */
3905 if (reg_mentioned_p (z_reg
, body
))
3907 insn
= NEXT_INSN (insn
);
3910 info
->found_call
= 1;
3911 info
->must_restore_reg
= 0;
3912 info
->last
= NEXT_INSN (insn
);
3914 info
->need_save_z
= 0;
3917 if (GET_CODE (insn
) == CODE_LABEL
3918 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
3921 if (GET_CODE (insn
) == JUMP_INSN
)
3923 if (reg_mentioned_p (z_reg
, insn
) == 0)
3926 info
->can_use_d
= 0;
3927 info
->must_save_reg
= 0;
3928 info
->must_restore_reg
= 0;
3929 info
->need_save_z
= 0;
3930 info
->last
= NEXT_INSN (insn
);
3933 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
3938 /* Z register dies here. */
3939 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
3941 body
= PATTERN (insn
);
3942 if (GET_CODE (body
) == SET
)
3944 rtx src
= XEXP (body
, 1);
3945 rtx dst
= XEXP (body
, 0);
3947 /* Condition code is set here. We have to restore the X/Y and
3948 save into Z before any test/compare insn because once we save/restore
3949 we can change the condition codes. When the compare insn uses Z and
3950 we can't use X/Y, the comparison is made with the *ZREG soft register
3951 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3954 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
3955 || (GET_CODE (src
) == COMPARE
&&
3956 (rtx_equal_p (XEXP (src
, 0), z_reg
)
3957 || rtx_equal_p (XEXP (src
, 1), z_reg
))))
3959 if (insn
== info
->first
)
3961 info
->must_load_z
= 0;
3962 info
->must_save_reg
= 0;
3963 info
->must_restore_reg
= 0;
3964 info
->need_save_z
= 0;
3965 info
->found_call
= 1;
3966 info
->regno
= SOFT_Z_REGNUM
;
3971 if (reg_mentioned_p (z_reg
, src
) == 0)
3973 info
->can_use_d
= 0;
3977 if (insn
!= info
->first
)
3980 /* Compare insn which uses Z. We have to save/restore the X/Y
3981 register without modifying the condition codes. For this
3982 we have to use a push/pop insn. */
3983 info
->must_push_reg
= 1;
3987 /* Z reg is set to something new. We don't need to load it. */
3990 if (!reg_mentioned_p (z_reg
, src
))
3992 /* Z reg is used before being set. Treat this as
3993 a new sequence of Z register replacement. */
3994 if (insn
!= info
->first
)
3998 info
->must_load_z
= 0;
4000 info
->z_set_count
++;
4001 info
->z_value
= src
;
4003 info
->z_loaded_with_sp
= 1;
4005 else if (reg_mentioned_p (z_reg
, dst
))
4006 info
->can_use_d
= 0;
4008 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4009 | reg_mentioned_p (d_reg
, dst
);
4010 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4011 | reg_mentioned_p (ix_reg
, dst
);
4012 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4013 | reg_mentioned_p (iy_reg
, dst
);
4014 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4016 /* If z is used as an address operand (like (MEM (reg z))),
4017 we can't replace it with d. */
4018 if (this_insn_uses_z
&& !Z_REG_P (src
)
4019 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4020 && Z_REG_P (XEXP (src
, 0))
4021 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4022 && insn
== info
->first
4023 && dead_register_here (insn
, d_reg
)))
4024 info
->can_use_d
= 0;
4026 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4027 if (TARGET_M6812
&& !z_dies_here
4028 && ((this_insn_uses_z
&& side_effects_p (src
))
4029 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4031 info
->need_save_z
= 1;
4032 info
->z_set_count
++;
4034 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4036 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4038 fatal_insn ("Registers IX, IY and Z used in the same INSN", insn
);
4041 if (this_insn_uses_d
)
4042 info
->can_use_d
= 0;
4044 /* IX and IY are used at the same time, we have to restore
4045 the value of the scratch register before this insn. */
4046 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4051 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4052 info
->can_use_d
= 0;
4054 if (info
->x_used
== 0 && this_insn_uses_ix
)
4058 /* We have a (set (REG:HI X) (REG:HI Z)).
4059 Since we use Z as the replacement register, this insn
4060 is no longer necessary. We turn it into a note. We must
4061 not reload the old value of X. */
4062 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4066 info
->need_save_z
= 0;
4069 info
->must_save_reg
= 0;
4070 info
->must_restore_reg
= 0;
4071 info
->found_call
= 1;
4072 info
->can_use_d
= 0;
4073 PUT_CODE (insn
, NOTE
);
4074 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4075 NOTE_SOURCE_FILE (insn
) = 0;
4076 info
->last
= NEXT_INSN (insn
);
4081 && (rtx_equal_p (src
, z_reg
)
4082 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4086 info
->need_save_z
= 0;
4089 info
->last
= NEXT_INSN (insn
);
4090 info
->must_save_reg
= 0;
4091 info
->must_restore_reg
= 0;
4093 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4094 && !reg_mentioned_p (ix_reg
, src
))
4099 info
->need_save_z
= 0;
4103 info
->save_before_last
= 1;
4105 info
->must_restore_reg
= 0;
4106 info
->last
= NEXT_INSN (insn
);
4108 else if (info
->can_use_d
)
4110 info
->last
= NEXT_INSN (insn
);
4116 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4117 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4119 info
->need_save_z
= 0;
4121 info
->last
= NEXT_INSN (insn
);
4122 info
->regno
= HARD_X_REGNUM
;
4123 info
->must_save_reg
= 0;
4124 info
->must_restore_reg
= 0;
4127 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4129 info
->regno
= HARD_X_REGNUM
;
4130 info
->must_restore_reg
= 0;
4131 info
->must_save_reg
= 0;
4135 if (info
->y_used
== 0 && this_insn_uses_iy
)
4139 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4143 info
->need_save_z
= 0;
4146 info
->must_save_reg
= 0;
4147 info
->must_restore_reg
= 0;
4148 info
->found_call
= 1;
4149 info
->can_use_d
= 0;
4150 PUT_CODE (insn
, NOTE
);
4151 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4152 NOTE_SOURCE_FILE (insn
) = 0;
4153 info
->last
= NEXT_INSN (insn
);
4158 && (rtx_equal_p (src
, z_reg
)
4159 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4164 info
->need_save_z
= 0;
4166 info
->last
= NEXT_INSN (insn
);
4167 info
->must_save_reg
= 0;
4168 info
->must_restore_reg
= 0;
4170 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4171 && !reg_mentioned_p (iy_reg
, src
))
4176 info
->need_save_z
= 0;
4180 info
->save_before_last
= 1;
4182 info
->must_restore_reg
= 0;
4183 info
->last
= NEXT_INSN (insn
);
4185 else if (info
->can_use_d
)
4187 info
->last
= NEXT_INSN (insn
);
4194 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4195 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4197 info
->need_save_z
= 0;
4199 info
->last
= NEXT_INSN (insn
);
4200 info
->regno
= HARD_Y_REGNUM
;
4201 info
->must_save_reg
= 0;
4202 info
->must_restore_reg
= 0;
4205 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4207 info
->regno
= HARD_Y_REGNUM
;
4208 info
->must_restore_reg
= 0;
4209 info
->must_save_reg
= 0;
4215 info
->need_save_z
= 0;
4217 if (info
->last
== 0)
4218 info
->last
= NEXT_INSN (insn
);
4221 return info
->last
!= NULL_RTX
? 0 : 1;
4223 if (GET_CODE (body
) == PARALLEL
)
4226 char ix_clobber
= 0;
4227 char iy_clobber
= 0;
4229 this_insn_uses_iy
= 0;
4230 this_insn_uses_ix
= 0;
4231 this_insn_uses_z
= 0;
4233 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4236 int uses_ix
, uses_iy
, uses_z
;
4238 x
= XVECEXP (body
, 0, i
);
4240 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4241 info
->can_use_d
= 0;
4243 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4244 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4245 uses_z
= reg_mentioned_p (z_reg
, x
);
4246 if (GET_CODE (x
) == CLOBBER
)
4248 ix_clobber
|= uses_ix
;
4249 iy_clobber
|= uses_iy
;
4250 z_clobber
|= uses_z
;
4254 this_insn_uses_ix
|= uses_ix
;
4255 this_insn_uses_iy
|= uses_iy
;
4256 this_insn_uses_z
|= uses_z
;
4258 if (uses_z
&& GET_CODE (x
) == SET
)
4260 rtx dst
= XEXP (x
, 0);
4263 info
->z_set_count
++;
4265 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4266 info
->need_save_z
= 1;
4269 info
->need_save_z
= 0;
4273 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4274 this_insn_uses_ix
, this_insn_uses_iy
,
4275 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4278 if (this_insn_uses_z
)
4279 info
->can_use_d
= 0;
4281 if (z_clobber
&& info
->first
!= insn
)
4283 info
->need_save_z
= 0;
4287 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4289 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4291 info
->must_load_z
= 0;
4293 if (dead_register_here (insn
, d_reg
))
4295 info
->regno
= HARD_D_REGNUM
;
4296 info
->must_save_reg
= 0;
4297 info
->must_restore_reg
= 0;
4299 else if (dead_register_here (insn
, ix_reg
))
4301 info
->regno
= HARD_X_REGNUM
;
4302 info
->must_save_reg
= 0;
4303 info
->must_restore_reg
= 0;
4305 else if (dead_register_here (insn
, iy_reg
))
4307 info
->regno
= HARD_Y_REGNUM
;
4308 info
->must_save_reg
= 0;
4309 info
->must_restore_reg
= 0;
4311 if (info
->regno
>= 0)
4313 info
->last
= NEXT_INSN (insn
);
4316 if (this_insn_uses_ix
== 0)
4318 info
->regno
= HARD_X_REGNUM
;
4319 info
->must_save_reg
= 1;
4320 info
->must_restore_reg
= 1;
4322 else if (this_insn_uses_iy
== 0)
4324 info
->regno
= HARD_Y_REGNUM
;
4325 info
->must_save_reg
= 1;
4326 info
->must_restore_reg
= 1;
4330 info
->regno
= HARD_D_REGNUM
;
4331 info
->must_save_reg
= 1;
4332 info
->must_restore_reg
= 1;
4334 info
->last
= NEXT_INSN (insn
);
4338 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4339 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4341 if (this_insn_uses_z
)
4343 if (info
->y_used
== 0 && iy_clobber
)
4345 info
->regno
= HARD_Y_REGNUM
;
4346 info
->must_save_reg
= 0;
4347 info
->must_restore_reg
= 0;
4349 info
->last
= NEXT_INSN (insn
);
4350 info
->save_before_last
= 1;
4354 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4356 if (this_insn_uses_z
)
4358 fatal_insn ("Cannot do z-register replacement", insn
);
4362 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4369 if (iy_clobber
|| z_clobber
)
4371 info
->last
= NEXT_INSN (insn
);
4372 info
->save_before_last
= 1;
4377 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4384 if (ix_clobber
|| z_clobber
)
4386 info
->last
= NEXT_INSN (insn
);
4387 info
->save_before_last
= 1;
4394 info
->need_save_z
= 0;
4398 if (GET_CODE (body
) == CLOBBER
)
4401 /* IX and IY are used at the same time, we have to restore
4402 the value of the scratch register before this insn. */
4403 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4407 if (info
->x_used
== 0 && this_insn_uses_ix
)
4415 if (info
->y_used
== 0 && this_insn_uses_iy
)
4429 m68hc11_find_z_replacement (insn
, info
)
4431 struct replace_info
*info
;
4435 info
->replace_reg
= NULL_RTX
;
4436 info
->must_load_z
= 1;
4437 info
->need_save_z
= 1;
4438 info
->must_save_reg
= 1;
4439 info
->must_restore_reg
= 1;
4443 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4444 info
->found_call
= 0;
4448 info
->z_set_count
= 0;
4449 info
->z_value
= NULL_RTX
;
4450 info
->must_push_reg
= 0;
4451 info
->save_before_last
= 0;
4452 info
->z_loaded_with_sp
= 0;
4454 /* Scan the insn forward to find an address register that is not used.
4456 - the flow of the program changes,
4457 - when we detect that both X and Y are necessary,
4458 - when the Z register dies,
4459 - when the condition codes are set. */
4461 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4463 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4467 /* May be we can use Y or X if they contain the same value as Z.
4468 This happens very often after the reload. */
4469 if (info
->z_set_count
== 1)
4471 rtx p
= info
->first
;
4476 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4478 else if (info
->y_used
)
4480 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4482 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4485 info
->regno
= HARD_Y_REGNUM
;
4487 info
->regno
= HARD_X_REGNUM
;
4488 info
->must_load_z
= 0;
4489 info
->must_save_reg
= 0;
4490 info
->must_restore_reg
= 0;
4491 info
->found_call
= 1;
4494 if (info
->z_set_count
== 0)
4495 info
->need_save_z
= 0;
4498 info
->need_save_z
= 0;
4500 if (info
->last
== 0)
4503 if (info
->regno
>= 0)
4506 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4508 else if (info
->can_use_d
)
4510 reg
= HARD_D_REGNUM
;
4511 info
->replace_reg
= d_reg
;
4513 else if (info
->x_used
)
4515 reg
= HARD_Y_REGNUM
;
4516 info
->replace_reg
= iy_reg
;
4520 reg
= HARD_X_REGNUM
;
4521 info
->replace_reg
= ix_reg
;
4525 if (info
->must_save_reg
&& info
->must_restore_reg
)
4527 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4529 info
->must_save_reg
= 0;
4530 info
->must_restore_reg
= 0;
4535 /* The insn uses the Z register. Find a replacement register for it
4536 (either X or Y) and replace it in the insn and the next ones until
4537 the flow changes or the replacement register is used. Instructions
4538 are emited before and after the Z-block to preserve the value of
4539 Z and of the replacement register. */
4542 m68hc11_z_replacement (insn
)
4547 struct replace_info info
;
4549 /* Find trivial case where we only need to replace z with the
4550 equivalent soft register. */
4551 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4553 rtx body
= PATTERN (insn
);
4554 rtx src
= XEXP (body
, 1);
4555 rtx dst
= XEXP (body
, 0);
4557 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4559 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4562 else if (Z_REG_P (src
)
4563 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4565 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4568 else if (D_REG_P (dst
)
4569 && m68hc11_arith_operator (src
, GET_MODE (src
))
4570 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4572 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4575 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4576 && INTVAL (src
) == 0)
4578 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4579 /* Force it to be re-recognized. */
4580 INSN_CODE (insn
) = -1;
4585 m68hc11_find_z_replacement (insn
, &info
);
4587 replace_reg
= info
.replace_reg
;
4588 replace_reg_qi
= NULL_RTX
;
4590 /* Save the X register in a .page0 location. */
4591 if (info
.must_save_reg
&& !info
.must_push_reg
)
4595 if (info
.must_push_reg
&& 0)
4596 dst
= gen_rtx (MEM
, HImode
,
4597 gen_rtx (PRE_DEC
, HImode
,
4598 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4600 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4602 emit_insn_before (gen_movhi (dst
,
4603 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4605 if (info
.must_load_z
&& !info
.must_push_reg
)
4607 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4608 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4613 /* Replace all occurence of Z by replace_reg.
4614 Stop when the last instruction to replace is reached.
4615 Also stop when we detect a change in the flow (but it's not
4616 necessary; just safeguard). */
4618 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4622 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4625 if (GET_CODE (insn
) != INSN
4626 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4629 body
= PATTERN (insn
);
4630 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4631 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4633 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4635 printf ("Reg mentioned here...:\n");
4640 /* Stack pointer was decremented by 2 due to the push.
4641 Correct that by adding 2 to the destination. */
4642 if (info
.must_push_reg
4643 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4647 src
= SET_SRC (body
);
4648 dst
= SET_DEST (body
);
4649 if (SP_REG_P (src
) && Z_REG_P (dst
))
4651 emit_insn_after (gen_addhi3 (dst
,
4654 VOIDmode
, 2)), insn
);
4658 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4659 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4661 INSN_CODE (insn
) = -1;
4662 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4663 fatal_insn ("Cannot do z-register replacement", insn
);
4666 /* Likewise for (REG:QI Z). */
4667 if (reg_mentioned_p (z_reg
, insn
))
4669 if (replace_reg_qi
== NULL_RTX
)
4670 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4671 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4674 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4678 /* Save Z before restoring the old value. */
4679 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
4681 rtx save_pos_insn
= insn
;
4683 /* If Z is clobber by the last insn, we have to save its value
4684 before the last instruction. */
4685 if (info
.save_before_last
)
4686 save_pos_insn
= PREV_INSN (save_pos_insn
);
4688 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
4689 gen_rtx (REG
, HImode
, info
.regno
)),
4693 if (info
.must_push_reg
&& info
.last
)
4697 body
= PATTERN (info
.last
);
4698 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
4700 gen_rtx (USE
, VOIDmode
,
4702 gen_rtx (USE
, VOIDmode
,
4703 gen_rtx (REG
, HImode
,
4705 PATTERN (info
.last
) = new_body
;
4707 /* Force recognition on insn since we changed it. */
4708 INSN_CODE (insn
) = -1;
4710 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
4712 fatal_insn ("Invalid Z register replacement for insn", insn
);
4714 insn
= NEXT_INSN (info
.last
);
4717 /* Restore replacement register unless it was died. */
4718 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
4722 if (info
.must_push_reg
&& 0)
4723 dst
= gen_rtx (MEM
, HImode
,
4724 gen_rtx (POST_INC
, HImode
,
4725 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4727 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4729 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4736 /* Scan all the insn and re-affects some registers
4737 - The Z register (if it was used), is affected to X or Y depending
4738 on the instruction. */
4741 m68hc11_reassign_regs (first
)
4746 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
4747 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
4748 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
4749 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
4751 /* Scan all insns to replace Z by X or Y preserving the old value
4752 of X/Y and restoring it afterward. */
4754 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
4758 if (GET_CODE (insn
) == CODE_LABEL
4759 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
4762 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
4765 body
= PATTERN (insn
);
4766 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
4769 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
4770 || GET_CODE (body
) == ASM_OPERANDS
4771 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
4774 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4775 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4778 /* If Z appears in this insn, replace it in the current insn
4779 and the next ones until the flow changes or we have to
4780 restore back the replacement register. */
4782 if (reg_mentioned_p (z_reg
, body
))
4784 m68hc11_z_replacement (insn
);
4789 printf ("Insn not handled by Z replacement:\n");
4798 m68hc11_reorg (first
)
4804 z_replacement_completed
= 0;
4805 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
4807 /* Some RTX are shared at this point. This breaks the Z register
4808 replacement, unshare everything. */
4809 unshare_all_rtl_again (first
);
4811 /* Force a split of all splitable insn. This is necessary for the
4812 Z register replacement mechanism because we end up with basic insns. */
4813 split_all_insns (0);
4816 z_replacement_completed
= 1;
4817 m68hc11_reassign_regs (first
);
4819 /* After some splitting, there are some oportunities for CSE pass.
4820 This happens quite often when 32-bit or above patterns are split. */
4821 if (optimize
> 0 && split_done
)
4822 reload_cse_regs (first
);
4824 /* Re-create the REG_DEAD notes. These notes are used in the machine
4825 description to use the best assembly directives. */
4828 /* Before recomputing the REG_DEAD notes, remove all of them.
4829 This is necessary because the reload_cse_regs() pass can
4830 have replaced some (MEM) with a register. In that case,
4831 the REG_DEAD that could exist for that register may become
4833 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
4839 pnote
= ®_NOTES (insn
);
4842 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
4843 *pnote
= XEXP (*pnote
, 1);
4845 pnote
= &XEXP (*pnote
, 1);
4850 find_basic_blocks (first
, max_reg_num (), 0);
4851 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
4854 z_replacement_completed
= 2;
4856 /* If optimizing, then go ahead and split insns that must be
4857 split after Z register replacement. This gives more opportunities
4858 for peephole (in particular for consecutives xgdx/xgdy). */
4860 split_all_insns (0);
4862 /* Once insns are split after the z_replacement_completed == 2,
4863 we must not re-run the life_analysis. The xgdx/xgdy patterns
4864 are not recognized and the life_analysis pass removes some
4865 insns because it thinks some (SETs) are noops or made to dead
4866 stores (which is false due to the swap).
4868 Do a simple pass to eliminate the noop set that the final
4869 split could generate (because it was easier for split definition). */
4873 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
4877 if (INSN_DELETED_P (insn
))
4879 if (GET_RTX_CLASS (GET_CODE (insn
)) != 'i')
4882 /* Remove the (set (R) (R)) insns generated by some splits. */
4883 body
= PATTERN (insn
);
4884 if (GET_CODE (body
) == SET
4885 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
4887 PUT_CODE (insn
, NOTE
);
4888 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4889 NOTE_SOURCE_FILE (insn
) = 0;
4897 /* Cost functions. */
4899 /* Cost of moving memory. */
4901 m68hc11_memory_move_cost (mode
, class, in
)
4902 enum machine_mode mode
;
4903 enum reg_class
class;
4904 int in ATTRIBUTE_UNUSED
;
4906 if (class <= H_REGS
)
4908 if (GET_MODE_SIZE (mode
) <= 2)
4909 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
4911 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
4915 if (GET_MODE_SIZE (mode
) <= 2)
4916 return COSTS_N_INSNS (2);
4918 return COSTS_N_INSNS (4);
4923 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4924 Reload does not check the constraint of set insns when the two registers
4925 have a move cost of 2. Setting a higher cost will force reload to check
4928 m68hc11_register_move_cost (from
, to
)
4929 enum reg_class from
;
4932 if (from
>= S_REGS
&& to
>= S_REGS
)
4934 return COSTS_N_INSNS (3);
4936 if (from
<= S_REGS
&& to
<= S_REGS
)
4938 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
4940 return COSTS_N_INSNS (2);
4944 /* Provide the costs of an addressing mode that contains ADDR.
4945 If ADDR is not a valid address, its cost is irrelevant. */
4948 m68hc11_address_cost (addr
)
4953 switch (GET_CODE (addr
))
4956 /* Make the cost of hard registers and specially SP, FP small. */
4957 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
4974 register rtx plus0
= XEXP (addr
, 0);
4975 register rtx plus1
= XEXP (addr
, 1);
4977 if (GET_CODE (plus0
) != REG
)
4980 switch (GET_CODE (plus1
))
4983 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
4984 || INTVAL (plus1
) < m68hc11_min_offset
)
4986 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
4990 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5012 if (SP_REG_P (XEXP (addr
, 0)))
5021 printf ("Address cost: %d for :", cost
);
5030 m68hc11_shift_cost (mode
, x
, shift
)
5031 enum machine_mode mode
;
5037 total
= rtx_cost (x
, SET
);
5039 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5040 else if (mode
== HImode
)
5041 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5042 else if (shift
== 8 || shift
== 16 || shift
== 32)
5043 total
+= m68hc11_cost
->shiftHI_const
[8];
5044 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5046 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5049 /* For SI and others, the cost is higher. */
5050 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5051 total
*= GET_MODE_SIZE (mode
) / 2;
5053 /* When optimizing for size, make shift more costly so that
5054 multiplications are prefered. */
5055 if (optimize_size
&& (shift
% 8) != 0)
5062 m68hc11_rtx_costs (x
, code
, outer_code
)
5065 enum rtx_code outer_code ATTRIBUTE_UNUSED
;
5067 enum machine_mode mode
= GET_MODE (x
);
5078 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5080 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5083 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5084 total
+= m68hc11_cost
->shift_var
;
5090 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5091 total
+= m68hc11_cost
->logical
;
5093 /* Logical instructions are byte instructions only. */
5094 total
*= GET_MODE_SIZE (mode
);
5099 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5100 total
+= m68hc11_cost
->add
;
5101 if (GET_MODE_SIZE (mode
) > 2)
5103 total
*= GET_MODE_SIZE (mode
) / 2;
5110 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5114 total
+= m68hc11_cost
->divQI
;
5118 total
+= m68hc11_cost
->divHI
;
5123 total
+= m68hc11_cost
->divSI
;
5129 /* mul instruction produces 16-bit result. */
5130 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5131 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5132 return m68hc11_cost
->multQI
5133 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5134 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5136 /* emul instruction produces 32-bit result for 68HC12. */
5137 if (TARGET_M6812
&& mode
== SImode
5138 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5139 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5140 return m68hc11_cost
->multHI
5141 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5142 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5144 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5148 total
+= m68hc11_cost
->multQI
;
5152 total
+= m68hc11_cost
->multHI
;
5157 total
+= m68hc11_cost
->multSI
;
5164 extra_cost
= COSTS_N_INSNS (2);
5171 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5174 return total
+ COSTS_N_INSNS (1);
5178 return total
+ COSTS_N_INSNS (2);
5182 return total
+ COSTS_N_INSNS (4);
5184 return total
+ COSTS_N_INSNS (8);
5187 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5188 return COSTS_N_INSNS (1);
5190 return COSTS_N_INSNS (1);
5193 return COSTS_N_INSNS (4);
5198 /* print_options - called at the start of the code generation for a
5201 extern char *asm_file_name
;
5204 #include <sys/types.h>
5213 extern int save_argc
;
5214 extern char **save_argv
;
5216 fprintf (out
, ";;; Command:\t");
5217 for (i
= 0; i
< save_argc
; i
++)
5219 fprintf (out
, "%s", save_argv
[i
]);
5220 if (i
+ 1 < save_argc
)
5223 fprintf (out
, "\n");
5225 a_time
= ctime (&c_time
);
5226 fprintf (out
, ";;; Compiled:\t%s", a_time
);
5229 #define __VERSION__ "[unknown]"
5231 fprintf (out
, ";;; (META)compiled by GNU C version %s.\n", __VERSION__
);
5233 fprintf (out
, ";;; (META)compiled by CC.\n");
5238 m68hc11_asm_file_start (out
, main_file
)
5242 fprintf (out
, ";;;-----------------------------------------\n");
5243 fprintf (out
, ";;; Start MC68HC11 gcc assembly output\n");
5244 fprintf (out
, ";;; gcc compiler %s\n", version_string
);
5245 print_options (out
);
5246 fprintf (out
, ";;;-----------------------------------------\n");
5247 output_file_directive (out
, main_file
);
5252 m68hc11_add_gc_roots ()
5254 ggc_add_rtx_root (&m68hc11_soft_tmp_reg
, 1);
5255 ggc_add_rtx_root (&ix_reg
, 1);
5256 ggc_add_rtx_root (&iy_reg
, 1);
5257 ggc_add_rtx_root (&d_reg
, 1);
5258 ggc_add_rtx_root (&da_reg
, 1);
5259 ggc_add_rtx_root (&z_reg
, 1);
5260 ggc_add_rtx_root (&z_reg_qi
, 1);
5261 ggc_add_rtx_root (&stack_push_word
, 1);
5262 ggc_add_rtx_root (&stack_pop_word
, 1);