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
40 #if GCC_VERSION > 2095
44 #include "hard-reg-set.h"
46 #include "insn-config.h"
47 #include "conditions.h"
49 #include "insn-attr.h"
54 #include "basic-block.h"
55 #if GCC_VERSION > 2095
59 #include "m68hc11-protos.h"
62 #if GCC_VERSION == 2095
63 extern char *version_string;
66 static void print_options PARAMS ((FILE *));
67 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
68 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
69 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
70 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
72 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
73 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
74 static int must_parenthesize PARAMS ((rtx));
76 static int m68hc11_auto_inc_p PARAMS ((rtx));
78 void create_regs_rtx PARAMS ((void));
80 static void asm_print_register PARAMS ((FILE *, int));
82 rtx m68hc11_soft_tmp_reg;
84 /* Must be set to 1 to produce debug messages. */
87 extern FILE *asm_out_file;
95 static int regs_inited = 0;
98 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
99 int current_function_interrupt;
101 /* Set to 1 by expand_prologue() when the function is a trap handler. */
102 int current_function_trap;
104 /* Min offset that is valid for the indirect addressing mode. */
105 HOST_WIDE_INT m68hc11_min_offset = 0;
107 /* Max offset that is valid for the indirect addressing mode. */
108 HOST_WIDE_INT m68hc11_max_offset = 256;
110 /* The class value for base registers. */
111 enum reg_class m68hc11_base_reg_class = A_REGS;
113 /* The class value for index registers. This is NO_REGS for 68HC11. */
114 enum reg_class m68hc11_index_reg_class = NO_REGS;
116 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
118 /* Tables that tell whether a given hard register is valid for
119 a base or an index register. It is filled at init time depending
120 on the target processor. */
121 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
122 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
124 /* A correction offset which is applied to the stack pointer.
125 This is 1 for 68HC11 and 0 for 68HC12. */
126 int m68hc11_sp_correction;
128 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
129 rtx m68hc11_compare_op0;
130 rtx m68hc11_compare_op1;
133 /* Machine specific options */
135 const char *m68hc11_regparm_string;
136 const char *m68hc11_reg_alloc_order;
137 const char *m68hc11_soft_reg_count;
139 static void m68hc11_add_gc_roots PARAMS ((void));
141 static int nb_soft_regs;
143 #if GCC_VERSION > 2095
144 /* Flag defined in c-decl.c
146 Nonzero means don't recognize the non-ANSI builtin functions.
149 It is set by 'm68hc11_override_options' to ensure that bcmp() and
150 bzero() are not defined. Their prototype are wrong and they
151 conflict with newlib definition. Don't define as external to
152 avoid a link problem for f77. */
153 int flag_no_nonansi_builtin;
157 m68hc11_override_options ()
159 m68hc11_add_gc_roots ();
161 #if GCC_VERSION > 2095
162 flag_no_nonansi_builtin = 1;
165 memset (m68hc11_reg_valid_for_index, 0,
166 sizeof (m68hc11_reg_valid_for_index));
167 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
169 /* Configure for a 68hc11 processor. */
172 /* If gcc was built for a 68hc12, invalidate that because
173 a -m68hc11 option was specified on the command line. */
174 if (TARGET_DEFAULT != MASK_M6811)
175 target_flags &= ~TARGET_DEFAULT;
177 m68hc11_min_offset = 0;
178 m68hc11_max_offset = 256;
179 m68hc11_index_reg_class = NO_REGS;
180 m68hc11_base_reg_class = A_REGS;
181 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
182 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
183 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
184 m68hc11_sp_correction = 1;
185 m68hc11_tmp_regs_class = D_REGS;
186 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
187 m68hc11_soft_reg_count = "4";
190 /* Configure for a 68hc12 processor. */
193 m68hc11_min_offset = 0;
194 m68hc11_max_offset = 65536;
195 m68hc11_index_reg_class = D_REGS;
196 m68hc11_base_reg_class = A_OR_SP_REGS;
197 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
198 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
199 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
200 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
201 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
202 m68hc11_sp_correction = 0;
203 m68hc11_tmp_regs_class = TMP_REGS;
204 target_flags &= ~MASK_M6811;
205 if (m68hc11_soft_reg_count == 0)
206 m68hc11_soft_reg_count = "2";
213 m68hc11_conditional_register_usage ()
216 int cnt = atoi (m68hc11_soft_reg_count);
220 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
221 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
224 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
227 call_used_regs[i] = 1;
232 /* Reload and register operations. */
234 static const char *reg_class_names[] = REG_CLASS_NAMES;
240 /* regs_inited = 1; */
241 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
242 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
243 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
244 da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
245 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
247 stack_push_word = gen_rtx (MEM, HImode,
248 gen_rtx (PRE_DEC, HImode,
249 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
250 stack_pop_word = gen_rtx (MEM, HImode,
251 gen_rtx (POST_INC, HImode,
252 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
256 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
257 - 8 bit values are stored anywhere (except the SP register).
258 - 16 bit values can be stored in any register whose mode is 16
259 - 32 bit values can be stored in D, X registers or in a soft register
260 (except the last one because we need 2 soft registers)
261 - Values whose size is > 32 bit are not stored in real hard
262 registers. They may be stored in soft registers if there are
265 hard_regno_mode_ok (regno, mode)
267 enum machine_mode mode;
269 switch (GET_MODE_SIZE (mode))
272 return S_REGNO_P (regno) && nb_soft_regs >= 4;
275 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
278 return G_REGNO_P (regno);
281 /* We have to accept a QImode in X or Y registers. Otherwise, the
282 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
283 in the insns. Reload fails if the insn rejects the register class 'a'
284 as well as if it accepts it. Patterns that failed were
285 zero_extend_qihi2 and iorqi3. */
287 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
295 limit_reload_class (mode, class)
296 enum machine_mode mode;
297 enum reg_class class;
301 if (class == m68hc11_base_reg_class || class == SP_REGS
302 || class == Y_REGS || class == X_REGS
303 || class == X_OR_SP_REGS || class == Y_OR_S_REGS
304 || class == A_OR_SP_REGS)
309 printf ("Forcing to A_REGS\n");
312 return m68hc11_base_reg_class;
318 preferred_reload_class (operand, class)
320 enum reg_class class;
322 enum machine_mode mode;
324 mode = GET_MODE (operand);
328 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
331 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
332 return m68hc11_base_reg_class;
334 if (class >= S_REGS && (GET_CODE (operand) == MEM
335 || GET_CODE (operand) == CONST_INT))
337 /* S_REGS class must not be used. The movhi template does not
338 work to move a memory to a soft register.
339 Restrict to a hard reg. */
344 case D_OR_A_OR_S_REGS:
350 case D_OR_SP_OR_S_REGS:
351 class = D_OR_SP_REGS;
353 case D_OR_Y_OR_S_REGS:
356 case D_OR_X_OR_S_REGS:
372 else if (class == Y_REGS && GET_CODE (operand) == MEM)
376 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
380 else if (class >= S_REGS && S_REG_P (operand))
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 >= S_REGS)
418 printf ("Class = %s for: ", reg_class_names[class]);
426 printf (" => class=%s\n", reg_class_names[class]);
434 /* Return 1 if the operand is a valid indexed addressing mode.
435 For 68hc11: n,r with n in [0..255] and r in A_REGS class
436 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
438 register_indirect_p (operand, mode, strict)
440 enum machine_mode mode;
445 switch (GET_CODE (operand))
451 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
452 return register_indirect_p (XEXP (operand, 0), mode, strict);
456 base = XEXP (operand, 0);
457 if (GET_CODE (base) == MEM)
460 offset = XEXP (operand, 1);
461 if (GET_CODE (offset) == MEM)
464 if (GET_CODE (base) == REG)
466 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
472 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
474 if (GET_CODE (offset) == REG)
476 if (!VALID_CONSTANT_OFFSET_P (base, mode))
482 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
487 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
494 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
495 a 68HC12 1-byte index addressing mode. */
497 m68hc11_small_indexed_indirect_p (operand, mode)
499 enum machine_mode mode;
503 if (GET_CODE (operand) != MEM)
506 operand = XEXP (operand, 0);
507 if (CONSTANT_ADDRESS_P (operand))
510 if (PUSH_POP_ADDRESS_P (operand))
513 if (!register_indirect_p (operand, mode,
514 (reload_completed | reload_in_progress)))
517 if (TARGET_M6812 && GET_CODE (operand) == PLUS
518 && (reload_completed | reload_in_progress))
520 base = XEXP (operand, 0);
521 offset = XEXP (operand, 1);
522 if (GET_CODE (base) == CONST_INT)
525 switch (GET_MODE_SIZE (mode))
528 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
533 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
538 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
547 m68hc11_register_indirect_p (operand, mode)
549 enum machine_mode mode;
551 if (GET_CODE (operand) != MEM)
554 operand = XEXP (operand, 0);
555 return register_indirect_p (operand, mode,
556 (reload_completed | reload_in_progress));
560 go_if_legitimate_address_internal (operand, mode, strict)
562 enum machine_mode mode;
565 if (CONSTANT_ADDRESS_P (operand))
567 /* Reject the global variables if they are too wide. This forces
568 a load of their address in a register and generates smaller code. */
569 if (GET_MODE_SIZE (mode) == 8)
574 if (register_indirect_p (operand, mode, strict))
578 if (PUSH_POP_ADDRESS_P (operand))
582 if (symbolic_memory_operand (operand, mode))
590 m68hc11_go_if_legitimate_address (operand, mode, strict)
592 enum machine_mode mode;
599 printf ("Checking: ");
604 result = go_if_legitimate_address_internal (operand, mode, strict);
608 printf (" -> %s\n", result == 0 ? "NO" : "YES");
615 printf ("go_if_legitimate%s, ret 0: %d:",
616 (strict ? "_strict" : ""), mode);
625 m68hc11_legitimize_address (operand, old_operand, mode)
626 rtx *operand ATTRIBUTE_UNUSED;
627 rtx old_operand ATTRIBUTE_UNUSED;
628 enum machine_mode mode ATTRIBUTE_UNUSED;
635 m68hc11_reload_operands (operands)
638 enum machine_mode mode;
640 if (regs_inited == 0)
643 mode = GET_MODE (operands[1]);
645 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
646 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
648 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
649 rtx base = XEXP (XEXP (operands[1], 0), 0);
651 if (GET_CODE (base) != REG)
658 /* If the offset is out of range, we have to compute the address
659 with a separate add instruction. We try to do with with an 8-bit
660 add on the A register. This is possible only if the lowest part
661 of the offset (ie, big_offset % 256) is a valid constant offset
662 with respect to the mode. If it's not, we have to generate a
663 16-bit add on the D register. From:
665 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
669 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
670 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
671 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
672 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
674 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
675 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
678 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
681 rtx reg = operands[0];
683 int val = INTVAL (big_offset);
686 /* We use the 'operands[0]' as a scratch register to compute the
687 address. Make sure 'base' is in that register. */
688 if (!rtx_equal_p (base, operands[0]))
690 emit_move_insn (reg, base);
700 vh = (val >> 8) & 0x0FF;
704 /* Create the lowest part offset that still remains to be added.
705 If it's not a valid offset, do a 16-bit add. */
706 offset = gen_rtx (CONST_INT, VOIDmode, vl);
707 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
709 emit_insn (gen_rtx (SET, VOIDmode, reg,
710 gen_rtx (PLUS, HImode, reg, big_offset)));
715 emit_insn (gen_rtx (SET, VOIDmode, reg,
716 gen_rtx (PLUS, HImode, reg,
718 VOIDmode, vh << 8))));
720 emit_move_insn (operands[0],
721 gen_rtx (MEM, GET_MODE (operands[1]),
722 gen_rtx (PLUS, Pmode, reg, offset)));
727 /* Use the normal gen_movhi pattern. */
732 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
735 enum machine_mode dmode;
736 enum machine_mode smode;
746 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
750 ret = emit_library_call_value (libcall, NULL_RTX, 1, dmode, 1,
752 equiv = gen_rtx (code, dmode, operands[1]);
756 ret = emit_library_call_value (libcall, operands[0], 1, dmode, 2,
757 operands[1], smode, operands[2],
759 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
766 insns = get_insns ();
768 emit_libcall_block (insns, operands[0], ret, equiv);
771 /* Returns true if X is a PRE/POST increment decrement
772 (same as auto_inc_p() in rtlanal.c but do not take into
773 account the stack). */
775 m68hc11_auto_inc_p (x)
778 return GET_CODE (x) == PRE_DEC
779 || GET_CODE (x) == POST_INC
780 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
784 /* Predicates for machine description. */
787 memory_reload_operand (operand, mode)
789 enum machine_mode mode ATTRIBUTE_UNUSED;
791 return GET_CODE (operand) == MEM
792 && GET_CODE (XEXP (operand, 0)) == PLUS
793 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
794 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
795 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
796 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
800 tst_operand (operand, mode)
802 enum machine_mode mode;
804 if (GET_CODE (operand) == MEM)
806 rtx addr = XEXP (operand, 0);
807 if (m68hc11_auto_inc_p (addr))
810 return nonimmediate_operand (operand, mode);
814 cmp_operand (operand, mode)
816 enum machine_mode mode;
818 if (GET_CODE (operand) == MEM)
820 rtx addr = XEXP (operand, 0);
821 if (m68hc11_auto_inc_p (addr))
824 return general_operand (operand, mode);
828 non_push_operand (operand, mode)
830 enum machine_mode mode;
832 if (general_operand (operand, mode) == 0)
835 if (push_operand (operand, mode) == 1)
841 reg_or_some_mem_operand (operand, mode)
843 enum machine_mode mode;
845 if (GET_CODE (operand) == MEM)
847 rtx op = XEXP (operand, 0);
849 if (symbolic_memory_operand (op, mode))
852 if (IS_STACK_PUSH (operand))
855 if (m68hc11_register_indirect_p (operand, mode))
861 return register_operand (operand, mode);
865 stack_register_operand (operand, mode)
867 enum machine_mode mode ATTRIBUTE_UNUSED;
869 return SP_REG_P (operand);
873 d_register_operand (operand, mode)
875 enum machine_mode mode ATTRIBUTE_UNUSED;
877 if (GET_CODE (operand) == SUBREG)
878 operand = XEXP (operand, 0);
880 return GET_CODE (operand) == REG
881 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
882 || REGNO (operand) == HARD_D_REGNUM);
886 hard_addr_reg_operand (operand, mode)
888 enum machine_mode mode ATTRIBUTE_UNUSED;
890 if (GET_CODE (operand) == SUBREG)
891 operand = XEXP (operand, 0);
893 return GET_CODE (operand) == REG
894 && (REGNO (operand) == HARD_X_REGNUM
895 || REGNO (operand) == HARD_Y_REGNUM
896 || REGNO (operand) == HARD_Z_REGNUM);
900 hard_reg_operand (operand, mode)
902 enum machine_mode mode ATTRIBUTE_UNUSED;
904 if (GET_CODE (operand) == SUBREG)
905 operand = XEXP (operand, 0);
907 return GET_CODE (operand) == REG
908 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
909 || H_REGNO_P (REGNO (operand)));
913 memory_indexed_operand (operand, mode)
915 enum machine_mode mode ATTRIBUTE_UNUSED;
917 if (GET_CODE (operand) != MEM)
920 operand = XEXP (operand, 0);
921 if (GET_CODE (operand) == PLUS)
923 if (GET_CODE (XEXP (operand, 0)) == REG)
924 operand = XEXP (operand, 0);
925 else if (GET_CODE (XEXP (operand, 1)) == REG)
926 operand = XEXP (operand, 1);
928 return GET_CODE (operand) == REG
929 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
930 || A_REGNO_P (REGNO (operand)));
934 push_pop_operand_p (operand)
937 if (GET_CODE (operand) != MEM)
941 operand = XEXP (operand, 0);
942 return PUSH_POP_ADDRESS_P (operand);
945 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
946 reference and a constant. */
949 symbolic_memory_operand (op, mode)
951 enum machine_mode mode;
953 switch (GET_CODE (op))
960 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
961 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
962 && GET_CODE (XEXP (op, 1)) == CONST_INT);
964 /* ??? This clause seems to be irrelevant. */
966 return GET_MODE (op) == mode;
969 return symbolic_memory_operand (XEXP (op, 0), mode)
970 && symbolic_memory_operand (XEXP (op, 1), mode);
978 m68hc11_logical_operator (op, mode)
980 enum machine_mode mode ATTRIBUTE_UNUSED;
982 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
986 m68hc11_arith_operator (op, mode)
988 enum machine_mode mode ATTRIBUTE_UNUSED;
990 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
991 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
992 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
993 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
994 || GET_CODE (op) == ROTATERT;
998 m68hc11_non_shift_operator (op, mode)
1000 enum machine_mode mode ATTRIBUTE_UNUSED;
1002 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1003 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1008 m68hc11_unary_operator (op, mode)
1010 enum machine_mode mode ATTRIBUTE_UNUSED;
1012 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1013 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1020 m68hc11_block_profiler (out, blockno)
1021 FILE *out ATTRIBUTE_UNUSED;
1022 int blockno ATTRIBUTE_UNUSED;
1028 m68hc11_function_block_profiler (out, block_or_label)
1029 FILE *out ATTRIBUTE_UNUSED;
1030 int block_or_label ATTRIBUTE_UNUSED;
1035 /* Declaration of types. */
1037 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1038 with arguments ARGS is a valid machine specific attribute for DECL.
1039 The attributes in ATTRIBUTES have previously been assigned to DECL. */
1042 m68hc11_valid_decl_attribute_p (decl, attributes, identifier, args)
1043 tree decl ATTRIBUTE_UNUSED;
1044 tree attributes ATTRIBUTE_UNUSED;
1045 tree identifier ATTRIBUTE_UNUSED;
1046 tree args ATTRIBUTE_UNUSED;
1051 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1052 with arguments ARGS is a valid machine specific attribute for TYPE.
1053 The attributes in ATTRIBUTES have previously been assigned to TYPE. */
1056 m68hc11_valid_type_attribute_p (type, attributes, identifier, args)
1058 tree attributes ATTRIBUTE_UNUSED;
1062 if (TREE_CODE (type) != FUNCTION_TYPE
1063 && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL)
1066 if (TREE_CODE (type) == FUNCTION_TYPE)
1068 if (is_attribute_p ("interrupt", identifier))
1069 return (args == NULL_TREE);
1070 if (is_attribute_p ("trap", identifier))
1071 return (args == NULL_TREE);
1077 /* If defined, a C expression whose value is zero if the attributes on
1078 TYPE1 and TYPE2 are incompatible, one if they are compatible, and
1079 two if they are nearly compatible (which causes a warning to be
1083 m68hc11_comp_type_attributes (type1, type2)
1084 tree type1 ATTRIBUTE_UNUSED;
1085 tree type2 ATTRIBUTE_UNUSED;
1090 /* If defined, a C statement that assigns default attributes to newly
1094 m68hc11_set_default_type_attributes (type)
1095 tree type ATTRIBUTE_UNUSED;
1099 /* Define this macro if references to a symbol must be treated
1100 differently depending on something about the variable or function
1101 named by the symbol (such as what section it is in).
1103 For the 68HC11, we want to recognize trap handlers so that we
1104 handle calls to traps in a special manner (by issuing the trap).
1105 This information is stored in SYMBOL_REF_FLAG. */
1107 m68hc11_encode_section_info (decl)
1114 if (TREE_CODE (decl) != FUNCTION_DECL)
1117 rtl = DECL_RTL (decl);
1119 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1120 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1121 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
1125 /* Argument support functions. */
1127 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1128 Arrays are passed by references and other types by value.
1130 SCz: I tried to pass DImode by reference but it seems that this
1131 does not work very well. */
1133 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1134 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1135 enum machine_mode mode ATTRIBUTE_UNUSED;
1137 int named ATTRIBUTE_UNUSED;
1139 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1140 /* Consider complex values as aggregates, so care for TCmode. */
1141 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1142 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1146 /* Define the offset between two registers, one to be eliminated, and the
1147 other its replacement, at the start of a routine. */
1149 m68hc11_initial_elimination_offset (from, to)
1158 /* For a trap handler, we must take into account the registers which
1159 are pushed on the stack during the trap (except the PC). */
1160 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1161 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1162 if (trap_handler && from == ARG_POINTER_REGNUM)
1167 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1169 /* 2 is for the saved frame.
1170 1 is for the 'sts' correction when creating the frame. */
1171 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1174 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1179 /* Push any 2 byte pseudo hard registers that we need to save. */
1180 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1182 if (regs_ever_live[regno] && !call_used_regs[regno])
1188 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1190 return get_frame_size () + size;
1193 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1195 return size - m68hc11_sp_correction;
1200 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1201 for a call to a function whose data type is FNTYPE.
1202 For a library call, FNTYPE is 0. */
1205 m68hc11_init_cumulative_args (cum, fntype, libname)
1206 CUMULATIVE_ARGS *cum;
1212 z_replacement_completed = 0;
1216 /* For a library call, we must find out the type of the return value.
1217 When the return value is bigger than 4 bytes, it is returned in
1218 memory. In that case, the first argument of the library call is a
1219 pointer to the memory location. Because the first argument is passed in
1220 register D, we have to identify this, so that the first function
1221 parameter is not passed in D either. */
1227 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1230 /* If the library ends in 'di' or in 'df', we assume it's
1231 returning some DImode or some DFmode which are 64-bit wide. */
1232 name = XSTR (libname, 0);
1233 len = strlen (name);
1235 && ((name[len - 2] == 'd'
1236 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1237 || (name[len - 3] == 'd'
1238 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1240 /* We are in. Mark the first parameter register as already used. */
1247 ret_type = TREE_TYPE (fntype);
1249 if (ret_type && aggregate_value_p (ret_type))
1256 /* Update the data in CUM to advance over an argument
1257 of mode MODE and data type TYPE.
1258 (TYPE is null for libcalls where that information may not be available.) */
1261 m68hc11_function_arg_advance (cum, mode, type, named)
1262 CUMULATIVE_ARGS *cum;
1263 enum machine_mode mode;
1265 int named ATTRIBUTE_UNUSED;
1267 if (mode != BLKmode)
1269 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1272 cum->words = GET_MODE_SIZE (mode);
1276 cum->words += GET_MODE_SIZE (mode);
1277 if (cum->words <= HARD_REG_SIZE)
1283 cum->words += int_size_in_bytes (type);
1288 /* Define where to put the arguments to a function.
1289 Value is zero to push the argument on the stack,
1290 or a hard register in which to store the argument.
1292 MODE is the argument's machine mode.
1293 TYPE is the data type of the argument (as a tree).
1294 This is null for libcalls where that information may
1296 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1297 the preceding args and about the function being called.
1298 NAMED is nonzero if this argument is a named parameter
1299 (otherwise it is an extra parameter matching an ellipsis). */
1302 m68hc11_function_arg (cum, mode, type, named)
1303 const CUMULATIVE_ARGS *cum;
1304 enum machine_mode mode;
1305 tree type ATTRIBUTE_UNUSED;
1306 int named ATTRIBUTE_UNUSED;
1308 if (cum->words != 0)
1313 if (mode != BLKmode)
1315 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1316 return gen_rtx (REG, mode, HARD_X_REGNUM);
1318 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1322 return gen_rtx (REG, mode, HARD_D_REGNUM);
1327 #if GCC_VERSION > 2095
1329 /* The "standard" implementation of va_start: just assign `nextarg' to
1332 m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
1333 int stdarg_p ATTRIBUTE_UNUSED;
1339 /* SCz: the default implementation in builtins.c adjust the
1340 nextarg using UNITS_PER_WORD. This works only with -mshort
1341 and fails when integers are 32-bit. Here is the correct way. */
1343 nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
1345 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1346 make_tree (ptr_type_node, nextarg));
1347 TREE_SIDE_EFFECTS (t) = 1;
1349 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1353 m68hc11_va_arg (valist, type)
1358 HOST_WIDE_INT align;
1359 HOST_WIDE_INT rounded_size;
1363 /* Compute the rounded size of the type. */
1364 align = PARM_BOUNDARY / BITS_PER_UNIT;
1365 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1369 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
1371 if (pad_direction == downward)
1373 /* Small args are padded downward. */
1376 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1377 if (rounded_size > align)
1380 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1381 build_int_2 (rounded_size - adj, 0));
1384 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1385 addr = copy_to_reg (addr);
1387 /* Compute new value for AP. */
1388 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1389 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1390 build_int_2 (rounded_size, 0)));
1391 TREE_SIDE_EFFECTS (t) = 1;
1392 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1398 /* If defined, a C expression which determines whether, and in which direction,
1399 to pad out an argument with extra space. The value should be of type
1400 `enum direction': either `upward' to pad above the argument,
1401 `downward' to pad below, or `none' to inhibit padding.
1403 Structures are stored left shifted in their argument slot. */
1405 m68hc11_function_arg_padding (mode, type)
1406 enum machine_mode mode;
1409 if (type != 0 && AGGREGATE_TYPE_P (type))
1412 /* This is the default definition. */
1413 return (!BYTES_BIG_ENDIAN
1416 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1417 && int_size_in_bytes (type) <
1418 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1419 PARM_BOUNDARY) ? downward : upward));
1423 /* Function prologue and epilogue. */
1425 /* Emit a move after the reload pass has completed. This is used to
1426 emit the prologue and epilogue. */
1428 emit_move_after_reload (to, from, scratch)
1429 rtx to, from, scratch;
1433 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1435 insn = emit_move_insn (to, from);
1439 emit_move_insn (scratch, from);
1440 insn = emit_move_insn (to, scratch);
1443 /* Put a REG_INC note to tell the flow analysis that the instruction
1445 if (IS_STACK_PUSH (to))
1447 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1448 XEXP (XEXP (to, 0), 0),
1451 else if (IS_STACK_POP (from))
1453 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1454 XEXP (XEXP (from, 0), 0),
1460 m68hc11_total_frame_size ()
1465 size = get_frame_size ();
1466 if (current_function_interrupt)
1468 size += 3 * HARD_REG_SIZE;
1470 if (frame_pointer_needed)
1471 size += HARD_REG_SIZE;
1473 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1474 if (regs_ever_live[regno] && !call_used_regs[regno])
1475 size += HARD_REG_SIZE;
1481 m68hc11_function_epilogue (out, size)
1482 FILE *out ATTRIBUTE_UNUSED;
1483 int size ATTRIBUTE_UNUSED;
1485 /* We catch the function epilogue generation to have a chance
1486 to clear the z_replacement_completed flag. */
1487 z_replacement_completed = 0;
1498 if (reload_completed != 1)
1501 size = get_frame_size ();
1505 /* Generate specific prologue for interrupt handlers. */
1506 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1507 current_function_interrupt = lookup_attribute ("interrupt",
1508 func_attr) != NULL_TREE;
1509 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1511 /* Get the scratch register to build the frame and push registers.
1512 If the first argument is a 32-bit quantity, the D+X registers
1513 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1514 For 68HC12, this scratch register is not used. */
1515 if (current_function_args_info.nregs == 2)
1520 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1521 Other soft registers in page0 need not to be saved because they
1522 will be restored by C functions. For a trap handler, we don't
1523 need to preserve these registers because this is a synchronous call. */
1524 if (current_function_interrupt)
1526 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1527 emit_move_after_reload (stack_push_word,
1528 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1529 emit_move_after_reload (stack_push_word,
1530 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1534 /* Save current stack frame. */
1535 if (frame_pointer_needed)
1536 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1538 /* Allocate local variables. */
1539 if (TARGET_M6812 && size >= 2)
1541 emit_insn (gen_addhi3 (stack_pointer_rtx,
1542 stack_pointer_rtx, GEN_INT (-size)));
1548 insn = gen_rtx_PARALLEL
1551 gen_rtx_SET (VOIDmode,
1553 gen_rtx_PLUS (HImode,
1556 gen_rtx_CLOBBER (VOIDmode, scratch)));
1563 /* Allocate by pushing scratch values. */
1564 for (i = 2; i <= size; i += 2)
1565 emit_move_after_reload (stack_push_word, ix_reg, 0);
1568 emit_insn (gen_addhi3 (stack_pointer_rtx,
1569 stack_pointer_rtx, GEN_INT (-1)));
1572 /* Create the frame pointer. */
1573 if (frame_pointer_needed)
1574 emit_move_after_reload (hard_frame_pointer_rtx,
1575 stack_pointer_rtx, scratch);
1577 /* Push any 2 byte pseudo hard registers that we need to save. */
1578 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1580 if (regs_ever_live[regno] && !call_used_regs[regno])
1582 emit_move_after_reload (stack_push_word,
1583 gen_rtx (REG, HImode, regno), scratch);
1596 if (reload_completed != 1)
1599 size = get_frame_size ();
1601 /* If we are returning a value in two registers, we have to preserve the
1602 X register and use the Y register to restore the stack and the saved
1603 registers. Otherwise, use X because it's faster (and smaller). */
1604 if (current_function_return_rtx == 0)
1606 else if (GET_CODE (current_function_return_rtx) == MEM)
1607 return_size = HARD_REG_SIZE;
1609 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1611 if (return_size > HARD_REG_SIZE)
1616 /* Pop any 2 byte pseudo hard registers that we saved. */
1617 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1619 if (regs_ever_live[regno] && !call_used_regs[regno])
1621 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1622 stack_pop_word, scratch);
1626 /* de-allocate auto variables */
1627 if (TARGET_M6812 && size >= 2)
1629 emit_insn (gen_addhi3 (stack_pointer_rtx,
1630 stack_pointer_rtx, GEN_INT (size)));
1636 insn = gen_rtx_PARALLEL
1639 gen_rtx_SET (VOIDmode,
1641 gen_rtx_PLUS (HImode,
1644 gen_rtx_CLOBBER (VOIDmode, scratch)));
1651 for (i = 2; i <= size; i += 2)
1652 emit_move_after_reload (scratch, stack_pop_word, scratch);
1654 emit_insn (gen_addhi3 (stack_pointer_rtx,
1655 stack_pointer_rtx, GEN_INT (1)));
1658 /* Restore previous frame pointer. */
1659 if (frame_pointer_needed)
1660 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1662 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1663 if (current_function_interrupt)
1665 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1666 stack_pop_word, scratch);
1667 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1668 stack_pop_word, scratch);
1669 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1672 /* If the trap handler returns some value, copy the value
1673 in D, X onto the stack so that the rti will pop the return value
1675 else if (current_function_trap && return_size != 0)
1677 rtx addr_reg = stack_pointer_rtx;
1681 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1684 emit_move_after_reload (gen_rtx (MEM, HImode,
1685 gen_rtx (PLUS, HImode, addr_reg,
1686 GEN_INT (1))), d_reg, 0);
1687 if (return_size > HARD_REG_SIZE)
1688 emit_move_after_reload (gen_rtx (MEM, HImode,
1689 gen_rtx (PLUS, HImode, addr_reg,
1690 GEN_INT (3))), ix_reg, 0);
1693 emit_jump_insn (gen_return ());
1697 /* Low and High part extraction for 68HC11. These routines are
1698 similar to gen_lowpart and gen_highpart but they have been
1699 fixed to work for constants and 68HC11 specific registers. */
1702 m68hc11_gen_lowpart (mode, x)
1703 enum machine_mode mode;
1706 /* We assume that the low part of an auto-inc mode is the same with
1707 the mode changed and that the caller split the larger mode in the
1709 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1711 return gen_rtx (MEM, mode, XEXP (x, 0));
1714 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1715 floating-point constant. A CONST_DOUBLE is used whenever the
1716 constant requires more than one word in order to be adequately
1718 if (GET_CODE (x) == CONST_DOUBLE)
1722 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1726 if (GET_MODE (x) == SFmode)
1728 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1729 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1735 split_double (x, &first, &second);
1739 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1741 return gen_rtx (CONST_INT, VOIDmode, l[0] & 0x0ffff);
1745 l[0] = CONST_DOUBLE_LOW (x);
1748 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1749 else if (mode == HImode && GET_MODE (x) == SFmode)
1750 return gen_rtx (CONST_INT, VOIDmode, l[0] & 0x0FFFF);
1755 if (mode == QImode && D_REG_P (x))
1756 return gen_rtx (REG, mode, HARD_B_REGNUM);
1758 /* gen_lowpart crashes when it is called with a SUBREG. */
1759 if (GET_CODE (x) == SUBREG && SUBREG_WORD (x) != 0)
1762 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + 2);
1763 else if (mode == HImode)
1764 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_WORD (x) + 1);
1768 x = gen_lowpart (mode, x);
1770 /* Return a different rtx to avoid to share it in several insns
1771 (when used by a split pattern). Sharing addresses within
1772 a MEM breaks the Z register replacement (and reloading). */
1773 if (GET_CODE (x) == MEM)
1779 m68hc11_gen_highpart (mode, x)
1780 enum machine_mode mode;
1783 /* We assume that the high part of an auto-inc mode is the same with
1784 the mode changed and that the caller split the larger mode in the
1786 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1788 return gen_rtx (MEM, mode, XEXP (x, 0));
1791 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1792 floating-point constant. A CONST_DOUBLE is used whenever the
1793 constant requires more than one word in order to be adequately
1795 if (GET_CODE (x) == CONST_DOUBLE)
1799 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1803 if (GET_MODE (x) == SFmode)
1805 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1806 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1812 split_double (x, &first, &second);
1816 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1818 return gen_rtx (CONST_INT, VOIDmode, (l[1] >> 16) & 0x0ffff);
1822 l[1] = CONST_DOUBLE_HIGH (x);
1826 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1827 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1828 return gen_rtx (CONST_INT, VOIDmode, (l[0] >> 16) & 0x0FFFF);
1832 if (GET_CODE (x) == CONST_INT)
1834 HOST_WIDE_INT val = INTVAL (x);
1838 return gen_rtx (CONST_INT, VOIDmode, val >> 8);
1840 else if (mode == HImode)
1842 return gen_rtx (CONST_INT, VOIDmode, val >> 16);
1845 if (mode == QImode && D_REG_P (x))
1846 return gen_rtx (REG, mode, HARD_A_REGNUM);
1848 /* There is no way in GCC to represent the upper part of a word register.
1849 To obtain the 8-bit upper part of a soft register, we change the
1850 reg into a mem rtx. This is possible because they are physically
1851 located in memory. There is no offset because we are big-endian. */
1852 if (mode == QImode && S_REG_P (x))
1856 /* For 68HC12, avoid the '*' for direct addressing mode. */
1857 pos = TARGET_M6812 ? 1 : 0;
1858 return gen_rtx (MEM, QImode,
1859 gen_rtx (SYMBOL_REF, Pmode,
1860 ®_names[REGNO (x)][pos]));
1863 /* gen_highpart crashes when it is called with a SUBREG. */
1864 if (GET_CODE (x) == SUBREG && SUBREG_WORD (x) != 0)
1866 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1868 x = gen_highpart (mode, x);
1870 /* Return a different rtx to avoid to share it in several insns
1871 (when used by a split pattern). Sharing addresses within
1872 a MEM breaks the Z register replacement (and reloading). */
1873 if (GET_CODE (x) == MEM)
1879 /* Obscure register manipulation. */
1881 /* Finds backward in the instructions to see if register 'reg' is
1882 dead. This is used when generating code to see if we can use 'reg'
1883 as a scratch register. This allows us to choose a better generation
1884 of code when we know that some register dies or can be clobbered. */
1887 dead_register_here (x, reg)
1895 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
1899 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1900 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
1906 if (GET_CODE (body) == CALL_INSN)
1908 if (GET_CODE (body) == JUMP_INSN)
1911 if (GET_CODE (body) == SET)
1913 rtx dst = XEXP (body, 0);
1915 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
1917 if (x_reg && rtx_equal_p (dst, x_reg))
1920 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
1923 else if (reg_mentioned_p (reg, p)
1924 || (x_reg && reg_mentioned_p (x_reg, p)))
1928 /* Scan forward to see if the register is set in some insns and never
1930 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
1934 if (GET_CODE (p) == CODE_LABEL
1935 || GET_CODE (p) == JUMP_INSN
1936 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
1939 if (GET_CODE (p) != INSN)
1943 if (GET_CODE (body) == SET)
1945 rtx src = XEXP (body, 1);
1946 rtx dst = XEXP (body, 0);
1948 if (GET_CODE (dst) == REG
1949 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
1953 /* Register is used (may be in source or in dest). */
1954 if (reg_mentioned_p (reg, p)
1955 || (x_reg != 0 && GET_MODE (p) == SImode
1956 && reg_mentioned_p (x_reg, p)))
1959 return p == 0 ? 1 : 0;
1963 /* Code generation operations called from machine description file. */
1965 /* Print the name of register 'regno' in the assembly file. */
1967 asm_print_register (file, regno)
1971 const char *name = reg_names[regno];
1973 if (TARGET_M6812 && name[0] == '*')
1976 asm_fprintf (file, "%s", name);
1979 /* A C compound statement to output to stdio stream STREAM the
1980 assembler syntax for an instruction operand X. X is an RTL
1983 CODE is a value that can be used to specify one of several ways
1984 of printing the operand. It is used when identical operands
1985 must be printed differently depending on the context. CODE
1986 comes from the `%' specification that was used to request
1987 printing of the operand. If the specification was just `%DIGIT'
1988 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
1989 is the ASCII code for LTR.
1991 If X is a register, this macro should print the register's name.
1992 The names can be found in an array `reg_names' whose type is
1993 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
1995 When the machine description has a specification `%PUNCT' (a `%'
1996 followed by a punctuation character), this macro is called with
1997 a null pointer for X and the punctuation character for CODE.
1999 The M68HC11 specific codes are:
2001 'b' for the low part of the operand.
2002 'h' for the high part of the operand
2003 The 'b' or 'h' modifiers have no effect if the operand has
2004 the QImode and is not a S_REG_P (soft register). If the
2005 operand is a hard register, these two modifiers have no effect.
2006 't' generate the temporary scratch register. The operand is
2008 'T' generate the low-part temporary scratch register. The operand is
2012 print_operand (file, op, letter)
2019 asm_print_register (file, SOFT_TMP_REGNUM);
2022 else if (letter == 'T')
2024 asm_print_register (file, SOFT_TMP_REGNUM);
2025 asm_fprintf (file, "+1");
2028 else if (letter == '#')
2030 asm_fprintf (file, "%0I");
2033 if (GET_CODE (op) == REG)
2035 if (letter == 'b' && S_REG_P (op))
2037 asm_print_register (file, REGNO (op));
2038 asm_fprintf (file, "+1");
2042 asm_print_register (file, REGNO (op));
2047 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2050 asm_fprintf (file, "%0I%%lo(");
2052 asm_fprintf (file, "%0I%%hi(");
2054 output_addr_const (file, op);
2055 asm_fprintf (file, ")");
2059 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2060 are specified. If we already have a QImode, there is nothing to do. */
2061 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2065 op = m68hc11_gen_lowpart (QImode, op);
2067 else if (letter == 'h')
2069 op = m68hc11_gen_highpart (QImode, op);
2073 if (GET_CODE (op) == MEM)
2075 rtx base = XEXP (op, 0);
2076 switch (GET_CODE (base))
2081 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2082 asm_print_register (file, REGNO (XEXP (base, 0)));
2091 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2092 asm_print_register (file, REGNO (XEXP (base, 0)));
2093 asm_fprintf (file, "-");
2102 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2103 asm_print_register (file, REGNO (XEXP (base, 0)));
2104 asm_fprintf (file, "+");
2113 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2114 asm_print_register (file, REGNO (XEXP (base, 0)));
2121 output_address (base);
2125 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2128 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2129 ASM_OUTPUT_FLOAT_OPERAND (letter, file, r);
2131 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode)
2134 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2135 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r);
2137 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2140 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2141 ASM_OUTPUT_DOUBLE_OPERAND (file, r);
2146 asm_fprintf (file, "%0I");
2147 output_addr_const (file, op);
2151 /* Returns true if the operand 'op' must be printed with parenthesis
2152 arround it. This must be done only if there is a symbol whose name
2153 is a processor register. */
2155 must_parenthesize (op)
2160 switch (GET_CODE (op))
2163 name = XSTR (op, 0);
2164 /* Avoid a conflict between symbol name and a possible
2166 return (strcasecmp (name, "a") == 0
2167 || strcasecmp (name, "b") == 0
2168 || strcasecmp (name, "d") == 0
2169 || strcasecmp (name, "x") == 0
2170 || strcasecmp (name, "y") == 0
2171 || strcasecmp (name, "pc") == 0
2172 || strcasecmp (name, "sp") == 0
2173 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2177 return must_parenthesize (XEXP (op, 0))
2178 || must_parenthesize (XEXP (op, 1));
2184 return must_parenthesize (XEXP (op, 0));
2195 /* A C compound statement to output to stdio stream STREAM the
2196 assembler syntax for an instruction operand that is a memory
2197 reference whose address is ADDR. ADDR is an RTL expression. */
2200 print_operand_address (file, addr)
2206 int need_parenthesis = 0;
2208 switch (GET_CODE (addr))
2211 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2214 asm_fprintf (file, "0,");
2215 asm_print_register (file, REGNO (addr));
2219 base = XEXP (addr, 0);
2220 switch (GET_CODE (base))
2225 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2226 asm_print_register (file, REGNO (XEXP (base, 0)));
2235 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2236 asm_print_register (file, REGNO (XEXP (base, 0)));
2237 asm_fprintf (file, "-");
2246 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2247 asm_print_register (file, REGNO (XEXP (base, 0)));
2248 asm_fprintf (file, "+");
2257 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2258 asm_print_register (file, REGNO (XEXP (base, 0)));
2265 need_parenthesis = must_parenthesize (base);
2266 if (need_parenthesis)
2267 asm_fprintf (file, "(");
2269 output_addr_const (file, base);
2270 if (need_parenthesis)
2271 asm_fprintf (file, ")");
2277 base = XEXP (addr, 0);
2278 offset = XEXP (addr, 1);
2279 if (!G_REG_P (base) && G_REG_P (offset))
2281 base = XEXP (addr, 1);
2282 offset = XEXP (addr, 0);
2284 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2286 need_parenthesis = must_parenthesize (addr);
2288 if (need_parenthesis)
2289 asm_fprintf (file, "(");
2291 output_addr_const (file, base);
2292 asm_fprintf (file, "+");
2293 output_addr_const (file, offset);
2294 if (need_parenthesis)
2295 asm_fprintf (file, ")");
2297 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2303 asm_print_register (file, REGNO (offset));
2304 asm_fprintf (file, ",");
2305 asm_print_register (file, REGNO (base));
2312 output_addr_const (file, offset);
2313 asm_fprintf (file, ",");
2314 asm_print_register (file, REGNO (base));
2324 if (GET_CODE (addr) == CONST_INT
2325 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2327 asm_fprintf (file, "%d", INTVAL (addr));
2331 need_parenthesis = must_parenthesize (addr);
2332 if (need_parenthesis)
2333 asm_fprintf (file, "(");
2335 output_addr_const (file, addr);
2336 if (need_parenthesis)
2337 asm_fprintf (file, ")");
2344 /* Splitting of some instructions. */
2347 m68hc11_expand_compare (code, op0, op1)
2353 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2357 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2358 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2359 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2366 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2368 rtx op0, op1, label;
2372 switch (GET_MODE (op0))
2376 tmp = m68hc11_expand_compare (code, op0, op1);
2377 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2378 gen_rtx_LABEL_REF (VOIDmode, label),
2380 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2384 /* SCz: from i386.c */
2387 /* Don't expand the comparison early, so that we get better code
2388 when jump or whoever decides to reverse the comparison. */
2393 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2394 &m68hc11_compare_op1);
2396 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2397 m68hc11_compare_op0, m68hc11_compare_op1);
2398 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2399 gen_rtx_LABEL_REF (VOIDmode, label),
2401 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2403 use_fcomi = ix86_use_fcomi_compare (code);
2404 vec = rtvec_alloc (3 + !use_fcomi);
2405 RTVEC_ELT (vec, 0) = tmp;
2407 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2409 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2412 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2414 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2420 /* Expand SImode branch into multiple compare+branch. */
2422 rtx lo[2], hi[2], label2;
2423 enum rtx_code code1, code2, code3;
2425 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2430 code = swap_condition (code);
2432 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2433 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2434 hi[0] = m68hc11_gen_highpart (HImode, op0);
2435 hi[1] = m68hc11_gen_highpart (HImode, op1);
2437 /* Otherwise, if we are doing less-than, op1 is a constant and the
2438 low word is zero, then we can just examine the high word. */
2440 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2441 && (code == LT || code == LTU))
2443 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2447 /* Otherwise, we need two or three jumps. */
2449 label2 = gen_label_rtx ();
2452 code2 = swap_condition (code);
2453 code3 = unsigned_condition (code);
2494 * if (hi(a) < hi(b)) goto true;
2495 * if (hi(a) > hi(b)) goto false;
2496 * if (lo(a) < lo(b)) goto true;
2500 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2502 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2504 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2507 emit_label (label2);
2518 /* Split a DI, SI or HI move into several smaller move operations.
2519 The scratch register 'scratch' is used as a temporary to load
2520 store intermediate values. It must be a hard register. */
2522 m68hc11_split_move (to, from, scratch)
2523 rtx to, from, scratch;
2525 rtx low_to, low_from;
2526 rtx high_to, high_from;
2527 enum machine_mode mode;
2529 mode = GET_MODE (to);
2530 if (GET_MODE_SIZE (mode) == 8)
2532 else if (GET_MODE_SIZE (mode) == 4)
2537 low_to = m68hc11_gen_lowpart (mode, to);
2538 high_to = m68hc11_gen_highpart (mode, to);
2540 low_from = m68hc11_gen_lowpart (mode, from);
2541 if (mode == SImode && GET_CODE (from) == CONST_INT)
2543 if (INTVAL (from) >= 0)
2544 high_from = const0_rtx;
2546 high_from = constm1_rtx;
2549 high_from = m68hc11_gen_highpart (mode, from);
2553 m68hc11_split_move (low_to, low_from, scratch);
2554 m68hc11_split_move (high_to, high_from, scratch);
2556 else if (H_REG_P (to) || H_REG_P (from)
2558 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2559 || m68hc11_small_indexed_indirect_p (from,
2561 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2562 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2564 emit_move_insn (low_to, low_from);
2565 emit_move_insn (high_to, high_from);
2571 emit_move_insn (scratch, low_from);
2572 insn = emit_move_insn (low_to, scratch);
2574 emit_move_insn (scratch, high_from);
2575 insn = emit_move_insn (high_to, scratch);
2580 simplify_logical (mode, code, operand, result)
2581 enum machine_mode mode;
2590 if (GET_CODE (operand) != CONST_INT)
2598 val = INTVAL (operand);
2602 if ((val & mask) == 0)
2604 if ((val & mask) == mask)
2605 *result = constm1_rtx;
2609 if ((val & mask) == 0)
2610 *result = const0_rtx;
2611 if ((val & mask) == mask)
2616 if ((val & mask) == 0)
2624 m68hc11_emit_logical (mode, code, operands)
2625 enum machine_mode mode;
2632 need_copy = (rtx_equal_p (operands[0], operands[1])
2633 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2635 operands[1] = simplify_logical (mode, code, operands[1], &result);
2636 operands[2] = simplify_logical (mode, code, operands[2], &result);
2638 if (result && GET_CODE (result) == CONST_INT)
2640 if (!H_REG_P (operands[0]) && operands[3]
2641 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2643 emit_move_insn (operands[3], result);
2644 emit_move_insn (operands[0], operands[3]);
2648 emit_move_insn (operands[0], result);
2651 else if (operands[1] != 0 && operands[2] != 0)
2655 if (!H_REG_P (operands[0]) && operands[3])
2657 emit_move_insn (operands[3], operands[1]);
2658 emit_insn (gen_rtx (SET, mode,
2660 gen_rtx (code, mode,
2661 operands[3], operands[2])));
2662 insn = emit_move_insn (operands[0], operands[3]);
2666 insn = emit_insn (gen_rtx (SET, mode,
2668 gen_rtx (code, mode,
2669 operands[0], operands[2])));
2673 /* The logical operation is similar to a copy. */
2678 if (GET_CODE (operands[1]) == CONST_INT)
2683 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2685 emit_move_insn (operands[3], src);
2686 emit_move_insn (operands[0], operands[3]);
2690 emit_move_insn (operands[0], src);
2696 m68hc11_split_logical (mode, code, operands)
2697 enum machine_mode mode;
2704 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2705 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2706 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2708 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2710 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
2712 if (INTVAL (operands[1]) >= 0)
2713 high[1] = const0_rtx;
2715 high[1] = constm1_rtx;
2718 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2720 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
2722 if (INTVAL (operands[2]) >= 0)
2723 high[2] = const0_rtx;
2725 high[2] = constm1_rtx;
2728 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2730 low[3] = operands[3];
2731 high[3] = operands[3];
2734 m68hc11_split_logical (HImode, code, low);
2735 m68hc11_split_logical (HImode, code, high);
2739 m68hc11_emit_logical (mode, code, low);
2740 m68hc11_emit_logical (mode, code, high);
2744 /* Code generation. */
2747 m68hc11_output_swap (insn, operands)
2748 rtx insn ATTRIBUTE_UNUSED;
2751 /* We have to be careful with the cc_status. An address register swap
2752 is generated for some comparison. The comparison is made with D
2753 but the branch really uses the address register. See the split
2754 pattern for compare. The xgdx/xgdy preserve the flags but after
2755 the exchange, the flags will reflect to the value of X and not D.
2756 Tell this by setting the cc_status according to the cc_prev_status. */
2757 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2759 if (cc_prev_status.value1 != 0
2760 && (D_REG_P (cc_prev_status.value1)
2761 || X_REG_P (cc_prev_status.value1)))
2763 cc_status = cc_prev_status;
2764 if (D_REG_P (cc_status.value1))
2765 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2768 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2774 output_asm_insn ("xgdx", operands);
2778 if (cc_prev_status.value1 != 0
2779 && (D_REG_P (cc_prev_status.value1)
2780 || Y_REG_P (cc_prev_status.value1)))
2782 cc_status = cc_prev_status;
2783 if (D_REG_P (cc_status.value1))
2784 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2787 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2793 output_asm_insn ("xgdy", operands);
2797 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2798 This is used to decide whether a move that set flags should be used
2801 next_insn_test_reg (insn, reg)
2807 insn = next_nonnote_insn (insn);
2808 if (GET_CODE (insn) != INSN)
2811 body = PATTERN (insn);
2812 if (sets_cc0_p (body) != 1)
2815 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
2821 /* Generate the code to move a 16-bit operand into another one. */
2824 m68hc11_gen_movhi (insn, operands)
2830 /* Move a register or memory to the same location.
2831 This is possible because such insn can appear
2832 in a non-optimizing mode. */
2833 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
2835 cc_status = cc_prev_status;
2841 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
2843 switch (REGNO (operands[1]))
2848 output_asm_insn ("psh%1", operands);
2855 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2857 switch (REGNO (operands[0]))
2862 output_asm_insn ("pul%0", operands);
2869 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
2871 output_asm_insn ("tfr\t%1,%0", operands);
2873 else if (H_REG_P (operands[0]))
2875 if (SP_REG_P (operands[0]))
2876 output_asm_insn ("lds\t%1", operands);
2878 output_asm_insn ("ld%0\t%1", operands);
2880 else if (H_REG_P (operands[1]))
2882 if (SP_REG_P (operands[1]))
2883 output_asm_insn ("sts\t%0", operands);
2885 output_asm_insn ("st%1\t%0", operands);
2889 rtx from = operands[1];
2890 rtx to = operands[0];
2892 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
2893 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
2894 || (m68hc11_register_indirect_p (to, GET_MODE (to))
2895 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
2901 ops[0] = operands[2];
2904 m68hc11_gen_movhi (insn, ops);
2906 ops[1] = operands[2];
2907 m68hc11_gen_movhi (insn, ops);
2911 /* !!!! SCz wrong here. */
2916 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
2918 output_asm_insn ("clr\t%h0", operands);
2919 output_asm_insn ("clr\t%b0", operands);
2923 output_asm_insn ("movw\t%1,%0", operands);
2930 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2932 switch (REGNO (operands[0]))
2936 output_asm_insn ("pul%0", operands);
2939 output_asm_insn ("pula", operands);
2940 output_asm_insn ("pulb", operands);
2947 /* Some moves to a hard register are special. Not all of them
2948 are really supported and we have to use a temporary
2949 location to provide them (either the stack of a temp var). */
2950 if (H_REG_P (operands[0]))
2952 switch (REGNO (operands[0]))
2955 if (X_REG_P (operands[1]))
2957 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
2959 m68hc11_output_swap (insn, operands);
2961 else if (next_insn_test_reg (insn, operands[0]))
2963 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
2967 cc_status = cc_prev_status;
2968 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
2971 else if (Y_REG_P (operands[1]))
2973 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
2975 m68hc11_output_swap (insn, operands);
2979 /* %t means *ZTMP scratch register. */
2980 output_asm_insn ("sty\t%t1", operands);
2981 output_asm_insn ("ldd\t%t1", operands);
2984 else if (SP_REG_P (operands[1]))
2989 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
2990 output_asm_insn ("xgdx", operands);
2991 output_asm_insn ("tsx", operands);
2992 output_asm_insn ("xgdx", operands);
2994 else if (IS_STACK_POP (operands[1]))
2996 output_asm_insn ("pula\n\tpulb", operands);
2998 else if (GET_CODE (operands[1]) == CONST_INT
2999 && INTVAL (operands[1]) == 0)
3001 output_asm_insn ("clra\n\tclrb", operands);
3005 output_asm_insn ("ldd\t%1", operands);
3010 if (D_REG_P (operands[1]))
3012 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3014 m68hc11_output_swap (insn, operands);
3016 else if (next_insn_test_reg (insn, operands[0]))
3018 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3022 cc_status = cc_prev_status;
3023 output_asm_insn ("pshb", operands);
3024 output_asm_insn ("psha", operands);
3025 output_asm_insn ("pulx", operands);
3028 else if (Y_REG_P (operands[1]))
3030 output_asm_insn ("sty\t%t1", operands);
3031 output_asm_insn ("ldx\t%t1", operands);
3033 else if (SP_REG_P (operands[1]))
3035 /* tsx, tsy preserve the flags */
3036 cc_status = cc_prev_status;
3037 output_asm_insn ("tsx", operands);
3041 output_asm_insn ("ldx\t%1", operands);
3046 if (D_REG_P (operands[1]))
3048 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3050 m68hc11_output_swap (insn, operands);
3054 output_asm_insn ("std\t%t1", operands);
3055 output_asm_insn ("ldy\t%t1", operands);
3058 else if (X_REG_P (operands[1]))
3060 output_asm_insn ("stx\t%t1", operands);
3061 output_asm_insn ("ldy\t%t1", operands);
3063 else if (SP_REG_P (operands[1]))
3065 /* tsx, tsy preserve the flags */
3066 cc_status = cc_prev_status;
3067 output_asm_insn ("tsy", operands);
3071 output_asm_insn ("ldy\t%1", operands);
3075 case HARD_SP_REGNUM:
3076 if (D_REG_P (operands[1]))
3078 cc_status = cc_prev_status;
3079 output_asm_insn ("xgdx", operands);
3080 output_asm_insn ("txs", operands);
3081 output_asm_insn ("xgdx", operands);
3083 else if (X_REG_P (operands[1]))
3085 /* tys, txs preserve the flags */
3086 cc_status = cc_prev_status;
3087 output_asm_insn ("txs", operands);
3089 else if (Y_REG_P (operands[1]))
3091 /* tys, txs preserve the flags */
3092 cc_status = cc_prev_status;
3093 output_asm_insn ("tys", operands);
3097 /* lds sets the flags but the des does not. */
3099 output_asm_insn ("lds\t%1", operands);
3100 output_asm_insn ("des", operands);
3105 fatal_insn ("Invalid register in the move instruction", insn);
3110 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3111 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3113 output_asm_insn ("sts\t%0", operands);
3117 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3119 switch (REGNO (operands[1]))
3123 output_asm_insn ("psh%1", operands);
3126 output_asm_insn ("pshb", operands);
3127 output_asm_insn ("psha", operands);
3135 /* Operand 1 must be a hard register. */
3136 if (!H_REG_P (operands[1]))
3138 fatal_insn ("Invalid operand in the instruction", insn);
3141 reg = REGNO (operands[1]);
3145 output_asm_insn ("std\t%0", operands);
3149 output_asm_insn ("stx\t%0", operands);
3153 output_asm_insn ("sty\t%0", operands);
3156 case HARD_SP_REGNUM:
3160 if (reg_mentioned_p (ix_reg, operands[0]))
3162 output_asm_insn ("sty\t%t0", operands);
3163 output_asm_insn ("tsy", operands);
3164 output_asm_insn ("sty\t%0", operands);
3165 output_asm_insn ("ldy\t%t0", operands);
3169 output_asm_insn ("stx\t%t0", operands);
3170 output_asm_insn ("tsx", operands);
3171 output_asm_insn ("stx\t%0", operands);
3172 output_asm_insn ("ldx\t%t0", operands);
3178 fatal_insn ("Invalid register in the move instruction", insn);
3184 m68hc11_gen_movqi (insn, operands)
3188 /* Move a register or memory to the same location.
3189 This is possible because such insn can appear
3190 in a non-optimizing mode. */
3191 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3193 cc_status = cc_prev_status;
3200 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3202 output_asm_insn ("tfr\t%1,%0", operands);
3204 else if (H_REG_P (operands[0]))
3206 if (Q_REG_P (operands[0]))
3207 output_asm_insn ("lda%0\t%1", operands);
3208 else if (D_REG_P (operands[0]))
3209 output_asm_insn ("ldab\t%1", operands);
3211 output_asm_insn ("ld%0\t%1", operands);
3213 else if (H_REG_P (operands[1]))
3215 if (Q_REG_P (operands[1]))
3216 output_asm_insn ("sta%1\t%0", operands);
3217 else if (D_REG_P (operands[1]))
3218 output_asm_insn ("staa\t%0", operands);
3220 output_asm_insn ("st%1\t%0", operands);
3224 rtx from = operands[1];
3225 rtx to = operands[0];
3227 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3228 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3229 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3230 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3236 ops[0] = operands[2];
3239 m68hc11_gen_movqi (insn, ops);
3241 ops[1] = operands[2];
3242 m68hc11_gen_movqi (insn, ops);
3246 /* !!!! SCz wrong here. */
3251 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3253 output_asm_insn ("clr\t%b0", operands);
3257 output_asm_insn ("movb\t%1,%0", operands);
3264 if (H_REG_P (operands[0]))
3266 switch (REGNO (operands[0]))
3270 if (X_REG_P (operands[1]))
3272 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3274 m68hc11_output_swap (insn, operands);
3278 output_asm_insn ("stx\t%t1", operands);
3279 output_asm_insn ("ldab\t%T0", operands);
3282 else if (Y_REG_P (operands[1]))
3284 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3286 m68hc11_output_swap (insn, operands);
3290 output_asm_insn ("sty\t%t1", operands);
3291 output_asm_insn ("ldab\t%T0", operands);
3294 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3295 && !DA_REG_P (operands[1]))
3297 output_asm_insn ("ldab\t%b1", operands);
3299 else if (DA_REG_P (operands[1]))
3301 output_asm_insn ("tab", operands);
3305 cc_status = cc_prev_status;
3311 if (X_REG_P (operands[1]))
3313 output_asm_insn ("stx\t%t1", operands);
3314 output_asm_insn ("ldaa\t%T0", operands);
3316 else if (Y_REG_P (operands[1]))
3318 output_asm_insn ("sty\t%t1", operands);
3319 output_asm_insn ("ldaa\t%T0", operands);
3321 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3322 && !DA_REG_P (operands[1]))
3324 output_asm_insn ("ldaa\t%b1", operands);
3326 else if (!DA_REG_P (operands[1]))
3328 output_asm_insn ("tba", operands);
3332 cc_status = cc_prev_status;
3337 if (D_REG_P (operands[1]))
3339 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3341 m68hc11_output_swap (insn, operands);
3345 output_asm_insn ("stab\t%T1", operands);
3346 output_asm_insn ("ldx\t%t1", operands);
3350 else if (Y_REG_P (operands[1]))
3352 output_asm_insn ("sty\t%t0", operands);
3353 output_asm_insn ("ldx\t%t0", operands);
3355 else if (GET_CODE (operands[1]) == CONST_INT)
3357 output_asm_insn ("ldx\t%1", operands);
3359 else if (dead_register_here (insn, d_reg))
3361 output_asm_insn ("ldab\t%b1", operands);
3362 output_asm_insn ("xgdx", operands);
3364 else if (!reg_mentioned_p (operands[0], operands[1]))
3366 output_asm_insn ("xgdx", operands);
3367 output_asm_insn ("ldab\t%b1", operands);
3368 output_asm_insn ("xgdx", operands);
3372 output_asm_insn ("pshb", operands);
3373 output_asm_insn ("ldab\t%b1", operands);
3374 output_asm_insn ("stab\t%T1", operands);
3375 output_asm_insn ("ldx\t%t1", operands);
3376 output_asm_insn ("pulb", operands);
3382 if (D_REG_P (operands[1]))
3384 output_asm_insn ("stab\t%T1", operands);
3385 output_asm_insn ("ldy\t%t1", operands);
3388 else if (X_REG_P (operands[1]))
3390 output_asm_insn ("stx\t%t1", operands);
3391 output_asm_insn ("ldy\t%t1", operands);
3394 else if (GET_CODE (operands[1]) == CONST_INT)
3396 output_asm_insn ("ldy\t%1", operands);
3398 else if (dead_register_here (insn, d_reg))
3400 output_asm_insn ("ldab\t%b1", operands);
3401 output_asm_insn ("xgdy", operands);
3403 else if (!reg_mentioned_p (operands[0], operands[1]))
3405 output_asm_insn ("xgdy", operands);
3406 output_asm_insn ("ldab\t%b1", operands);
3407 output_asm_insn ("xgdy", operands);
3411 output_asm_insn ("pshb", operands);
3412 output_asm_insn ("ldab\t%b1", operands);
3413 output_asm_insn ("stab\t%T1", operands);
3414 output_asm_insn ("ldy\t%t1", operands);
3415 output_asm_insn ("pulb", operands);
3421 fatal_insn ("Invalid register in the instruction", insn);
3425 else if (H_REG_P (operands[1]))
3427 switch (REGNO (operands[1]))
3431 output_asm_insn ("stab\t%b0", operands);
3435 output_asm_insn ("staa\t%b0", operands);
3439 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3443 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3447 fatal_insn ("Invalid register in the move instruction", insn);
3454 fatal_insn ("Operand 1 must be a hard register", insn);
3458 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3459 The source and destination must be D or A and the shift must
3462 m68hc11_gen_rotate (code, insn, operands)
3469 if (GET_CODE (operands[2]) != CONST_INT
3470 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3471 fatal_insn ("Invalid rotate insn", insn);
3473 val = INTVAL (operands[2]);
3474 if (code == ROTATERT)
3475 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3477 if (GET_MODE (operands[0]) != QImode)
3480 /* Rotate by 8-bits if the shift is within [5..11]. */
3481 if (val >= 5 && val <= 11)
3483 output_asm_insn ("psha", operands);
3484 output_asm_insn ("tba", operands);
3485 output_asm_insn ("pulb", operands);
3489 /* If the shift is big, invert the rotation. */
3497 /* Set the carry to bit-15, but don't change D yet. */
3498 if (GET_MODE (operands[0]) != QImode)
3500 output_asm_insn ("asra", operands);
3501 output_asm_insn ("rola", operands);
3506 /* Rotate B first to move the carry to bit-0. */
3507 if (D_REG_P (operands[0]))
3508 output_asm_insn ("rolb", operands);
3510 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3511 output_asm_insn ("rola", operands);
3516 /* Set the carry to bit-8 of D. */
3517 if (val != 0 && GET_MODE (operands[0]) != QImode)
3519 output_asm_insn ("tap", operands);
3524 /* Rotate B first to move the carry to bit-7. */
3525 if (D_REG_P (operands[0]))
3526 output_asm_insn ("rorb", operands);
3528 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3529 output_asm_insn ("rora", operands);
3536 /* Store in cc_status the expressions that the condition codes will
3537 describe after execution of an instruction whose pattern is EXP.
3538 Do not alter them if the instruction would not alter the cc's. */
3541 m68hc11_notice_update_cc (exp, insn)
3543 rtx insn ATTRIBUTE_UNUSED;
3545 /* recognize SET insn's. */
3546 if (GET_CODE (exp) == SET)
3548 /* Jumps do not alter the cc's. */
3549 if (SET_DEST (exp) == pc_rtx)
3552 /* NOTE: most instructions don't affect the carry bit, but the
3553 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3554 the conditions.h header. */
3556 /* Function calls clobber the cc's. */
3557 else if (GET_CODE (SET_SRC (exp)) == CALL)
3562 /* Tests and compares set the cc's in predictable ways. */
3563 else if (SET_DEST (exp) == cc0_rtx)
3565 cc_status.flags = 0;
3566 cc_status.value1 = XEXP (exp, 0);
3567 cc_status.value2 = XEXP (exp, 1);
3571 /* All other instructions affect the condition codes. */
3572 cc_status.flags = 0;
3573 cc_status.value1 = XEXP (exp, 0);
3574 cc_status.value2 = XEXP (exp, 1);
3579 /* Default action if we haven't recognized something
3580 and returned earlier. */
3584 if (cc_status.value2 != 0)
3585 switch (GET_CODE (cc_status.value2))
3587 /* These logical operations can generate several insns.
3588 The flags are setup according to what is generated. */
3594 /* The (not ...) generates several 'com' instructions for
3595 non QImode. We have to invalidate the flags. */
3597 if (GET_MODE (cc_status.value2) != QImode)
3609 if (GET_MODE (cc_status.value2) != VOIDmode)
3610 cc_status.flags |= CC_NO_OVERFLOW;
3613 /* The asl sets the overflow bit in such a way that this
3614 makes the flags unusable for a next compare insn. */
3618 if (GET_MODE (cc_status.value2) != VOIDmode)
3619 cc_status.flags |= CC_NO_OVERFLOW;
3622 /* A load/store instruction does not affect the carry. */
3627 cc_status.flags |= CC_NO_OVERFLOW;
3633 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3635 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3636 cc_status.value2 = 0;
3640 /* Machine Specific Reorg. */
3642 /* Z register replacement:
3644 GCC treats the Z register as an index base address register like
3645 X or Y. In general, it uses it during reload to compute the address
3646 of some operand. This helps the reload pass to avoid to fall into the
3647 register spill failure.
3649 The Z register is in the A_REGS class. In the machine description,
3650 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3652 It can appear everywhere an X or Y register can appear, except for
3653 some templates in the clobber section (when a clobber of X or Y is asked).
3654 For a given instruction, the template must ensure that no more than
3655 2 'A' registers are used. Otherwise, the register replacement is not
3658 To replace the Z register, the algorithm is not terrific:
3659 1. Insns that do not use the Z register are not changed
3660 2. When a Z register is used, we scan forward the insns to see
3661 a potential register to use: either X or Y and sometimes D.
3662 We stop when a call, a label or a branch is seen, or when we
3663 detect that both X and Y are used (probably at different times, but it does
3665 3. The register that will be used for the replacement of Z is saved
3666 in a .page0 register or on the stack. If the first instruction that
3667 used Z, uses Z as an input, the value is loaded from another .page0
3668 register. The replacement register is pushed on the stack in the
3669 rare cases where a compare insn uses Z and we couldn't find if X/Y
3671 4. The Z register is replaced in all instructions until we reach
3672 the end of the Z-block, as detected by step 2.
3673 5. If we detect that Z is still alive, its value is saved.
3674 If the replacement register is alive, its old value is loaded.
3676 The Z register can be disabled with -ffixed-z.
3686 int must_restore_reg;
3697 int save_before_last;
3698 int z_loaded_with_sp;
3701 static rtx z_reg_qi;
3703 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
3704 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
3705 static void m68hc11_z_replacement PARAMS ((rtx));
3706 static void m68hc11_reassign_regs PARAMS ((rtx));
3708 int z_replacement_completed = 0;
3710 /* Analyze the insn to find out which replacement register to use and
3711 the boundaries of the replacement.
3712 Returns 0 if we reached the last insn to be replaced, 1 if we can
3713 continue replacement in next insns. */
3716 m68hc11_check_z_replacement (insn, info)
3718 struct replace_info *info;
3720 int this_insn_uses_ix;
3721 int this_insn_uses_iy;
3722 int this_insn_uses_z;
3723 int this_insn_uses_d;
3727 /* A call is said to clobber the Z register, we don't need
3728 to save the value of Z. We also don't need to restore
3729 the replacement register (unless it is used by the call). */
3730 if (GET_CODE (insn) == CALL_INSN)
3732 body = PATTERN (insn);
3734 info->can_use_d = 0;
3736 /* If the call is an indirect call with Z, we have to use the
3737 Y register because X can be used as an input (D+X).
3738 We also must not save Z nor restore Y. */
3739 if (reg_mentioned_p (z_reg, body))
3741 insn = NEXT_INSN (insn);
3744 info->found_call = 1;
3745 info->must_restore_reg = 0;
3746 info->last = NEXT_INSN (insn);
3748 info->need_save_z = 0;
3751 if (GET_CODE (insn) == CODE_LABEL
3752 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
3755 if (GET_CODE (insn) == JUMP_INSN)
3757 if (reg_mentioned_p (z_reg, insn) == 0)
3760 info->can_use_d = 0;
3761 info->must_save_reg = 0;
3762 info->must_restore_reg = 0;
3763 info->need_save_z = 0;
3764 info->last = NEXT_INSN (insn);
3767 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
3772 /* Z register dies here. */
3773 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
3775 body = PATTERN (insn);
3776 if (GET_CODE (body) == SET)
3778 rtx src = XEXP (body, 1);
3779 rtx dst = XEXP (body, 0);
3781 /* Condition code is set here. We have to restore the X/Y and
3782 save into Z before any test/compare insn because once we save/restore
3783 we can change the condition codes. When the compare insn uses Z and
3784 we can't use X/Y, the comparison is made with the *ZREG soft register
3785 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3788 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
3789 || (GET_CODE (src) == COMPARE &&
3790 (rtx_equal_p (XEXP (src, 0), z_reg)
3791 || rtx_equal_p (XEXP (src, 1), z_reg))))
3793 if (insn == info->first)
3795 info->must_load_z = 0;
3796 info->must_save_reg = 0;
3797 info->must_restore_reg = 0;
3798 info->need_save_z = 0;
3799 info->found_call = 1;
3800 info->regno = SOFT_Z_REGNUM;
3805 if (reg_mentioned_p (z_reg, src) == 0)
3807 info->can_use_d = 0;
3811 if (insn != info->first)
3814 /* Compare insn which uses Z. We have to save/restore the X/Y
3815 register without modifying the condition codes. For this
3816 we have to use a push/pop insn. */
3817 info->must_push_reg = 1;
3821 /* Z reg is set to something new. We don't need to load it. */
3824 if (!reg_mentioned_p (z_reg, src))
3826 if (insn == info->first)
3828 info->must_load_z = 0;
3831 info->z_set_count++;
3832 info->z_value = src;
3834 info->z_loaded_with_sp = 1;
3836 else if (reg_mentioned_p (z_reg, dst))
3837 info->can_use_d = 0;
3839 this_insn_uses_d = reg_mentioned_p (d_reg, src)
3840 | reg_mentioned_p (d_reg, dst);
3841 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
3842 | reg_mentioned_p (ix_reg, dst);
3843 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
3844 | reg_mentioned_p (iy_reg, dst);
3845 this_insn_uses_z = reg_mentioned_p (z_reg, src);
3847 /* If z is used as an address operand (like (MEM (reg z))),
3848 we can't replace it with d. */
3849 if (this_insn_uses_z && !Z_REG_P (src))
3850 info->can_use_d = 0;
3851 this_insn_uses_z |= reg_mentioned_p (z_reg, dst);
3853 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
3855 fatal_insn ("Registers IX, IY and Z used in the same INSN", insn);
3858 if (this_insn_uses_d)
3859 info->can_use_d = 0;
3861 /* IX and IY are used at the same time, we have to restore
3862 the value of the scratch register before this insn. */
3863 if (this_insn_uses_ix && this_insn_uses_iy)
3868 if (info->x_used == 0 && this_insn_uses_ix)
3872 /* We have a (set (REG:HI X) (REG:HI Z)).
3873 Since we use Z as the replacement register, this insn
3874 is no longer necessary. We turn it into a note. We must
3875 not reload the old value of X. */
3876 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
3880 info->need_save_z = 0;
3883 info->must_save_reg = 0;
3884 info->must_restore_reg = 0;
3885 info->found_call = 1;
3886 info->can_use_d = 0;
3887 PUT_CODE (insn, NOTE);
3888 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
3889 NOTE_SOURCE_FILE (insn) = 0;
3890 info->last = NEXT_INSN (insn);
3895 && (rtx_equal_p (src, z_reg)
3896 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
3900 info->need_save_z = 0;
3903 info->last = NEXT_INSN (insn);
3904 info->must_save_reg = 0;
3905 info->must_restore_reg = 0;
3907 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
3908 && !reg_mentioned_p (ix_reg, src))
3913 info->need_save_z = 0;
3917 info->save_before_last = 1;
3919 info->must_restore_reg = 0;
3920 info->last = NEXT_INSN (insn);
3922 else if (info->can_use_d)
3924 info->last = NEXT_INSN (insn);
3930 if (z_dies_here && !reg_mentioned_p (src, ix_reg)
3931 && GET_CODE (src) == REG && REGNO (src) == HARD_X_REGNUM)
3933 info->need_save_z = 0;
3935 info->last = NEXT_INSN (insn);
3936 info->regno = HARD_X_REGNUM;
3937 info->must_save_reg = 0;
3938 info->must_restore_reg = 0;
3942 if (info->y_used == 0 && this_insn_uses_iy)
3946 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
3950 info->need_save_z = 0;
3953 info->must_save_reg = 0;
3954 info->must_restore_reg = 0;
3955 info->found_call = 1;
3956 info->can_use_d = 0;
3957 PUT_CODE (insn, NOTE);
3958 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
3959 NOTE_SOURCE_FILE (insn) = 0;
3960 info->last = NEXT_INSN (insn);
3965 && (rtx_equal_p (src, z_reg)
3966 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
3971 info->need_save_z = 0;
3973 info->last = NEXT_INSN (insn);
3974 info->must_save_reg = 0;
3975 info->must_restore_reg = 0;
3977 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
3978 && !reg_mentioned_p (iy_reg, src))
3983 info->need_save_z = 0;
3987 info->save_before_last = 1;
3989 info->must_restore_reg = 0;
3990 info->last = NEXT_INSN (insn);
3992 else if (info->can_use_d)
3994 info->last = NEXT_INSN (insn);
4001 if (z_dies_here && !reg_mentioned_p (src, iy_reg)
4002 && GET_CODE (src) == REG && REGNO (src) == HARD_Y_REGNUM)
4004 info->need_save_z = 0;
4006 info->last = NEXT_INSN (insn);
4007 info->regno = HARD_Y_REGNUM;
4008 info->must_save_reg = 0;
4009 info->must_restore_reg = 0;
4015 info->need_save_z = 0;
4017 if (info->last == 0)
4018 info->last = NEXT_INSN (insn);
4021 return info->last != NULL_RTX ? 0 : 1;
4023 if (GET_CODE (body) == PARALLEL)
4026 char ix_clobber = 0;
4027 char iy_clobber = 0;
4029 this_insn_uses_iy = 0;
4030 this_insn_uses_ix = 0;
4031 this_insn_uses_z = 0;
4033 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4036 int uses_ix, uses_iy, uses_z;
4038 x = XVECEXP (body, 0, i);
4040 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4041 info->can_use_d = 0;
4043 uses_ix = reg_mentioned_p (ix_reg, x);
4044 uses_iy = reg_mentioned_p (iy_reg, x);
4045 uses_z = reg_mentioned_p (z_reg, x);
4046 if (GET_CODE (x) == CLOBBER)
4048 ix_clobber |= uses_ix;
4049 iy_clobber |= uses_iy;
4050 z_clobber |= uses_z;
4054 this_insn_uses_ix |= uses_ix;
4055 this_insn_uses_iy |= uses_iy;
4056 this_insn_uses_z |= uses_z;
4058 if (uses_z && GET_CODE (x) == SET)
4060 rtx dst = XEXP (x, 0);
4063 info->z_set_count++;
4066 info->need_save_z = 0;
4070 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4071 this_insn_uses_ix, this_insn_uses_iy,
4072 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4075 if (this_insn_uses_z)
4076 info->can_use_d = 0;
4078 if (z_clobber && info->first != insn)
4080 info->need_save_z = 0;
4084 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4086 if (this_insn_uses_z == 0 && insn == info->first)
4088 info->must_load_z = 0;
4090 if (dead_register_here (insn, d_reg))
4092 info->regno = HARD_D_REGNUM;
4093 info->must_save_reg = 0;
4094 info->must_restore_reg = 0;
4096 else if (dead_register_here (insn, ix_reg))
4098 info->regno = HARD_X_REGNUM;
4099 info->must_save_reg = 0;
4100 info->must_restore_reg = 0;
4102 else if (dead_register_here (insn, iy_reg))
4104 info->regno = HARD_Y_REGNUM;
4105 info->must_save_reg = 0;
4106 info->must_restore_reg = 0;
4108 if (info->regno >= 0)
4110 info->last = NEXT_INSN (insn);
4113 if (this_insn_uses_ix == 0)
4115 info->regno = HARD_X_REGNUM;
4116 info->must_save_reg = 1;
4117 info->must_restore_reg = 1;
4119 else if (this_insn_uses_iy == 0)
4121 info->regno = HARD_Y_REGNUM;
4122 info->must_save_reg = 1;
4123 info->must_restore_reg = 1;
4127 info->regno = HARD_D_REGNUM;
4128 info->must_save_reg = 1;
4129 info->must_restore_reg = 1;
4131 info->last = NEXT_INSN (insn);
4135 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4136 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4138 if (this_insn_uses_z)
4140 if (info->y_used == 0 && iy_clobber)
4142 info->regno = HARD_Y_REGNUM;
4143 info->must_save_reg = 0;
4144 info->must_restore_reg = 0;
4146 info->last = NEXT_INSN (insn);
4147 info->save_before_last = 1;
4151 if (this_insn_uses_ix && this_insn_uses_iy)
4153 if (this_insn_uses_z)
4155 fatal_insn ("Cannot do z-register replacement", insn);
4159 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4166 if (iy_clobber || z_clobber)
4168 info->last = NEXT_INSN (insn);
4169 info->save_before_last = 1;
4174 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4181 if (ix_clobber || z_clobber)
4183 info->last = NEXT_INSN (insn);
4184 info->save_before_last = 1;
4191 info->need_save_z = 0;
4195 if (GET_CODE (body) == CLOBBER)
4198 /* IX and IY are used at the same time, we have to restore
4199 the value of the scratch register before this insn. */
4200 if (this_insn_uses_ix && this_insn_uses_iy)
4204 if (info->x_used == 0 && this_insn_uses_ix)
4212 if (info->y_used == 0 && this_insn_uses_iy)
4226 m68hc11_find_z_replacement (insn, info)
4228 struct replace_info *info;
4232 info->replace_reg = NULL_RTX;
4233 info->must_load_z = 1;
4234 info->need_save_z = 1;
4235 info->must_save_reg = 1;
4236 info->must_restore_reg = 1;
4240 info->can_use_d = TARGET_M6811 ? 1 : 0;
4241 info->found_call = 0;
4245 info->z_set_count = 0;
4246 info->z_value = NULL_RTX;
4247 info->must_push_reg = 0;
4248 info->save_before_last = 0;
4249 info->z_loaded_with_sp = 0;
4251 /* Scan the insn forward to find an address register that is not used.
4253 - the flow of the program changes,
4254 - when we detect that both X and Y are necessary,
4255 - when the Z register dies,
4256 - when the condition codes are set. */
4258 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4260 if (m68hc11_check_z_replacement (insn, info) == 0)
4264 /* May be we can use Y or X if they contain the same value as Z.
4265 This happens very often after the reload. */
4266 if (info->z_set_count == 1)
4268 rtx p = info->first;
4273 v = find_last_value (iy_reg, &p, insn, 1);
4275 else if (info->y_used)
4277 v = find_last_value (ix_reg, &p, insn, 1);
4279 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4282 info->regno = HARD_Y_REGNUM;
4284 info->regno = HARD_X_REGNUM;
4285 info->must_load_z = 0;
4286 info->must_save_reg = 0;
4287 info->must_restore_reg = 0;
4288 info->found_call = 1;
4291 if (info->z_set_count == 0)
4292 info->need_save_z = 0;
4295 info->need_save_z = 0;
4297 if (info->last == 0)
4300 if (info->regno >= 0)
4303 info->replace_reg = gen_rtx (REG, HImode, reg);
4305 else if (info->can_use_d)
4307 reg = HARD_D_REGNUM;
4308 info->replace_reg = d_reg;
4310 else if (info->x_used)
4312 reg = HARD_Y_REGNUM;
4313 info->replace_reg = iy_reg;
4317 reg = HARD_X_REGNUM;
4318 info->replace_reg = ix_reg;
4322 if (info->must_save_reg && info->must_restore_reg)
4324 if (insn && dead_register_here (insn, info->replace_reg))
4326 info->must_save_reg = 0;
4327 info->must_restore_reg = 0;
4332 /* The insn uses the Z register. Find a replacement register for it
4333 (either X or Y) and replace it in the insn and the next ones until
4334 the flow changes or the replacement register is used. Instructions
4335 are emited before and after the Z-block to preserve the value of
4336 Z and of the replacement register. */
4339 m68hc11_z_replacement (insn)
4344 struct replace_info info;
4346 /* Find trivial case where we only need to replace z with the
4347 equivalent soft register. */
4348 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4350 rtx body = PATTERN (insn);
4351 rtx src = XEXP (body, 1);
4352 rtx dst = XEXP (body, 0);
4354 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4356 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4359 else if (Z_REG_P (src)
4360 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4362 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4365 else if (D_REG_P (dst)
4366 && m68hc11_arith_operator (src, GET_MODE (src))
4367 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4369 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4372 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4373 && INTVAL (src) == 0)
4375 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4380 m68hc11_find_z_replacement (insn, &info);
4382 replace_reg = info.replace_reg;
4383 replace_reg_qi = NULL_RTX;
4385 /* Save the X register in a .page0 location. */
4386 if (info.must_save_reg && !info.must_push_reg)
4390 if (info.must_push_reg && 0)
4391 dst = gen_rtx (MEM, HImode,
4392 gen_rtx (PRE_DEC, HImode,
4393 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4395 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4397 emit_insn_before (gen_movhi (dst,
4398 gen_rtx (REG, HImode, info.regno)), insn);
4400 if (info.must_load_z && !info.must_push_reg)
4402 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4403 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4408 /* Replace all occurence of Z by replace_reg.
4409 Stop when the last instruction to replace is reached.
4410 Also stop when we detect a change in the flow (but it's not
4411 necessary; just safeguard). */
4413 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4417 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4420 if (GET_CODE (insn) != INSN
4421 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4424 body = PATTERN (insn);
4425 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4426 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4428 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4430 printf ("Reg mentioned here...:\n");
4435 /* Stack pointer was decremented by 2 due to the push.
4436 Correct that by adding 2 to the destination. */
4437 if (info.must_push_reg
4438 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4442 src = SET_SRC (body);
4443 dst = SET_DEST (body);
4444 if (SP_REG_P (src) && Z_REG_P (dst))
4446 emit_insn_after (gen_addhi3 (dst,
4449 VOIDmode, 2)), insn);
4453 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4454 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4456 INSN_CODE (insn) = -1;
4457 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4458 fatal_insn ("Cannot do z-register replacement", insn);
4461 /* Likewise for (REG:QI Z). */
4462 if (reg_mentioned_p (z_reg, insn))
4464 if (replace_reg_qi == NULL_RTX)
4465 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4466 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4469 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4473 /* Save Z before restoring the old value. */
4474 if (insn && info.need_save_z && !info.must_push_reg)
4476 rtx save_pos_insn = insn;
4478 /* If Z is clobber by the last insn, we have to save its value
4479 before the last instruction. */
4480 if (info.save_before_last)
4481 save_pos_insn = PREV_INSN (save_pos_insn);
4483 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4484 gen_rtx (REG, HImode, info.regno)),
4488 if (info.must_push_reg && info.last)
4492 body = PATTERN (info.last);
4493 new_body = gen_rtx (PARALLEL, VOIDmode,
4495 gen_rtx (USE, VOIDmode,
4497 gen_rtx (USE, VOIDmode,
4498 gen_rtx (REG, HImode,
4500 PATTERN (info.last) = new_body;
4502 /* Force recognition on insn since we changed it. */
4503 INSN_CODE (insn) = -1;
4505 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4507 fatal_insn ("Invalid Z register replacement for insn", insn);
4509 insn = NEXT_INSN (info.last);
4512 /* Restore replacement register unless it was died. */
4513 if (insn && info.must_restore_reg && !info.must_push_reg)
4517 if (info.must_push_reg && 0)
4518 dst = gen_rtx (MEM, HImode,
4519 gen_rtx (POST_INC, HImode,
4520 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4522 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4524 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4531 /* Scan all the insn and re-affects some registers
4532 - The Z register (if it was used), is affected to X or Y depending
4533 on the instruction. */
4536 m68hc11_reassign_regs (first)
4541 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
4542 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
4543 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4544 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
4546 /* Scan all insns to replace Z by X or Y preserving the old value
4547 of X/Y and restoring it afterward. */
4549 for (insn = first; insn; insn = NEXT_INSN (insn))
4553 if (GET_CODE (insn) == CODE_LABEL
4554 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4557 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4560 body = PATTERN (insn);
4561 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4564 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4565 || GET_CODE (body) == ASM_OPERANDS
4566 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4569 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4570 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4573 /* If Z appears in this insn, replace it in the current insn
4574 and the next ones until the flow changes or we have to
4575 restore back the replacement register. */
4577 if (reg_mentioned_p (z_reg, body))
4579 m68hc11_z_replacement (insn);
4584 printf ("Insn not handled by Z replacement:\n");
4591 #if GCC_VERSION == 2095
4592 /* Split all insns in the function. If UPD_LIFE, update life info after. */
4595 m68hc11_split_all_insns (first)
4601 for (insn = first; insn; insn = NEXT_INSN (insn))
4605 if (INSN_DELETED_P (insn))
4607 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4610 last = try_split (PATTERN (insn), insn, 1);
4612 /* When not optimizing, the old insn will be still left around
4613 with only the 'deleted' bit set. Transform it into a note
4614 to avoid confusion of subsequent processing. */
4615 if (INSN_DELETED_P (insn))
4617 PUT_CODE (insn, NOTE);
4618 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4619 NOTE_SOURCE_FILE (insn) = 0;
4625 PUT_CODE (insn, NOTE);
4626 NOTE_SOURCE_FILE (insn) = 0;
4627 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4633 #endif /* GCC_VERSION == 2095 */
4636 m68hc11_reorg (first)
4641 z_replacement_completed = 0;
4642 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4644 #if GCC_VERSION > 2095
4645 /* Some RTX are shared at this point. This breaks the Z register
4646 replacement, unshare everything. */
4647 unshare_all_rtl_again (first);
4650 /* Force a split of all splitable insn. This is necessary for the
4651 Z register replacement mechanism because we end up with basic insns. */
4652 #if GCC_VERSION > 2095
4653 split_all_insns (0);
4656 split_done = m68hc11_split_all_insns (first);
4659 z_replacement_completed = 1;
4660 m68hc11_reassign_regs (first);
4662 /* After some splitting, there are some oportunities for CSE pass.
4663 This happens quite often when 32-bit or above patterns are split. */
4664 if (optimize > 0 && split_done)
4665 reload_cse_regs (first);
4667 /* Re-create the REG_DEAD notes. These notes are used in the machine
4668 description to use the best assembly directives. */
4671 #if GCC_VERSION > 2095
4672 find_basic_blocks (first, max_reg_num (), 0);
4673 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
4675 find_basic_blocks (first, max_reg_num (), 0, 1);
4676 life_analysis (first, max_reg_num (), 0,
4677 1 /* SCz: dead code elim fails. Must investigate. */ );
4681 z_replacement_completed = 2;
4683 /* If optimizing, then go ahead and split insns that must be
4684 split after Z register replacement. This gives more opportunities
4685 for peephole (in particular for consecutives xgdx/xgdy). */
4687 #if GCC_VERSION > 2095
4688 split_all_insns (0);
4690 m68hc11_split_all_insns (first);
4693 /* Once insns are split after the z_replacement_completed == 2,
4694 we must not re-run the life_analysis. The xgdx/xgdy patterns
4695 are not recognized and the life_analysis pass removes some
4696 insns because it thinks some (SETs) are noops or made to dead
4697 stores (which is false due to the swap).
4699 Do a simple pass to eliminate the noop set that the final
4700 split could generate (because it was easier for split definition). */
4704 for (insn = first; insn; insn = NEXT_INSN (insn))
4708 if (INSN_DELETED_P (insn))
4710 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4713 /* Remove the (set (R) (R)) insns generated by some splits. */
4714 body = PATTERN (insn);
4715 if (GET_CODE (body) == SET
4716 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
4718 PUT_CODE (insn, NOTE);
4719 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4720 NOTE_SOURCE_FILE (insn) = 0;
4728 /* Cost functions. */
4730 #define COSTS_N_INSNS(N) ((N) * 4 - 2)
4732 /* Cost of moving memory. */
4734 m68hc11_memory_move_cost (mode, class, in)
4735 enum machine_mode mode;
4736 enum reg_class class;
4737 int in ATTRIBUTE_UNUSED;
4739 if (class <= H_REGS)
4741 if (GET_MODE_SIZE (mode) <= 2)
4742 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4744 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
4748 if (GET_MODE_SIZE (mode) <= 2)
4749 return COSTS_N_INSNS (2);
4751 return COSTS_N_INSNS (4);
4756 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4757 Reload does not check the constraint of set insns when the two registers
4758 have a move cost of 2. Setting a higher cost will force reload to check
4761 m68hc11_register_move_cost (from, to)
4762 enum reg_class from;
4765 if (from >= S_REGS && to >= S_REGS)
4767 return COSTS_N_INSNS (3);
4769 if (from <= S_REGS && to <= S_REGS)
4771 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4773 return COSTS_N_INSNS (2);
4777 /* Provide the costs of an addressing mode that contains ADDR.
4778 If ADDR is not a valid address, its cost is irrelevant. */
4781 m68hc11_address_cost (addr)
4786 switch (GET_CODE (addr))
4789 /* Make the cost of hard registers and specially SP, FP small. */
4790 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
4807 register rtx plus0 = XEXP (addr, 0);
4808 register rtx plus1 = XEXP (addr, 1);
4810 if (GET_CODE (plus0) != REG)
4813 switch (GET_CODE (plus1))
4816 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
4817 || INTVAL (plus1) < m68hc11_min_offset)
4819 else if (INTVAL (plus1) >= m68hc11_max_offset)
4823 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
4845 if (SP_REG_P (XEXP (addr, 0)))
4854 printf ("Address cost: %d for :", cost);
4863 m68hc11_rtx_costs (x, code, outer_code)
4865 enum rtx_code code, outer_code;
4867 enum machine_mode mode = GET_MODE (x);
4874 return m68hc11_address_cost (XEXP (x, 0)) + 4;
4881 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4883 int val = INTVAL (XEXP (x, 1));
4886 /* 8 or 16 shift instructions are fast.
4887 Others are proportional to the shift counter. */
4888 if (val == 8 || val == 16 || val == -8 || val == -16)
4892 cost = COSTS_N_INSNS (val + 1);
4893 cost += rtx_cost (XEXP (x, 0), outer_code);
4894 if (GET_MODE_SIZE (mode) >= 4 && val)
4900 total = rtx_cost (XEXP (x, 0), outer_code);
4901 if (GET_MODE_SIZE (mode) >= 4)
4903 total += COSTS_N_INSNS (16);
4907 total += COSTS_N_INSNS (8);
4918 total = rtx_cost (XEXP (x, 0), outer_code)
4919 + rtx_cost (XEXP (x, 1), outer_code);
4920 if (GET_MODE_SIZE (mode) <= 2)
4922 total += COSTS_N_INSNS (2);
4926 total += COSTS_N_INSNS (4);
4932 if (mode == QImode || mode == HImode)
4936 else if (mode == SImode)
4948 return TARGET_OP_TIME ? 10 : 2;
4952 return TARGET_OP_TIME ? 30 : 4;
4956 return TARGET_OP_TIME ? 100 : 20;
4962 extra_cost = COSTS_N_INSNS (2);
4969 total = rtx_cost (XEXP (x, 0), outer_code);
4972 return total + extra_cost + COSTS_N_INSNS (1);
4976 return total + extra_cost + COSTS_N_INSNS (2);
4980 return total + extra_cost + COSTS_N_INSNS (4);
4982 return total + extra_cost + COSTS_N_INSNS (8);
4985 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
4986 return COSTS_N_INSNS (1);
4988 return COSTS_N_INSNS (1);
4991 return COSTS_N_INSNS (4);
4996 /* print_options - called at the start of the code generation for a
4999 #if GCC_VERSION == 2095
5000 extern char *main_input_filename;
5002 extern char *asm_file_name;
5005 #include <sys/types.h>
5014 extern int save_argc;
5015 extern char **save_argv;
5017 fprintf (out, ";;; Command:\t");
5018 for (i = 0; i < save_argc; i++)
5020 fprintf (out, "%s", save_argv[i]);
5021 if (i + 1 < save_argc)
5024 fprintf (out, "\n");
5026 a_time = ctime (&c_time);
5027 fprintf (out, ";;; Compiled:\t%s", a_time);
5030 #define __VERSION__ "[unknown]"
5032 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
5034 fprintf (out, ";;; (META)compiled by CC.\n");
5039 m68hc11_asm_file_start (out, main_file)
5043 fprintf (out, ";;;-----------------------------------------\n");
5044 fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
5045 fprintf (out, ";;; gcc compiler %s\n", version_string);
5046 print_options (out);
5047 fprintf (out, ";;;-----------------------------------------\n");
5048 output_file_directive (out, main_file);
5053 m68hc11_add_gc_roots ()
5055 #if GCC_VERSION > 2095
5056 ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
5057 ggc_add_rtx_root (&ix_reg, 1);
5058 ggc_add_rtx_root (&iy_reg, 1);
5059 ggc_add_rtx_root (&d_reg, 1);
5060 ggc_add_rtx_root (&da_reg, 1);
5061 ggc_add_rtx_root (&z_reg, 1);
5062 ggc_add_rtx_root (&z_reg_qi, 1);
5063 ggc_add_rtx_root (&stack_push_word, 1);
5064 ggc_add_rtx_root (&stack_pop_word, 1);