1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
3 Free Software Foundation, Inc.
4 Contributed by Stephane Carrez (stcarrez@nerim.fr)
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
24 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
25 on gcc 2.6.3. I have used it as a starting point for this port.
26 However, this new port is a complete re-write. Its internal
27 design is completely different. The generated code is not
28 compatible with the gcc 2.6.3 port.
30 The gcc 2.6.3 port is available at:
32 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
39 #include "coretypes.h"
45 #include "hard-reg-set.h"
47 #include "insn-config.h"
48 #include "conditions.h"
50 #include "insn-attr.h"
56 #include "basic-block.h"
61 #include "target-def.h"
63 static void emit_move_after_reload (rtx
, rtx
, rtx
);
64 static rtx
simplify_logical (enum machine_mode
, int, rtx
, rtx
*);
65 static void m68hc11_emit_logical (enum machine_mode
, int, rtx
*);
66 static void m68hc11_reorg (void);
67 static int go_if_legitimate_address_internal (rtx
, enum machine_mode
, int);
68 static int register_indirect_p (rtx
, enum machine_mode
, int);
69 static rtx
m68hc11_expand_compare (enum rtx_code
, rtx
, rtx
);
70 static int must_parenthesize (rtx
);
71 static int m68hc11_address_cost (rtx
);
72 static int m68hc11_shift_cost (enum machine_mode
, rtx
, int);
73 static int m68hc11_rtx_costs_1 (rtx
, enum rtx_code
, enum rtx_code
);
74 static bool m68hc11_rtx_costs (rtx
, int, int, int *);
75 static int m68hc11_auto_inc_p (rtx
);
76 static tree
m68hc11_handle_fntype_attribute (tree
*, tree
, tree
, int, bool *);
77 const struct attribute_spec m68hc11_attribute_table
[];
79 void create_regs_rtx (void);
81 static void asm_print_register (FILE *, int);
82 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT
);
83 static void m68hc11_asm_out_constructor (rtx
, int);
84 static void m68hc11_asm_out_destructor (rtx
, int);
85 static void m68hc11_file_start (void);
86 static void m68hc11_encode_section_info (tree
, rtx
, int);
87 static unsigned int m68hc11_section_type_flags (tree
, const char*, int);
88 static int autoinc_mode (rtx
);
89 static int m68hc11_make_autoinc_notes (rtx
*, void *);
90 static void m68hc11_init_libfuncs (void);
92 /* Must be set to 1 to produce debug messages. */
95 extern FILE *asm_out_file
;
100 rtx m68hc11_soft_tmp_reg
;
101 static GTY(()) rtx stack_push_word
;
102 static GTY(()) rtx stack_pop_word
;
103 static GTY(()) rtx z_reg
;
104 static GTY(()) rtx z_reg_qi
;
105 static int regs_inited
= 0;
107 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
108 int current_function_interrupt
;
110 /* Set to 1 by expand_prologue() when the function is a trap handler. */
111 int current_function_trap
;
113 /* Set to 1 when the current function is placed in 68HC12 banked
114 memory and must return with rtc. */
115 int current_function_far
;
117 /* Min offset that is valid for the indirect addressing mode. */
118 HOST_WIDE_INT m68hc11_min_offset
= 0;
120 /* Max offset that is valid for the indirect addressing mode. */
121 HOST_WIDE_INT m68hc11_max_offset
= 256;
123 /* The class value for base registers. */
124 enum reg_class m68hc11_base_reg_class
= A_REGS
;
126 /* The class value for index registers. This is NO_REGS for 68HC11. */
127 enum reg_class m68hc11_index_reg_class
= NO_REGS
;
129 enum reg_class m68hc11_tmp_regs_class
= NO_REGS
;
131 /* Tables that tell whether a given hard register is valid for
132 a base or an index register. It is filled at init time depending
133 on the target processor. */
134 unsigned char m68hc11_reg_valid_for_base
[FIRST_PSEUDO_REGISTER
];
135 unsigned char m68hc11_reg_valid_for_index
[FIRST_PSEUDO_REGISTER
];
137 /* A correction offset which is applied to the stack pointer.
138 This is 1 for 68HC11 and 0 for 68HC12. */
139 int m68hc11_sp_correction
;
141 #define ADDR_STRICT 0x01 /* Accept only registers in class A_REGS */
142 #define ADDR_INCDEC 0x02 /* Post/Pre inc/dec */
143 #define ADDR_INDEXED 0x04 /* D-reg index */
144 #define ADDR_OFFSET 0x08
145 #define ADDR_INDIRECT 0x10 /* Accept (mem (mem ...)) for [n,X] */
146 #define ADDR_CONST 0x20 /* Accept const and symbol_ref */
148 int m68hc11_addr_mode
;
149 int m68hc11_mov_addr_mode
;
151 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
152 rtx m68hc11_compare_op0
;
153 rtx m68hc11_compare_op1
;
156 const struct processor_costs
*m68hc11_cost
;
158 /* Costs for a 68HC11. */
159 static const struct processor_costs m6811_cost
= {
164 /* non-constant shift */
167 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
168 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
169 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
172 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
173 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
174 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
175 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
176 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
177 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
182 COSTS_N_INSNS (20 * 4),
184 COSTS_N_INSNS (20 * 16),
193 /* Costs for a 68HC12. */
194 static const struct processor_costs m6812_cost
= {
199 /* non-constant shift */
202 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
203 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
204 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
207 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
208 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
209 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
210 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
211 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
212 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
219 COSTS_N_INSNS (3 * 4),
228 /* Machine specific options */
230 const char *m68hc11_regparm_string
;
231 const char *m68hc11_reg_alloc_order
;
232 const char *m68hc11_soft_reg_count
;
234 static int nb_soft_regs
;
236 /* Initialize the GCC target structure. */
237 #undef TARGET_ATTRIBUTE_TABLE
238 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
240 #undef TARGET_ASM_ALIGNED_HI_OP
241 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
243 #undef TARGET_ASM_FUNCTION_EPILOGUE
244 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
246 #undef TARGET_ASM_FILE_START
247 #define TARGET_ASM_FILE_START m68hc11_file_start
248 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
249 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
251 #undef TARGET_ENCODE_SECTION_INFO
252 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
254 #undef TARGET_SECTION_TYPE_FLAGS
255 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
257 #undef TARGET_RTX_COSTS
258 #define TARGET_RTX_COSTS m68hc11_rtx_costs
259 #undef TARGET_ADDRESS_COST
260 #define TARGET_ADDRESS_COST m68hc11_address_cost
262 #undef TARGET_MACHINE_DEPENDENT_REORG
263 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
265 #undef TARGET_INIT_LIBFUNCS
266 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
268 struct gcc_target targetm
= TARGET_INITIALIZER
;
271 m68hc11_override_options (void)
273 memset (m68hc11_reg_valid_for_index
, 0,
274 sizeof (m68hc11_reg_valid_for_index
));
275 memset (m68hc11_reg_valid_for_base
, 0, sizeof (m68hc11_reg_valid_for_base
));
277 /* Compilation with -fpic generates a wrong code. */
280 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
281 (flag_pic
> 1) ? "PIC" : "pic");
285 /* Do not enable -fweb because it breaks the 32-bit shift patterns
286 by breaking the match_dup of those patterns. The shift patterns
287 will no longer be recognized after that. */
290 /* Configure for a 68hc11 processor. */
293 /* If gcc was built for a 68hc12, invalidate that because
294 a -m68hc11 option was specified on the command line. */
295 if (TARGET_DEFAULT
!= MASK_M6811
)
296 target_flags
&= ~TARGET_DEFAULT
;
299 target_flags
&= ~(TARGET_AUTO_INC_DEC
| TARGET_MIN_MAX
);
300 m68hc11_cost
= &m6811_cost
;
301 m68hc11_min_offset
= 0;
302 m68hc11_max_offset
= 256;
303 m68hc11_index_reg_class
= NO_REGS
;
304 m68hc11_base_reg_class
= A_REGS
;
305 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
306 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
307 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
308 m68hc11_sp_correction
= 1;
309 m68hc11_tmp_regs_class
= D_REGS
;
310 m68hc11_addr_mode
= ADDR_OFFSET
;
311 m68hc11_mov_addr_mode
= 0;
312 if (m68hc11_soft_reg_count
== 0 && !TARGET_M6812
)
313 m68hc11_soft_reg_count
= "4";
316 /* Configure for a 68hc12 processor. */
319 m68hc11_cost
= &m6812_cost
;
320 m68hc11_min_offset
= -65536;
321 m68hc11_max_offset
= 65536;
322 m68hc11_index_reg_class
= D_REGS
;
323 m68hc11_base_reg_class
= A_OR_SP_REGS
;
324 m68hc11_reg_valid_for_base
[HARD_X_REGNUM
] = 1;
325 m68hc11_reg_valid_for_base
[HARD_Y_REGNUM
] = 1;
326 m68hc11_reg_valid_for_base
[HARD_Z_REGNUM
] = 1;
327 m68hc11_reg_valid_for_base
[HARD_SP_REGNUM
] = 1;
328 m68hc11_reg_valid_for_index
[HARD_D_REGNUM
] = 1;
329 m68hc11_sp_correction
= 0;
330 m68hc11_tmp_regs_class
= TMP_REGS
;
331 m68hc11_addr_mode
= ADDR_INDIRECT
| ADDR_OFFSET
| ADDR_CONST
332 | (TARGET_AUTO_INC_DEC
? ADDR_INCDEC
: 0);
333 m68hc11_mov_addr_mode
= ADDR_OFFSET
| ADDR_CONST
334 | (TARGET_AUTO_INC_DEC
? ADDR_INCDEC
: 0);
335 target_flags
&= ~MASK_M6811
;
336 target_flags
|= MASK_NO_DIRECT_MODE
;
337 if (m68hc11_soft_reg_count
== 0)
338 m68hc11_soft_reg_count
= "0";
340 if (TARGET_LONG_CALLS
)
341 current_function_far
= 1;
348 m68hc11_conditional_register_usage (void)
351 int cnt
= atoi (m68hc11_soft_reg_count
);
355 if (cnt
> SOFT_REG_LAST
- SOFT_REG_FIRST
)
356 cnt
= SOFT_REG_LAST
- SOFT_REG_FIRST
;
359 for (i
= SOFT_REG_FIRST
+ cnt
; i
< SOFT_REG_LAST
; i
++)
362 call_used_regs
[i
] = 1;
365 /* For 68HC12, the Z register emulation is not necessary when the
366 frame pointer is not used. The frame pointer is eliminated and
367 replaced by the stack register (which is a BASE_REG_CLASS). */
368 if (TARGET_M6812
&& flag_omit_frame_pointer
&& optimize
)
370 fixed_regs
[HARD_Z_REGNUM
] = 1;
375 /* Reload and register operations. */
377 static const char *const reg_class_names
[] = REG_CLASS_NAMES
;
381 create_regs_rtx (void)
383 /* regs_inited = 1; */
384 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
385 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
386 d_reg
= gen_rtx (REG
, HImode
, HARD_D_REGNUM
);
387 m68hc11_soft_tmp_reg
= gen_rtx (REG
, HImode
, SOFT_TMP_REGNUM
);
389 stack_push_word
= gen_rtx (MEM
, HImode
,
390 gen_rtx (PRE_DEC
, HImode
,
391 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
392 stack_pop_word
= gen_rtx (MEM
, HImode
,
393 gen_rtx (POST_INC
, HImode
,
394 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
398 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
399 - 8 bit values are stored anywhere (except the SP register).
400 - 16 bit values can be stored in any register whose mode is 16
401 - 32 bit values can be stored in D, X registers or in a soft register
402 (except the last one because we need 2 soft registers)
403 - Values whose size is > 32 bit are not stored in real hard
404 registers. They may be stored in soft registers if there are
407 hard_regno_mode_ok (int regno
, enum machine_mode mode
)
409 switch (GET_MODE_SIZE (mode
))
412 return S_REGNO_P (regno
) && nb_soft_regs
>= 4;
415 return X_REGNO_P (regno
) || (S_REGNO_P (regno
) && nb_soft_regs
>= 2);
418 return G_REGNO_P (regno
);
421 /* We have to accept a QImode in X or Y registers. Otherwise, the
422 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
423 in the insns. Reload fails if the insn rejects the register class 'a'
424 as well as if it accepts it. Patterns that failed were
425 zero_extend_qihi2 and iorqi3. */
427 return G_REGNO_P (regno
) && !SP_REGNO_P (regno
);
435 m68hc11_hard_regno_rename_ok (int reg1
, int reg2
)
437 /* Don't accept renaming to Z register. We will replace it to
438 X,Y or D during machine reorg pass. */
439 if (reg2
== HARD_Z_REGNUM
)
442 /* Don't accept renaming D,X to Y register as the code will be bigger. */
443 if (TARGET_M6811
&& reg2
== HARD_Y_REGNUM
444 && (D_REGNO_P (reg1
) || X_REGNO_P (reg1
)))
451 preferred_reload_class (rtx operand
, enum reg_class
class)
453 enum machine_mode mode
;
455 mode
= GET_MODE (operand
);
459 printf ("Preferred reload: (class=%s): ", reg_class_names
[class]);
462 if (class == D_OR_A_OR_S_REGS
&& SP_REG_P (operand
))
463 return m68hc11_base_reg_class
;
465 if (class >= S_REGS
&& (GET_CODE (operand
) == MEM
466 || GET_CODE (operand
) == CONST_INT
))
468 /* S_REGS class must not be used. The movhi template does not
469 work to move a memory to a soft register.
470 Restrict to a hard reg. */
475 case D_OR_A_OR_S_REGS
:
481 case D_OR_SP_OR_S_REGS
:
482 class = D_OR_SP_REGS
;
484 case D_OR_Y_OR_S_REGS
:
487 case D_OR_X_OR_S_REGS
:
503 else if (class == Y_REGS
&& GET_CODE (operand
) == MEM
)
507 else if (class == A_OR_D_REGS
&& GET_MODE_SIZE (mode
) == 4)
511 else if (class >= S_REGS
&& S_REG_P (operand
))
517 case D_OR_A_OR_S_REGS
:
523 case D_OR_SP_OR_S_REGS
:
524 class = D_OR_SP_REGS
;
526 case D_OR_Y_OR_S_REGS
:
529 case D_OR_X_OR_S_REGS
:
545 else if (class >= S_REGS
)
549 printf ("Class = %s for: ", reg_class_names
[class]);
557 printf (" => class=%s\n", reg_class_names
[class]);
565 /* Return 1 if the operand is a valid indexed addressing mode.
566 For 68hc11: n,r with n in [0..255] and r in A_REGS class
567 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
569 register_indirect_p (rtx operand
, enum machine_mode mode
, int addr_mode
)
573 switch (GET_CODE (operand
))
576 if ((addr_mode
& ADDR_INDIRECT
) && GET_MODE_SIZE (mode
) <= 2)
577 return register_indirect_p (XEXP (operand
, 0), mode
,
578 addr_mode
& (ADDR_STRICT
| ADDR_OFFSET
));
585 if (addr_mode
& ADDR_INCDEC
)
586 return register_indirect_p (XEXP (operand
, 0), mode
,
587 addr_mode
& ADDR_STRICT
);
591 base
= XEXP (operand
, 0);
592 if (GET_CODE (base
) == MEM
)
595 offset
= XEXP (operand
, 1);
596 if (GET_CODE (offset
) == MEM
)
599 /* Indexed addressing mode with 2 registers. */
600 if (GET_CODE (base
) == REG
&& GET_CODE (offset
) == REG
)
602 if (!(addr_mode
& ADDR_INDEXED
))
605 addr_mode
&= ADDR_STRICT
;
606 if (REGNO_OK_FOR_BASE_P2 (REGNO (base
), addr_mode
)
607 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset
), addr_mode
))
610 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset
), addr_mode
)
611 && REGNO_OK_FOR_INDEX_P2 (REGNO (base
), addr_mode
))
617 if (!(addr_mode
& ADDR_OFFSET
))
620 if (GET_CODE (base
) == REG
)
622 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
625 if (!(addr_mode
& ADDR_STRICT
))
628 return REGNO_OK_FOR_BASE_P2 (REGNO (base
), 1);
631 if (GET_CODE (offset
) == REG
)
633 if (!VALID_CONSTANT_OFFSET_P (base
, mode
))
636 if (!(addr_mode
& ADDR_STRICT
))
639 return REGNO_OK_FOR_BASE_P2 (REGNO (offset
), 1);
644 return REGNO_OK_FOR_BASE_P2 (REGNO (operand
), addr_mode
& ADDR_STRICT
);
647 if (addr_mode
& ADDR_CONST
)
648 return VALID_CONSTANT_OFFSET_P (operand
, mode
);
656 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
657 a 68HC12 1-byte index addressing mode. */
659 m68hc11_small_indexed_indirect_p (rtx operand
, enum machine_mode mode
)
664 if (GET_CODE (operand
) == REG
&& reload_in_progress
665 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
666 && reg_equiv_memory_loc
[REGNO (operand
)])
668 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
669 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
672 if (GET_CODE (operand
) != MEM
)
675 operand
= XEXP (operand
, 0);
676 if (CONSTANT_ADDRESS_P (operand
))
679 if (PUSH_POP_ADDRESS_P (operand
))
682 addr_mode
= m68hc11_mov_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
683 if (!register_indirect_p (operand
, mode
, addr_mode
))
686 if (TARGET_M6812
&& GET_CODE (operand
) == PLUS
687 && (reload_completed
| reload_in_progress
))
689 base
= XEXP (operand
, 0);
690 offset
= XEXP (operand
, 1);
692 /* The offset can be a symbol address and this is too big
693 for the operand constraint. */
694 if (GET_CODE (base
) != CONST_INT
&& GET_CODE (offset
) != CONST_INT
)
697 if (GET_CODE (base
) == CONST_INT
)
700 switch (GET_MODE_SIZE (mode
))
703 if (INTVAL (offset
) < -16 + 6 || INTVAL (offset
) > 15 - 6)
708 if (INTVAL (offset
) < -16 + 2 || INTVAL (offset
) > 15 - 2)
713 if (INTVAL (offset
) < -16 || INTVAL (offset
) > 15)
722 m68hc11_register_indirect_p (rtx operand
, enum machine_mode mode
)
726 if (GET_CODE (operand
) == REG
&& reload_in_progress
727 && REGNO (operand
) >= FIRST_PSEUDO_REGISTER
728 && reg_equiv_memory_loc
[REGNO (operand
)])
730 operand
= reg_equiv_memory_loc
[REGNO (operand
)];
731 operand
= eliminate_regs (operand
, 0, NULL_RTX
);
733 if (GET_CODE (operand
) != MEM
)
736 operand
= XEXP (operand
, 0);
737 addr_mode
= m68hc11_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
738 return register_indirect_p (operand
, mode
, addr_mode
);
742 go_if_legitimate_address_internal (rtx operand
, enum machine_mode mode
,
747 if (CONSTANT_ADDRESS_P (operand
) && TARGET_M6812
)
749 /* Reject the global variables if they are too wide. This forces
750 a load of their address in a register and generates smaller code. */
751 if (GET_MODE_SIZE (mode
) == 8)
756 addr_mode
= m68hc11_addr_mode
| (strict
? ADDR_STRICT
: 0);
757 if (register_indirect_p (operand
, mode
, addr_mode
))
761 if (PUSH_POP_ADDRESS_P (operand
))
765 if (symbolic_memory_operand (operand
, mode
))
773 m68hc11_go_if_legitimate_address (rtx operand
, enum machine_mode mode
,
780 printf ("Checking: ");
785 result
= go_if_legitimate_address_internal (operand
, mode
, strict
);
789 printf (" -> %s\n", result
== 0 ? "NO" : "YES");
796 printf ("go_if_legitimate%s, ret 0: %d:",
797 (strict
? "_strict" : ""), mode
);
806 m68hc11_legitimize_address (rtx
*operand ATTRIBUTE_UNUSED
,
807 rtx old_operand ATTRIBUTE_UNUSED
,
808 enum machine_mode mode ATTRIBUTE_UNUSED
)
815 m68hc11_reload_operands (rtx operands
[])
817 enum machine_mode mode
;
819 if (regs_inited
== 0)
822 mode
= GET_MODE (operands
[1]);
824 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
825 if (A_REG_P (operands
[0]) && memory_reload_operand (operands
[1], mode
))
827 rtx big_offset
= XEXP (XEXP (operands
[1], 0), 1);
828 rtx base
= XEXP (XEXP (operands
[1], 0), 0);
830 if (GET_CODE (base
) != REG
)
837 /* If the offset is out of range, we have to compute the address
838 with a separate add instruction. We try to do with with an 8-bit
839 add on the A register. This is possible only if the lowest part
840 of the offset (ie, big_offset % 256) is a valid constant offset
841 with respect to the mode. If it's not, we have to generate a
842 16-bit add on the D register. From:
844 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
848 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
849 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
850 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
851 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
853 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
854 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
857 if (!VALID_CONSTANT_OFFSET_P (big_offset
, mode
))
860 rtx reg
= operands
[0];
862 int val
= INTVAL (big_offset
);
865 /* We use the 'operands[0]' as a scratch register to compute the
866 address. Make sure 'base' is in that register. */
867 if (!rtx_equal_p (base
, operands
[0]))
869 emit_move_insn (reg
, base
);
879 vh
= (val
>> 8) & 0x0FF;
883 /* Create the lowest part offset that still remains to be added.
884 If it's not a valid offset, do a 16-bit add. */
885 offset
= GEN_INT (vl
);
886 if (!VALID_CONSTANT_OFFSET_P (offset
, mode
))
888 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
889 gen_rtx (PLUS
, HImode
, reg
, big_offset
)));
894 emit_insn (gen_rtx (SET
, VOIDmode
, reg
,
895 gen_rtx (PLUS
, HImode
, reg
,
896 GEN_INT (vh
<< 8))));
898 emit_move_insn (operands
[0],
899 gen_rtx (MEM
, GET_MODE (operands
[1]),
900 gen_rtx (PLUS
, Pmode
, reg
, offset
)));
905 /* Use the normal gen_movhi pattern. */
910 m68hc11_emit_libcall (const char *name
, enum rtx_code code
,
911 enum machine_mode dmode
, enum machine_mode smode
,
912 int noperands
, rtx
*operands
)
920 libcall
= gen_rtx_SYMBOL_REF (Pmode
, name
);
924 ret
= emit_library_call_value (libcall
, NULL_RTX
, LCT_CONST
,
925 dmode
, 1, operands
[1], smode
);
926 equiv
= gen_rtx (code
, dmode
, operands
[1]);
930 ret
= emit_library_call_value (libcall
, NULL_RTX
,
932 operands
[1], smode
, operands
[2],
934 equiv
= gen_rtx (code
, dmode
, operands
[1], operands
[2]);
941 insns
= get_insns ();
943 emit_libcall_block (insns
, operands
[0], ret
, equiv
);
946 /* Returns true if X is a PRE/POST increment decrement
947 (same as auto_inc_p() in rtlanal.c but do not take into
948 account the stack). */
950 m68hc11_auto_inc_p (rtx x
)
952 return GET_CODE (x
) == PRE_DEC
953 || GET_CODE (x
) == POST_INC
954 || GET_CODE (x
) == POST_DEC
|| GET_CODE (x
) == PRE_INC
;
958 /* Predicates for machine description. */
961 memory_reload_operand (rtx operand
, enum machine_mode mode ATTRIBUTE_UNUSED
)
963 return GET_CODE (operand
) == MEM
964 && GET_CODE (XEXP (operand
, 0)) == PLUS
965 && ((GET_CODE (XEXP (XEXP (operand
, 0), 0)) == REG
966 && GET_CODE (XEXP (XEXP (operand
, 0), 1)) == CONST_INT
)
967 || (GET_CODE (XEXP (XEXP (operand
, 0), 1)) == REG
968 && GET_CODE (XEXP (XEXP (operand
, 0), 0)) == CONST_INT
));
972 tst_operand (rtx operand
, enum machine_mode mode
)
974 if (GET_CODE (operand
) == MEM
&& reload_completed
== 0)
976 rtx addr
= XEXP (operand
, 0);
977 if (m68hc11_auto_inc_p (addr
))
980 return nonimmediate_operand (operand
, mode
);
984 cmp_operand (rtx operand
, enum machine_mode mode
)
986 if (GET_CODE (operand
) == MEM
)
988 rtx addr
= XEXP (operand
, 0);
989 if (m68hc11_auto_inc_p (addr
))
992 return general_operand (operand
, mode
);
996 non_push_operand (rtx operand
, enum machine_mode mode
)
998 if (general_operand (operand
, mode
) == 0)
1001 if (push_operand (operand
, mode
) == 1)
1007 reg_or_some_mem_operand (rtx operand
, enum machine_mode mode
)
1009 if (GET_CODE (operand
) == MEM
)
1011 rtx op
= XEXP (operand
, 0);
1013 if (symbolic_memory_operand (op
, mode
))
1016 if (IS_STACK_PUSH (operand
))
1019 if (m68hc11_register_indirect_p (operand
, mode
))
1025 return register_operand (operand
, mode
);
1029 m68hc11_symbolic_p (rtx operand
, enum machine_mode mode
)
1031 if (GET_CODE (operand
) == MEM
)
1033 rtx op
= XEXP (operand
, 0);
1035 if (symbolic_memory_operand (op
, mode
))
1042 m68hc11_indirect_p (rtx operand
, enum machine_mode mode
)
1044 if (GET_CODE (operand
) == MEM
&& GET_MODE (operand
) == mode
)
1046 rtx op
= XEXP (operand
, 0);
1049 if (symbolic_memory_operand (op
, mode
))
1050 return TARGET_M6812
;
1052 if (reload_in_progress
)
1055 operand
= XEXP (operand
, 0);
1056 addr_mode
= m68hc11_addr_mode
| (reload_completed
? ADDR_STRICT
: 0);
1057 return register_indirect_p (operand
, mode
, addr_mode
);
1063 stack_register_operand (rtx operand
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1065 return SP_REG_P (operand
);
1069 d_register_operand (rtx operand
, enum machine_mode mode
)
1071 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1074 if (GET_CODE (operand
) == SUBREG
)
1075 operand
= XEXP (operand
, 0);
1077 return GET_CODE (operand
) == REG
1078 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1079 || REGNO (operand
) == HARD_D_REGNUM
1080 || (mode
== QImode
&& REGNO (operand
) == HARD_B_REGNUM
));
1084 hard_addr_reg_operand (rtx operand
, enum machine_mode mode
)
1086 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1089 if (GET_CODE (operand
) == SUBREG
)
1090 operand
= XEXP (operand
, 0);
1092 return GET_CODE (operand
) == REG
1093 && (REGNO (operand
) == HARD_X_REGNUM
1094 || REGNO (operand
) == HARD_Y_REGNUM
1095 || REGNO (operand
) == HARD_Z_REGNUM
);
1099 hard_reg_operand (rtx operand
, enum machine_mode mode
)
1101 if (GET_MODE (operand
) != mode
&& mode
!= VOIDmode
)
1104 if (GET_CODE (operand
) == SUBREG
)
1105 operand
= XEXP (operand
, 0);
1107 return GET_CODE (operand
) == REG
1108 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1109 || H_REGNO_P (REGNO (operand
)));
1113 memory_indexed_operand (rtx operand
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1115 if (GET_CODE (operand
) != MEM
)
1118 operand
= XEXP (operand
, 0);
1119 if (GET_CODE (operand
) == PLUS
)
1121 if (GET_CODE (XEXP (operand
, 0)) == REG
)
1122 operand
= XEXP (operand
, 0);
1123 else if (GET_CODE (XEXP (operand
, 1)) == REG
)
1124 operand
= XEXP (operand
, 1);
1126 return GET_CODE (operand
) == REG
1127 && (REGNO (operand
) >= FIRST_PSEUDO_REGISTER
1128 || A_REGNO_P (REGNO (operand
)));
1132 push_pop_operand_p (rtx operand
)
1134 if (GET_CODE (operand
) != MEM
)
1138 operand
= XEXP (operand
, 0);
1139 return PUSH_POP_ADDRESS_P (operand
);
1142 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1143 reference and a constant. */
1146 symbolic_memory_operand (rtx op
, enum machine_mode mode
)
1148 switch (GET_CODE (op
))
1156 return ((GET_CODE (XEXP (op
, 0)) == SYMBOL_REF
1157 || GET_CODE (XEXP (op
, 0)) == LABEL_REF
)
1158 && GET_CODE (XEXP (op
, 1)) == CONST_INT
);
1160 /* ??? This clause seems to be irrelevant. */
1162 return GET_MODE (op
) == mode
;
1165 return symbolic_memory_operand (XEXP (op
, 0), mode
)
1166 && symbolic_memory_operand (XEXP (op
, 1), mode
);
1174 m68hc11_eq_compare_operator (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1176 return GET_CODE (op
) == EQ
|| GET_CODE (op
) == NE
;
1180 m68hc11_logical_operator (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1182 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
;
1186 m68hc11_arith_operator (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1188 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1189 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
1190 || GET_CODE (op
) == ASHIFT
|| GET_CODE (op
) == ASHIFTRT
1191 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ROTATE
1192 || GET_CODE (op
) == ROTATERT
;
1196 m68hc11_non_shift_operator (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1198 return GET_CODE (op
) == AND
|| GET_CODE (op
) == IOR
|| GET_CODE (op
) == XOR
1199 || GET_CODE (op
) == PLUS
|| GET_CODE (op
) == MINUS
;
1202 /* Return true if op is a shift operator. */
1204 m68hc11_shift_operator (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1206 return GET_CODE (op
) == ROTATE
|| GET_CODE (op
) == ROTATERT
1207 || GET_CODE (op
) == LSHIFTRT
|| GET_CODE (op
) == ASHIFT
1208 || GET_CODE (op
) == ASHIFTRT
;
1212 m68hc11_unary_operator (rtx op
, enum machine_mode mode ATTRIBUTE_UNUSED
)
1214 return GET_CODE (op
) == NEG
|| GET_CODE (op
) == NOT
1215 || GET_CODE (op
) == SIGN_EXTEND
|| GET_CODE (op
) == ZERO_EXTEND
;
1218 /* Emit the code to build the trampoline used to call a nested function.
1222 ldy #&CXT movw #&CXT,*_.d1
1223 sty *_.d1 jmp FNADDR
1228 m68hc11_initialize_trampoline (rtx tramp
, rtx fnaddr
, rtx cxt
)
1230 const char *static_chain_reg
= reg_names
[STATIC_CHAIN_REGNUM
];
1233 if (*static_chain_reg
== '*')
1237 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x18ce));
1238 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1239 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1241 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1242 gen_rtx_CONST (QImode
,
1243 gen_rtx_SYMBOL_REF (Pmode
,
1244 static_chain_reg
)));
1245 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 7)),
1247 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 8)), fnaddr
);
1251 emit_move_insn (gen_rtx_MEM (HImode
, tramp
), GEN_INT (0x1803));
1252 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 2)), cxt
);
1253 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 4)),
1254 gen_rtx_CONST (HImode
,
1255 gen_rtx_SYMBOL_REF (Pmode
,
1256 static_chain_reg
)));
1257 emit_move_insn (gen_rtx_MEM (QImode
, plus_constant (tramp
, 6)),
1259 emit_move_insn (gen_rtx_MEM (HImode
, plus_constant (tramp
, 7)), fnaddr
);
1263 /* Declaration of types. */
1265 const struct attribute_spec m68hc11_attribute_table
[] =
1267 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1268 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1269 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1270 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1271 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute
},
1272 { NULL
, 0, 0, false, false, false, NULL
}
1275 /* Keep track of the symbol which has a `trap' attribute and which uses
1276 the `swi' calling convention. Since there is only one trap, we only
1277 record one such symbol. If there are several, a warning is reported. */
1278 static rtx trap_handler_symbol
= 0;
1280 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1281 arguments as in struct attribute_spec.handler. */
1283 m68hc11_handle_fntype_attribute (tree
*node
, tree name
,
1284 tree args ATTRIBUTE_UNUSED
,
1285 int flags ATTRIBUTE_UNUSED
,
1288 if (TREE_CODE (*node
) != FUNCTION_TYPE
1289 && TREE_CODE (*node
) != METHOD_TYPE
1290 && TREE_CODE (*node
) != FIELD_DECL
1291 && TREE_CODE (*node
) != TYPE_DECL
)
1293 warning ("`%s' attribute only applies to functions",
1294 IDENTIFIER_POINTER (name
));
1295 *no_add_attrs
= true;
1301 /* We want to recognize trap handlers so that we handle calls to traps
1302 in a special manner (by issuing the trap). This information is stored
1303 in SYMBOL_REF_FLAG. */
1306 m68hc11_encode_section_info (tree decl
, rtx rtl
, int first ATTRIBUTE_UNUSED
)
1312 if (TREE_CODE (decl
) != FUNCTION_DECL
)
1315 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (decl
));
1318 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1320 else if (lookup_attribute ("near", func_attr
) == NULL_TREE
)
1321 is_far
= TARGET_LONG_CALLS
!= 0;
1323 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1324 if (trap_handler
&& is_far
)
1326 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1331 if (trap_handler_symbol
!= 0)
1332 warning ("`trap' attribute is already used");
1334 trap_handler_symbol
= XEXP (rtl
, 0);
1336 SYMBOL_REF_FLAG (XEXP (rtl
, 0)) = is_far
;
1340 m68hc11_section_type_flags (tree decl
, const char *name
, int reloc
)
1342 unsigned int flags
= default_section_type_flags (decl
, name
, reloc
);
1344 if (strncmp (name
, ".eeprom", 7) == 0)
1346 flags
|= SECTION_WRITE
| SECTION_CODE
| SECTION_OVERRIDE
;
1353 m68hc11_is_far_symbol (rtx sym
)
1355 if (GET_CODE (sym
) == MEM
)
1356 sym
= XEXP (sym
, 0);
1358 return SYMBOL_REF_FLAG (sym
);
1362 m68hc11_is_trap_symbol (rtx sym
)
1364 if (GET_CODE (sym
) == MEM
)
1365 sym
= XEXP (sym
, 0);
1367 return trap_handler_symbol
!= 0 && rtx_equal_p (trap_handler_symbol
, sym
);
1371 /* Argument support functions. */
1373 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1374 Arrays are passed by references and other types by value.
1376 SCz: I tried to pass DImode by reference but it seems that this
1377 does not work very well. */
1379 m68hc11_function_arg_pass_by_reference (const CUMULATIVE_ARGS
*cum ATTRIBUTE_UNUSED
,
1380 enum machine_mode mode ATTRIBUTE_UNUSED
,
1382 int named ATTRIBUTE_UNUSED
)
1384 return ((type
&& TREE_CODE (type
) == ARRAY_TYPE
)
1385 /* Consider complex values as aggregates, so care for TCmode. */
1386 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1387 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1391 /* Define the offset between two registers, one to be eliminated, and the
1392 other its replacement, at the start of a routine. */
1394 m68hc11_initial_elimination_offset (int from
, int to
)
1401 /* For a trap handler, we must take into account the registers which
1402 are pushed on the stack during the trap (except the PC). */
1403 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1404 current_function_interrupt
= lookup_attribute ("interrupt",
1405 func_attr
) != NULL_TREE
;
1406 trap_handler
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1408 if (lookup_attribute ("far", func_attr
) != 0)
1409 current_function_far
= 1;
1410 else if (lookup_attribute ("near", func_attr
) != 0)
1411 current_function_far
= 0;
1413 current_function_far
= (TARGET_LONG_CALLS
!= 0
1414 && !current_function_interrupt
1417 if (trap_handler
&& from
== ARG_POINTER_REGNUM
)
1420 /* For a function using 'call/rtc' we must take into account the
1421 page register which is pushed in the call. */
1422 else if (current_function_far
&& from
== ARG_POINTER_REGNUM
)
1427 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1429 /* 2 is for the saved frame.
1430 1 is for the 'sts' correction when creating the frame. */
1431 return get_frame_size () + 2 + m68hc11_sp_correction
+ size
;
1434 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_FRAME_POINTER_REGNUM
)
1436 return m68hc11_sp_correction
;
1439 /* Push any 2 byte pseudo hard registers that we need to save. */
1440 for (regno
= SOFT_REG_FIRST
; regno
< SOFT_REG_LAST
; regno
++)
1442 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1448 if (from
== ARG_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1450 return get_frame_size () + size
;
1453 if (from
== FRAME_POINTER_REGNUM
&& to
== HARD_SP_REGNUM
)
1460 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1461 for a call to a function whose data type is FNTYPE.
1462 For a library call, FNTYPE is 0. */
1465 m68hc11_init_cumulative_args (CUMULATIVE_ARGS
*cum
, tree fntype
, rtx libname
)
1469 z_replacement_completed
= 0;
1473 /* For a library call, we must find out the type of the return value.
1474 When the return value is bigger than 4 bytes, it is returned in
1475 memory. In that case, the first argument of the library call is a
1476 pointer to the memory location. Because the first argument is passed in
1477 register D, we have to identify this, so that the first function
1478 parameter is not passed in D either. */
1484 if (libname
== 0 || GET_CODE (libname
) != SYMBOL_REF
)
1487 /* If the library ends in 'di' or in 'df', we assume it's
1488 returning some DImode or some DFmode which are 64-bit wide. */
1489 name
= XSTR (libname
, 0);
1490 len
= strlen (name
);
1492 && ((name
[len
- 2] == 'd'
1493 && (name
[len
- 1] == 'f' || name
[len
- 1] == 'i'))
1494 || (name
[len
- 3] == 'd'
1495 && (name
[len
- 2] == 'i' || name
[len
- 2] == 'f'))))
1497 /* We are in. Mark the first parameter register as already used. */
1504 ret_type
= TREE_TYPE (fntype
);
1506 if (ret_type
&& aggregate_value_p (ret_type
, fntype
))
1513 /* Update the data in CUM to advance over an argument
1514 of mode MODE and data type TYPE.
1515 (TYPE is null for libcalls where that information may not be available.) */
1518 m68hc11_function_arg_advance (CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1519 tree type
, int named ATTRIBUTE_UNUSED
)
1521 if (mode
!= BLKmode
)
1523 if (cum
->words
== 0 && GET_MODE_SIZE (mode
) == 4)
1526 cum
->words
= GET_MODE_SIZE (mode
);
1530 cum
->words
+= GET_MODE_SIZE (mode
);
1531 if (cum
->words
<= HARD_REG_SIZE
)
1537 cum
->words
+= int_size_in_bytes (type
);
1542 /* Define where to put the arguments to a function.
1543 Value is zero to push the argument on the stack,
1544 or a hard register in which to store the argument.
1546 MODE is the argument's machine mode.
1547 TYPE is the data type of the argument (as a tree).
1548 This is null for libcalls where that information may
1550 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1551 the preceding args and about the function being called.
1552 NAMED is nonzero if this argument is a named parameter
1553 (otherwise it is an extra parameter matching an ellipsis). */
1556 m68hc11_function_arg (const CUMULATIVE_ARGS
*cum
, enum machine_mode mode
,
1557 tree type ATTRIBUTE_UNUSED
, int named ATTRIBUTE_UNUSED
)
1559 if (cum
->words
!= 0)
1564 if (mode
!= BLKmode
)
1566 if (GET_MODE_SIZE (mode
) == 2 * HARD_REG_SIZE
)
1567 return gen_rtx (REG
, mode
, HARD_X_REGNUM
);
1569 if (GET_MODE_SIZE (mode
) > HARD_REG_SIZE
)
1573 return gen_rtx (REG
, mode
, HARD_D_REGNUM
);
1578 /* If defined, a C expression which determines whether, and in which direction,
1579 to pad out an argument with extra space. The value should be of type
1580 `enum direction': either `upward' to pad above the argument,
1581 `downward' to pad below, or `none' to inhibit padding.
1583 Structures are stored left shifted in their argument slot. */
1585 m68hc11_function_arg_padding (enum machine_mode mode
, tree type
)
1587 if (type
!= 0 && AGGREGATE_TYPE_P (type
))
1590 /* Fall back to the default. */
1591 return DEFAULT_FUNCTION_ARG_PADDING (mode
, type
);
1595 /* Function prologue and epilogue. */
1597 /* Emit a move after the reload pass has completed. This is used to
1598 emit the prologue and epilogue. */
1600 emit_move_after_reload (rtx to
, rtx from
, rtx scratch
)
1604 if (TARGET_M6812
|| H_REG_P (to
) || H_REG_P (from
))
1606 insn
= emit_move_insn (to
, from
);
1610 emit_move_insn (scratch
, from
);
1611 insn
= emit_move_insn (to
, scratch
);
1614 /* Put a REG_INC note to tell the flow analysis that the instruction
1616 if (IS_STACK_PUSH (to
))
1618 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1619 XEXP (XEXP (to
, 0), 0),
1622 else if (IS_STACK_POP (from
))
1624 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1625 XEXP (XEXP (from
, 0), 0),
1629 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1630 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1631 The problem is that we are lying to gcc and use `txs' for x = sp
1632 (which is not really true because txs is really x = sp + 1). */
1633 else if (TARGET_M6811
&& SP_REG_P (from
))
1635 REG_NOTES (insn
) = gen_rtx_EXPR_LIST (REG_INC
,
1642 m68hc11_total_frame_size (void)
1647 size
= get_frame_size ();
1648 if (current_function_interrupt
)
1650 size
+= 3 * HARD_REG_SIZE
;
1652 if (frame_pointer_needed
)
1653 size
+= HARD_REG_SIZE
;
1655 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1656 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1657 size
+= HARD_REG_SIZE
;
1663 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED
,
1664 HOST_WIDE_INT size ATTRIBUTE_UNUSED
)
1666 /* We catch the function epilogue generation to have a chance
1667 to clear the z_replacement_completed flag. */
1668 z_replacement_completed
= 0;
1672 expand_prologue (void)
1679 if (reload_completed
!= 1)
1682 size
= get_frame_size ();
1686 /* Generate specific prologue for interrupt handlers. */
1687 func_attr
= TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl
));
1688 current_function_interrupt
= lookup_attribute ("interrupt",
1689 func_attr
) != NULL_TREE
;
1690 current_function_trap
= lookup_attribute ("trap", func_attr
) != NULL_TREE
;
1691 if (lookup_attribute ("far", func_attr
) != NULL_TREE
)
1692 current_function_far
= 1;
1693 else if (lookup_attribute ("near", func_attr
) != NULL_TREE
)
1694 current_function_far
= 0;
1696 current_function_far
= (TARGET_LONG_CALLS
!= 0
1697 && !current_function_interrupt
1698 && !current_function_trap
);
1700 /* Get the scratch register to build the frame and push registers.
1701 If the first argument is a 32-bit quantity, the D+X registers
1702 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1703 For 68HC12, this scratch register is not used. */
1704 if (current_function_args_info
.nregs
== 2)
1709 /* Save current stack frame. */
1710 if (frame_pointer_needed
)
1711 emit_move_after_reload (stack_push_word
, hard_frame_pointer_rtx
, scratch
);
1713 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1714 Other soft registers in page0 need not to be saved because they
1715 will be restored by C functions. For a trap handler, we don't
1716 need to preserve these registers because this is a synchronous call. */
1717 if (current_function_interrupt
)
1719 emit_move_after_reload (stack_push_word
, m68hc11_soft_tmp_reg
, scratch
);
1720 emit_move_after_reload (stack_push_word
,
1721 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
), scratch
);
1722 emit_move_after_reload (stack_push_word
,
1723 gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1727 /* Allocate local variables. */
1728 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1730 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1731 stack_pointer_rtx
, GEN_INT (-size
)));
1733 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1737 insn
= gen_rtx_PARALLEL
1740 gen_rtx_SET (VOIDmode
,
1742 gen_rtx_PLUS (HImode
,
1745 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1752 /* Allocate by pushing scratch values. */
1753 for (i
= 2; i
<= size
; i
+= 2)
1754 emit_move_after_reload (stack_push_word
, ix_reg
, 0);
1757 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1758 stack_pointer_rtx
, GEN_INT (-1)));
1761 /* Create the frame pointer. */
1762 if (frame_pointer_needed
)
1763 emit_move_after_reload (hard_frame_pointer_rtx
,
1764 stack_pointer_rtx
, scratch
);
1766 /* Push any 2 byte pseudo hard registers that we need to save. */
1767 for (regno
= SOFT_REG_FIRST
; regno
<= SOFT_REG_LAST
; regno
++)
1769 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1771 emit_move_after_reload (stack_push_word
,
1772 gen_rtx (REG
, HImode
, regno
), scratch
);
1778 expand_epilogue (void)
1785 if (reload_completed
!= 1)
1788 size
= get_frame_size ();
1790 /* If we are returning a value in two registers, we have to preserve the
1791 X register and use the Y register to restore the stack and the saved
1792 registers. Otherwise, use X because it's faster (and smaller). */
1793 if (current_function_return_rtx
== 0)
1795 else if (GET_CODE (current_function_return_rtx
) == MEM
)
1796 return_size
= HARD_REG_SIZE
;
1798 return_size
= GET_MODE_SIZE (GET_MODE (current_function_return_rtx
));
1800 if (return_size
> HARD_REG_SIZE
&& return_size
<= 2 * HARD_REG_SIZE
)
1805 /* Pop any 2 byte pseudo hard registers that we saved. */
1806 for (regno
= SOFT_REG_LAST
; regno
>= SOFT_REG_FIRST
; regno
--)
1808 if (regs_ever_live
[regno
] && !call_used_regs
[regno
])
1810 emit_move_after_reload (gen_rtx (REG
, HImode
, regno
),
1811 stack_pop_word
, scratch
);
1815 /* de-allocate auto variables */
1816 if (TARGET_M6812
&& (size
> 4 || size
== 3))
1818 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1819 stack_pointer_rtx
, GEN_INT (size
)));
1821 else if ((!optimize_size
&& size
> 8) || (optimize_size
&& size
> 10))
1825 insn
= gen_rtx_PARALLEL
1828 gen_rtx_SET (VOIDmode
,
1830 gen_rtx_PLUS (HImode
,
1833 gen_rtx_CLOBBER (VOIDmode
, scratch
)));
1840 for (i
= 2; i
<= size
; i
+= 2)
1841 emit_move_after_reload (scratch
, stack_pop_word
, scratch
);
1843 emit_insn (gen_addhi3 (stack_pointer_rtx
,
1844 stack_pointer_rtx
, GEN_INT (1)));
1847 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1848 if (current_function_interrupt
)
1850 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
),
1851 stack_pop_word
, scratch
);
1852 emit_move_after_reload (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
1853 stack_pop_word
, scratch
);
1854 emit_move_after_reload (m68hc11_soft_tmp_reg
, stack_pop_word
, scratch
);
1857 /* Restore previous frame pointer. */
1858 if (frame_pointer_needed
)
1859 emit_move_after_reload (hard_frame_pointer_rtx
, stack_pop_word
, scratch
);
1861 /* If the trap handler returns some value, copy the value
1862 in D, X onto the stack so that the rti will pop the return value
1864 else if (current_function_trap
&& return_size
!= 0)
1866 rtx addr_reg
= stack_pointer_rtx
;
1870 emit_move_after_reload (scratch
, stack_pointer_rtx
, 0);
1873 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1874 gen_rtx (PLUS
, HImode
, addr_reg
,
1875 GEN_INT (1))), d_reg
, 0);
1876 if (return_size
> HARD_REG_SIZE
)
1877 emit_move_after_reload (gen_rtx (MEM
, HImode
,
1878 gen_rtx (PLUS
, HImode
, addr_reg
,
1879 GEN_INT (3))), ix_reg
, 0);
1882 emit_jump_insn (gen_return ());
1886 /* Low and High part extraction for 68HC11. These routines are
1887 similar to gen_lowpart and gen_highpart but they have been
1888 fixed to work for constants and 68HC11 specific registers. */
1891 m68hc11_gen_lowpart (enum machine_mode mode
, rtx x
)
1893 /* We assume that the low part of an auto-inc mode is the same with
1894 the mode changed and that the caller split the larger mode in the
1896 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1898 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1901 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1902 floating-point constant. A CONST_DOUBLE is used whenever the
1903 constant requires more than one word in order to be adequately
1905 if (GET_CODE (x
) == CONST_DOUBLE
)
1909 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1913 if (GET_MODE (x
) == SFmode
)
1915 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1916 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[0]);
1922 split_double (x
, &first
, &second
);
1926 return GEN_INT (l
[0]);
1928 return gen_int_mode (l
[0], HImode
);
1932 l
[0] = CONST_DOUBLE_LOW (x
);
1935 return GEN_INT (l
[0]);
1936 else if (mode
== HImode
&& GET_MODE (x
) == SFmode
)
1937 return gen_int_mode (l
[0], HImode
);
1942 if (mode
== QImode
&& D_REG_P (x
))
1943 return gen_rtx (REG
, mode
, HARD_B_REGNUM
);
1945 /* gen_lowpart crashes when it is called with a SUBREG. */
1946 if (GET_CODE (x
) == SUBREG
&& SUBREG_BYTE (x
) != 0)
1949 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 4);
1950 else if (mode
== HImode
)
1951 return gen_rtx_SUBREG (mode
, SUBREG_REG (x
), SUBREG_BYTE (x
) + 2);
1955 x
= gen_lowpart (mode
, x
);
1957 /* Return a different rtx to avoid to share it in several insns
1958 (when used by a split pattern). Sharing addresses within
1959 a MEM breaks the Z register replacement (and reloading). */
1960 if (GET_CODE (x
) == MEM
)
1966 m68hc11_gen_highpart (enum machine_mode mode
, rtx x
)
1968 /* We assume that the high part of an auto-inc mode is the same with
1969 the mode changed and that the caller split the larger mode in the
1971 if (GET_CODE (x
) == MEM
&& m68hc11_auto_inc_p (XEXP (x
, 0)))
1973 return gen_rtx (MEM
, mode
, XEXP (x
, 0));
1976 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1977 floating-point constant. A CONST_DOUBLE is used whenever the
1978 constant requires more than one word in order to be adequately
1980 if (GET_CODE (x
) == CONST_DOUBLE
)
1984 if (GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
1988 if (GET_MODE (x
) == SFmode
)
1990 REAL_VALUE_FROM_CONST_DOUBLE (r
, x
);
1991 REAL_VALUE_TO_TARGET_SINGLE (r
, l
[1]);
1997 split_double (x
, &first
, &second
);
2001 return GEN_INT (l
[1]);
2003 return gen_int_mode ((l
[1] >> 16), HImode
);
2007 l
[1] = CONST_DOUBLE_HIGH (x
);
2011 return GEN_INT (l
[1]);
2012 else if (mode
== HImode
&& GET_MODE_CLASS (GET_MODE (x
)) == MODE_FLOAT
)
2013 return gen_int_mode ((l
[0] >> 16), HImode
);
2017 if (GET_CODE (x
) == CONST_INT
)
2019 HOST_WIDE_INT val
= INTVAL (x
);
2023 return gen_int_mode (val
>> 8, QImode
);
2025 else if (mode
== HImode
)
2027 return gen_int_mode (val
>> 16, HImode
);
2030 if (mode
== QImode
&& D_REG_P (x
))
2031 return gen_rtx (REG
, mode
, HARD_A_REGNUM
);
2033 /* There is no way in GCC to represent the upper part of a word register.
2034 To obtain the 8-bit upper part of a soft register, we change the
2035 reg into a mem rtx. This is possible because they are physically
2036 located in memory. There is no offset because we are big-endian. */
2037 if (mode
== QImode
&& S_REG_P (x
))
2041 /* Avoid the '*' for direct addressing mode when this
2042 addressing mode is disabled. */
2043 pos
= TARGET_NO_DIRECT_MODE
? 1 : 0;
2044 return gen_rtx (MEM
, QImode
,
2045 gen_rtx (SYMBOL_REF
, Pmode
,
2046 ®_names
[REGNO (x
)][pos
]));
2049 /* gen_highpart crashes when it is called with a SUBREG. */
2050 if (GET_CODE (x
) == SUBREG
)
2052 return gen_rtx (SUBREG
, mode
, XEXP (x
, 0), XEXP (x
, 1));
2054 if (GET_CODE (x
) == REG
)
2056 if (REGNO (x
) < FIRST_PSEUDO_REGISTER
)
2057 return gen_rtx (REG
, mode
, REGNO (x
));
2059 return gen_rtx_SUBREG (mode
, x
, 0);
2062 if (GET_CODE (x
) == MEM
)
2064 x
= change_address (x
, mode
, 0);
2066 /* Return a different rtx to avoid to share it in several insns
2067 (when used by a split pattern). Sharing addresses within
2068 a MEM breaks the Z register replacement (and reloading). */
2069 if (GET_CODE (x
) == MEM
)
2077 /* Obscure register manipulation. */
2079 /* Finds backward in the instructions to see if register 'reg' is
2080 dead. This is used when generating code to see if we can use 'reg'
2081 as a scratch register. This allows us to choose a better generation
2082 of code when we know that some register dies or can be clobbered. */
2085 dead_register_here (rtx x
, rtx reg
)
2091 x_reg
= gen_rtx (REG
, SImode
, HARD_X_REGNUM
);
2095 for (p
= PREV_INSN (x
); p
&& GET_CODE (p
) != CODE_LABEL
; p
= PREV_INSN (p
))
2102 if (GET_CODE (body
) == CALL_INSN
)
2104 if (GET_CODE (body
) == JUMP_INSN
)
2107 if (GET_CODE (body
) == SET
)
2109 rtx dst
= XEXP (body
, 0);
2111 if (GET_CODE (dst
) == REG
&& REGNO (dst
) == REGNO (reg
))
2113 if (x_reg
&& rtx_equal_p (dst
, x_reg
))
2116 if (find_regno_note (p
, REG_DEAD
, REGNO (reg
)))
2119 else if (reg_mentioned_p (reg
, p
)
2120 || (x_reg
&& reg_mentioned_p (x_reg
, p
)))
2124 /* Scan forward to see if the register is set in some insns and never
2126 for (p
= x
/*NEXT_INSN (x) */ ; p
; p
= NEXT_INSN (p
))
2130 if (GET_CODE (p
) == CODE_LABEL
2131 || GET_CODE (p
) == JUMP_INSN
2132 || GET_CODE (p
) == CALL_INSN
|| GET_CODE (p
) == BARRIER
)
2135 if (GET_CODE (p
) != INSN
)
2139 if (GET_CODE (body
) == SET
)
2141 rtx src
= XEXP (body
, 1);
2142 rtx dst
= XEXP (body
, 0);
2144 if (GET_CODE (dst
) == REG
2145 && REGNO (dst
) == REGNO (reg
) && !reg_mentioned_p (reg
, src
))
2149 /* Register is used (may be in source or in dest). */
2150 if (reg_mentioned_p (reg
, p
)
2151 || (x_reg
!= 0 && GET_MODE (p
) == SImode
2152 && reg_mentioned_p (x_reg
, p
)))
2155 return p
== 0 ? 1 : 0;
2159 /* Code generation operations called from machine description file. */
2161 /* Print the name of register 'regno' in the assembly file. */
2163 asm_print_register (FILE *file
, int regno
)
2165 const char *name
= reg_names
[regno
];
2167 if (TARGET_NO_DIRECT_MODE
&& name
[0] == '*')
2170 fprintf (file
, "%s", name
);
2173 /* A C compound statement to output to stdio stream STREAM the
2174 assembler syntax for an instruction operand X. X is an RTL
2177 CODE is a value that can be used to specify one of several ways
2178 of printing the operand. It is used when identical operands
2179 must be printed differently depending on the context. CODE
2180 comes from the `%' specification that was used to request
2181 printing of the operand. If the specification was just `%DIGIT'
2182 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2183 is the ASCII code for LTR.
2185 If X is a register, this macro should print the register's name.
2186 The names can be found in an array `reg_names' whose type is
2187 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2189 When the machine description has a specification `%PUNCT' (a `%'
2190 followed by a punctuation character), this macro is called with
2191 a null pointer for X and the punctuation character for CODE.
2193 The M68HC11 specific codes are:
2195 'b' for the low part of the operand.
2196 'h' for the high part of the operand
2197 The 'b' or 'h' modifiers have no effect if the operand has
2198 the QImode and is not a S_REG_P (soft register). If the
2199 operand is a hard register, these two modifiers have no effect.
2200 't' generate the temporary scratch register. The operand is
2202 'T' generate the low-part temporary scratch register. The operand is
2206 print_operand (FILE *file
, rtx op
, int letter
)
2210 asm_print_register (file
, SOFT_TMP_REGNUM
);
2213 else if (letter
== 'T')
2215 asm_print_register (file
, SOFT_TMP_REGNUM
);
2216 fprintf (file
, "+1");
2219 else if (letter
== '#')
2221 asm_fprintf (file
, "%I");
2224 if (GET_CODE (op
) == REG
)
2226 if (letter
== 'b' && S_REG_P (op
))
2228 asm_print_register (file
, REGNO (op
));
2229 fprintf (file
, "+1");
2231 else if (letter
== 'b' && D_REG_P (op
))
2233 asm_print_register (file
, HARD_B_REGNUM
);
2237 asm_print_register (file
, REGNO (op
));
2242 if (GET_CODE (op
) == SYMBOL_REF
&& (letter
== 'b' || letter
== 'h'))
2245 asm_fprintf (file
, "%I%%lo(");
2247 asm_fprintf (file
, "%I%%hi(");
2249 output_addr_const (file
, op
);
2250 fprintf (file
, ")");
2254 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2255 are specified. If we already have a QImode, there is nothing to do. */
2256 if (GET_MODE (op
) == HImode
|| GET_MODE (op
) == VOIDmode
)
2260 op
= m68hc11_gen_lowpart (QImode
, op
);
2262 else if (letter
== 'h')
2264 op
= m68hc11_gen_highpart (QImode
, op
);
2268 if (GET_CODE (op
) == MEM
)
2270 rtx base
= XEXP (op
, 0);
2271 switch (GET_CODE (base
))
2276 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (op
)));
2277 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2286 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2287 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2288 fprintf (file
, "-");
2297 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (op
)));
2298 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2299 fprintf (file
, "+");
2308 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (op
)));
2309 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2318 fprintf (file
, "[");
2319 print_operand_address (file
, XEXP (base
, 0));
2320 fprintf (file
, "]");
2327 output_address (base
);
2331 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == SFmode
)
2336 REAL_VALUE_FROM_CONST_DOUBLE (r
, op
);
2337 REAL_VALUE_TO_TARGET_SINGLE (r
, l
);
2338 asm_fprintf (file
, "%I0x%lx", l
);
2340 else if (GET_CODE (op
) == CONST_DOUBLE
&& GET_MODE (op
) == DFmode
)
2344 real_to_decimal (dstr
, CONST_DOUBLE_REAL_VALUE (op
),
2345 sizeof (dstr
), 0, 1);
2346 asm_fprintf (file
, "%I0r%s", dstr
);
2350 int need_parenthesize
= 0;
2353 asm_fprintf (file
, "%I");
2355 need_parenthesize
= must_parenthesize (op
);
2357 if (need_parenthesize
)
2358 fprintf (file
, "(");
2360 output_addr_const (file
, op
);
2361 if (need_parenthesize
)
2362 fprintf (file
, ")");
2366 /* Returns true if the operand 'op' must be printed with parenthesis
2367 around it. This must be done only if there is a symbol whose name
2368 is a processor register. */
2370 must_parenthesize (rtx op
)
2374 switch (GET_CODE (op
))
2377 name
= XSTR (op
, 0);
2378 /* Avoid a conflict between symbol name and a possible
2380 return (strcasecmp (name
, "a") == 0
2381 || strcasecmp (name
, "b") == 0
2382 || strcasecmp (name
, "d") == 0
2383 || strcasecmp (name
, "x") == 0
2384 || strcasecmp (name
, "y") == 0
2385 || strcasecmp (name
, "ix") == 0
2386 || strcasecmp (name
, "iy") == 0
2387 || strcasecmp (name
, "pc") == 0
2388 || strcasecmp (name
, "sp") == 0
2389 || strcasecmp (name
, "ccr") == 0) ? 1 : 0;
2393 return must_parenthesize (XEXP (op
, 0))
2394 || must_parenthesize (XEXP (op
, 1));
2400 return must_parenthesize (XEXP (op
, 0));
2411 /* A C compound statement to output to stdio stream STREAM the
2412 assembler syntax for an instruction operand that is a memory
2413 reference whose address is ADDR. ADDR is an RTL expression. */
2416 print_operand_address (FILE *file
, rtx addr
)
2420 int need_parenthesis
= 0;
2422 switch (GET_CODE (addr
))
2425 if (!REG_P (addr
) || !REG_OK_FOR_BASE_STRICT_P (addr
))
2428 fprintf (file
, "0,");
2429 asm_print_register (file
, REGNO (addr
));
2433 base
= XEXP (addr
, 0);
2434 switch (GET_CODE (base
))
2439 fprintf (file
, "%u,-", GET_MODE_SIZE (GET_MODE (addr
)));
2440 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2449 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2450 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2451 fprintf (file
, "-");
2460 fprintf (file
, "%u,", GET_MODE_SIZE (GET_MODE (addr
)));
2461 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2462 fprintf (file
, "+");
2471 fprintf (file
, "%u,+", GET_MODE_SIZE (GET_MODE (addr
)));
2472 asm_print_register (file
, REGNO (XEXP (base
, 0)));
2479 need_parenthesis
= must_parenthesize (base
);
2480 if (need_parenthesis
)
2481 fprintf (file
, "(");
2483 output_addr_const (file
, base
);
2484 if (need_parenthesis
)
2485 fprintf (file
, ")");
2491 base
= XEXP (addr
, 0);
2492 offset
= XEXP (addr
, 1);
2493 if (!G_REG_P (base
) && G_REG_P (offset
))
2495 base
= XEXP (addr
, 1);
2496 offset
= XEXP (addr
, 0);
2498 if ((CONSTANT_ADDRESS_P (base
)) && (CONSTANT_ADDRESS_P (offset
)))
2500 need_parenthesis
= must_parenthesize (addr
);
2502 if (need_parenthesis
)
2503 fprintf (file
, "(");
2505 output_addr_const (file
, base
);
2506 fprintf (file
, "+");
2507 output_addr_const (file
, offset
);
2508 if (need_parenthesis
)
2509 fprintf (file
, ")");
2511 else if (REG_P (base
) && REG_OK_FOR_BASE_STRICT_P (base
))
2517 asm_print_register (file
, REGNO (offset
));
2518 fprintf (file
, ",");
2519 asm_print_register (file
, REGNO (base
));
2526 need_parenthesis
= must_parenthesize (offset
);
2527 if (need_parenthesis
)
2528 fprintf (file
, "(");
2530 output_addr_const (file
, offset
);
2531 if (need_parenthesis
)
2532 fprintf (file
, ")");
2533 fprintf (file
, ",");
2534 asm_print_register (file
, REGNO (base
));
2544 if (GET_CODE (addr
) == CONST_INT
2545 && INTVAL (addr
) < 0x8000 && INTVAL (addr
) >= -0x8000)
2547 fprintf (file
, HOST_WIDE_INT_PRINT_DEC
, INTVAL (addr
));
2551 need_parenthesis
= must_parenthesize (addr
);
2552 if (need_parenthesis
)
2553 fprintf (file
, "(");
2555 output_addr_const (file
, addr
);
2556 if (need_parenthesis
)
2557 fprintf (file
, ")");
2564 /* Splitting of some instructions. */
2567 m68hc11_expand_compare (enum rtx_code code
, rtx op0
, rtx op1
)
2571 if (GET_MODE_CLASS (GET_MODE (op0
)) == MODE_FLOAT
)
2575 emit_insn (gen_rtx_SET (VOIDmode
, cc0_rtx
,
2576 gen_rtx_COMPARE (VOIDmode
, op0
, op1
)));
2577 ret
= gen_rtx (code
, VOIDmode
, cc0_rtx
, const0_rtx
);
2584 m68hc11_expand_compare_and_branch (enum rtx_code code
, rtx op0
, rtx op1
,
2589 switch (GET_MODE (op0
))
2593 tmp
= m68hc11_expand_compare (code
, op0
, op1
);
2594 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2595 gen_rtx_LABEL_REF (VOIDmode
, label
),
2597 emit_jump_insn (gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
));
2601 /* SCz: from i386.c */
2604 /* Don't expand the comparison early, so that we get better code
2605 when jump or whoever decides to reverse the comparison. */
2610 code
= m68hc11_prepare_fp_compare_args (code
, &m68hc11_compare_op0
,
2611 &m68hc11_compare_op1
);
2613 tmp
= gen_rtx_fmt_ee (code
, m68hc11_fp_compare_mode (code
),
2614 m68hc11_compare_op0
, m68hc11_compare_op1
);
2615 tmp
= gen_rtx_IF_THEN_ELSE (VOIDmode
, tmp
,
2616 gen_rtx_LABEL_REF (VOIDmode
, label
),
2618 tmp
= gen_rtx_SET (VOIDmode
, pc_rtx
, tmp
);
2620 use_fcomi
= ix86_use_fcomi_compare (code
);
2621 vec
= rtvec_alloc (3 + !use_fcomi
);
2622 RTVEC_ELT (vec
, 0) = tmp
;
2624 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 18));
2626 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_REG (CCFPmode
, 17));
2629 = gen_rtx_CLOBBER (VOIDmode
, gen_rtx_SCRATCH (HImode
));
2631 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode
, vec
));
2637 /* Expand SImode branch into multiple compare+branch. */
2639 rtx lo
[2], hi
[2], label2
;
2640 enum rtx_code code1
, code2
, code3
;
2642 if (CONSTANT_P (op0
) && !CONSTANT_P (op1
))
2647 code
= swap_condition (code
);
2649 lo
[0] = m68hc11_gen_lowpart (HImode
, op0
);
2650 lo
[1] = m68hc11_gen_lowpart (HImode
, op1
);
2651 hi
[0] = m68hc11_gen_highpart (HImode
, op0
);
2652 hi
[1] = m68hc11_gen_highpart (HImode
, op1
);
2654 /* Otherwise, if we are doing less-than, op1 is a constant and the
2655 low word is zero, then we can just examine the high word. */
2657 if (GET_CODE (hi
[1]) == CONST_INT
&& lo
[1] == const0_rtx
2658 && (code
== LT
|| code
== LTU
))
2660 return m68hc11_expand_compare_and_branch (code
, hi
[0], hi
[1],
2664 /* Otherwise, we need two or three jumps. */
2666 label2
= gen_label_rtx ();
2669 code2
= swap_condition (code
);
2670 code3
= unsigned_condition (code
);
2711 * if (hi(a) < hi(b)) goto true;
2712 * if (hi(a) > hi(b)) goto false;
2713 * if (lo(a) < lo(b)) goto true;
2717 m68hc11_expand_compare_and_branch (code1
, hi
[0], hi
[1], label
);
2719 m68hc11_expand_compare_and_branch (code2
, hi
[0], hi
[1], label2
);
2721 m68hc11_expand_compare_and_branch (code3
, lo
[0], lo
[1], label
);
2724 emit_label (label2
);
2734 /* Return the increment/decrement mode of a MEM if it is such.
2735 Return CONST if it is anything else. */
2737 autoinc_mode (rtx x
)
2739 if (GET_CODE (x
) != MEM
)
2743 if (GET_CODE (x
) == PRE_INC
2744 || GET_CODE (x
) == PRE_DEC
2745 || GET_CODE (x
) == POST_INC
2746 || GET_CODE (x
) == POST_DEC
)
2747 return GET_CODE (x
);
2753 m68hc11_make_autoinc_notes (rtx
*x
, void *data
)
2757 switch (GET_CODE (*x
))
2764 REG_NOTES (insn
) = alloc_EXPR_LIST (REG_INC
, XEXP (*x
, 0),
2773 /* Split a DI, SI or HI move into several smaller move operations.
2774 The scratch register 'scratch' is used as a temporary to load
2775 store intermediate values. It must be a hard register. */
2777 m68hc11_split_move (rtx to
, rtx from
, rtx scratch
)
2779 rtx low_to
, low_from
;
2780 rtx high_to
, high_from
;
2782 enum machine_mode mode
;
2784 int autoinc_from
= autoinc_mode (from
);
2785 int autoinc_to
= autoinc_mode (to
);
2787 mode
= GET_MODE (to
);
2789 /* If the TO and FROM contain autoinc modes that are not compatible
2790 together (one pop and the other a push), we must change one to
2791 an offsetable operand and generate an appropriate add at the end. */
2792 if (TARGET_M6812
&& GET_MODE_SIZE (mode
) > 2)
2797 /* The source uses an autoinc mode which is not compatible with
2798 a split (this would result in a word swap). */
2799 if (autoinc_from
== PRE_INC
|| autoinc_from
== POST_DEC
)
2801 code
= GET_CODE (XEXP (from
, 0));
2802 reg
= XEXP (XEXP (from
, 0), 0);
2803 offset
= GET_MODE_SIZE (GET_MODE (from
));
2804 if (code
== POST_DEC
)
2807 if (code
== PRE_INC
)
2808 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2810 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2811 if (code
== POST_DEC
)
2812 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2816 /* Likewise for destination. */
2817 if (autoinc_to
== PRE_INC
|| autoinc_to
== POST_DEC
)
2819 code
= GET_CODE (XEXP (to
, 0));
2820 reg
= XEXP (XEXP (to
, 0), 0);
2821 offset
= GET_MODE_SIZE (GET_MODE (to
));
2822 if (code
== POST_DEC
)
2825 if (code
== PRE_INC
)
2826 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2828 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2829 if (code
== POST_DEC
)
2830 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2834 /* The source and destination auto increment modes must be compatible
2835 with each other: same direction. */
2836 if ((autoinc_to
!= autoinc_from
2837 && autoinc_to
!= CONST
&& autoinc_from
!= CONST
)
2838 /* The destination address register must not be used within
2839 the source operand because the source address would change
2840 while doing the copy. */
2841 || (autoinc_to
!= CONST
2842 && reg_mentioned_p (XEXP (XEXP (to
, 0), 0), from
)
2843 && !IS_STACK_PUSH (to
)))
2845 /* Must change the destination. */
2846 code
= GET_CODE (XEXP (to
, 0));
2847 reg
= XEXP (XEXP (to
, 0), 0);
2848 offset
= GET_MODE_SIZE (GET_MODE (to
));
2849 if (code
== PRE_DEC
|| code
== POST_DEC
)
2852 if (code
== PRE_DEC
|| code
== PRE_INC
)
2853 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2854 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to
), reg
), from
, scratch
);
2855 if (code
== POST_DEC
|| code
== POST_INC
)
2856 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2861 /* Likewise, the source address register must not be used within
2862 the destination operand. */
2863 if (autoinc_from
!= CONST
2864 && reg_mentioned_p (XEXP (XEXP (from
, 0), 0), to
)
2865 && !IS_STACK_PUSH (to
))
2867 /* Must change the source. */
2868 code
= GET_CODE (XEXP (from
, 0));
2869 reg
= XEXP (XEXP (from
, 0), 0);
2870 offset
= GET_MODE_SIZE (GET_MODE (from
));
2871 if (code
== PRE_DEC
|| code
== POST_DEC
)
2874 if (code
== PRE_DEC
|| code
== PRE_INC
)
2875 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2876 m68hc11_split_move (to
, gen_rtx_MEM (GET_MODE (from
), reg
), scratch
);
2877 if (code
== POST_DEC
|| code
== POST_INC
)
2878 emit_insn (gen_addhi3 (reg
, reg
, GEN_INT (offset
)));
2884 if (GET_MODE_SIZE (mode
) == 8)
2886 else if (GET_MODE_SIZE (mode
) == 4)
2892 && IS_STACK_PUSH (to
)
2893 && reg_mentioned_p (gen_rtx (REG
, HImode
, HARD_SP_REGNUM
), from
))
2899 else if (mode
== HImode
)
2907 low_to
= m68hc11_gen_lowpart (mode
, to
);
2908 high_to
= m68hc11_gen_highpart (mode
, to
);
2910 low_from
= m68hc11_gen_lowpart (mode
, from
);
2911 if (mode
== SImode
&& GET_CODE (from
) == CONST_INT
)
2913 if (INTVAL (from
) >= 0)
2914 high_from
= const0_rtx
;
2916 high_from
= constm1_rtx
;
2919 high_from
= m68hc11_gen_highpart (mode
, from
);
2923 high_from
= adjust_address (high_from
, mode
, offset
);
2924 low_from
= high_from
;
2927 /* When copying with a POST_INC mode, we must copy the
2928 high part and then the low part to guarantee a correct
2931 && GET_MODE_SIZE (mode
) >= 2
2932 && autoinc_from
!= autoinc_to
2933 && (autoinc_from
== POST_INC
|| autoinc_to
== POST_INC
))
2942 low_from
= high_from
;
2947 m68hc11_split_move (low_to
, low_from
, scratch
);
2948 m68hc11_split_move (high_to
, high_from
, scratch
);
2950 else if (H_REG_P (to
) || H_REG_P (from
)
2951 || (low_from
== const0_rtx
2952 && high_from
== const0_rtx
2953 && ! push_operand (to
, GET_MODE (to
))
2954 && ! H_REG_P (scratch
))
2956 && (!m68hc11_register_indirect_p (from
, GET_MODE (from
))
2957 || m68hc11_small_indexed_indirect_p (from
,
2959 && (!m68hc11_register_indirect_p (to
, GET_MODE (to
))
2960 || m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
)))))
2962 insn
= emit_move_insn (low_to
, low_from
);
2963 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2965 insn
= emit_move_insn (high_to
, high_from
);
2966 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2970 insn
= emit_move_insn (scratch
, low_from
);
2971 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2972 insn
= emit_move_insn (low_to
, scratch
);
2973 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2975 insn
= emit_move_insn (scratch
, high_from
);
2976 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2977 insn
= emit_move_insn (high_to
, scratch
);
2978 for_each_rtx (&PATTERN (insn
), m68hc11_make_autoinc_notes
, insn
);
2983 simplify_logical (enum machine_mode mode
, int code
, rtx operand
, rtx
*result
)
2989 if (GET_CODE (operand
) != CONST_INT
)
2997 val
= INTVAL (operand
);
3001 if ((val
& mask
) == 0)
3003 if ((val
& mask
) == mask
)
3004 *result
= constm1_rtx
;
3008 if ((val
& mask
) == 0)
3009 *result
= const0_rtx
;
3010 if ((val
& mask
) == mask
)
3015 if ((val
& mask
) == 0)
3023 m68hc11_emit_logical (enum machine_mode mode
, int code
, rtx
*operands
)
3028 need_copy
= (rtx_equal_p (operands
[0], operands
[1])
3029 || rtx_equal_p (operands
[0], operands
[2])) ? 0 : 1;
3031 operands
[1] = simplify_logical (mode
, code
, operands
[1], &result
);
3032 operands
[2] = simplify_logical (mode
, code
, operands
[2], &result
);
3034 if (result
&& GET_CODE (result
) == CONST_INT
)
3036 if (!H_REG_P (operands
[0]) && operands
[3]
3037 && (INTVAL (result
) != 0 || IS_STACK_PUSH (operands
[0])))
3039 emit_move_insn (operands
[3], result
);
3040 emit_move_insn (operands
[0], operands
[3]);
3044 emit_move_insn (operands
[0], result
);
3047 else if (operands
[1] != 0 && operands
[2] != 0)
3051 if (!H_REG_P (operands
[0]) && operands
[3])
3053 emit_move_insn (operands
[3], operands
[1]);
3054 emit_insn (gen_rtx (SET
, mode
,
3056 gen_rtx (code
, mode
,
3057 operands
[3], operands
[2])));
3058 insn
= emit_move_insn (operands
[0], operands
[3]);
3062 insn
= emit_insn (gen_rtx (SET
, mode
,
3064 gen_rtx (code
, mode
,
3065 operands
[0], operands
[2])));
3069 /* The logical operation is similar to a copy. */
3074 if (GET_CODE (operands
[1]) == CONST_INT
)
3079 if (!H_REG_P (operands
[0]) && !H_REG_P (src
))
3081 emit_move_insn (operands
[3], src
);
3082 emit_move_insn (operands
[0], operands
[3]);
3086 emit_move_insn (operands
[0], src
);
3092 m68hc11_split_logical (enum machine_mode mode
, int code
, rtx
*operands
)
3097 low
[0] = m68hc11_gen_lowpart (mode
, operands
[0]);
3098 low
[1] = m68hc11_gen_lowpart (mode
, operands
[1]);
3099 low
[2] = m68hc11_gen_lowpart (mode
, operands
[2]);
3101 high
[0] = m68hc11_gen_highpart (mode
, operands
[0]);
3103 if (mode
== SImode
&& GET_CODE (operands
[1]) == CONST_INT
)
3105 if (INTVAL (operands
[1]) >= 0)
3106 high
[1] = const0_rtx
;
3108 high
[1] = constm1_rtx
;
3111 high
[1] = m68hc11_gen_highpart (mode
, operands
[1]);
3113 if (mode
== SImode
&& GET_CODE (operands
[2]) == CONST_INT
)
3115 if (INTVAL (operands
[2]) >= 0)
3116 high
[2] = const0_rtx
;
3118 high
[2] = constm1_rtx
;
3121 high
[2] = m68hc11_gen_highpart (mode
, operands
[2]);
3123 low
[3] = operands
[3];
3124 high
[3] = operands
[3];
3127 m68hc11_split_logical (HImode
, code
, low
);
3128 m68hc11_split_logical (HImode
, code
, high
);
3132 m68hc11_emit_logical (mode
, code
, low
);
3133 m68hc11_emit_logical (mode
, code
, high
);
3137 /* Code generation. */
3140 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED
, rtx operands
[])
3142 /* We have to be careful with the cc_status. An address register swap
3143 is generated for some comparison. The comparison is made with D
3144 but the branch really uses the address register. See the split
3145 pattern for compare. The xgdx/xgdy preserve the flags but after
3146 the exchange, the flags will reflect to the value of X and not D.
3147 Tell this by setting the cc_status according to the cc_prev_status. */
3148 if (X_REG_P (operands
[1]) || X_REG_P (operands
[0]))
3150 if (cc_prev_status
.value1
!= 0
3151 && (D_REG_P (cc_prev_status
.value1
)
3152 || X_REG_P (cc_prev_status
.value1
)))
3154 cc_status
= cc_prev_status
;
3155 if (D_REG_P (cc_status
.value1
))
3156 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3159 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3165 output_asm_insn ("xgdx", operands
);
3169 if (cc_prev_status
.value1
!= 0
3170 && (D_REG_P (cc_prev_status
.value1
)
3171 || Y_REG_P (cc_prev_status
.value1
)))
3173 cc_status
= cc_prev_status
;
3174 if (D_REG_P (cc_status
.value1
))
3175 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3178 cc_status
.value1
= gen_rtx (REG
, GET_MODE (cc_status
.value1
),
3184 output_asm_insn ("xgdy", operands
);
3188 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3189 This is used to decide whether a move that set flags should be used
3192 next_insn_test_reg (rtx insn
, rtx reg
)
3196 insn
= next_nonnote_insn (insn
);
3197 if (GET_CODE (insn
) != INSN
)
3200 body
= PATTERN (insn
);
3201 if (sets_cc0_p (body
) != 1)
3204 if (rtx_equal_p (XEXP (body
, 1), reg
) == 0)
3210 /* Generate the code to move a 16-bit operand into another one. */
3213 m68hc11_gen_movhi (rtx insn
, rtx
*operands
)
3217 /* Move a register or memory to the same location.
3218 This is possible because such insn can appear
3219 in a non-optimizing mode. */
3220 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3222 cc_status
= cc_prev_status
;
3228 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3230 cc_status
= cc_prev_status
;
3231 switch (REGNO (operands
[1]))
3236 output_asm_insn ("psh%1", operands
);
3238 case HARD_SP_REGNUM
:
3239 output_asm_insn ("sts\t2,-sp", operands
);
3246 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3248 cc_status
= cc_prev_status
;
3249 switch (REGNO (operands
[0]))
3254 output_asm_insn ("pul%0", operands
);
3261 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3263 m68hc11_notice_keep_cc (operands
[0]);
3264 output_asm_insn ("tfr\t%1,%0", operands
);
3266 else if (H_REG_P (operands
[0]))
3268 if (SP_REG_P (operands
[0]))
3269 output_asm_insn ("lds\t%1", operands
);
3271 output_asm_insn ("ld%0\t%1", operands
);
3273 else if (H_REG_P (operands
[1]))
3275 if (SP_REG_P (operands
[1]))
3276 output_asm_insn ("sts\t%0", operands
);
3278 output_asm_insn ("st%1\t%0", operands
);
3282 rtx from
= operands
[1];
3283 rtx to
= operands
[0];
3285 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3286 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3287 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3288 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3294 ops
[0] = operands
[2];
3297 m68hc11_gen_movhi (insn
, ops
);
3299 ops
[1] = operands
[2];
3300 m68hc11_gen_movhi (insn
, ops
);
3304 /* !!!! SCz wrong here. */
3305 fatal_insn ("move insn not handled", insn
);
3310 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3312 output_asm_insn ("clr\t%h0", operands
);
3313 output_asm_insn ("clr\t%b0", operands
);
3317 m68hc11_notice_keep_cc (operands
[0]);
3318 output_asm_insn ("movw\t%1,%0", operands
);
3325 if (IS_STACK_POP (operands
[1]) && H_REG_P (operands
[0]))
3327 cc_status
= cc_prev_status
;
3328 switch (REGNO (operands
[0]))
3332 output_asm_insn ("pul%0", operands
);
3335 output_asm_insn ("pula", operands
);
3336 output_asm_insn ("pulb", operands
);
3343 /* Some moves to a hard register are special. Not all of them
3344 are really supported and we have to use a temporary
3345 location to provide them (either the stack of a temp var). */
3346 if (H_REG_P (operands
[0]))
3348 switch (REGNO (operands
[0]))
3351 if (X_REG_P (operands
[1]))
3353 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3355 m68hc11_output_swap (insn
, operands
);
3357 else if (next_insn_test_reg (insn
, operands
[0]))
3359 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands
);
3363 m68hc11_notice_keep_cc (operands
[0]);
3364 output_asm_insn ("pshx\n\tpula\n\tpulb", operands
);
3367 else if (Y_REG_P (operands
[1]))
3369 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3371 m68hc11_output_swap (insn
, operands
);
3375 /* %t means *ZTMP scratch register. */
3376 output_asm_insn ("sty\t%t1", operands
);
3377 output_asm_insn ("ldd\t%t1", operands
);
3380 else if (SP_REG_P (operands
[1]))
3385 if (optimize
== 0 || dead_register_here (insn
, ix_reg
) == 0)
3386 output_asm_insn ("xgdx", operands
);
3387 output_asm_insn ("tsx", operands
);
3388 output_asm_insn ("xgdx", operands
);
3390 else if (IS_STACK_POP (operands
[1]))
3392 output_asm_insn ("pula\n\tpulb", operands
);
3394 else if (GET_CODE (operands
[1]) == CONST_INT
3395 && INTVAL (operands
[1]) == 0)
3397 output_asm_insn ("clra\n\tclrb", operands
);
3401 output_asm_insn ("ldd\t%1", operands
);
3406 if (D_REG_P (operands
[1]))
3408 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3410 m68hc11_output_swap (insn
, operands
);
3412 else if (next_insn_test_reg (insn
, operands
[0]))
3414 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands
);
3418 m68hc11_notice_keep_cc (operands
[0]);
3419 output_asm_insn ("pshb", operands
);
3420 output_asm_insn ("psha", operands
);
3421 output_asm_insn ("pulx", operands
);
3424 else if (Y_REG_P (operands
[1]))
3426 /* When both D and Y are dead, use the sequence xgdy, xgdx
3427 to move Y into X. The D and Y registers are modified. */
3428 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
)
3429 && dead_register_here (insn
, d_reg
))
3431 output_asm_insn ("xgdy", operands
);
3432 output_asm_insn ("xgdx", operands
);
3435 else if (!optimize_size
)
3437 output_asm_insn ("sty\t%t1", operands
);
3438 output_asm_insn ("ldx\t%t1", operands
);
3443 output_asm_insn ("pshy", operands
);
3444 output_asm_insn ("pulx", operands
);
3447 else if (SP_REG_P (operands
[1]))
3449 /* tsx, tsy preserve the flags */
3450 cc_status
= cc_prev_status
;
3451 output_asm_insn ("tsx", operands
);
3455 output_asm_insn ("ldx\t%1", operands
);
3460 if (D_REG_P (operands
[1]))
3462 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3464 m68hc11_output_swap (insn
, operands
);
3468 output_asm_insn ("std\t%t1", operands
);
3469 output_asm_insn ("ldy\t%t1", operands
);
3472 else if (X_REG_P (operands
[1]))
3474 /* When both D and X are dead, use the sequence xgdx, xgdy
3475 to move X into Y. The D and X registers are modified. */
3476 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
)
3477 && dead_register_here (insn
, d_reg
))
3479 output_asm_insn ("xgdx", operands
);
3480 output_asm_insn ("xgdy", operands
);
3483 else if (!optimize_size
)
3485 output_asm_insn ("stx\t%t1", operands
);
3486 output_asm_insn ("ldy\t%t1", operands
);
3491 output_asm_insn ("pshx", operands
);
3492 output_asm_insn ("puly", operands
);
3495 else if (SP_REG_P (operands
[1]))
3497 /* tsx, tsy preserve the flags */
3498 cc_status
= cc_prev_status
;
3499 output_asm_insn ("tsy", operands
);
3503 output_asm_insn ("ldy\t%1", operands
);
3507 case HARD_SP_REGNUM
:
3508 if (D_REG_P (operands
[1]))
3510 m68hc11_notice_keep_cc (operands
[0]);
3511 output_asm_insn ("xgdx", operands
);
3512 output_asm_insn ("txs", operands
);
3513 output_asm_insn ("xgdx", operands
);
3515 else if (X_REG_P (operands
[1]))
3517 /* tys, txs preserve the flags */
3518 cc_status
= cc_prev_status
;
3519 output_asm_insn ("txs", operands
);
3521 else if (Y_REG_P (operands
[1]))
3523 /* tys, txs preserve the flags */
3524 cc_status
= cc_prev_status
;
3525 output_asm_insn ("tys", operands
);
3529 /* lds sets the flags but the des does not. */
3531 output_asm_insn ("lds\t%1", operands
);
3532 output_asm_insn ("des", operands
);
3537 fatal_insn ("invalid register in the move instruction", insn
);
3542 if (SP_REG_P (operands
[1]) && REG_P (operands
[0])
3543 && REGNO (operands
[0]) == HARD_FRAME_POINTER_REGNUM
)
3545 output_asm_insn ("sts\t%0", operands
);
3549 if (IS_STACK_PUSH (operands
[0]) && H_REG_P (operands
[1]))
3551 cc_status
= cc_prev_status
;
3552 switch (REGNO (operands
[1]))
3556 output_asm_insn ("psh%1", operands
);
3559 output_asm_insn ("pshb", operands
);
3560 output_asm_insn ("psha", operands
);
3568 /* Operand 1 must be a hard register. */
3569 if (!H_REG_P (operands
[1]))
3571 fatal_insn ("invalid operand in the instruction", insn
);
3574 reg
= REGNO (operands
[1]);
3578 output_asm_insn ("std\t%0", operands
);
3582 output_asm_insn ("stx\t%0", operands
);
3586 output_asm_insn ("sty\t%0", operands
);
3589 case HARD_SP_REGNUM
:
3593 if (REG_P (operands
[0]) && REGNO (operands
[0]) == SOFT_TMP_REGNUM
)
3595 output_asm_insn ("pshx", operands
);
3596 output_asm_insn ("tsx", operands
);
3597 output_asm_insn ("inx", operands
);
3598 output_asm_insn ("inx", operands
);
3599 output_asm_insn ("stx\t%0", operands
);
3600 output_asm_insn ("pulx", operands
);
3603 else if (reg_mentioned_p (ix_reg
, operands
[0]))
3605 output_asm_insn ("sty\t%t0", operands
);
3606 output_asm_insn ("tsy", operands
);
3607 output_asm_insn ("sty\t%0", operands
);
3608 output_asm_insn ("ldy\t%t0", operands
);
3612 output_asm_insn ("stx\t%t0", operands
);
3613 output_asm_insn ("tsx", operands
);
3614 output_asm_insn ("stx\t%0", operands
);
3615 output_asm_insn ("ldx\t%t0", operands
);
3621 fatal_insn ("invalid register in the move instruction", insn
);
3627 m68hc11_gen_movqi (rtx insn
, rtx
*operands
)
3629 /* Move a register or memory to the same location.
3630 This is possible because such insn can appear
3631 in a non-optimizing mode. */
3632 if (operands
[0] == operands
[1] || rtx_equal_p (operands
[0], operands
[1]))
3634 cc_status
= cc_prev_status
;
3641 if (H_REG_P (operands
[0]) && H_REG_P (operands
[1]))
3643 m68hc11_notice_keep_cc (operands
[0]);
3644 output_asm_insn ("tfr\t%1,%0", operands
);
3646 else if (H_REG_P (operands
[0]))
3648 if (Q_REG_P (operands
[0]))
3649 output_asm_insn ("lda%0\t%b1", operands
);
3650 else if (D_REG_P (operands
[0]))
3651 output_asm_insn ("ldab\t%b1", operands
);
3655 else if (H_REG_P (operands
[1]))
3657 if (Q_REG_P (operands
[1]))
3658 output_asm_insn ("sta%1\t%b0", operands
);
3659 else if (D_REG_P (operands
[1]))
3660 output_asm_insn ("stab\t%b0", operands
);
3666 rtx from
= operands
[1];
3667 rtx to
= operands
[0];
3669 if ((m68hc11_register_indirect_p (from
, GET_MODE (from
))
3670 && !m68hc11_small_indexed_indirect_p (from
, GET_MODE (from
)))
3671 || (m68hc11_register_indirect_p (to
, GET_MODE (to
))
3672 && !m68hc11_small_indexed_indirect_p (to
, GET_MODE (to
))))
3678 ops
[0] = operands
[2];
3681 m68hc11_gen_movqi (insn
, ops
);
3683 ops
[1] = operands
[2];
3684 m68hc11_gen_movqi (insn
, ops
);
3688 /* !!!! SCz wrong here. */
3689 fatal_insn ("move insn not handled", insn
);
3694 if (GET_CODE (from
) == CONST_INT
&& INTVAL (from
) == 0)
3696 output_asm_insn ("clr\t%b0", operands
);
3700 m68hc11_notice_keep_cc (operands
[0]);
3701 output_asm_insn ("movb\t%b1,%b0", operands
);
3709 if (H_REG_P (operands
[0]))
3711 switch (REGNO (operands
[0]))
3715 if (X_REG_P (operands
[1]))
3717 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_X_REGNUM
))
3719 m68hc11_output_swap (insn
, operands
);
3723 output_asm_insn ("stx\t%t1", operands
);
3724 output_asm_insn ("ldab\t%T0", operands
);
3727 else if (Y_REG_P (operands
[1]))
3729 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_Y_REGNUM
))
3731 m68hc11_output_swap (insn
, operands
);
3735 output_asm_insn ("sty\t%t1", operands
);
3736 output_asm_insn ("ldab\t%T0", operands
);
3739 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3740 && !DA_REG_P (operands
[1]))
3742 output_asm_insn ("ldab\t%b1", operands
);
3744 else if (DA_REG_P (operands
[1]))
3746 output_asm_insn ("tab", operands
);
3750 cc_status
= cc_prev_status
;
3756 if (X_REG_P (operands
[1]))
3758 output_asm_insn ("stx\t%t1", operands
);
3759 output_asm_insn ("ldaa\t%T0", operands
);
3761 else if (Y_REG_P (operands
[1]))
3763 output_asm_insn ("sty\t%t1", operands
);
3764 output_asm_insn ("ldaa\t%T0", operands
);
3766 else if (!DB_REG_P (operands
[1]) && !D_REG_P (operands
[1])
3767 && !DA_REG_P (operands
[1]))
3769 output_asm_insn ("ldaa\t%b1", operands
);
3771 else if (!DA_REG_P (operands
[1]))
3773 output_asm_insn ("tba", operands
);
3777 cc_status
= cc_prev_status
;
3782 if (D_REG_P (operands
[1]))
3784 if (optimize
&& find_regno_note (insn
, REG_DEAD
, HARD_D_REGNUM
))
3786 m68hc11_output_swap (insn
, operands
);
3790 output_asm_insn ("stab\t%T1", operands
);
3791 output_asm_insn ("ldx\t%t1", operands
);
3795 else if (Y_REG_P (operands
[1]))
3797 output_asm_insn ("sty\t%t0", operands
);
3798 output_asm_insn ("ldx\t%t0", operands
);
3800 else if (GET_CODE (operands
[1]) == CONST_INT
)
3802 output_asm_insn ("ldx\t%1", operands
);
3804 else if (dead_register_here (insn
, d_reg
))
3806 output_asm_insn ("ldab\t%b1", operands
);
3807 output_asm_insn ("xgdx", operands
);
3809 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3811 output_asm_insn ("xgdx", operands
);
3812 output_asm_insn ("ldab\t%b1", operands
);
3813 output_asm_insn ("xgdx", operands
);
3817 output_asm_insn ("pshb", operands
);
3818 output_asm_insn ("ldab\t%b1", operands
);
3819 output_asm_insn ("stab\t%T1", operands
);
3820 output_asm_insn ("ldx\t%t1", operands
);
3821 output_asm_insn ("pulb", operands
);
3827 if (D_REG_P (operands
[1]))
3829 output_asm_insn ("stab\t%T1", operands
);
3830 output_asm_insn ("ldy\t%t1", operands
);
3833 else if (X_REG_P (operands
[1]))
3835 output_asm_insn ("stx\t%t1", operands
);
3836 output_asm_insn ("ldy\t%t1", operands
);
3839 else if (GET_CODE (operands
[1]) == CONST_INT
)
3841 output_asm_insn ("ldy\t%1", operands
);
3843 else if (dead_register_here (insn
, d_reg
))
3845 output_asm_insn ("ldab\t%b1", operands
);
3846 output_asm_insn ("xgdy", operands
);
3848 else if (!reg_mentioned_p (operands
[0], operands
[1]))
3850 output_asm_insn ("xgdy", operands
);
3851 output_asm_insn ("ldab\t%b1", operands
);
3852 output_asm_insn ("xgdy", operands
);
3856 output_asm_insn ("pshb", operands
);
3857 output_asm_insn ("ldab\t%b1", operands
);
3858 output_asm_insn ("stab\t%T1", operands
);
3859 output_asm_insn ("ldy\t%t1", operands
);
3860 output_asm_insn ("pulb", operands
);
3866 fatal_insn ("invalid register in the instruction", insn
);
3870 else if (H_REG_P (operands
[1]))
3872 switch (REGNO (operands
[1]))
3876 output_asm_insn ("stab\t%b0", operands
);
3880 output_asm_insn ("staa\t%b0", operands
);
3884 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands
);
3888 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands
);
3892 fatal_insn ("invalid register in the move instruction", insn
);
3899 fatal_insn ("operand 1 must be a hard register", insn
);
3903 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3904 The source and destination must be D or A and the shift must
3907 m68hc11_gen_rotate (enum rtx_code code
, rtx insn
, rtx operands
[])
3911 if (GET_CODE (operands
[2]) != CONST_INT
3912 || (!D_REG_P (operands
[0]) && !DA_REG_P (operands
[0])))
3913 fatal_insn ("invalid rotate insn", insn
);
3915 val
= INTVAL (operands
[2]);
3916 if (code
== ROTATERT
)
3917 val
= GET_MODE_SIZE (GET_MODE (operands
[0])) * BITS_PER_UNIT
- val
;
3919 if (GET_MODE (operands
[0]) != QImode
)
3922 /* Rotate by 8-bits if the shift is within [5..11]. */
3923 if (val
>= 5 && val
<= 11)
3926 output_asm_insn ("exg\ta,b", operands
);
3929 output_asm_insn ("psha", operands
);
3930 output_asm_insn ("tba", operands
);
3931 output_asm_insn ("pulb", operands
);
3936 /* If the shift is big, invert the rotation. */
3946 /* Set the carry to bit-15, but don't change D yet. */
3947 if (GET_MODE (operands
[0]) != QImode
)
3949 output_asm_insn ("asra", operands
);
3950 output_asm_insn ("rola", operands
);
3953 /* Rotate B first to move the carry to bit-0. */
3954 if (D_REG_P (operands
[0]))
3955 output_asm_insn ("rolb", operands
);
3957 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3958 output_asm_insn ("rola", operands
);
3965 /* Set the carry to bit-8 of D. */
3966 if (GET_MODE (operands
[0]) != QImode
)
3967 output_asm_insn ("tap", operands
);
3969 /* Rotate B first to move the carry to bit-7. */
3970 if (D_REG_P (operands
[0]))
3971 output_asm_insn ("rorb", operands
);
3973 if (GET_MODE (operands
[0]) != QImode
|| DA_REG_P (operands
[0]))
3974 output_asm_insn ("rora", operands
);
3981 /* Store in cc_status the expressions that the condition codes will
3982 describe after execution of an instruction whose pattern is EXP.
3983 Do not alter them if the instruction would not alter the cc's. */
3986 m68hc11_notice_update_cc (rtx exp
, rtx insn ATTRIBUTE_UNUSED
)
3988 /* recognize SET insn's. */
3989 if (GET_CODE (exp
) == SET
)
3991 /* Jumps do not alter the cc's. */
3992 if (SET_DEST (exp
) == pc_rtx
)
3995 /* NOTE: most instructions don't affect the carry bit, but the
3996 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3997 the conditions.h header. */
3999 /* Function calls clobber the cc's. */
4000 else if (GET_CODE (SET_SRC (exp
)) == CALL
)
4005 /* Tests and compares set the cc's in predictable ways. */
4006 else if (SET_DEST (exp
) == cc0_rtx
)
4008 cc_status
.flags
= 0;
4009 cc_status
.value1
= XEXP (exp
, 0);
4010 cc_status
.value2
= XEXP (exp
, 1);
4014 /* All other instructions affect the condition codes. */
4015 cc_status
.flags
= 0;
4016 cc_status
.value1
= XEXP (exp
, 0);
4017 cc_status
.value2
= XEXP (exp
, 1);
4022 /* Default action if we haven't recognized something
4023 and returned earlier. */
4027 if (cc_status
.value2
!= 0)
4028 switch (GET_CODE (cc_status
.value2
))
4030 /* These logical operations can generate several insns.
4031 The flags are setup according to what is generated. */
4037 /* The (not ...) generates several 'com' instructions for
4038 non QImode. We have to invalidate the flags. */
4040 if (GET_MODE (cc_status
.value2
) != QImode
)
4052 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4053 cc_status
.flags
|= CC_NO_OVERFLOW
;
4056 /* The asl sets the overflow bit in such a way that this
4057 makes the flags unusable for a next compare insn. */
4061 if (GET_MODE (cc_status
.value2
) != VOIDmode
)
4062 cc_status
.flags
|= CC_NO_OVERFLOW
;
4065 /* A load/store instruction does not affect the carry. */
4070 cc_status
.flags
|= CC_NO_OVERFLOW
;
4076 if (cc_status
.value1
&& GET_CODE (cc_status
.value1
) == REG
4078 && reg_overlap_mentioned_p (cc_status
.value1
, cc_status
.value2
))
4079 cc_status
.value2
= 0;
4081 else if (cc_status
.value1
&& side_effects_p (cc_status
.value1
))
4082 cc_status
.value1
= 0;
4084 else if (cc_status
.value2
&& side_effects_p (cc_status
.value2
))
4085 cc_status
.value2
= 0;
4088 /* The current instruction does not affect the flags but changes
4089 the register 'reg'. See if the previous flags can be kept for the
4090 next instruction to avoid a comparison. */
4092 m68hc11_notice_keep_cc (rtx reg
)
4095 || cc_prev_status
.value1
== 0
4096 || rtx_equal_p (reg
, cc_prev_status
.value1
)
4097 || (cc_prev_status
.value2
4098 && reg_mentioned_p (reg
, cc_prev_status
.value2
)))
4101 cc_status
= cc_prev_status
;
4106 /* Machine Specific Reorg. */
4108 /* Z register replacement:
4110 GCC treats the Z register as an index base address register like
4111 X or Y. In general, it uses it during reload to compute the address
4112 of some operand. This helps the reload pass to avoid to fall into the
4113 register spill failure.
4115 The Z register is in the A_REGS class. In the machine description,
4116 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4118 It can appear everywhere an X or Y register can appear, except for
4119 some templates in the clobber section (when a clobber of X or Y is asked).
4120 For a given instruction, the template must ensure that no more than
4121 2 'A' registers are used. Otherwise, the register replacement is not
4124 To replace the Z register, the algorithm is not terrific:
4125 1. Insns that do not use the Z register are not changed
4126 2. When a Z register is used, we scan forward the insns to see
4127 a potential register to use: either X or Y and sometimes D.
4128 We stop when a call, a label or a branch is seen, or when we
4129 detect that both X and Y are used (probably at different times, but it does
4131 3. The register that will be used for the replacement of Z is saved
4132 in a .page0 register or on the stack. If the first instruction that
4133 used Z, uses Z as an input, the value is loaded from another .page0
4134 register. The replacement register is pushed on the stack in the
4135 rare cases where a compare insn uses Z and we couldn't find if X/Y
4137 4. The Z register is replaced in all instructions until we reach
4138 the end of the Z-block, as detected by step 2.
4139 5. If we detect that Z is still alive, its value is saved.
4140 If the replacement register is alive, its old value is loaded.
4142 The Z register can be disabled with -ffixed-z.
4152 int must_restore_reg
;
4163 int save_before_last
;
4164 int z_loaded_with_sp
;
4167 static int m68hc11_check_z_replacement (rtx
, struct replace_info
*);
4168 static void m68hc11_find_z_replacement (rtx
, struct replace_info
*);
4169 static void m68hc11_z_replacement (rtx
);
4170 static void m68hc11_reassign_regs (rtx
);
4172 int z_replacement_completed
= 0;
4174 /* Analyze the insn to find out which replacement register to use and
4175 the boundaries of the replacement.
4176 Returns 0 if we reached the last insn to be replaced, 1 if we can
4177 continue replacement in next insns. */
4180 m68hc11_check_z_replacement (rtx insn
, struct replace_info
*info
)
4182 int this_insn_uses_ix
;
4183 int this_insn_uses_iy
;
4184 int this_insn_uses_z
;
4185 int this_insn_uses_z_in_dst
;
4186 int this_insn_uses_d
;
4190 /* A call is said to clobber the Z register, we don't need
4191 to save the value of Z. We also don't need to restore
4192 the replacement register (unless it is used by the call). */
4193 if (GET_CODE (insn
) == CALL_INSN
)
4195 body
= PATTERN (insn
);
4197 info
->can_use_d
= 0;
4199 /* If the call is an indirect call with Z, we have to use the
4200 Y register because X can be used as an input (D+X).
4201 We also must not save Z nor restore Y. */
4202 if (reg_mentioned_p (z_reg
, body
))
4204 insn
= NEXT_INSN (insn
);
4207 info
->found_call
= 1;
4208 info
->must_restore_reg
= 0;
4209 info
->last
= NEXT_INSN (insn
);
4211 info
->need_save_z
= 0;
4214 if (GET_CODE (insn
) == CODE_LABEL
4215 || GET_CODE (insn
) == BARRIER
|| GET_CODE (insn
) == ASM_INPUT
)
4218 if (GET_CODE (insn
) == JUMP_INSN
)
4220 if (reg_mentioned_p (z_reg
, insn
) == 0)
4223 info
->can_use_d
= 0;
4224 info
->must_save_reg
= 0;
4225 info
->must_restore_reg
= 0;
4226 info
->need_save_z
= 0;
4227 info
->last
= NEXT_INSN (insn
);
4230 if (GET_CODE (insn
) != INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4235 /* Z register dies here. */
4236 z_dies_here
= find_regno_note (insn
, REG_DEAD
, HARD_Z_REGNUM
) != NULL
;
4238 body
= PATTERN (insn
);
4239 if (GET_CODE (body
) == SET
)
4241 rtx src
= XEXP (body
, 1);
4242 rtx dst
= XEXP (body
, 0);
4244 /* Condition code is set here. We have to restore the X/Y and
4245 save into Z before any test/compare insn because once we save/restore
4246 we can change the condition codes. When the compare insn uses Z and
4247 we can't use X/Y, the comparison is made with the *ZREG soft register
4248 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4251 if ((GET_CODE (src
) == REG
&& REGNO (src
) == HARD_Z_REGNUM
)
4252 || (GET_CODE (src
) == COMPARE
&&
4253 ((rtx_equal_p (XEXP (src
, 0), z_reg
)
4254 && H_REG_P (XEXP (src
, 1)))
4255 || (rtx_equal_p (XEXP (src
, 1), z_reg
)
4256 && H_REG_P (XEXP (src
, 0))))))
4258 if (insn
== info
->first
)
4260 info
->must_load_z
= 0;
4261 info
->must_save_reg
= 0;
4262 info
->must_restore_reg
= 0;
4263 info
->need_save_z
= 0;
4264 info
->found_call
= 1;
4265 info
->regno
= SOFT_Z_REGNUM
;
4266 info
->last
= NEXT_INSN (insn
);
4270 if (reg_mentioned_p (z_reg
, src
) == 0)
4272 info
->can_use_d
= 0;
4276 if (insn
!= info
->first
)
4279 /* Compare insn which uses Z. We have to save/restore the X/Y
4280 register without modifying the condition codes. For this
4281 we have to use a push/pop insn. */
4282 info
->must_push_reg
= 1;
4286 /* Z reg is set to something new. We don't need to load it. */
4289 if (!reg_mentioned_p (z_reg
, src
))
4291 /* Z reg is used before being set. Treat this as
4292 a new sequence of Z register replacement. */
4293 if (insn
!= info
->first
)
4297 info
->must_load_z
= 0;
4299 info
->z_set_count
++;
4300 info
->z_value
= src
;
4302 info
->z_loaded_with_sp
= 1;
4304 else if (reg_mentioned_p (z_reg
, dst
))
4305 info
->can_use_d
= 0;
4307 this_insn_uses_d
= reg_mentioned_p (d_reg
, src
)
4308 | reg_mentioned_p (d_reg
, dst
);
4309 this_insn_uses_ix
= reg_mentioned_p (ix_reg
, src
)
4310 | reg_mentioned_p (ix_reg
, dst
);
4311 this_insn_uses_iy
= reg_mentioned_p (iy_reg
, src
)
4312 | reg_mentioned_p (iy_reg
, dst
);
4313 this_insn_uses_z
= reg_mentioned_p (z_reg
, src
);
4315 /* If z is used as an address operand (like (MEM (reg z))),
4316 we can't replace it with d. */
4317 if (this_insn_uses_z
&& !Z_REG_P (src
)
4318 && !(m68hc11_arith_operator (src
, GET_MODE (src
))
4319 && Z_REG_P (XEXP (src
, 0))
4320 && !reg_mentioned_p (z_reg
, XEXP (src
, 1))
4321 && insn
== info
->first
4322 && dead_register_here (insn
, d_reg
)))
4323 info
->can_use_d
= 0;
4325 this_insn_uses_z_in_dst
= reg_mentioned_p (z_reg
, dst
);
4326 if (TARGET_M6812
&& !z_dies_here
4327 && ((this_insn_uses_z
&& side_effects_p (src
))
4328 || (this_insn_uses_z_in_dst
&& side_effects_p (dst
))))
4330 info
->need_save_z
= 1;
4331 info
->z_set_count
++;
4333 this_insn_uses_z
|= this_insn_uses_z_in_dst
;
4335 if (this_insn_uses_z
&& this_insn_uses_ix
&& this_insn_uses_iy
)
4337 fatal_insn ("registers IX, IY and Z used in the same INSN", insn
);
4340 if (this_insn_uses_d
)
4341 info
->can_use_d
= 0;
4343 /* IX and IY are used at the same time, we have to restore
4344 the value of the scratch register before this insn. */
4345 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4350 if (this_insn_uses_ix
&& X_REG_P (dst
) && GET_MODE (dst
) == SImode
)
4351 info
->can_use_d
= 0;
4353 if (info
->x_used
== 0 && this_insn_uses_ix
)
4357 /* We have a (set (REG:HI X) (REG:HI Z)).
4358 Since we use Z as the replacement register, this insn
4359 is no longer necessary. We turn it into a note. We must
4360 not reload the old value of X. */
4361 if (X_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4365 info
->need_save_z
= 0;
4368 info
->must_save_reg
= 0;
4369 info
->must_restore_reg
= 0;
4370 info
->found_call
= 1;
4371 info
->can_use_d
= 0;
4372 PUT_CODE (insn
, NOTE
);
4373 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4374 NOTE_SOURCE_FILE (insn
) = 0;
4375 info
->last
= NEXT_INSN (insn
);
4380 && (rtx_equal_p (src
, z_reg
)
4381 || (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
))))
4385 info
->need_save_z
= 0;
4388 info
->last
= NEXT_INSN (insn
);
4389 info
->must_save_reg
= 0;
4390 info
->must_restore_reg
= 0;
4392 else if (X_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4393 && !reg_mentioned_p (ix_reg
, src
))
4398 info
->need_save_z
= 0;
4400 else if (TARGET_M6812
&& side_effects_p (src
))
4403 info
->must_restore_reg
= 0;
4408 info
->save_before_last
= 1;
4410 info
->must_restore_reg
= 0;
4411 info
->last
= NEXT_INSN (insn
);
4413 else if (info
->can_use_d
)
4415 info
->last
= NEXT_INSN (insn
);
4421 if (z_dies_here
&& !reg_mentioned_p (ix_reg
, src
)
4422 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_X_REGNUM
)
4424 info
->need_save_z
= 0;
4426 info
->last
= NEXT_INSN (insn
);
4427 info
->regno
= HARD_X_REGNUM
;
4428 info
->must_save_reg
= 0;
4429 info
->must_restore_reg
= 0;
4432 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, ix_reg
))
4434 info
->regno
= HARD_X_REGNUM
;
4435 info
->must_restore_reg
= 0;
4436 info
->must_save_reg
= 0;
4440 if (info
->y_used
== 0 && this_insn_uses_iy
)
4444 if (Y_REG_P (dst
) && rtx_equal_p (src
, z_reg
))
4448 info
->need_save_z
= 0;
4451 info
->must_save_reg
= 0;
4452 info
->must_restore_reg
= 0;
4453 info
->found_call
= 1;
4454 info
->can_use_d
= 0;
4455 PUT_CODE (insn
, NOTE
);
4456 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
4457 NOTE_SOURCE_FILE (insn
) = 0;
4458 info
->last
= NEXT_INSN (insn
);
4463 && (rtx_equal_p (src
, z_reg
)
4464 || (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
))))
4469 info
->need_save_z
= 0;
4471 info
->last
= NEXT_INSN (insn
);
4472 info
->must_save_reg
= 0;
4473 info
->must_restore_reg
= 0;
4475 else if (Y_REG_P (dst
) && reg_mentioned_p (z_reg
, src
)
4476 && !reg_mentioned_p (iy_reg
, src
))
4481 info
->need_save_z
= 0;
4483 else if (TARGET_M6812
&& side_effects_p (src
))
4486 info
->must_restore_reg
= 0;
4491 info
->save_before_last
= 1;
4493 info
->must_restore_reg
= 0;
4494 info
->last
= NEXT_INSN (insn
);
4496 else if (info
->can_use_d
)
4498 info
->last
= NEXT_INSN (insn
);
4505 if (z_dies_here
&& !reg_mentioned_p (iy_reg
, src
)
4506 && GET_CODE (dst
) == REG
&& REGNO (dst
) == HARD_Y_REGNUM
)
4508 info
->need_save_z
= 0;
4510 info
->last
= NEXT_INSN (insn
);
4511 info
->regno
= HARD_Y_REGNUM
;
4512 info
->must_save_reg
= 0;
4513 info
->must_restore_reg
= 0;
4516 if (rtx_equal_p (src
, z_reg
) && rtx_equal_p (dst
, iy_reg
))
4518 info
->regno
= HARD_Y_REGNUM
;
4519 info
->must_restore_reg
= 0;
4520 info
->must_save_reg
= 0;
4526 info
->need_save_z
= 0;
4528 if (info
->last
== 0)
4529 info
->last
= NEXT_INSN (insn
);
4532 return info
->last
!= NULL_RTX
? 0 : 1;
4534 if (GET_CODE (body
) == PARALLEL
)
4537 char ix_clobber
= 0;
4538 char iy_clobber
= 0;
4540 this_insn_uses_iy
= 0;
4541 this_insn_uses_ix
= 0;
4542 this_insn_uses_z
= 0;
4544 for (i
= XVECLEN (body
, 0) - 1; i
>= 0; i
--)
4547 int uses_ix
, uses_iy
, uses_z
;
4549 x
= XVECEXP (body
, 0, i
);
4551 if (info
->can_use_d
&& reg_mentioned_p (d_reg
, x
))
4552 info
->can_use_d
= 0;
4554 uses_ix
= reg_mentioned_p (ix_reg
, x
);
4555 uses_iy
= reg_mentioned_p (iy_reg
, x
);
4556 uses_z
= reg_mentioned_p (z_reg
, x
);
4557 if (GET_CODE (x
) == CLOBBER
)
4559 ix_clobber
|= uses_ix
;
4560 iy_clobber
|= uses_iy
;
4561 z_clobber
|= uses_z
;
4565 this_insn_uses_ix
|= uses_ix
;
4566 this_insn_uses_iy
|= uses_iy
;
4567 this_insn_uses_z
|= uses_z
;
4569 if (uses_z
&& GET_CODE (x
) == SET
)
4571 rtx dst
= XEXP (x
, 0);
4574 info
->z_set_count
++;
4576 if (TARGET_M6812
&& uses_z
&& side_effects_p (x
))
4577 info
->need_save_z
= 1;
4580 info
->need_save_z
= 0;
4584 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4585 this_insn_uses_ix
, this_insn_uses_iy
,
4586 this_insn_uses_z
, ix_clobber
, iy_clobber
, z_clobber
);
4589 if (this_insn_uses_z
)
4590 info
->can_use_d
= 0;
4592 if (z_clobber
&& info
->first
!= insn
)
4594 info
->need_save_z
= 0;
4598 if (z_clobber
&& info
->x_used
== 0 && info
->y_used
== 0)
4600 if (this_insn_uses_z
== 0 && insn
== info
->first
)
4602 info
->must_load_z
= 0;
4604 if (dead_register_here (insn
, d_reg
))
4606 info
->regno
= HARD_D_REGNUM
;
4607 info
->must_save_reg
= 0;
4608 info
->must_restore_reg
= 0;
4610 else if (dead_register_here (insn
, ix_reg
))
4612 info
->regno
= HARD_X_REGNUM
;
4613 info
->must_save_reg
= 0;
4614 info
->must_restore_reg
= 0;
4616 else if (dead_register_here (insn
, iy_reg
))
4618 info
->regno
= HARD_Y_REGNUM
;
4619 info
->must_save_reg
= 0;
4620 info
->must_restore_reg
= 0;
4622 if (info
->regno
>= 0)
4624 info
->last
= NEXT_INSN (insn
);
4627 if (this_insn_uses_ix
== 0)
4629 info
->regno
= HARD_X_REGNUM
;
4630 info
->must_save_reg
= 1;
4631 info
->must_restore_reg
= 1;
4633 else if (this_insn_uses_iy
== 0)
4635 info
->regno
= HARD_Y_REGNUM
;
4636 info
->must_save_reg
= 1;
4637 info
->must_restore_reg
= 1;
4641 info
->regno
= HARD_D_REGNUM
;
4642 info
->must_save_reg
= 1;
4643 info
->must_restore_reg
= 1;
4645 info
->last
= NEXT_INSN (insn
);
4649 if (((info
->x_used
|| this_insn_uses_ix
) && iy_clobber
)
4650 || ((info
->y_used
|| this_insn_uses_iy
) && ix_clobber
))
4652 if (this_insn_uses_z
)
4654 if (info
->y_used
== 0 && iy_clobber
)
4656 info
->regno
= HARD_Y_REGNUM
;
4657 info
->must_save_reg
= 0;
4658 info
->must_restore_reg
= 0;
4660 if (info
->first
!= insn
4661 && ((info
->y_used
&& ix_clobber
)
4662 || (info
->x_used
&& iy_clobber
)))
4665 info
->last
= NEXT_INSN (insn
);
4666 info
->save_before_last
= 1;
4670 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4672 if (this_insn_uses_z
)
4674 fatal_insn ("cannot do z-register replacement", insn
);
4678 if (info
->x_used
== 0 && (this_insn_uses_ix
|| ix_clobber
))
4685 if (iy_clobber
|| z_clobber
)
4687 info
->last
= NEXT_INSN (insn
);
4688 info
->save_before_last
= 1;
4693 if (info
->y_used
== 0 && (this_insn_uses_iy
|| iy_clobber
))
4700 if (ix_clobber
|| z_clobber
)
4702 info
->last
= NEXT_INSN (insn
);
4703 info
->save_before_last
= 1;
4710 info
->need_save_z
= 0;
4714 if (GET_CODE (body
) == CLOBBER
)
4717 /* IX and IY are used at the same time, we have to restore
4718 the value of the scratch register before this insn. */
4719 if (this_insn_uses_ix
&& this_insn_uses_iy
)
4723 if (info
->x_used
== 0 && this_insn_uses_ix
)
4731 if (info
->y_used
== 0 && this_insn_uses_iy
)
4745 m68hc11_find_z_replacement (rtx insn
, struct replace_info
*info
)
4749 info
->replace_reg
= NULL_RTX
;
4750 info
->must_load_z
= 1;
4751 info
->need_save_z
= 1;
4752 info
->must_save_reg
= 1;
4753 info
->must_restore_reg
= 1;
4757 info
->can_use_d
= TARGET_M6811
? 1 : 0;
4758 info
->found_call
= 0;
4762 info
->z_set_count
= 0;
4763 info
->z_value
= NULL_RTX
;
4764 info
->must_push_reg
= 0;
4765 info
->save_before_last
= 0;
4766 info
->z_loaded_with_sp
= 0;
4768 /* Scan the insn forward to find an address register that is not used.
4770 - the flow of the program changes,
4771 - when we detect that both X and Y are necessary,
4772 - when the Z register dies,
4773 - when the condition codes are set. */
4775 for (; insn
&& info
->z_died
== 0; insn
= NEXT_INSN (insn
))
4777 if (m68hc11_check_z_replacement (insn
, info
) == 0)
4781 /* May be we can use Y or X if they contain the same value as Z.
4782 This happens very often after the reload. */
4783 if (info
->z_set_count
== 1)
4785 rtx p
= info
->first
;
4790 v
= find_last_value (iy_reg
, &p
, insn
, 1);
4792 else if (info
->y_used
)
4794 v
= find_last_value (ix_reg
, &p
, insn
, 1);
4796 if (v
&& (v
!= iy_reg
&& v
!= ix_reg
) && rtx_equal_p (v
, info
->z_value
))
4799 info
->regno
= HARD_Y_REGNUM
;
4801 info
->regno
= HARD_X_REGNUM
;
4802 info
->must_load_z
= 0;
4803 info
->must_save_reg
= 0;
4804 info
->must_restore_reg
= 0;
4805 info
->found_call
= 1;
4808 if (info
->z_set_count
== 0)
4809 info
->need_save_z
= 0;
4812 info
->need_save_z
= 0;
4814 if (info
->last
== 0)
4817 if (info
->regno
>= 0)
4820 info
->replace_reg
= gen_rtx (REG
, HImode
, reg
);
4822 else if (info
->can_use_d
)
4824 reg
= HARD_D_REGNUM
;
4825 info
->replace_reg
= d_reg
;
4827 else if (info
->x_used
)
4829 reg
= HARD_Y_REGNUM
;
4830 info
->replace_reg
= iy_reg
;
4834 reg
= HARD_X_REGNUM
;
4835 info
->replace_reg
= ix_reg
;
4839 if (info
->must_save_reg
&& info
->must_restore_reg
)
4841 if (insn
&& dead_register_here (insn
, info
->replace_reg
))
4843 info
->must_save_reg
= 0;
4844 info
->must_restore_reg
= 0;
4849 /* The insn uses the Z register. Find a replacement register for it
4850 (either X or Y) and replace it in the insn and the next ones until
4851 the flow changes or the replacement register is used. Instructions
4852 are emitted before and after the Z-block to preserve the value of
4853 Z and of the replacement register. */
4856 m68hc11_z_replacement (rtx insn
)
4860 struct replace_info info
;
4862 /* Find trivial case where we only need to replace z with the
4863 equivalent soft register. */
4864 if (GET_CODE (insn
) == INSN
&& GET_CODE (PATTERN (insn
)) == SET
)
4866 rtx body
= PATTERN (insn
);
4867 rtx src
= XEXP (body
, 1);
4868 rtx dst
= XEXP (body
, 0);
4870 if (Z_REG_P (dst
) && (H_REG_P (src
) && !SP_REG_P (src
)))
4872 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4875 else if (Z_REG_P (src
)
4876 && ((H_REG_P (dst
) && !SP_REG_P (src
)) || dst
== cc0_rtx
))
4878 XEXP (body
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4881 else if (D_REG_P (dst
)
4882 && m68hc11_arith_operator (src
, GET_MODE (src
))
4883 && D_REG_P (XEXP (src
, 0)) && Z_REG_P (XEXP (src
, 1)))
4885 XEXP (src
, 1) = gen_rtx (REG
, GET_MODE (src
), SOFT_Z_REGNUM
);
4888 else if (Z_REG_P (dst
) && GET_CODE (src
) == CONST_INT
4889 && INTVAL (src
) == 0)
4891 XEXP (body
, 0) = gen_rtx (REG
, GET_MODE (dst
), SOFT_Z_REGNUM
);
4892 /* Force it to be re-recognized. */
4893 INSN_CODE (insn
) = -1;
4898 m68hc11_find_z_replacement (insn
, &info
);
4900 replace_reg
= info
.replace_reg
;
4901 replace_reg_qi
= NULL_RTX
;
4903 /* Save the X register in a .page0 location. */
4904 if (info
.must_save_reg
&& !info
.must_push_reg
)
4908 if (info
.must_push_reg
&& 0)
4909 dst
= gen_rtx (MEM
, HImode
,
4910 gen_rtx (PRE_DEC
, HImode
,
4911 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
4913 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
4915 emit_insn_before (gen_movhi (dst
,
4916 gen_rtx (REG
, HImode
, info
.regno
)), insn
);
4918 if (info
.must_load_z
&& !info
.must_push_reg
)
4920 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
4921 gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
)),
4926 /* Replace all occurrence of Z by replace_reg.
4927 Stop when the last instruction to replace is reached.
4928 Also stop when we detect a change in the flow (but it's not
4929 necessary; just safeguard). */
4931 for (; insn
&& insn
!= info
.last
; insn
= NEXT_INSN (insn
))
4935 if (GET_CODE (insn
) == CODE_LABEL
|| GET_CODE (insn
) == BARRIER
)
4938 if (GET_CODE (insn
) != INSN
4939 && GET_CODE (insn
) != CALL_INSN
&& GET_CODE (insn
) != JUMP_INSN
)
4942 body
= PATTERN (insn
);
4943 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
4944 || GET_CODE (body
) == ASM_OPERANDS
4945 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
4949 if (debug_m6811
&& reg_mentioned_p (replace_reg
, body
))
4951 printf ("Reg mentioned here...:\n");
4956 /* Stack pointer was decremented by 2 due to the push.
4957 Correct that by adding 2 to the destination. */
4958 if (info
.must_push_reg
4959 && info
.z_loaded_with_sp
&& GET_CODE (body
) == SET
)
4963 src
= SET_SRC (body
);
4964 dst
= SET_DEST (body
);
4965 if (SP_REG_P (src
) && Z_REG_P (dst
))
4966 emit_insn_after (gen_addhi3 (dst
, dst
, const2_rtx
), insn
);
4969 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4970 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4972 INSN_CODE (insn
) = -1;
4973 if (!validate_replace_rtx (z_reg
, replace_reg
, insn
))
4974 fatal_insn ("cannot do z-register replacement", insn
);
4977 /* Likewise for (REG:QI Z). */
4978 if (reg_mentioned_p (z_reg
, insn
))
4980 if (replace_reg_qi
== NULL_RTX
)
4981 replace_reg_qi
= gen_rtx (REG
, QImode
, REGNO (replace_reg
));
4982 validate_replace_rtx (z_reg_qi
, replace_reg_qi
, insn
);
4985 /* If there is a REG_INC note on Z, replace it with a
4986 REG_INC note on the replacement register. This is necessary
4987 to make sure that the flow pass will identify the change
4988 and it will not remove a possible insn that saves Z. */
4989 for (note
= REG_NOTES (insn
); note
; note
= XEXP (note
, 1))
4991 if (REG_NOTE_KIND (note
) == REG_INC
4992 && GET_CODE (XEXP (note
, 0)) == REG
4993 && REGNO (XEXP (note
, 0)) == REGNO (z_reg
))
4995 XEXP (note
, 0) = replace_reg
;
4999 if (GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5003 /* Save Z before restoring the old value. */
5004 if (insn
&& info
.need_save_z
&& !info
.must_push_reg
)
5006 rtx save_pos_insn
= insn
;
5008 /* If Z is clobber by the last insn, we have to save its value
5009 before the last instruction. */
5010 if (info
.save_before_last
)
5011 save_pos_insn
= PREV_INSN (save_pos_insn
);
5013 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, SOFT_Z_REGNUM
),
5014 gen_rtx (REG
, HImode
, info
.regno
)),
5018 if (info
.must_push_reg
&& info
.last
)
5022 body
= PATTERN (info
.last
);
5023 new_body
= gen_rtx (PARALLEL
, VOIDmode
,
5025 gen_rtx (USE
, VOIDmode
,
5027 gen_rtx (USE
, VOIDmode
,
5028 gen_rtx (REG
, HImode
,
5030 PATTERN (info
.last
) = new_body
;
5032 /* Force recognition on insn since we changed it. */
5033 INSN_CODE (insn
) = -1;
5035 if (!validate_replace_rtx (z_reg
, replace_reg
, info
.last
))
5037 fatal_insn ("invalid Z register replacement for insn", insn
);
5039 insn
= NEXT_INSN (info
.last
);
5042 /* Restore replacement register unless it was died. */
5043 if (insn
&& info
.must_restore_reg
&& !info
.must_push_reg
)
5047 if (info
.must_push_reg
&& 0)
5048 dst
= gen_rtx (MEM
, HImode
,
5049 gen_rtx (POST_INC
, HImode
,
5050 gen_rtx (REG
, HImode
, HARD_SP_REGNUM
)));
5052 dst
= gen_rtx (REG
, HImode
, SOFT_SAVED_XY_REGNUM
);
5054 emit_insn_before (gen_movhi (gen_rtx (REG
, HImode
, info
.regno
),
5061 /* Scan all the insn and re-affects some registers
5062 - The Z register (if it was used), is affected to X or Y depending
5063 on the instruction. */
5066 m68hc11_reassign_regs (rtx first
)
5070 ix_reg
= gen_rtx (REG
, HImode
, HARD_X_REGNUM
);
5071 iy_reg
= gen_rtx (REG
, HImode
, HARD_Y_REGNUM
);
5072 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5073 z_reg_qi
= gen_rtx (REG
, QImode
, HARD_Z_REGNUM
);
5075 /* Scan all insns to replace Z by X or Y preserving the old value
5076 of X/Y and restoring it afterward. */
5078 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5082 if (GET_CODE (insn
) == CODE_LABEL
5083 || GET_CODE (insn
) == NOTE
|| GET_CODE (insn
) == BARRIER
)
5089 body
= PATTERN (insn
);
5090 if (GET_CODE (body
) == CLOBBER
|| GET_CODE (body
) == USE
)
5093 if (GET_CODE (body
) == CONST_INT
|| GET_CODE (body
) == ASM_INPUT
5094 || GET_CODE (body
) == ASM_OPERANDS
5095 || GET_CODE (body
) == UNSPEC
|| GET_CODE (body
) == UNSPEC_VOLATILE
)
5098 if (GET_CODE (body
) == SET
|| GET_CODE (body
) == PARALLEL
5099 || GET_CODE (insn
) == CALL_INSN
|| GET_CODE (insn
) == JUMP_INSN
)
5102 /* If Z appears in this insn, replace it in the current insn
5103 and the next ones until the flow changes or we have to
5104 restore back the replacement register. */
5106 if (reg_mentioned_p (z_reg
, body
))
5108 m68hc11_z_replacement (insn
);
5113 printf ("insn not handled by Z replacement:\n");
5121 /* Machine-dependent reorg pass.
5122 Specific optimizations are defined here:
5123 - this pass changes the Z register into either X or Y
5124 (it preserves X/Y previous values in a memory slot in page0).
5126 When this pass is finished, the global variable
5127 'z_replacement_completed' is set to 2. */
5130 m68hc11_reorg (void)
5135 z_replacement_completed
= 0;
5136 z_reg
= gen_rtx (REG
, HImode
, HARD_Z_REGNUM
);
5137 first
= get_insns ();
5139 /* Some RTX are shared at this point. This breaks the Z register
5140 replacement, unshare everything. */
5141 unshare_all_rtl_again (first
);
5143 /* Force a split of all splitable insn. This is necessary for the
5144 Z register replacement mechanism because we end up with basic insns. */
5145 split_all_insns_noflow ();
5148 z_replacement_completed
= 1;
5149 m68hc11_reassign_regs (first
);
5152 compute_bb_for_insn ();
5154 /* After some splitting, there are some opportunities for CSE pass.
5155 This happens quite often when 32-bit or above patterns are split. */
5156 if (optimize
> 0 && split_done
)
5158 reload_cse_regs (first
);
5161 /* Re-create the REG_DEAD notes. These notes are used in the machine
5162 description to use the best assembly directives. */
5165 /* Before recomputing the REG_DEAD notes, remove all of them.
5166 This is necessary because the reload_cse_regs() pass can
5167 have replaced some (MEM) with a register. In that case,
5168 the REG_DEAD that could exist for that register may become
5170 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5176 pnote
= ®_NOTES (insn
);
5179 if (REG_NOTE_KIND (*pnote
) == REG_DEAD
)
5180 *pnote
= XEXP (*pnote
, 1);
5182 pnote
= &XEXP (*pnote
, 1);
5187 life_analysis (first
, 0, PROP_REG_INFO
| PROP_DEATH_NOTES
);
5190 z_replacement_completed
= 2;
5192 /* If optimizing, then go ahead and split insns that must be
5193 split after Z register replacement. This gives more opportunities
5194 for peephole (in particular for consecutives xgdx/xgdy). */
5196 split_all_insns_noflow ();
5198 /* Once insns are split after the z_replacement_completed == 2,
5199 we must not re-run the life_analysis. The xgdx/xgdy patterns
5200 are not recognized and the life_analysis pass removes some
5201 insns because it thinks some (SETs) are noops or made to dead
5202 stores (which is false due to the swap).
5204 Do a simple pass to eliminate the noop set that the final
5205 split could generate (because it was easier for split definition). */
5209 for (insn
= first
; insn
; insn
= NEXT_INSN (insn
))
5213 if (INSN_DELETED_P (insn
))
5218 /* Remove the (set (R) (R)) insns generated by some splits. */
5219 body
= PATTERN (insn
);
5220 if (GET_CODE (body
) == SET
5221 && rtx_equal_p (SET_SRC (body
), SET_DEST (body
)))
5223 PUT_CODE (insn
, NOTE
);
5224 NOTE_LINE_NUMBER (insn
) = NOTE_INSN_DELETED
;
5225 NOTE_SOURCE_FILE (insn
) = 0;
5232 /* Override memcpy */
5235 m68hc11_init_libfuncs (void)
5237 memcpy_libfunc
= init_one_libfunc ("__memcpy");
5238 memcmp_libfunc
= init_one_libfunc ("__memcmp");
5239 memset_libfunc
= init_one_libfunc ("__memset");
5244 /* Cost functions. */
5246 /* Cost of moving memory. */
5248 m68hc11_memory_move_cost (enum machine_mode mode
, enum reg_class
class,
5249 int in ATTRIBUTE_UNUSED
)
5251 if (class <= H_REGS
&& class > NO_REGS
)
5253 if (GET_MODE_SIZE (mode
) <= 2)
5254 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5256 return COSTS_N_INSNS (2) + (reload_completed
| reload_in_progress
);
5260 if (GET_MODE_SIZE (mode
) <= 2)
5261 return COSTS_N_INSNS (3);
5263 return COSTS_N_INSNS (4);
5268 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5269 Reload does not check the constraint of set insns when the two registers
5270 have a move cost of 2. Setting a higher cost will force reload to check
5273 m68hc11_register_move_cost (enum machine_mode mode
, enum reg_class from
,
5276 /* All costs are symmetric, so reduce cases by putting the
5277 lower number class as the destination. */
5280 enum reg_class tmp
= to
;
5281 to
= from
, from
= tmp
;
5284 return m68hc11_memory_move_cost (mode
, S_REGS
, 0);
5285 else if (from
<= S_REGS
)
5286 return COSTS_N_INSNS (1) + (reload_completed
| reload_in_progress
);
5288 return COSTS_N_INSNS (2);
5292 /* Provide the costs of an addressing mode that contains ADDR.
5293 If ADDR is not a valid address, its cost is irrelevant. */
5296 m68hc11_address_cost (rtx addr
)
5300 switch (GET_CODE (addr
))
5303 /* Make the cost of hard registers and specially SP, FP small. */
5304 if (REGNO (addr
) < FIRST_PSEUDO_REGISTER
)
5321 register rtx plus0
= XEXP (addr
, 0);
5322 register rtx plus1
= XEXP (addr
, 1);
5324 if (GET_CODE (plus0
) != REG
)
5327 switch (GET_CODE (plus1
))
5330 if (INTVAL (plus1
) >= 2 * m68hc11_max_offset
5331 || INTVAL (plus1
) < m68hc11_min_offset
)
5333 else if (INTVAL (plus1
) >= m68hc11_max_offset
)
5337 if (REGNO (plus0
) < FIRST_PSEUDO_REGISTER
)
5359 if (SP_REG_P (XEXP (addr
, 0)))
5368 printf ("Address cost: %d for :", cost
);
5377 m68hc11_shift_cost (enum machine_mode mode
, rtx x
, int shift
)
5381 total
= rtx_cost (x
, SET
);
5383 total
+= m68hc11_cost
->shiftQI_const
[shift
% 8];
5384 else if (mode
== HImode
)
5385 total
+= m68hc11_cost
->shiftHI_const
[shift
% 16];
5386 else if (shift
== 8 || shift
== 16 || shift
== 32)
5387 total
+= m68hc11_cost
->shiftHI_const
[8];
5388 else if (shift
!= 0 && shift
!= 16 && shift
!= 32)
5390 total
+= m68hc11_cost
->shiftHI_const
[1] * shift
;
5393 /* For SI and others, the cost is higher. */
5394 if (GET_MODE_SIZE (mode
) > 2 && (shift
% 16) != 0)
5395 total
*= GET_MODE_SIZE (mode
) / 2;
5397 /* When optimizing for size, make shift more costly so that
5398 multiplications are preferred. */
5399 if (optimize_size
&& (shift
% 8) != 0)
5406 m68hc11_rtx_costs_1 (rtx x
, enum rtx_code code
,
5407 enum rtx_code outer_code ATTRIBUTE_UNUSED
)
5409 enum machine_mode mode
= GET_MODE (x
);
5420 if (GET_CODE (XEXP (x
, 1)) == CONST_INT
)
5422 return m68hc11_shift_cost (mode
, XEXP (x
, 0), INTVAL (XEXP (x
, 1)));
5425 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5426 total
+= m68hc11_cost
->shift_var
;
5432 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5433 total
+= m68hc11_cost
->logical
;
5435 /* Logical instructions are byte instructions only. */
5436 total
*= GET_MODE_SIZE (mode
);
5441 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5442 total
+= m68hc11_cost
->add
;
5443 if (GET_MODE_SIZE (mode
) > 2)
5445 total
*= GET_MODE_SIZE (mode
) / 2;
5452 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5456 total
+= m68hc11_cost
->divQI
;
5460 total
+= m68hc11_cost
->divHI
;
5465 total
+= m68hc11_cost
->divSI
;
5471 /* mul instruction produces 16-bit result. */
5472 if (mode
== HImode
&& GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5473 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5474 return m68hc11_cost
->multQI
5475 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5476 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5478 /* emul instruction produces 32-bit result for 68HC12. */
5479 if (TARGET_M6812
&& mode
== SImode
5480 && GET_CODE (XEXP (x
, 0)) == ZERO_EXTEND
5481 && GET_CODE (XEXP (x
, 1)) == ZERO_EXTEND
)
5482 return m68hc11_cost
->multHI
5483 + rtx_cost (XEXP (XEXP (x
, 0), 0), code
)
5484 + rtx_cost (XEXP (XEXP (x
, 1), 0), code
);
5486 total
= rtx_cost (XEXP (x
, 0), code
) + rtx_cost (XEXP (x
, 1), code
);
5490 total
+= m68hc11_cost
->multQI
;
5494 total
+= m68hc11_cost
->multHI
;
5499 total
+= m68hc11_cost
->multSI
;
5506 extra_cost
= COSTS_N_INSNS (2);
5513 total
= extra_cost
+ rtx_cost (XEXP (x
, 0), code
);
5516 return total
+ COSTS_N_INSNS (1);
5520 return total
+ COSTS_N_INSNS (2);
5524 return total
+ COSTS_N_INSNS (4);
5526 return total
+ COSTS_N_INSNS (8);
5529 if (GET_CODE (XEXP (x
, 1)) == PC
|| GET_CODE (XEXP (x
, 2)) == PC
)
5530 return COSTS_N_INSNS (1);
5532 return COSTS_N_INSNS (1);
5535 return COSTS_N_INSNS (4);
5540 m68hc11_rtx_costs (rtx x
, int code
, int outer_code
, int *total
)
5544 /* Constants are cheap. Moving them in registers must be avoided
5545 because most instructions do not handle two register operands. */
5551 /* Logical and arithmetic operations with a constant operand are
5552 better because they are not supported with two registers. */
5554 if (outer_code
== SET
&& x
== const0_rtx
)
5555 /* After reload, the reload_cse pass checks the cost to change
5556 a SET into a PLUS. Make const0 cheap then. */
5557 *total
= 1 - reload_completed
;
5582 *total
= m68hc11_rtx_costs_1 (x
, code
, outer_code
);
5592 m68hc11_file_start (void)
5594 default_file_start ();
5596 fprintf (asm_out_file
, "\t.mode %s\n", TARGET_SHORT
? "mshort" : "mlong");
5601 m68hc11_asm_out_constructor (rtx symbol
, int priority
)
5603 default_ctor_section_asm_out_constructor (symbol
, priority
);
5604 fprintf (asm_out_file
, "\t.globl\t__do_global_ctors\n");
5608 m68hc11_asm_out_destructor (rtx symbol
, int priority
)
5610 default_dtor_section_asm_out_destructor (symbol
, priority
);
5611 fprintf (asm_out_file
, "\t.globl\t__do_global_dtors\n");
5614 #include "gt-m68hc11.h"