1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@worldnet.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
23 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24 on gcc 2.6.3. I have used it as a starting point for this port.
25 However, this new port is a complete re-write. Its internal
26 design is completely different. The generated code is not
27 compatible with the gcc 2.6.3 port.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
42 #include "hard-reg-set.h"
44 #include "insn-config.h"
45 #include "conditions.h"
47 #include "insn-attr.h"
52 #include "basic-block.h"
56 #include "target-def.h"
58 static void print_options PARAMS ((FILE *));
59 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
60 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
61 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
62 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
64 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
65 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
66 static int must_parenthesize PARAMS ((rtx));
67 static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
68 static int m68hc11_auto_inc_p PARAMS ((rtx));
69 static int m68hc11_valid_type_attribute_p PARAMS((tree, tree,
72 void create_regs_rtx PARAMS ((void));
74 static void asm_print_register PARAMS ((FILE *, int));
76 rtx m68hc11_soft_tmp_reg;
78 /* Must be set to 1 to produce debug messages. */
81 extern FILE *asm_out_file;
89 static int regs_inited = 0;
92 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
93 int current_function_interrupt;
95 /* Set to 1 by expand_prologue() when the function is a trap handler. */
96 int current_function_trap;
98 /* Min offset that is valid for the indirect addressing mode. */
99 HOST_WIDE_INT m68hc11_min_offset = 0;
101 /* Max offset that is valid for the indirect addressing mode. */
102 HOST_WIDE_INT m68hc11_max_offset = 256;
104 /* The class value for base registers. */
105 enum reg_class m68hc11_base_reg_class = A_REGS;
107 /* The class value for index registers. This is NO_REGS for 68HC11. */
108 enum reg_class m68hc11_index_reg_class = NO_REGS;
110 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
112 /* Tables that tell whether a given hard register is valid for
113 a base or an index register. It is filled at init time depending
114 on the target processor. */
115 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
116 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
118 /* A correction offset which is applied to the stack pointer.
119 This is 1 for 68HC11 and 0 for 68HC12. */
120 int m68hc11_sp_correction;
122 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
123 rtx m68hc11_compare_op0;
124 rtx m68hc11_compare_op1;
127 struct processor_costs *m68hc11_cost;
129 /* Costs for a 68HC11. */
130 struct processor_costs m6811_cost = {
135 /* non-constant shift */
138 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
139 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
140 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
143 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
144 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
145 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
146 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
147 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
148 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
153 COSTS_N_INSNS (20 * 4),
155 COSTS_N_INSNS (20 * 16),
164 /* Costs for a 68HC12. */
165 struct processor_costs m6812_cost = {
170 /* non-constant shift */
173 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
174 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
175 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
178 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
179 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
180 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
181 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
182 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
183 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
190 COSTS_N_INSNS (3 * 4),
199 /* Machine specific options */
201 const char *m68hc11_regparm_string;
202 const char *m68hc11_reg_alloc_order;
203 const char *m68hc11_soft_reg_count;
205 static void m68hc11_add_gc_roots PARAMS ((void));
207 static int nb_soft_regs;
209 /* Initialize the GCC target structure. */
210 #undef TARGET_VALID_TYPE_ATTRIBUTE
211 #define TARGET_VALID_TYPE_ATTRIBUTE m68hc11_valid_type_attribute_p
213 struct gcc_target target = TARGET_INITIALIZER;
216 m68hc11_override_options ()
218 m68hc11_add_gc_roots ();
220 memset (m68hc11_reg_valid_for_index, 0,
221 sizeof (m68hc11_reg_valid_for_index));
222 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
224 /* Compilation with -fpic generates a wrong code. */
227 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
228 (flag_pic > 1) ? "PIC" : "pic");
232 /* Configure for a 68hc11 processor. */
235 /* If gcc was built for a 68hc12, invalidate that because
236 a -m68hc11 option was specified on the command line. */
237 if (TARGET_DEFAULT != MASK_M6811)
238 target_flags &= ~TARGET_DEFAULT;
240 m68hc11_cost = &m6811_cost;
241 m68hc11_min_offset = 0;
242 m68hc11_max_offset = 256;
243 m68hc11_index_reg_class = NO_REGS;
244 m68hc11_base_reg_class = A_REGS;
245 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
246 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
247 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
248 m68hc11_sp_correction = 1;
249 m68hc11_tmp_regs_class = D_REGS;
250 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
251 m68hc11_soft_reg_count = "4";
254 /* Configure for a 68hc12 processor. */
257 m68hc11_cost = &m6812_cost;
258 m68hc11_min_offset = -65536;
259 m68hc11_max_offset = 65536;
260 m68hc11_index_reg_class = D_REGS;
261 m68hc11_base_reg_class = A_OR_SP_REGS;
262 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
263 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
264 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
265 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
266 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
267 m68hc11_sp_correction = 0;
268 m68hc11_tmp_regs_class = TMP_REGS;
269 target_flags &= ~MASK_M6811;
270 if (m68hc11_soft_reg_count == 0)
271 m68hc11_soft_reg_count = "2";
278 m68hc11_conditional_register_usage ()
281 int cnt = atoi (m68hc11_soft_reg_count);
285 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
286 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
289 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
292 call_used_regs[i] = 1;
297 /* Reload and register operations. */
299 static const char *reg_class_names[] = REG_CLASS_NAMES;
305 /* regs_inited = 1; */
306 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
307 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
308 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
309 da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
310 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
312 stack_push_word = gen_rtx (MEM, HImode,
313 gen_rtx (PRE_DEC, HImode,
314 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
315 stack_pop_word = gen_rtx (MEM, HImode,
316 gen_rtx (POST_INC, HImode,
317 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
321 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
322 - 8 bit values are stored anywhere (except the SP register).
323 - 16 bit values can be stored in any register whose mode is 16
324 - 32 bit values can be stored in D, X registers or in a soft register
325 (except the last one because we need 2 soft registers)
326 - Values whose size is > 32 bit are not stored in real hard
327 registers. They may be stored in soft registers if there are
330 hard_regno_mode_ok (regno, mode)
332 enum machine_mode mode;
334 switch (GET_MODE_SIZE (mode))
337 return S_REGNO_P (regno) && nb_soft_regs >= 4;
340 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
343 return G_REGNO_P (regno);
346 /* We have to accept a QImode in X or Y registers. Otherwise, the
347 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
348 in the insns. Reload fails if the insn rejects the register class 'a'
349 as well as if it accepts it. Patterns that failed were
350 zero_extend_qihi2 and iorqi3. */
352 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
360 preferred_reload_class (operand, class)
362 enum reg_class class;
364 enum machine_mode mode;
366 mode = GET_MODE (operand);
370 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
373 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
374 return m68hc11_base_reg_class;
376 if (class >= S_REGS && (GET_CODE (operand) == MEM
377 || GET_CODE (operand) == CONST_INT))
379 /* S_REGS class must not be used. The movhi template does not
380 work to move a memory to a soft register.
381 Restrict to a hard reg. */
386 case D_OR_A_OR_S_REGS:
392 case D_OR_SP_OR_S_REGS:
393 class = D_OR_SP_REGS;
395 case D_OR_Y_OR_S_REGS:
398 case D_OR_X_OR_S_REGS:
414 else if (class == Y_REGS && GET_CODE (operand) == MEM)
418 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
422 else if (class >= S_REGS && S_REG_P (operand))
428 case D_OR_A_OR_S_REGS:
434 case D_OR_SP_OR_S_REGS:
435 class = D_OR_SP_REGS;
437 case D_OR_Y_OR_S_REGS:
440 case D_OR_X_OR_S_REGS:
456 else if (class >= S_REGS)
460 printf ("Class = %s for: ", reg_class_names[class]);
468 printf (" => class=%s\n", reg_class_names[class]);
476 /* Return 1 if the operand is a valid indexed addressing mode.
477 For 68hc11: n,r with n in [0..255] and r in A_REGS class
478 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
480 register_indirect_p (operand, mode, strict)
482 enum machine_mode mode;
487 switch (GET_CODE (operand))
493 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
494 return register_indirect_p (XEXP (operand, 0), mode, strict);
498 base = XEXP (operand, 0);
499 if (GET_CODE (base) == MEM)
502 offset = XEXP (operand, 1);
503 if (GET_CODE (offset) == MEM)
506 if (GET_CODE (base) == REG)
508 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
514 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
516 if (GET_CODE (offset) == REG)
518 if (!VALID_CONSTANT_OFFSET_P (base, mode))
524 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
529 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
536 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
537 a 68HC12 1-byte index addressing mode. */
539 m68hc11_small_indexed_indirect_p (operand, mode)
541 enum machine_mode mode;
545 if (GET_CODE (operand) != MEM)
548 operand = XEXP (operand, 0);
549 if (CONSTANT_ADDRESS_P (operand))
552 if (PUSH_POP_ADDRESS_P (operand))
555 if (!register_indirect_p (operand, mode,
556 (reload_completed | reload_in_progress)))
559 if (TARGET_M6812 && GET_CODE (operand) == PLUS
560 && (reload_completed | reload_in_progress))
562 base = XEXP (operand, 0);
563 offset = XEXP (operand, 1);
564 if (GET_CODE (base) == CONST_INT)
567 switch (GET_MODE_SIZE (mode))
570 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
575 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
580 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
589 m68hc11_register_indirect_p (operand, mode)
591 enum machine_mode mode;
593 if (GET_CODE (operand) != MEM)
596 operand = XEXP (operand, 0);
597 return register_indirect_p (operand, mode,
598 (reload_completed | reload_in_progress));
602 go_if_legitimate_address_internal (operand, mode, strict)
604 enum machine_mode mode;
607 if (CONSTANT_ADDRESS_P (operand))
609 /* Reject the global variables if they are too wide. This forces
610 a load of their address in a register and generates smaller code. */
611 if (GET_MODE_SIZE (mode) == 8)
616 if (register_indirect_p (operand, mode, strict))
620 if (PUSH_POP_ADDRESS_P (operand))
624 if (symbolic_memory_operand (operand, mode))
632 m68hc11_go_if_legitimate_address (operand, mode, strict)
634 enum machine_mode mode;
641 printf ("Checking: ");
646 result = go_if_legitimate_address_internal (operand, mode, strict);
650 printf (" -> %s\n", result == 0 ? "NO" : "YES");
657 printf ("go_if_legitimate%s, ret 0: %d:",
658 (strict ? "_strict" : ""), mode);
667 m68hc11_legitimize_address (operand, old_operand, mode)
668 rtx *operand ATTRIBUTE_UNUSED;
669 rtx old_operand ATTRIBUTE_UNUSED;
670 enum machine_mode mode ATTRIBUTE_UNUSED;
677 m68hc11_reload_operands (operands)
680 enum machine_mode mode;
682 if (regs_inited == 0)
685 mode = GET_MODE (operands[1]);
687 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
688 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
690 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
691 rtx base = XEXP (XEXP (operands[1], 0), 0);
693 if (GET_CODE (base) != REG)
700 /* If the offset is out of range, we have to compute the address
701 with a separate add instruction. We try to do with with an 8-bit
702 add on the A register. This is possible only if the lowest part
703 of the offset (ie, big_offset % 256) is a valid constant offset
704 with respect to the mode. If it's not, we have to generate a
705 16-bit add on the D register. From:
707 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
711 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
712 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
713 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
714 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
716 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
717 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
720 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
723 rtx reg = operands[0];
725 int val = INTVAL (big_offset);
728 /* We use the 'operands[0]' as a scratch register to compute the
729 address. Make sure 'base' is in that register. */
730 if (!rtx_equal_p (base, operands[0]))
732 emit_move_insn (reg, base);
742 vh = (val >> 8) & 0x0FF;
746 /* Create the lowest part offset that still remains to be added.
747 If it's not a valid offset, do a 16-bit add. */
748 offset = gen_rtx (CONST_INT, VOIDmode, vl);
749 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
751 emit_insn (gen_rtx (SET, VOIDmode, reg,
752 gen_rtx (PLUS, HImode, reg, big_offset)));
757 emit_insn (gen_rtx (SET, VOIDmode, reg,
758 gen_rtx (PLUS, HImode, reg,
760 VOIDmode, vh << 8))));
762 emit_move_insn (operands[0],
763 gen_rtx (MEM, GET_MODE (operands[1]),
764 gen_rtx (PLUS, Pmode, reg, offset)));
769 /* Use the normal gen_movhi pattern. */
774 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
777 enum machine_mode dmode;
778 enum machine_mode smode;
788 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
792 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
793 dmode, 1, operands[1], smode);
794 equiv = gen_rtx (code, dmode, operands[1]);
798 ret = emit_library_call_value (libcall, NULL_RTX,
800 operands[1], smode, operands[2],
802 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
809 insns = get_insns ();
811 emit_libcall_block (insns, operands[0], ret, equiv);
814 /* Returns true if X is a PRE/POST increment decrement
815 (same as auto_inc_p() in rtlanal.c but do not take into
816 account the stack). */
818 m68hc11_auto_inc_p (x)
821 return GET_CODE (x) == PRE_DEC
822 || GET_CODE (x) == POST_INC
823 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
827 /* Predicates for machine description. */
830 memory_reload_operand (operand, mode)
832 enum machine_mode mode ATTRIBUTE_UNUSED;
834 return GET_CODE (operand) == MEM
835 && GET_CODE (XEXP (operand, 0)) == PLUS
836 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
837 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
838 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
839 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
843 tst_operand (operand, mode)
845 enum machine_mode mode;
847 if (GET_CODE (operand) == MEM)
849 rtx addr = XEXP (operand, 0);
850 if (m68hc11_auto_inc_p (addr))
853 return nonimmediate_operand (operand, mode);
857 cmp_operand (operand, mode)
859 enum machine_mode mode;
861 if (GET_CODE (operand) == MEM)
863 rtx addr = XEXP (operand, 0);
864 if (m68hc11_auto_inc_p (addr))
867 return general_operand (operand, mode);
871 non_push_operand (operand, mode)
873 enum machine_mode mode;
875 if (general_operand (operand, mode) == 0)
878 if (push_operand (operand, mode) == 1)
884 reg_or_some_mem_operand (operand, mode)
886 enum machine_mode mode;
888 if (GET_CODE (operand) == MEM)
890 rtx op = XEXP (operand, 0);
892 if (symbolic_memory_operand (op, mode))
895 if (IS_STACK_PUSH (operand))
898 if (m68hc11_register_indirect_p (operand, mode))
904 return register_operand (operand, mode);
908 stack_register_operand (operand, mode)
910 enum machine_mode mode ATTRIBUTE_UNUSED;
912 return SP_REG_P (operand);
916 d_register_operand (operand, mode)
918 enum machine_mode mode ATTRIBUTE_UNUSED;
920 if (GET_CODE (operand) == SUBREG)
921 operand = XEXP (operand, 0);
923 return GET_CODE (operand) == REG
924 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
925 || REGNO (operand) == HARD_D_REGNUM);
929 hard_addr_reg_operand (operand, mode)
931 enum machine_mode mode ATTRIBUTE_UNUSED;
933 if (GET_CODE (operand) == SUBREG)
934 operand = XEXP (operand, 0);
936 return GET_CODE (operand) == REG
937 && (REGNO (operand) == HARD_X_REGNUM
938 || REGNO (operand) == HARD_Y_REGNUM
939 || REGNO (operand) == HARD_Z_REGNUM);
943 hard_reg_operand (operand, mode)
945 enum machine_mode mode ATTRIBUTE_UNUSED;
947 if (GET_CODE (operand) == SUBREG)
948 operand = XEXP (operand, 0);
950 return GET_CODE (operand) == REG
951 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
952 || H_REGNO_P (REGNO (operand)));
956 memory_indexed_operand (operand, mode)
958 enum machine_mode mode ATTRIBUTE_UNUSED;
960 if (GET_CODE (operand) != MEM)
963 operand = XEXP (operand, 0);
964 if (GET_CODE (operand) == PLUS)
966 if (GET_CODE (XEXP (operand, 0)) == REG)
967 operand = XEXP (operand, 0);
968 else if (GET_CODE (XEXP (operand, 1)) == REG)
969 operand = XEXP (operand, 1);
971 return GET_CODE (operand) == REG
972 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
973 || A_REGNO_P (REGNO (operand)));
977 push_pop_operand_p (operand)
980 if (GET_CODE (operand) != MEM)
984 operand = XEXP (operand, 0);
985 return PUSH_POP_ADDRESS_P (operand);
988 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
989 reference and a constant. */
992 symbolic_memory_operand (op, mode)
994 enum machine_mode mode;
996 switch (GET_CODE (op))
1003 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1004 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1005 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1007 /* ??? This clause seems to be irrelevant. */
1009 return GET_MODE (op) == mode;
1012 return symbolic_memory_operand (XEXP (op, 0), mode)
1013 && symbolic_memory_operand (XEXP (op, 1), mode);
1021 m68hc11_logical_operator (op, mode)
1023 enum machine_mode mode ATTRIBUTE_UNUSED;
1025 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1029 m68hc11_arith_operator (op, mode)
1031 enum machine_mode mode ATTRIBUTE_UNUSED;
1033 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1034 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1035 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1036 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1037 || GET_CODE (op) == ROTATERT;
1041 m68hc11_non_shift_operator (op, mode)
1043 enum machine_mode mode ATTRIBUTE_UNUSED;
1045 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1046 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1051 m68hc11_unary_operator (op, mode)
1053 enum machine_mode mode ATTRIBUTE_UNUSED;
1055 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1056 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1063 m68hc11_block_profiler (out, blockno)
1064 FILE *out ATTRIBUTE_UNUSED;
1065 int blockno ATTRIBUTE_UNUSED;
1071 m68hc11_function_block_profiler (out, block_or_label)
1072 FILE *out ATTRIBUTE_UNUSED;
1073 int block_or_label ATTRIBUTE_UNUSED;
1078 /* Emit the code to build the trampoline used to call a nested function.
1082 ldy #&CXT movw #&CXT,*_.d1
1083 sty *_.d1 jmp FNADDR
1088 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
1093 char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1096 if (*static_chain_reg == '*')
1100 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1101 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1102 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1104 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1105 gen_rtx_CONST (QImode,
1106 gen_rtx_SYMBOL_REF (Pmode,
1107 static_chain_reg)));
1108 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1110 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1114 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1115 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1116 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1117 gen_rtx_CONST (HImode,
1118 gen_rtx_SYMBOL_REF (Pmode,
1119 static_chain_reg)));
1120 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1122 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1126 /* Declaration of types. */
1128 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1129 with arguments ARGS is a valid machine specific attribute for TYPE.
1130 The attributes in ATTRIBUTES have previously been assigned to TYPE. */
1133 m68hc11_valid_type_attribute_p (type, attributes, identifier, args)
1135 tree attributes ATTRIBUTE_UNUSED;
1139 if (TREE_CODE (type) != FUNCTION_TYPE
1140 && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL)
1143 if (TREE_CODE (type) == FUNCTION_TYPE)
1145 if (is_attribute_p ("interrupt", identifier))
1146 return (args == NULL_TREE);
1147 if (is_attribute_p ("trap", identifier))
1148 return (args == NULL_TREE);
1154 /* Define this macro if references to a symbol must be treated
1155 differently depending on something about the variable or function
1156 named by the symbol (such as what section it is in).
1158 For the 68HC11, we want to recognize trap handlers so that we
1159 handle calls to traps in a special manner (by issuing the trap).
1160 This information is stored in SYMBOL_REF_FLAG. */
1162 m68hc11_encode_section_info (decl)
1169 if (TREE_CODE (decl) != FUNCTION_DECL)
1172 rtl = DECL_RTL (decl);
1174 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1175 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1176 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
1180 /* Argument support functions. */
1182 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1183 Arrays are passed by references and other types by value.
1185 SCz: I tried to pass DImode by reference but it seems that this
1186 does not work very well. */
1188 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1189 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1190 enum machine_mode mode ATTRIBUTE_UNUSED;
1192 int named ATTRIBUTE_UNUSED;
1194 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1195 /* Consider complex values as aggregates, so care for TCmode. */
1196 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1197 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1201 /* Define the offset between two registers, one to be eliminated, and the
1202 other its replacement, at the start of a routine. */
1204 m68hc11_initial_elimination_offset (from, to)
1213 /* For a trap handler, we must take into account the registers which
1214 are pushed on the stack during the trap (except the PC). */
1215 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1216 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1217 if (trap_handler && from == ARG_POINTER_REGNUM)
1222 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1224 /* 2 is for the saved frame.
1225 1 is for the 'sts' correction when creating the frame. */
1226 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1229 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1234 /* Push any 2 byte pseudo hard registers that we need to save. */
1235 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1237 if (regs_ever_live[regno] && !call_used_regs[regno])
1243 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1245 return get_frame_size () + size;
1248 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1250 return size - m68hc11_sp_correction;
1255 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1256 for a call to a function whose data type is FNTYPE.
1257 For a library call, FNTYPE is 0. */
1260 m68hc11_init_cumulative_args (cum, fntype, libname)
1261 CUMULATIVE_ARGS *cum;
1267 z_replacement_completed = 0;
1271 /* For a library call, we must find out the type of the return value.
1272 When the return value is bigger than 4 bytes, it is returned in
1273 memory. In that case, the first argument of the library call is a
1274 pointer to the memory location. Because the first argument is passed in
1275 register D, we have to identify this, so that the first function
1276 parameter is not passed in D either. */
1282 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1285 /* If the library ends in 'di' or in 'df', we assume it's
1286 returning some DImode or some DFmode which are 64-bit wide. */
1287 name = XSTR (libname, 0);
1288 len = strlen (name);
1290 && ((name[len - 2] == 'd'
1291 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1292 || (name[len - 3] == 'd'
1293 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1295 /* We are in. Mark the first parameter register as already used. */
1302 ret_type = TREE_TYPE (fntype);
1304 if (ret_type && aggregate_value_p (ret_type))
1311 /* Update the data in CUM to advance over an argument
1312 of mode MODE and data type TYPE.
1313 (TYPE is null for libcalls where that information may not be available.) */
1316 m68hc11_function_arg_advance (cum, mode, type, named)
1317 CUMULATIVE_ARGS *cum;
1318 enum machine_mode mode;
1320 int named ATTRIBUTE_UNUSED;
1322 if (mode != BLKmode)
1324 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1327 cum->words = GET_MODE_SIZE (mode);
1331 cum->words += GET_MODE_SIZE (mode);
1332 if (cum->words <= HARD_REG_SIZE)
1338 cum->words += int_size_in_bytes (type);
1343 /* Define where to put the arguments to a function.
1344 Value is zero to push the argument on the stack,
1345 or a hard register in which to store the argument.
1347 MODE is the argument's machine mode.
1348 TYPE is the data type of the argument (as a tree).
1349 This is null for libcalls where that information may
1351 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1352 the preceding args and about the function being called.
1353 NAMED is nonzero if this argument is a named parameter
1354 (otherwise it is an extra parameter matching an ellipsis). */
1357 m68hc11_function_arg (cum, mode, type, named)
1358 const CUMULATIVE_ARGS *cum;
1359 enum machine_mode mode;
1360 tree type ATTRIBUTE_UNUSED;
1361 int named ATTRIBUTE_UNUSED;
1363 if (cum->words != 0)
1368 if (mode != BLKmode)
1370 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1371 return gen_rtx (REG, mode, HARD_X_REGNUM);
1373 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1377 return gen_rtx (REG, mode, HARD_D_REGNUM);
1382 /* The "standard" implementation of va_start: just assign `nextarg' to
1385 m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
1386 int stdarg_p ATTRIBUTE_UNUSED;
1392 /* SCz: the default implementation in builtins.c adjust the
1393 nextarg using UNITS_PER_WORD. This works only with -mshort
1394 and fails when integers are 32-bit. Here is the correct way. */
1396 nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
1398 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1399 make_tree (ptr_type_node, nextarg));
1400 TREE_SIDE_EFFECTS (t) = 1;
1402 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1406 m68hc11_va_arg (valist, type)
1411 HOST_WIDE_INT align;
1412 HOST_WIDE_INT rounded_size;
1416 /* Compute the rounded size of the type. */
1417 align = PARM_BOUNDARY / BITS_PER_UNIT;
1418 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1422 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
1424 if (pad_direction == downward)
1426 /* Small args are padded downward. */
1429 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1430 if (rounded_size > align)
1433 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1434 build_int_2 (rounded_size - adj, 0));
1437 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1438 addr = copy_to_reg (addr);
1440 /* Compute new value for AP. */
1441 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1442 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1443 build_int_2 (rounded_size, 0)));
1444 TREE_SIDE_EFFECTS (t) = 1;
1445 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1450 /* If defined, a C expression which determines whether, and in which direction,
1451 to pad out an argument with extra space. The value should be of type
1452 `enum direction': either `upward' to pad above the argument,
1453 `downward' to pad below, or `none' to inhibit padding.
1455 Structures are stored left shifted in their argument slot. */
1457 m68hc11_function_arg_padding (mode, type)
1458 enum machine_mode mode;
1461 if (type != 0 && AGGREGATE_TYPE_P (type))
1464 /* This is the default definition. */
1465 return (!BYTES_BIG_ENDIAN
1468 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1469 && int_size_in_bytes (type) <
1470 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1471 PARM_BOUNDARY) ? downward : upward));
1475 /* Function prologue and epilogue. */
1477 /* Emit a move after the reload pass has completed. This is used to
1478 emit the prologue and epilogue. */
1480 emit_move_after_reload (to, from, scratch)
1481 rtx to, from, scratch;
1485 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1487 insn = emit_move_insn (to, from);
1491 emit_move_insn (scratch, from);
1492 insn = emit_move_insn (to, scratch);
1495 /* Put a REG_INC note to tell the flow analysis that the instruction
1497 if (IS_STACK_PUSH (to))
1499 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1500 XEXP (XEXP (to, 0), 0),
1503 else if (IS_STACK_POP (from))
1505 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1506 XEXP (XEXP (from, 0), 0),
1512 m68hc11_total_frame_size ()
1517 size = get_frame_size ();
1518 if (current_function_interrupt)
1520 size += 3 * HARD_REG_SIZE;
1522 if (frame_pointer_needed)
1523 size += HARD_REG_SIZE;
1525 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1526 if (regs_ever_live[regno] && !call_used_regs[regno])
1527 size += HARD_REG_SIZE;
1533 m68hc11_function_epilogue (out, size)
1534 FILE *out ATTRIBUTE_UNUSED;
1535 int size ATTRIBUTE_UNUSED;
1537 /* We catch the function epilogue generation to have a chance
1538 to clear the z_replacement_completed flag. */
1539 z_replacement_completed = 0;
1550 if (reload_completed != 1)
1553 size = get_frame_size ();
1557 /* Generate specific prologue for interrupt handlers. */
1558 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1559 current_function_interrupt = lookup_attribute ("interrupt",
1560 func_attr) != NULL_TREE;
1561 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1563 /* Get the scratch register to build the frame and push registers.
1564 If the first argument is a 32-bit quantity, the D+X registers
1565 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1566 For 68HC12, this scratch register is not used. */
1567 if (current_function_args_info.nregs == 2)
1572 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1573 Other soft registers in page0 need not to be saved because they
1574 will be restored by C functions. For a trap handler, we don't
1575 need to preserve these registers because this is a synchronous call. */
1576 if (current_function_interrupt)
1578 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1579 emit_move_after_reload (stack_push_word,
1580 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1581 emit_move_after_reload (stack_push_word,
1582 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1586 /* Save current stack frame. */
1587 if (frame_pointer_needed)
1588 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1590 /* Allocate local variables. */
1591 if (TARGET_M6812 && size >= 2)
1593 emit_insn (gen_addhi3 (stack_pointer_rtx,
1594 stack_pointer_rtx, GEN_INT (-size)));
1600 insn = gen_rtx_PARALLEL
1603 gen_rtx_SET (VOIDmode,
1605 gen_rtx_PLUS (HImode,
1608 gen_rtx_CLOBBER (VOIDmode, scratch)));
1615 /* Allocate by pushing scratch values. */
1616 for (i = 2; i <= size; i += 2)
1617 emit_move_after_reload (stack_push_word, ix_reg, 0);
1620 emit_insn (gen_addhi3 (stack_pointer_rtx,
1621 stack_pointer_rtx, GEN_INT (-1)));
1624 /* Create the frame pointer. */
1625 if (frame_pointer_needed)
1626 emit_move_after_reload (hard_frame_pointer_rtx,
1627 stack_pointer_rtx, scratch);
1629 /* Push any 2 byte pseudo hard registers that we need to save. */
1630 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1632 if (regs_ever_live[regno] && !call_used_regs[regno])
1634 emit_move_after_reload (stack_push_word,
1635 gen_rtx (REG, HImode, regno), scratch);
1648 if (reload_completed != 1)
1651 size = get_frame_size ();
1653 /* If we are returning a value in two registers, we have to preserve the
1654 X register and use the Y register to restore the stack and the saved
1655 registers. Otherwise, use X because it's faster (and smaller). */
1656 if (current_function_return_rtx == 0)
1658 else if (GET_CODE (current_function_return_rtx) == MEM)
1659 return_size = HARD_REG_SIZE;
1661 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1663 if (return_size > HARD_REG_SIZE)
1668 /* Pop any 2 byte pseudo hard registers that we saved. */
1669 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1671 if (regs_ever_live[regno] && !call_used_regs[regno])
1673 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1674 stack_pop_word, scratch);
1678 /* de-allocate auto variables */
1679 if (TARGET_M6812 && size >= 2)
1681 emit_insn (gen_addhi3 (stack_pointer_rtx,
1682 stack_pointer_rtx, GEN_INT (size)));
1688 insn = gen_rtx_PARALLEL
1691 gen_rtx_SET (VOIDmode,
1693 gen_rtx_PLUS (HImode,
1696 gen_rtx_CLOBBER (VOIDmode, scratch)));
1703 for (i = 2; i <= size; i += 2)
1704 emit_move_after_reload (scratch, stack_pop_word, scratch);
1706 emit_insn (gen_addhi3 (stack_pointer_rtx,
1707 stack_pointer_rtx, GEN_INT (1)));
1710 /* Restore previous frame pointer. */
1711 if (frame_pointer_needed)
1712 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1714 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1715 if (current_function_interrupt)
1717 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1718 stack_pop_word, scratch);
1719 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1720 stack_pop_word, scratch);
1721 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1724 /* If the trap handler returns some value, copy the value
1725 in D, X onto the stack so that the rti will pop the return value
1727 else if (current_function_trap && return_size != 0)
1729 rtx addr_reg = stack_pointer_rtx;
1733 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1736 emit_move_after_reload (gen_rtx (MEM, HImode,
1737 gen_rtx (PLUS, HImode, addr_reg,
1738 GEN_INT (1))), d_reg, 0);
1739 if (return_size > HARD_REG_SIZE)
1740 emit_move_after_reload (gen_rtx (MEM, HImode,
1741 gen_rtx (PLUS, HImode, addr_reg,
1742 GEN_INT (3))), ix_reg, 0);
1745 emit_jump_insn (gen_return ());
1749 /* Low and High part extraction for 68HC11. These routines are
1750 similar to gen_lowpart and gen_highpart but they have been
1751 fixed to work for constants and 68HC11 specific registers. */
1754 m68hc11_gen_lowpart (mode, x)
1755 enum machine_mode mode;
1758 /* We assume that the low part of an auto-inc mode is the same with
1759 the mode changed and that the caller split the larger mode in the
1761 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1763 return gen_rtx (MEM, mode, XEXP (x, 0));
1766 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1767 floating-point constant. A CONST_DOUBLE is used whenever the
1768 constant requires more than one word in order to be adequately
1770 if (GET_CODE (x) == CONST_DOUBLE)
1774 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1778 if (GET_MODE (x) == SFmode)
1780 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1781 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1787 split_double (x, &first, &second);
1791 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1793 return gen_rtx (CONST_INT, VOIDmode,
1794 trunc_int_for_mode (l[0], HImode));
1798 l[0] = CONST_DOUBLE_LOW (x);
1801 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1802 else if (mode == HImode && GET_MODE (x) == SFmode)
1803 return gen_rtx (CONST_INT, VOIDmode,
1804 trunc_int_for_mode (l[0], HImode));
1809 if (mode == QImode && D_REG_P (x))
1810 return gen_rtx (REG, mode, HARD_B_REGNUM);
1812 /* gen_lowpart crashes when it is called with a SUBREG. */
1813 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1816 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1817 else if (mode == HImode)
1818 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1822 x = gen_lowpart (mode, x);
1824 /* Return a different rtx to avoid to share it in several insns
1825 (when used by a split pattern). Sharing addresses within
1826 a MEM breaks the Z register replacement (and reloading). */
1827 if (GET_CODE (x) == MEM)
1833 m68hc11_gen_highpart (mode, x)
1834 enum machine_mode mode;
1837 /* We assume that the high part of an auto-inc mode is the same with
1838 the mode changed and that the caller split the larger mode in the
1840 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1842 return gen_rtx (MEM, mode, XEXP (x, 0));
1845 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1846 floating-point constant. A CONST_DOUBLE is used whenever the
1847 constant requires more than one word in order to be adequately
1849 if (GET_CODE (x) == CONST_DOUBLE)
1853 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1857 if (GET_MODE (x) == SFmode)
1859 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1860 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1866 split_double (x, &first, &second);
1870 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1872 return gen_rtx (CONST_INT, VOIDmode,
1873 trunc_int_for_mode ((l[1] >> 16), HImode));
1877 l[1] = CONST_DOUBLE_HIGH (x);
1881 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1882 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1883 return gen_rtx (CONST_INT, VOIDmode,
1884 trunc_int_for_mode ((l[0] >> 16), HImode));
1888 if (GET_CODE (x) == CONST_INT)
1890 HOST_WIDE_INT val = INTVAL (x);
1894 return gen_rtx (CONST_INT, VOIDmode,
1895 trunc_int_for_mode (val >> 8, QImode));
1897 else if (mode == HImode)
1899 return gen_rtx (CONST_INT, VOIDmode,
1900 trunc_int_for_mode (val >> 16, HImode));
1903 if (mode == QImode && D_REG_P (x))
1904 return gen_rtx (REG, mode, HARD_A_REGNUM);
1906 /* There is no way in GCC to represent the upper part of a word register.
1907 To obtain the 8-bit upper part of a soft register, we change the
1908 reg into a mem rtx. This is possible because they are physically
1909 located in memory. There is no offset because we are big-endian. */
1910 if (mode == QImode && S_REG_P (x))
1914 /* For 68HC12, avoid the '*' for direct addressing mode. */
1915 pos = TARGET_M6812 ? 1 : 0;
1916 return gen_rtx (MEM, QImode,
1917 gen_rtx (SYMBOL_REF, Pmode,
1918 ®_names[REGNO (x)][pos]));
1921 /* gen_highpart crashes when it is called with a SUBREG. */
1922 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1924 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1926 x = gen_highpart (mode, x);
1928 /* Return a different rtx to avoid to share it in several insns
1929 (when used by a split pattern). Sharing addresses within
1930 a MEM breaks the Z register replacement (and reloading). */
1931 if (GET_CODE (x) == MEM)
1937 /* Obscure register manipulation. */
1939 /* Finds backward in the instructions to see if register 'reg' is
1940 dead. This is used when generating code to see if we can use 'reg'
1941 as a scratch register. This allows us to choose a better generation
1942 of code when we know that some register dies or can be clobbered. */
1945 dead_register_here (x, reg)
1953 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
1957 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1958 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
1964 if (GET_CODE (body) == CALL_INSN)
1966 if (GET_CODE (body) == JUMP_INSN)
1969 if (GET_CODE (body) == SET)
1971 rtx dst = XEXP (body, 0);
1973 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
1975 if (x_reg && rtx_equal_p (dst, x_reg))
1978 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
1981 else if (reg_mentioned_p (reg, p)
1982 || (x_reg && reg_mentioned_p (x_reg, p)))
1986 /* Scan forward to see if the register is set in some insns and never
1988 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
1992 if (GET_CODE (p) == CODE_LABEL
1993 || GET_CODE (p) == JUMP_INSN
1994 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
1997 if (GET_CODE (p) != INSN)
2001 if (GET_CODE (body) == SET)
2003 rtx src = XEXP (body, 1);
2004 rtx dst = XEXP (body, 0);
2006 if (GET_CODE (dst) == REG
2007 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2011 /* Register is used (may be in source or in dest). */
2012 if (reg_mentioned_p (reg, p)
2013 || (x_reg != 0 && GET_MODE (p) == SImode
2014 && reg_mentioned_p (x_reg, p)))
2017 return p == 0 ? 1 : 0;
2021 /* Code generation operations called from machine description file. */
2023 /* Print the name of register 'regno' in the assembly file. */
2025 asm_print_register (file, regno)
2029 const char *name = reg_names[regno];
2031 if (TARGET_M6812 && name[0] == '*')
2034 asm_fprintf (file, "%s", name);
2037 /* A C compound statement to output to stdio stream STREAM the
2038 assembler syntax for an instruction operand X. X is an RTL
2041 CODE is a value that can be used to specify one of several ways
2042 of printing the operand. It is used when identical operands
2043 must be printed differently depending on the context. CODE
2044 comes from the `%' specification that was used to request
2045 printing of the operand. If the specification was just `%DIGIT'
2046 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2047 is the ASCII code for LTR.
2049 If X is a register, this macro should print the register's name.
2050 The names can be found in an array `reg_names' whose type is
2051 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2053 When the machine description has a specification `%PUNCT' (a `%'
2054 followed by a punctuation character), this macro is called with
2055 a null pointer for X and the punctuation character for CODE.
2057 The M68HC11 specific codes are:
2059 'b' for the low part of the operand.
2060 'h' for the high part of the operand
2061 The 'b' or 'h' modifiers have no effect if the operand has
2062 the QImode and is not a S_REG_P (soft register). If the
2063 operand is a hard register, these two modifiers have no effect.
2064 't' generate the temporary scratch register. The operand is
2066 'T' generate the low-part temporary scratch register. The operand is
2070 print_operand (file, op, letter)
2077 asm_print_register (file, SOFT_TMP_REGNUM);
2080 else if (letter == 'T')
2082 asm_print_register (file, SOFT_TMP_REGNUM);
2083 asm_fprintf (file, "+1");
2086 else if (letter == '#')
2088 asm_fprintf (file, "%0I");
2091 if (GET_CODE (op) == REG)
2093 if (letter == 'b' && S_REG_P (op))
2095 asm_print_register (file, REGNO (op));
2096 asm_fprintf (file, "+1");
2100 asm_print_register (file, REGNO (op));
2105 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2108 asm_fprintf (file, "%0I%%lo(");
2110 asm_fprintf (file, "%0I%%hi(");
2112 output_addr_const (file, op);
2113 asm_fprintf (file, ")");
2117 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2118 are specified. If we already have a QImode, there is nothing to do. */
2119 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2123 op = m68hc11_gen_lowpart (QImode, op);
2125 else if (letter == 'h')
2127 op = m68hc11_gen_highpart (QImode, op);
2131 if (GET_CODE (op) == MEM)
2133 rtx base = XEXP (op, 0);
2134 switch (GET_CODE (base))
2139 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2140 asm_print_register (file, REGNO (XEXP (base, 0)));
2149 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2150 asm_print_register (file, REGNO (XEXP (base, 0)));
2151 asm_fprintf (file, "-");
2160 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2161 asm_print_register (file, REGNO (XEXP (base, 0)));
2162 asm_fprintf (file, "+");
2171 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2172 asm_print_register (file, REGNO (XEXP (base, 0)));
2179 output_address (base);
2183 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2186 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2187 ASM_OUTPUT_FLOAT_OPERAND (letter, file, r);
2189 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode)
2192 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2193 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r);
2195 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2198 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2199 ASM_OUTPUT_DOUBLE_OPERAND (file, r);
2203 int need_parenthesize = 0;
2206 asm_fprintf (file, "%0I");
2208 need_parenthesize = must_parenthesize (op);
2210 if (need_parenthesize)
2211 asm_fprintf (file, "(");
2213 output_addr_const (file, op);
2214 if (need_parenthesize)
2215 asm_fprintf (file, ")");
2219 /* Returns true if the operand 'op' must be printed with parenthesis
2220 arround it. This must be done only if there is a symbol whose name
2221 is a processor register. */
2223 must_parenthesize (op)
2228 switch (GET_CODE (op))
2231 name = XSTR (op, 0);
2232 /* Avoid a conflict between symbol name and a possible
2234 return (strcasecmp (name, "a") == 0
2235 || strcasecmp (name, "b") == 0
2236 || strcasecmp (name, "d") == 0
2237 || strcasecmp (name, "x") == 0
2238 || strcasecmp (name, "y") == 0
2239 || strcasecmp (name, "pc") == 0
2240 || strcasecmp (name, "sp") == 0
2241 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2245 return must_parenthesize (XEXP (op, 0))
2246 || must_parenthesize (XEXP (op, 1));
2252 return must_parenthesize (XEXP (op, 0));
2263 /* A C compound statement to output to stdio stream STREAM the
2264 assembler syntax for an instruction operand that is a memory
2265 reference whose address is ADDR. ADDR is an RTL expression. */
2268 print_operand_address (file, addr)
2274 int need_parenthesis = 0;
2276 switch (GET_CODE (addr))
2279 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2282 asm_fprintf (file, "0,");
2283 asm_print_register (file, REGNO (addr));
2287 base = XEXP (addr, 0);
2288 switch (GET_CODE (base))
2293 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2294 asm_print_register (file, REGNO (XEXP (base, 0)));
2303 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2304 asm_print_register (file, REGNO (XEXP (base, 0)));
2305 asm_fprintf (file, "-");
2314 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2315 asm_print_register (file, REGNO (XEXP (base, 0)));
2316 asm_fprintf (file, "+");
2325 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2326 asm_print_register (file, REGNO (XEXP (base, 0)));
2333 need_parenthesis = must_parenthesize (base);
2334 if (need_parenthesis)
2335 asm_fprintf (file, "(");
2337 output_addr_const (file, base);
2338 if (need_parenthesis)
2339 asm_fprintf (file, ")");
2345 base = XEXP (addr, 0);
2346 offset = XEXP (addr, 1);
2347 if (!G_REG_P (base) && G_REG_P (offset))
2349 base = XEXP (addr, 1);
2350 offset = XEXP (addr, 0);
2352 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2354 need_parenthesis = must_parenthesize (addr);
2356 if (need_parenthesis)
2357 asm_fprintf (file, "(");
2359 output_addr_const (file, base);
2360 asm_fprintf (file, "+");
2361 output_addr_const (file, offset);
2362 if (need_parenthesis)
2363 asm_fprintf (file, ")");
2365 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2371 asm_print_register (file, REGNO (offset));
2372 asm_fprintf (file, ",");
2373 asm_print_register (file, REGNO (base));
2380 output_addr_const (file, offset);
2381 asm_fprintf (file, ",");
2382 asm_print_register (file, REGNO (base));
2392 if (GET_CODE (addr) == CONST_INT
2393 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2395 asm_fprintf (file, "%d", INTVAL (addr));
2399 need_parenthesis = must_parenthesize (addr);
2400 if (need_parenthesis)
2401 asm_fprintf (file, "(");
2403 output_addr_const (file, addr);
2404 if (need_parenthesis)
2405 asm_fprintf (file, ")");
2412 /* Splitting of some instructions. */
2415 m68hc11_expand_compare (code, op0, op1)
2421 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2425 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2426 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2427 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2434 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2436 rtx op0, op1, label;
2440 switch (GET_MODE (op0))
2444 tmp = m68hc11_expand_compare (code, op0, op1);
2445 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2446 gen_rtx_LABEL_REF (VOIDmode, label),
2448 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2452 /* SCz: from i386.c */
2455 /* Don't expand the comparison early, so that we get better code
2456 when jump or whoever decides to reverse the comparison. */
2461 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2462 &m68hc11_compare_op1);
2464 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2465 m68hc11_compare_op0, m68hc11_compare_op1);
2466 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2467 gen_rtx_LABEL_REF (VOIDmode, label),
2469 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2471 use_fcomi = ix86_use_fcomi_compare (code);
2472 vec = rtvec_alloc (3 + !use_fcomi);
2473 RTVEC_ELT (vec, 0) = tmp;
2475 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2477 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2480 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2482 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2488 /* Expand SImode branch into multiple compare+branch. */
2490 rtx lo[2], hi[2], label2;
2491 enum rtx_code code1, code2, code3;
2493 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2498 code = swap_condition (code);
2500 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2501 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2502 hi[0] = m68hc11_gen_highpart (HImode, op0);
2503 hi[1] = m68hc11_gen_highpart (HImode, op1);
2505 /* Otherwise, if we are doing less-than, op1 is a constant and the
2506 low word is zero, then we can just examine the high word. */
2508 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2509 && (code == LT || code == LTU))
2511 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2515 /* Otherwise, we need two or three jumps. */
2517 label2 = gen_label_rtx ();
2520 code2 = swap_condition (code);
2521 code3 = unsigned_condition (code);
2562 * if (hi(a) < hi(b)) goto true;
2563 * if (hi(a) > hi(b)) goto false;
2564 * if (lo(a) < lo(b)) goto true;
2568 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2570 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2572 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2575 emit_label (label2);
2586 /* Split a DI, SI or HI move into several smaller move operations.
2587 The scratch register 'scratch' is used as a temporary to load
2588 store intermediate values. It must be a hard register. */
2590 m68hc11_split_move (to, from, scratch)
2591 rtx to, from, scratch;
2593 rtx low_to, low_from;
2594 rtx high_to, high_from;
2595 enum machine_mode mode;
2598 mode = GET_MODE (to);
2599 if (GET_MODE_SIZE (mode) == 8)
2601 else if (GET_MODE_SIZE (mode) == 4)
2607 && IS_STACK_PUSH (to)
2608 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2614 else if (mode == HImode)
2622 low_to = m68hc11_gen_lowpart (mode, to);
2623 high_to = m68hc11_gen_highpart (mode, to);
2625 low_from = m68hc11_gen_lowpart (mode, from);
2626 if (mode == SImode && GET_CODE (from) == CONST_INT)
2628 if (INTVAL (from) >= 0)
2629 high_from = const0_rtx;
2631 high_from = constm1_rtx;
2634 high_from = m68hc11_gen_highpart (mode, from);
2638 high_from = adj_offsettable_operand (high_from, offset);
2639 low_from = high_from;
2643 m68hc11_split_move (low_to, low_from, scratch);
2644 m68hc11_split_move (high_to, high_from, scratch);
2646 else if (H_REG_P (to) || H_REG_P (from)
2648 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2649 || m68hc11_small_indexed_indirect_p (from,
2651 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2652 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2654 emit_move_insn (low_to, low_from);
2655 emit_move_insn (high_to, high_from);
2661 emit_move_insn (scratch, low_from);
2662 insn = emit_move_insn (low_to, scratch);
2664 emit_move_insn (scratch, high_from);
2665 insn = emit_move_insn (high_to, scratch);
2670 simplify_logical (mode, code, operand, result)
2671 enum machine_mode mode;
2680 if (GET_CODE (operand) != CONST_INT)
2688 val = INTVAL (operand);
2692 if ((val & mask) == 0)
2694 if ((val & mask) == mask)
2695 *result = constm1_rtx;
2699 if ((val & mask) == 0)
2700 *result = const0_rtx;
2701 if ((val & mask) == mask)
2706 if ((val & mask) == 0)
2714 m68hc11_emit_logical (mode, code, operands)
2715 enum machine_mode mode;
2722 need_copy = (rtx_equal_p (operands[0], operands[1])
2723 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2725 operands[1] = simplify_logical (mode, code, operands[1], &result);
2726 operands[2] = simplify_logical (mode, code, operands[2], &result);
2728 if (result && GET_CODE (result) == CONST_INT)
2730 if (!H_REG_P (operands[0]) && operands[3]
2731 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2733 emit_move_insn (operands[3], result);
2734 emit_move_insn (operands[0], operands[3]);
2738 emit_move_insn (operands[0], result);
2741 else if (operands[1] != 0 && operands[2] != 0)
2745 if (!H_REG_P (operands[0]) && operands[3])
2747 emit_move_insn (operands[3], operands[1]);
2748 emit_insn (gen_rtx (SET, mode,
2750 gen_rtx (code, mode,
2751 operands[3], operands[2])));
2752 insn = emit_move_insn (operands[0], operands[3]);
2756 insn = emit_insn (gen_rtx (SET, mode,
2758 gen_rtx (code, mode,
2759 operands[0], operands[2])));
2763 /* The logical operation is similar to a copy. */
2768 if (GET_CODE (operands[1]) == CONST_INT)
2773 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2775 emit_move_insn (operands[3], src);
2776 emit_move_insn (operands[0], operands[3]);
2780 emit_move_insn (operands[0], src);
2786 m68hc11_split_logical (mode, code, operands)
2787 enum machine_mode mode;
2794 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2795 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2796 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2798 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2800 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
2802 if (INTVAL (operands[1]) >= 0)
2803 high[1] = const0_rtx;
2805 high[1] = constm1_rtx;
2808 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2810 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
2812 if (INTVAL (operands[2]) >= 0)
2813 high[2] = const0_rtx;
2815 high[2] = constm1_rtx;
2818 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2820 low[3] = operands[3];
2821 high[3] = operands[3];
2824 m68hc11_split_logical (HImode, code, low);
2825 m68hc11_split_logical (HImode, code, high);
2829 m68hc11_emit_logical (mode, code, low);
2830 m68hc11_emit_logical (mode, code, high);
2834 /* Code generation. */
2837 m68hc11_output_swap (insn, operands)
2838 rtx insn ATTRIBUTE_UNUSED;
2841 /* We have to be careful with the cc_status. An address register swap
2842 is generated for some comparison. The comparison is made with D
2843 but the branch really uses the address register. See the split
2844 pattern for compare. The xgdx/xgdy preserve the flags but after
2845 the exchange, the flags will reflect to the value of X and not D.
2846 Tell this by setting the cc_status according to the cc_prev_status. */
2847 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2849 if (cc_prev_status.value1 != 0
2850 && (D_REG_P (cc_prev_status.value1)
2851 || X_REG_P (cc_prev_status.value1)))
2853 cc_status = cc_prev_status;
2854 if (D_REG_P (cc_status.value1))
2855 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2858 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2864 output_asm_insn ("xgdx", operands);
2868 if (cc_prev_status.value1 != 0
2869 && (D_REG_P (cc_prev_status.value1)
2870 || Y_REG_P (cc_prev_status.value1)))
2872 cc_status = cc_prev_status;
2873 if (D_REG_P (cc_status.value1))
2874 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2877 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2883 output_asm_insn ("xgdy", operands);
2887 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2888 This is used to decide whether a move that set flags should be used
2891 next_insn_test_reg (insn, reg)
2897 insn = next_nonnote_insn (insn);
2898 if (GET_CODE (insn) != INSN)
2901 body = PATTERN (insn);
2902 if (sets_cc0_p (body) != 1)
2905 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
2911 /* Generate the code to move a 16-bit operand into another one. */
2914 m68hc11_gen_movhi (insn, operands)
2920 /* Move a register or memory to the same location.
2921 This is possible because such insn can appear
2922 in a non-optimizing mode. */
2923 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
2925 cc_status = cc_prev_status;
2931 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
2933 cc_status = cc_prev_status;
2934 switch (REGNO (operands[1]))
2939 output_asm_insn ("psh%1", operands);
2946 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2948 cc_status = cc_prev_status;
2949 switch (REGNO (operands[0]))
2954 output_asm_insn ("pul%0", operands);
2961 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
2963 m68hc11_notice_keep_cc (operands[0]);
2964 output_asm_insn ("tfr\t%1,%0", operands);
2966 else if (H_REG_P (operands[0]))
2968 if (SP_REG_P (operands[0]))
2969 output_asm_insn ("lds\t%1", operands);
2971 output_asm_insn ("ld%0\t%1", operands);
2973 else if (H_REG_P (operands[1]))
2975 if (SP_REG_P (operands[1]))
2976 output_asm_insn ("sts\t%0", operands);
2978 output_asm_insn ("st%1\t%0", operands);
2982 rtx from = operands[1];
2983 rtx to = operands[0];
2985 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
2986 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
2987 || (m68hc11_register_indirect_p (to, GET_MODE (to))
2988 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
2994 ops[0] = operands[2];
2997 m68hc11_gen_movhi (insn, ops);
2999 ops[1] = operands[2];
3000 m68hc11_gen_movhi (insn, ops);
3004 /* !!!! SCz wrong here. */
3005 fatal_insn ("Move insn not handled", insn);
3010 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3012 output_asm_insn ("clr\t%h0", operands);
3013 output_asm_insn ("clr\t%b0", operands);
3017 m68hc11_notice_keep_cc (operands[0]);
3018 output_asm_insn ("movw\t%1,%0", operands);
3025 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3027 cc_status = cc_prev_status;
3028 switch (REGNO (operands[0]))
3032 output_asm_insn ("pul%0", operands);
3035 output_asm_insn ("pula", operands);
3036 output_asm_insn ("pulb", operands);
3043 /* Some moves to a hard register are special. Not all of them
3044 are really supported and we have to use a temporary
3045 location to provide them (either the stack of a temp var). */
3046 if (H_REG_P (operands[0]))
3048 switch (REGNO (operands[0]))
3051 if (X_REG_P (operands[1]))
3053 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3055 m68hc11_output_swap (insn, operands);
3057 else if (next_insn_test_reg (insn, operands[0]))
3059 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3063 m68hc11_notice_keep_cc (operands[0]);
3064 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3067 else if (Y_REG_P (operands[1]))
3069 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3071 m68hc11_output_swap (insn, operands);
3075 /* %t means *ZTMP scratch register. */
3076 output_asm_insn ("sty\t%t1", operands);
3077 output_asm_insn ("ldd\t%t1", operands);
3080 else if (SP_REG_P (operands[1]))
3085 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3086 output_asm_insn ("xgdx", operands);
3087 output_asm_insn ("tsx", operands);
3088 output_asm_insn ("xgdx", operands);
3090 else if (IS_STACK_POP (operands[1]))
3092 output_asm_insn ("pula\n\tpulb", operands);
3094 else if (GET_CODE (operands[1]) == CONST_INT
3095 && INTVAL (operands[1]) == 0)
3097 output_asm_insn ("clra\n\tclrb", operands);
3101 output_asm_insn ("ldd\t%1", operands);
3106 if (D_REG_P (operands[1]))
3108 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3110 m68hc11_output_swap (insn, operands);
3112 else if (next_insn_test_reg (insn, operands[0]))
3114 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3118 m68hc11_notice_keep_cc (operands[0]);
3119 output_asm_insn ("pshb", operands);
3120 output_asm_insn ("psha", operands);
3121 output_asm_insn ("pulx", operands);
3124 else if (Y_REG_P (operands[1]))
3126 /* When both D and Y are dead, use the sequence xgdy, xgdx
3127 to move Y into X. The D and Y registers are modified. */
3128 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3129 && dead_register_here (insn, d_reg))
3131 output_asm_insn ("xgdy", operands);
3132 output_asm_insn ("xgdx", operands);
3137 output_asm_insn ("sty\t%t1", operands);
3138 output_asm_insn ("ldx\t%t1", operands);
3141 else if (SP_REG_P (operands[1]))
3143 /* tsx, tsy preserve the flags */
3144 cc_status = cc_prev_status;
3145 output_asm_insn ("tsx", operands);
3149 output_asm_insn ("ldx\t%1", operands);
3154 if (D_REG_P (operands[1]))
3156 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3158 m68hc11_output_swap (insn, operands);
3162 output_asm_insn ("std\t%t1", operands);
3163 output_asm_insn ("ldy\t%t1", operands);
3166 else if (X_REG_P (operands[1]))
3168 /* When both D and X are dead, use the sequence xgdx, xgdy
3169 to move X into Y. The D and X registers are modified. */
3170 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3171 && dead_register_here (insn, d_reg))
3173 output_asm_insn ("xgdx", operands);
3174 output_asm_insn ("xgdy", operands);
3179 output_asm_insn ("stx\t%t1", operands);
3180 output_asm_insn ("ldy\t%t1", operands);
3183 else if (SP_REG_P (operands[1]))
3185 /* tsx, tsy preserve the flags */
3186 cc_status = cc_prev_status;
3187 output_asm_insn ("tsy", operands);
3191 output_asm_insn ("ldy\t%1", operands);
3195 case HARD_SP_REGNUM:
3196 if (D_REG_P (operands[1]))
3198 m68hc11_notice_keep_cc (operands[0]);
3199 output_asm_insn ("xgdx", operands);
3200 output_asm_insn ("txs", operands);
3201 output_asm_insn ("xgdx", operands);
3203 else if (X_REG_P (operands[1]))
3205 /* tys, txs preserve the flags */
3206 cc_status = cc_prev_status;
3207 output_asm_insn ("txs", operands);
3209 else if (Y_REG_P (operands[1]))
3211 /* tys, txs preserve the flags */
3212 cc_status = cc_prev_status;
3213 output_asm_insn ("tys", operands);
3217 /* lds sets the flags but the des does not. */
3219 output_asm_insn ("lds\t%1", operands);
3220 output_asm_insn ("des", operands);
3225 fatal_insn ("Invalid register in the move instruction", insn);
3230 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3231 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3233 output_asm_insn ("sts\t%0", operands);
3237 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3239 cc_status = cc_prev_status;
3240 switch (REGNO (operands[1]))
3244 output_asm_insn ("psh%1", operands);
3247 output_asm_insn ("pshb", operands);
3248 output_asm_insn ("psha", operands);
3256 /* Operand 1 must be a hard register. */
3257 if (!H_REG_P (operands[1]))
3259 fatal_insn ("Invalid operand in the instruction", insn);
3262 reg = REGNO (operands[1]);
3266 output_asm_insn ("std\t%0", operands);
3270 output_asm_insn ("stx\t%0", operands);
3274 output_asm_insn ("sty\t%0", operands);
3277 case HARD_SP_REGNUM:
3281 if (reg_mentioned_p (ix_reg, operands[0]))
3283 output_asm_insn ("sty\t%t0", operands);
3284 output_asm_insn ("tsy", operands);
3285 output_asm_insn ("sty\t%0", operands);
3286 output_asm_insn ("ldy\t%t0", operands);
3290 output_asm_insn ("stx\t%t0", operands);
3291 output_asm_insn ("tsx", operands);
3292 output_asm_insn ("stx\t%0", operands);
3293 output_asm_insn ("ldx\t%t0", operands);
3299 fatal_insn ("Invalid register in the move instruction", insn);
3305 m68hc11_gen_movqi (insn, operands)
3309 /* Move a register or memory to the same location.
3310 This is possible because such insn can appear
3311 in a non-optimizing mode. */
3312 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3314 cc_status = cc_prev_status;
3321 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3323 m68hc11_notice_keep_cc (operands[0]);
3324 output_asm_insn ("tfr\t%1,%0", operands);
3326 else if (H_REG_P (operands[0]))
3328 if (Q_REG_P (operands[0]))
3329 output_asm_insn ("lda%0\t%b1", operands);
3330 else if (D_REG_P (operands[0]))
3331 output_asm_insn ("ldab\t%b1", operands);
3335 else if (H_REG_P (operands[1]))
3337 if (Q_REG_P (operands[1]))
3338 output_asm_insn ("sta%1\t%b0", operands);
3339 else if (D_REG_P (operands[1]))
3340 output_asm_insn ("stab\t%b0", operands);
3346 rtx from = operands[1];
3347 rtx to = operands[0];
3349 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3350 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3351 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3352 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3358 ops[0] = operands[2];
3361 m68hc11_gen_movqi (insn, ops);
3363 ops[1] = operands[2];
3364 m68hc11_gen_movqi (insn, ops);
3368 /* !!!! SCz wrong here. */
3369 fatal_insn ("Move insn not handled", insn);
3374 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3376 output_asm_insn ("clr\t%b0", operands);
3380 m68hc11_notice_keep_cc (operands[0]);
3381 output_asm_insn ("movb\t%b1,%b0", operands);
3389 if (H_REG_P (operands[0]))
3391 switch (REGNO (operands[0]))
3395 if (X_REG_P (operands[1]))
3397 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3399 m68hc11_output_swap (insn, operands);
3403 output_asm_insn ("stx\t%t1", operands);
3404 output_asm_insn ("ldab\t%T0", operands);
3407 else if (Y_REG_P (operands[1]))
3409 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3411 m68hc11_output_swap (insn, operands);
3415 output_asm_insn ("sty\t%t1", operands);
3416 output_asm_insn ("ldab\t%T0", operands);
3419 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3420 && !DA_REG_P (operands[1]))
3422 output_asm_insn ("ldab\t%b1", operands);
3424 else if (DA_REG_P (operands[1]))
3426 output_asm_insn ("tab", operands);
3430 cc_status = cc_prev_status;
3436 if (X_REG_P (operands[1]))
3438 output_asm_insn ("stx\t%t1", operands);
3439 output_asm_insn ("ldaa\t%T0", operands);
3441 else if (Y_REG_P (operands[1]))
3443 output_asm_insn ("sty\t%t1", operands);
3444 output_asm_insn ("ldaa\t%T0", operands);
3446 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3447 && !DA_REG_P (operands[1]))
3449 output_asm_insn ("ldaa\t%b1", operands);
3451 else if (!DA_REG_P (operands[1]))
3453 output_asm_insn ("tba", operands);
3457 cc_status = cc_prev_status;
3462 if (D_REG_P (operands[1]))
3464 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3466 m68hc11_output_swap (insn, operands);
3470 output_asm_insn ("stab\t%T1", operands);
3471 output_asm_insn ("ldx\t%t1", operands);
3475 else if (Y_REG_P (operands[1]))
3477 output_asm_insn ("sty\t%t0", operands);
3478 output_asm_insn ("ldx\t%t0", operands);
3480 else if (GET_CODE (operands[1]) == CONST_INT)
3482 output_asm_insn ("ldx\t%1", operands);
3484 else if (dead_register_here (insn, d_reg))
3486 output_asm_insn ("ldab\t%b1", operands);
3487 output_asm_insn ("xgdx", operands);
3489 else if (!reg_mentioned_p (operands[0], operands[1]))
3491 output_asm_insn ("xgdx", operands);
3492 output_asm_insn ("ldab\t%b1", operands);
3493 output_asm_insn ("xgdx", operands);
3497 output_asm_insn ("pshb", operands);
3498 output_asm_insn ("ldab\t%b1", operands);
3499 output_asm_insn ("stab\t%T1", operands);
3500 output_asm_insn ("ldx\t%t1", operands);
3501 output_asm_insn ("pulb", operands);
3507 if (D_REG_P (operands[1]))
3509 output_asm_insn ("stab\t%T1", operands);
3510 output_asm_insn ("ldy\t%t1", operands);
3513 else if (X_REG_P (operands[1]))
3515 output_asm_insn ("stx\t%t1", operands);
3516 output_asm_insn ("ldy\t%t1", operands);
3519 else if (GET_CODE (operands[1]) == CONST_INT)
3521 output_asm_insn ("ldy\t%1", operands);
3523 else if (dead_register_here (insn, d_reg))
3525 output_asm_insn ("ldab\t%b1", operands);
3526 output_asm_insn ("xgdy", operands);
3528 else if (!reg_mentioned_p (operands[0], operands[1]))
3530 output_asm_insn ("xgdy", operands);
3531 output_asm_insn ("ldab\t%b1", operands);
3532 output_asm_insn ("xgdy", operands);
3536 output_asm_insn ("pshb", operands);
3537 output_asm_insn ("ldab\t%b1", operands);
3538 output_asm_insn ("stab\t%T1", operands);
3539 output_asm_insn ("ldy\t%t1", operands);
3540 output_asm_insn ("pulb", operands);
3546 fatal_insn ("Invalid register in the instruction", insn);
3550 else if (H_REG_P (operands[1]))
3552 switch (REGNO (operands[1]))
3556 output_asm_insn ("stab\t%b0", operands);
3560 output_asm_insn ("staa\t%b0", operands);
3564 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3568 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3572 fatal_insn ("Invalid register in the move instruction", insn);
3579 fatal_insn ("Operand 1 must be a hard register", insn);
3583 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3584 The source and destination must be D or A and the shift must
3587 m68hc11_gen_rotate (code, insn, operands)
3594 if (GET_CODE (operands[2]) != CONST_INT
3595 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3596 fatal_insn ("Invalid rotate insn", insn);
3598 val = INTVAL (operands[2]);
3599 if (code == ROTATERT)
3600 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3602 if (GET_MODE (operands[0]) != QImode)
3605 /* Rotate by 8-bits if the shift is within [5..11]. */
3606 if (val >= 5 && val <= 11)
3608 output_asm_insn ("psha", operands);
3609 output_asm_insn ("tba", operands);
3610 output_asm_insn ("pulb", operands);
3614 /* If the shift is big, invert the rotation. */
3622 /* Set the carry to bit-15, but don't change D yet. */
3623 if (GET_MODE (operands[0]) != QImode)
3625 output_asm_insn ("asra", operands);
3626 output_asm_insn ("rola", operands);
3631 /* Rotate B first to move the carry to bit-0. */
3632 if (D_REG_P (operands[0]))
3633 output_asm_insn ("rolb", operands);
3635 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3636 output_asm_insn ("rola", operands);
3641 /* Set the carry to bit-8 of D. */
3642 if (val != 0 && GET_MODE (operands[0]) != QImode)
3644 output_asm_insn ("tap", operands);
3649 /* Rotate B first to move the carry to bit-7. */
3650 if (D_REG_P (operands[0]))
3651 output_asm_insn ("rorb", operands);
3653 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3654 output_asm_insn ("rora", operands);
3661 /* Store in cc_status the expressions that the condition codes will
3662 describe after execution of an instruction whose pattern is EXP.
3663 Do not alter them if the instruction would not alter the cc's. */
3666 m68hc11_notice_update_cc (exp, insn)
3668 rtx insn ATTRIBUTE_UNUSED;
3670 /* recognize SET insn's. */
3671 if (GET_CODE (exp) == SET)
3673 /* Jumps do not alter the cc's. */
3674 if (SET_DEST (exp) == pc_rtx)
3677 /* NOTE: most instructions don't affect the carry bit, but the
3678 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3679 the conditions.h header. */
3681 /* Function calls clobber the cc's. */
3682 else if (GET_CODE (SET_SRC (exp)) == CALL)
3687 /* Tests and compares set the cc's in predictable ways. */
3688 else if (SET_DEST (exp) == cc0_rtx)
3690 cc_status.flags = 0;
3691 cc_status.value1 = XEXP (exp, 0);
3692 cc_status.value2 = XEXP (exp, 1);
3696 /* All other instructions affect the condition codes. */
3697 cc_status.flags = 0;
3698 cc_status.value1 = XEXP (exp, 0);
3699 cc_status.value2 = XEXP (exp, 1);
3704 /* Default action if we haven't recognized something
3705 and returned earlier. */
3709 if (cc_status.value2 != 0)
3710 switch (GET_CODE (cc_status.value2))
3712 /* These logical operations can generate several insns.
3713 The flags are setup according to what is generated. */
3719 /* The (not ...) generates several 'com' instructions for
3720 non QImode. We have to invalidate the flags. */
3722 if (GET_MODE (cc_status.value2) != QImode)
3734 if (GET_MODE (cc_status.value2) != VOIDmode)
3735 cc_status.flags |= CC_NO_OVERFLOW;
3738 /* The asl sets the overflow bit in such a way that this
3739 makes the flags unusable for a next compare insn. */
3743 if (GET_MODE (cc_status.value2) != VOIDmode)
3744 cc_status.flags |= CC_NO_OVERFLOW;
3747 /* A load/store instruction does not affect the carry. */
3752 cc_status.flags |= CC_NO_OVERFLOW;
3758 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3760 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3761 cc_status.value2 = 0;
3764 /* The current instruction does not affect the flags but changes
3765 the register 'reg'. See if the previous flags can be kept for the
3766 next instruction to avoid a comparison. */
3768 m68hc11_notice_keep_cc (reg)
3772 || cc_prev_status.value1 == 0
3773 || rtx_equal_p (reg, cc_prev_status.value1)
3774 || (cc_prev_status.value2
3775 && reg_mentioned_p (reg, cc_prev_status.value2)))
3778 cc_status = cc_prev_status;
3783 /* Machine Specific Reorg. */
3785 /* Z register replacement:
3787 GCC treats the Z register as an index base address register like
3788 X or Y. In general, it uses it during reload to compute the address
3789 of some operand. This helps the reload pass to avoid to fall into the
3790 register spill failure.
3792 The Z register is in the A_REGS class. In the machine description,
3793 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3795 It can appear everywhere an X or Y register can appear, except for
3796 some templates in the clobber section (when a clobber of X or Y is asked).
3797 For a given instruction, the template must ensure that no more than
3798 2 'A' registers are used. Otherwise, the register replacement is not
3801 To replace the Z register, the algorithm is not terrific:
3802 1. Insns that do not use the Z register are not changed
3803 2. When a Z register is used, we scan forward the insns to see
3804 a potential register to use: either X or Y and sometimes D.
3805 We stop when a call, a label or a branch is seen, or when we
3806 detect that both X and Y are used (probably at different times, but it does
3808 3. The register that will be used for the replacement of Z is saved
3809 in a .page0 register or on the stack. If the first instruction that
3810 used Z, uses Z as an input, the value is loaded from another .page0
3811 register. The replacement register is pushed on the stack in the
3812 rare cases where a compare insn uses Z and we couldn't find if X/Y
3814 4. The Z register is replaced in all instructions until we reach
3815 the end of the Z-block, as detected by step 2.
3816 5. If we detect that Z is still alive, its value is saved.
3817 If the replacement register is alive, its old value is loaded.
3819 The Z register can be disabled with -ffixed-z.
3829 int must_restore_reg;
3840 int save_before_last;
3841 int z_loaded_with_sp;
3844 static rtx z_reg_qi;
3846 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
3847 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
3848 static void m68hc11_z_replacement PARAMS ((rtx));
3849 static void m68hc11_reassign_regs PARAMS ((rtx));
3851 int z_replacement_completed = 0;
3853 /* Analyze the insn to find out which replacement register to use and
3854 the boundaries of the replacement.
3855 Returns 0 if we reached the last insn to be replaced, 1 if we can
3856 continue replacement in next insns. */
3859 m68hc11_check_z_replacement (insn, info)
3861 struct replace_info *info;
3863 int this_insn_uses_ix;
3864 int this_insn_uses_iy;
3865 int this_insn_uses_z;
3866 int this_insn_uses_z_in_dst;
3867 int this_insn_uses_d;
3871 /* A call is said to clobber the Z register, we don't need
3872 to save the value of Z. We also don't need to restore
3873 the replacement register (unless it is used by the call). */
3874 if (GET_CODE (insn) == CALL_INSN)
3876 body = PATTERN (insn);
3878 info->can_use_d = 0;
3880 /* If the call is an indirect call with Z, we have to use the
3881 Y register because X can be used as an input (D+X).
3882 We also must not save Z nor restore Y. */
3883 if (reg_mentioned_p (z_reg, body))
3885 insn = NEXT_INSN (insn);
3888 info->found_call = 1;
3889 info->must_restore_reg = 0;
3890 info->last = NEXT_INSN (insn);
3892 info->need_save_z = 0;
3895 if (GET_CODE (insn) == CODE_LABEL
3896 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
3899 if (GET_CODE (insn) == JUMP_INSN)
3901 if (reg_mentioned_p (z_reg, insn) == 0)
3904 info->can_use_d = 0;
3905 info->must_save_reg = 0;
3906 info->must_restore_reg = 0;
3907 info->need_save_z = 0;
3908 info->last = NEXT_INSN (insn);
3911 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
3916 /* Z register dies here. */
3917 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
3919 body = PATTERN (insn);
3920 if (GET_CODE (body) == SET)
3922 rtx src = XEXP (body, 1);
3923 rtx dst = XEXP (body, 0);
3925 /* Condition code is set here. We have to restore the X/Y and
3926 save into Z before any test/compare insn because once we save/restore
3927 we can change the condition codes. When the compare insn uses Z and
3928 we can't use X/Y, the comparison is made with the *ZREG soft register
3929 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3932 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
3933 || (GET_CODE (src) == COMPARE &&
3934 (rtx_equal_p (XEXP (src, 0), z_reg)
3935 || rtx_equal_p (XEXP (src, 1), z_reg))))
3937 if (insn == info->first)
3939 info->must_load_z = 0;
3940 info->must_save_reg = 0;
3941 info->must_restore_reg = 0;
3942 info->need_save_z = 0;
3943 info->found_call = 1;
3944 info->regno = SOFT_Z_REGNUM;
3949 if (reg_mentioned_p (z_reg, src) == 0)
3951 info->can_use_d = 0;
3955 if (insn != info->first)
3958 /* Compare insn which uses Z. We have to save/restore the X/Y
3959 register without modifying the condition codes. For this
3960 we have to use a push/pop insn. */
3961 info->must_push_reg = 1;
3965 /* Z reg is set to something new. We don't need to load it. */
3968 if (!reg_mentioned_p (z_reg, src))
3970 /* Z reg is used before being set. Treat this as
3971 a new sequence of Z register replacement. */
3972 if (insn != info->first)
3976 info->must_load_z = 0;
3978 info->z_set_count++;
3979 info->z_value = src;
3981 info->z_loaded_with_sp = 1;
3983 else if (reg_mentioned_p (z_reg, dst))
3984 info->can_use_d = 0;
3986 this_insn_uses_d = reg_mentioned_p (d_reg, src)
3987 | reg_mentioned_p (d_reg, dst);
3988 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
3989 | reg_mentioned_p (ix_reg, dst);
3990 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
3991 | reg_mentioned_p (iy_reg, dst);
3992 this_insn_uses_z = reg_mentioned_p (z_reg, src);
3994 /* If z is used as an address operand (like (MEM (reg z))),
3995 we can't replace it with d. */
3996 if (this_insn_uses_z && !Z_REG_P (src)
3997 && !(m68hc11_arith_operator (src, GET_MODE (src))
3998 && Z_REG_P (XEXP (src, 0))
3999 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4000 && insn == info->first
4001 && dead_register_here (insn, d_reg)))
4002 info->can_use_d = 0;
4004 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4005 if (TARGET_M6812 && !z_dies_here
4006 && ((this_insn_uses_z && side_effects_p (src))
4007 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4009 info->need_save_z = 1;
4010 info->z_set_count++;
4012 this_insn_uses_z |= this_insn_uses_z_in_dst;
4014 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4016 fatal_insn ("Registers IX, IY and Z used in the same INSN", insn);
4019 if (this_insn_uses_d)
4020 info->can_use_d = 0;
4022 /* IX and IY are used at the same time, we have to restore
4023 the value of the scratch register before this insn. */
4024 if (this_insn_uses_ix && this_insn_uses_iy)
4029 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4030 info->can_use_d = 0;
4032 if (info->x_used == 0 && this_insn_uses_ix)
4036 /* We have a (set (REG:HI X) (REG:HI Z)).
4037 Since we use Z as the replacement register, this insn
4038 is no longer necessary. We turn it into a note. We must
4039 not reload the old value of X. */
4040 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4044 info->need_save_z = 0;
4047 info->must_save_reg = 0;
4048 info->must_restore_reg = 0;
4049 info->found_call = 1;
4050 info->can_use_d = 0;
4051 PUT_CODE (insn, NOTE);
4052 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4053 NOTE_SOURCE_FILE (insn) = 0;
4054 info->last = NEXT_INSN (insn);
4059 && (rtx_equal_p (src, z_reg)
4060 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4064 info->need_save_z = 0;
4067 info->last = NEXT_INSN (insn);
4068 info->must_save_reg = 0;
4069 info->must_restore_reg = 0;
4071 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4072 && !reg_mentioned_p (ix_reg, src))
4077 info->need_save_z = 0;
4081 info->save_before_last = 1;
4083 info->must_restore_reg = 0;
4084 info->last = NEXT_INSN (insn);
4086 else if (info->can_use_d)
4088 info->last = NEXT_INSN (insn);
4094 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4095 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4097 info->need_save_z = 0;
4099 info->last = NEXT_INSN (insn);
4100 info->regno = HARD_X_REGNUM;
4101 info->must_save_reg = 0;
4102 info->must_restore_reg = 0;
4105 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4107 info->regno = HARD_X_REGNUM;
4108 info->must_restore_reg = 0;
4109 info->must_save_reg = 0;
4113 if (info->y_used == 0 && this_insn_uses_iy)
4117 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4121 info->need_save_z = 0;
4124 info->must_save_reg = 0;
4125 info->must_restore_reg = 0;
4126 info->found_call = 1;
4127 info->can_use_d = 0;
4128 PUT_CODE (insn, NOTE);
4129 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4130 NOTE_SOURCE_FILE (insn) = 0;
4131 info->last = NEXT_INSN (insn);
4136 && (rtx_equal_p (src, z_reg)
4137 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4142 info->need_save_z = 0;
4144 info->last = NEXT_INSN (insn);
4145 info->must_save_reg = 0;
4146 info->must_restore_reg = 0;
4148 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4149 && !reg_mentioned_p (iy_reg, src))
4154 info->need_save_z = 0;
4158 info->save_before_last = 1;
4160 info->must_restore_reg = 0;
4161 info->last = NEXT_INSN (insn);
4163 else if (info->can_use_d)
4165 info->last = NEXT_INSN (insn);
4172 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4173 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4175 info->need_save_z = 0;
4177 info->last = NEXT_INSN (insn);
4178 info->regno = HARD_Y_REGNUM;
4179 info->must_save_reg = 0;
4180 info->must_restore_reg = 0;
4183 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4185 info->regno = HARD_Y_REGNUM;
4186 info->must_restore_reg = 0;
4187 info->must_save_reg = 0;
4193 info->need_save_z = 0;
4195 if (info->last == 0)
4196 info->last = NEXT_INSN (insn);
4199 return info->last != NULL_RTX ? 0 : 1;
4201 if (GET_CODE (body) == PARALLEL)
4204 char ix_clobber = 0;
4205 char iy_clobber = 0;
4207 this_insn_uses_iy = 0;
4208 this_insn_uses_ix = 0;
4209 this_insn_uses_z = 0;
4211 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4214 int uses_ix, uses_iy, uses_z;
4216 x = XVECEXP (body, 0, i);
4218 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4219 info->can_use_d = 0;
4221 uses_ix = reg_mentioned_p (ix_reg, x);
4222 uses_iy = reg_mentioned_p (iy_reg, x);
4223 uses_z = reg_mentioned_p (z_reg, x);
4224 if (GET_CODE (x) == CLOBBER)
4226 ix_clobber |= uses_ix;
4227 iy_clobber |= uses_iy;
4228 z_clobber |= uses_z;
4232 this_insn_uses_ix |= uses_ix;
4233 this_insn_uses_iy |= uses_iy;
4234 this_insn_uses_z |= uses_z;
4236 if (uses_z && GET_CODE (x) == SET)
4238 rtx dst = XEXP (x, 0);
4241 info->z_set_count++;
4243 if (TARGET_M6812 && uses_z && side_effects_p (x))
4244 info->need_save_z = 1;
4247 info->need_save_z = 0;
4251 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4252 this_insn_uses_ix, this_insn_uses_iy,
4253 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4256 if (this_insn_uses_z)
4257 info->can_use_d = 0;
4259 if (z_clobber && info->first != insn)
4261 info->need_save_z = 0;
4265 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4267 if (this_insn_uses_z == 0 && insn == info->first)
4269 info->must_load_z = 0;
4271 if (dead_register_here (insn, d_reg))
4273 info->regno = HARD_D_REGNUM;
4274 info->must_save_reg = 0;
4275 info->must_restore_reg = 0;
4277 else if (dead_register_here (insn, ix_reg))
4279 info->regno = HARD_X_REGNUM;
4280 info->must_save_reg = 0;
4281 info->must_restore_reg = 0;
4283 else if (dead_register_here (insn, iy_reg))
4285 info->regno = HARD_Y_REGNUM;
4286 info->must_save_reg = 0;
4287 info->must_restore_reg = 0;
4289 if (info->regno >= 0)
4291 info->last = NEXT_INSN (insn);
4294 if (this_insn_uses_ix == 0)
4296 info->regno = HARD_X_REGNUM;
4297 info->must_save_reg = 1;
4298 info->must_restore_reg = 1;
4300 else if (this_insn_uses_iy == 0)
4302 info->regno = HARD_Y_REGNUM;
4303 info->must_save_reg = 1;
4304 info->must_restore_reg = 1;
4308 info->regno = HARD_D_REGNUM;
4309 info->must_save_reg = 1;
4310 info->must_restore_reg = 1;
4312 info->last = NEXT_INSN (insn);
4316 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4317 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4319 if (this_insn_uses_z)
4321 if (info->y_used == 0 && iy_clobber)
4323 info->regno = HARD_Y_REGNUM;
4324 info->must_save_reg = 0;
4325 info->must_restore_reg = 0;
4327 info->last = NEXT_INSN (insn);
4328 info->save_before_last = 1;
4332 if (this_insn_uses_ix && this_insn_uses_iy)
4334 if (this_insn_uses_z)
4336 fatal_insn ("Cannot do z-register replacement", insn);
4340 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4347 if (iy_clobber || z_clobber)
4349 info->last = NEXT_INSN (insn);
4350 info->save_before_last = 1;
4355 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4362 if (ix_clobber || z_clobber)
4364 info->last = NEXT_INSN (insn);
4365 info->save_before_last = 1;
4372 info->need_save_z = 0;
4376 if (GET_CODE (body) == CLOBBER)
4379 /* IX and IY are used at the same time, we have to restore
4380 the value of the scratch register before this insn. */
4381 if (this_insn_uses_ix && this_insn_uses_iy)
4385 if (info->x_used == 0 && this_insn_uses_ix)
4393 if (info->y_used == 0 && this_insn_uses_iy)
4407 m68hc11_find_z_replacement (insn, info)
4409 struct replace_info *info;
4413 info->replace_reg = NULL_RTX;
4414 info->must_load_z = 1;
4415 info->need_save_z = 1;
4416 info->must_save_reg = 1;
4417 info->must_restore_reg = 1;
4421 info->can_use_d = TARGET_M6811 ? 1 : 0;
4422 info->found_call = 0;
4426 info->z_set_count = 0;
4427 info->z_value = NULL_RTX;
4428 info->must_push_reg = 0;
4429 info->save_before_last = 0;
4430 info->z_loaded_with_sp = 0;
4432 /* Scan the insn forward to find an address register that is not used.
4434 - the flow of the program changes,
4435 - when we detect that both X and Y are necessary,
4436 - when the Z register dies,
4437 - when the condition codes are set. */
4439 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4441 if (m68hc11_check_z_replacement (insn, info) == 0)
4445 /* May be we can use Y or X if they contain the same value as Z.
4446 This happens very often after the reload. */
4447 if (info->z_set_count == 1)
4449 rtx p = info->first;
4454 v = find_last_value (iy_reg, &p, insn, 1);
4456 else if (info->y_used)
4458 v = find_last_value (ix_reg, &p, insn, 1);
4460 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4463 info->regno = HARD_Y_REGNUM;
4465 info->regno = HARD_X_REGNUM;
4466 info->must_load_z = 0;
4467 info->must_save_reg = 0;
4468 info->must_restore_reg = 0;
4469 info->found_call = 1;
4472 if (info->z_set_count == 0)
4473 info->need_save_z = 0;
4476 info->need_save_z = 0;
4478 if (info->last == 0)
4481 if (info->regno >= 0)
4484 info->replace_reg = gen_rtx (REG, HImode, reg);
4486 else if (info->can_use_d)
4488 reg = HARD_D_REGNUM;
4489 info->replace_reg = d_reg;
4491 else if (info->x_used)
4493 reg = HARD_Y_REGNUM;
4494 info->replace_reg = iy_reg;
4498 reg = HARD_X_REGNUM;
4499 info->replace_reg = ix_reg;
4503 if (info->must_save_reg && info->must_restore_reg)
4505 if (insn && dead_register_here (insn, info->replace_reg))
4507 info->must_save_reg = 0;
4508 info->must_restore_reg = 0;
4513 /* The insn uses the Z register. Find a replacement register for it
4514 (either X or Y) and replace it in the insn and the next ones until
4515 the flow changes or the replacement register is used. Instructions
4516 are emited before and after the Z-block to preserve the value of
4517 Z and of the replacement register. */
4520 m68hc11_z_replacement (insn)
4525 struct replace_info info;
4527 /* Find trivial case where we only need to replace z with the
4528 equivalent soft register. */
4529 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4531 rtx body = PATTERN (insn);
4532 rtx src = XEXP (body, 1);
4533 rtx dst = XEXP (body, 0);
4535 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4537 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4540 else if (Z_REG_P (src)
4541 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4543 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4546 else if (D_REG_P (dst)
4547 && m68hc11_arith_operator (src, GET_MODE (src))
4548 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4550 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4553 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4554 && INTVAL (src) == 0)
4556 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4557 /* Force it to be re-recognized. */
4558 INSN_CODE (insn) = -1;
4563 m68hc11_find_z_replacement (insn, &info);
4565 replace_reg = info.replace_reg;
4566 replace_reg_qi = NULL_RTX;
4568 /* Save the X register in a .page0 location. */
4569 if (info.must_save_reg && !info.must_push_reg)
4573 if (info.must_push_reg && 0)
4574 dst = gen_rtx (MEM, HImode,
4575 gen_rtx (PRE_DEC, HImode,
4576 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4578 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4580 emit_insn_before (gen_movhi (dst,
4581 gen_rtx (REG, HImode, info.regno)), insn);
4583 if (info.must_load_z && !info.must_push_reg)
4585 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4586 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4591 /* Replace all occurence of Z by replace_reg.
4592 Stop when the last instruction to replace is reached.
4593 Also stop when we detect a change in the flow (but it's not
4594 necessary; just safeguard). */
4596 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4600 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4603 if (GET_CODE (insn) != INSN
4604 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4607 body = PATTERN (insn);
4608 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4609 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4611 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4613 printf ("Reg mentioned here...:\n");
4618 /* Stack pointer was decremented by 2 due to the push.
4619 Correct that by adding 2 to the destination. */
4620 if (info.must_push_reg
4621 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4625 src = SET_SRC (body);
4626 dst = SET_DEST (body);
4627 if (SP_REG_P (src) && Z_REG_P (dst))
4629 emit_insn_after (gen_addhi3 (dst,
4632 VOIDmode, 2)), insn);
4636 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4637 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4639 INSN_CODE (insn) = -1;
4640 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4641 fatal_insn ("Cannot do z-register replacement", insn);
4644 /* Likewise for (REG:QI Z). */
4645 if (reg_mentioned_p (z_reg, insn))
4647 if (replace_reg_qi == NULL_RTX)
4648 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4649 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4652 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4656 /* Save Z before restoring the old value. */
4657 if (insn && info.need_save_z && !info.must_push_reg)
4659 rtx save_pos_insn = insn;
4661 /* If Z is clobber by the last insn, we have to save its value
4662 before the last instruction. */
4663 if (info.save_before_last)
4664 save_pos_insn = PREV_INSN (save_pos_insn);
4666 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4667 gen_rtx (REG, HImode, info.regno)),
4671 if (info.must_push_reg && info.last)
4675 body = PATTERN (info.last);
4676 new_body = gen_rtx (PARALLEL, VOIDmode,
4678 gen_rtx (USE, VOIDmode,
4680 gen_rtx (USE, VOIDmode,
4681 gen_rtx (REG, HImode,
4683 PATTERN (info.last) = new_body;
4685 /* Force recognition on insn since we changed it. */
4686 INSN_CODE (insn) = -1;
4688 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4690 fatal_insn ("Invalid Z register replacement for insn", insn);
4692 insn = NEXT_INSN (info.last);
4695 /* Restore replacement register unless it was died. */
4696 if (insn && info.must_restore_reg && !info.must_push_reg)
4700 if (info.must_push_reg && 0)
4701 dst = gen_rtx (MEM, HImode,
4702 gen_rtx (POST_INC, HImode,
4703 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4705 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4707 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4714 /* Scan all the insn and re-affects some registers
4715 - The Z register (if it was used), is affected to X or Y depending
4716 on the instruction. */
4719 m68hc11_reassign_regs (first)
4724 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
4725 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
4726 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4727 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
4729 /* Scan all insns to replace Z by X or Y preserving the old value
4730 of X/Y and restoring it afterward. */
4732 for (insn = first; insn; insn = NEXT_INSN (insn))
4736 if (GET_CODE (insn) == CODE_LABEL
4737 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4740 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4743 body = PATTERN (insn);
4744 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4747 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4748 || GET_CODE (body) == ASM_OPERANDS
4749 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4752 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4753 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4756 /* If Z appears in this insn, replace it in the current insn
4757 and the next ones until the flow changes or we have to
4758 restore back the replacement register. */
4760 if (reg_mentioned_p (z_reg, body))
4762 m68hc11_z_replacement (insn);
4767 printf ("Insn not handled by Z replacement:\n");
4776 m68hc11_reorg (first)
4782 z_replacement_completed = 0;
4783 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4785 /* Some RTX are shared at this point. This breaks the Z register
4786 replacement, unshare everything. */
4787 unshare_all_rtl_again (first);
4789 /* Force a split of all splitable insn. This is necessary for the
4790 Z register replacement mechanism because we end up with basic insns. */
4791 split_all_insns (0);
4794 z_replacement_completed = 1;
4795 m68hc11_reassign_regs (first);
4797 /* After some splitting, there are some oportunities for CSE pass.
4798 This happens quite often when 32-bit or above patterns are split. */
4799 if (optimize > 0 && split_done)
4800 reload_cse_regs (first);
4802 /* Re-create the REG_DEAD notes. These notes are used in the machine
4803 description to use the best assembly directives. */
4806 /* Before recomputing the REG_DEAD notes, remove all of them.
4807 This is necessary because the reload_cse_regs() pass can
4808 have replaced some (MEM) with a register. In that case,
4809 the REG_DEAD that could exist for that register may become
4811 for (insn = first; insn; insn = NEXT_INSN (insn))
4817 pnote = ®_NOTES (insn);
4820 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
4821 *pnote = XEXP (*pnote, 1);
4823 pnote = &XEXP (*pnote, 1);
4828 find_basic_blocks (first, max_reg_num (), 0);
4829 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
4832 z_replacement_completed = 2;
4834 /* If optimizing, then go ahead and split insns that must be
4835 split after Z register replacement. This gives more opportunities
4836 for peephole (in particular for consecutives xgdx/xgdy). */
4838 split_all_insns (0);
4840 /* Once insns are split after the z_replacement_completed == 2,
4841 we must not re-run the life_analysis. The xgdx/xgdy patterns
4842 are not recognized and the life_analysis pass removes some
4843 insns because it thinks some (SETs) are noops or made to dead
4844 stores (which is false due to the swap).
4846 Do a simple pass to eliminate the noop set that the final
4847 split could generate (because it was easier for split definition). */
4851 for (insn = first; insn; insn = NEXT_INSN (insn))
4855 if (INSN_DELETED_P (insn))
4857 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4860 /* Remove the (set (R) (R)) insns generated by some splits. */
4861 body = PATTERN (insn);
4862 if (GET_CODE (body) == SET
4863 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
4865 PUT_CODE (insn, NOTE);
4866 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4867 NOTE_SOURCE_FILE (insn) = 0;
4875 /* Cost functions. */
4877 /* Cost of moving memory. */
4879 m68hc11_memory_move_cost (mode, class, in)
4880 enum machine_mode mode;
4881 enum reg_class class;
4882 int in ATTRIBUTE_UNUSED;
4884 if (class <= H_REGS)
4886 if (GET_MODE_SIZE (mode) <= 2)
4887 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4889 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
4893 if (GET_MODE_SIZE (mode) <= 2)
4894 return COSTS_N_INSNS (2);
4896 return COSTS_N_INSNS (4);
4901 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4902 Reload does not check the constraint of set insns when the two registers
4903 have a move cost of 2. Setting a higher cost will force reload to check
4906 m68hc11_register_move_cost (from, to)
4907 enum reg_class from;
4910 if (from >= S_REGS && to >= S_REGS)
4912 return COSTS_N_INSNS (3);
4914 if (from <= S_REGS && to <= S_REGS)
4916 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4918 return COSTS_N_INSNS (2);
4922 /* Provide the costs of an addressing mode that contains ADDR.
4923 If ADDR is not a valid address, its cost is irrelevant. */
4926 m68hc11_address_cost (addr)
4931 switch (GET_CODE (addr))
4934 /* Make the cost of hard registers and specially SP, FP small. */
4935 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
4952 register rtx plus0 = XEXP (addr, 0);
4953 register rtx plus1 = XEXP (addr, 1);
4955 if (GET_CODE (plus0) != REG)
4958 switch (GET_CODE (plus1))
4961 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
4962 || INTVAL (plus1) < m68hc11_min_offset)
4964 else if (INTVAL (plus1) >= m68hc11_max_offset)
4968 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
4990 if (SP_REG_P (XEXP (addr, 0)))
4999 printf ("Address cost: %d for :", cost);
5008 m68hc11_shift_cost (mode, x, shift)
5009 enum machine_mode mode;
5015 total = rtx_cost (x, SET);
5017 total += m68hc11_cost->shiftQI_const[shift % 8];
5018 else if (mode == HImode)
5019 total += m68hc11_cost->shiftHI_const[shift % 16];
5020 else if (shift == 8 || shift == 16 || shift == 32)
5021 total += m68hc11_cost->shiftHI_const[8];
5022 else if (shift != 0 && shift != 16 && shift != 32)
5024 total += m68hc11_cost->shiftHI_const[1] * shift;
5027 /* For SI and others, the cost is higher. */
5028 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5029 total *= GET_MODE_SIZE (mode) / 2;
5031 /* When optimizing for size, make shift more costly so that
5032 multiplications are prefered. */
5033 if (optimize_size && (shift % 8) != 0)
5040 m68hc11_rtx_costs (x, code, outer_code)
5043 enum rtx_code outer_code ATTRIBUTE_UNUSED;
5045 enum machine_mode mode = GET_MODE (x);
5056 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5058 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5061 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5062 total += m68hc11_cost->shift_var;
5068 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5069 total += m68hc11_cost->logical;
5071 /* Logical instructions are byte instructions only. */
5072 total *= GET_MODE_SIZE (mode);
5077 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5078 total += m68hc11_cost->add;
5079 if (GET_MODE_SIZE (mode) > 2)
5081 total *= GET_MODE_SIZE (mode) / 2;
5088 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5092 total += m68hc11_cost->divQI;
5096 total += m68hc11_cost->divHI;
5101 total += m68hc11_cost->divSI;
5107 /* mul instruction produces 16-bit result. */
5108 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5109 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5110 return m68hc11_cost->multQI
5111 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5112 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5114 /* emul instruction produces 32-bit result for 68HC12. */
5115 if (TARGET_M6812 && mode == SImode
5116 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5117 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5118 return m68hc11_cost->multHI
5119 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5120 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5122 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5126 total += m68hc11_cost->multQI;
5130 total += m68hc11_cost->multHI;
5135 total += m68hc11_cost->multSI;
5142 extra_cost = COSTS_N_INSNS (2);
5149 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5152 return total + COSTS_N_INSNS (1);
5156 return total + COSTS_N_INSNS (2);
5160 return total + COSTS_N_INSNS (4);
5162 return total + COSTS_N_INSNS (8);
5165 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5166 return COSTS_N_INSNS (1);
5168 return COSTS_N_INSNS (1);
5171 return COSTS_N_INSNS (4);
5176 /* print_options - called at the start of the code generation for a
5179 extern char *asm_file_name;
5182 #include <sys/types.h>
5191 extern int save_argc;
5192 extern char **save_argv;
5194 fprintf (out, ";;; Command:\t");
5195 for (i = 0; i < save_argc; i++)
5197 fprintf (out, "%s", save_argv[i]);
5198 if (i + 1 < save_argc)
5201 fprintf (out, "\n");
5203 a_time = ctime (&c_time);
5204 fprintf (out, ";;; Compiled:\t%s", a_time);
5207 #define __VERSION__ "[unknown]"
5209 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
5211 fprintf (out, ";;; (META)compiled by CC.\n");
5216 m68hc11_asm_file_start (out, main_file)
5220 fprintf (out, ";;;-----------------------------------------\n");
5221 fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
5222 fprintf (out, ";;; gcc compiler %s\n", version_string);
5223 print_options (out);
5224 fprintf (out, ";;;-----------------------------------------\n");
5225 output_file_directive (out, main_file);
5230 m68hc11_add_gc_roots ()
5232 ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
5233 ggc_add_rtx_root (&ix_reg, 1);
5234 ggc_add_rtx_root (&iy_reg, 1);
5235 ggc_add_rtx_root (&d_reg, 1);
5236 ggc_add_rtx_root (&da_reg, 1);
5237 ggc_add_rtx_root (&z_reg, 1);
5238 ggc_add_rtx_root (&z_reg_qi, 1);
5239 ggc_add_rtx_root (&stack_push_word, 1);
5240 ggc_add_rtx_root (&stack_pop_word, 1);