Merged trunk at revision 161680 into branch.
[official-gcc.git] / gcc / config / m68hc11 / m68hc11.c
blobad63ee8153d384f6f23318df0e33235f37bfd9c8
1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3 2009, 2010 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 3, or (at your option)
11 any later version.
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 COPYING3. If not see
20 <http://www.gnu.org/licenses/>.
22 Note:
23 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
24 on gcc 2.6.3. I have used it as a starting point for this port.
25 However, this new port is a complete re-write. Its internal
26 design is completely different. The generated code is not
27 compatible with the gcc 2.6.3 port.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
35 #include <stdio.h>
36 #include "config.h"
37 #include "system.h"
38 #include "coretypes.h"
39 #include "tm.h"
40 #include "rtl.h"
41 #include "tree.h"
42 #include "expr.h"
43 #include "tm_p.h"
44 #include "regs.h"
45 #include "hard-reg-set.h"
46 #include "insn-config.h"
47 #include "conditions.h"
48 #include "output.h"
49 #include "insn-attr.h"
50 #include "flags.h"
51 #include "recog.h"
52 #include "expr.h"
53 #include "libfuncs.h"
54 #include "toplev.h"
55 #include "basic-block.h"
56 #include "function.h"
57 #include "ggc.h"
58 #include "reload.h"
59 #include "target.h"
60 #include "target-def.h"
61 #include "df.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, enum rtx_code, rtx *);
66 static void m68hc11_reorg (void);
67 static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool);
68 static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool);
69 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
70 static int must_parenthesize (rtx);
71 static int m68hc11_address_cost (rtx, bool);
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 *, bool);
75 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
76 static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *);
78 void create_regs_rtx (void);
80 static void asm_print_register (FILE *, int);
81 static void m68hc11_print_operand (FILE *, rtx, int);
82 static void m68hc11_print_operand_address (FILE *, rtx);
83 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
84 static void m68hc11_asm_out_constructor (rtx, int);
85 static void m68hc11_asm_out_destructor (rtx, int);
86 static void m68hc11_file_start (void);
87 static void m68hc11_encode_section_info (tree, rtx, int);
88 static const char *m68hc11_strip_name_encoding (const char* str);
89 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
90 static int autoinc_mode (rtx);
91 static int m68hc11_make_autoinc_notes (rtx *, void *);
92 static void m68hc11_init_libfuncs (void);
93 static rtx m68hc11_struct_value_rtx (tree, int);
94 static bool m68hc11_return_in_memory (const_tree, const_tree);
95 static bool m68hc11_can_eliminate (const int, const int);
96 static void m68hc11_trampoline_init (rtx, tree, rtx);
98 /* Must be set to 1 to produce debug messages. */
99 int debug_m6811 = 0;
101 extern FILE *asm_out_file;
103 rtx ix_reg;
104 rtx iy_reg;
105 rtx d_reg;
106 rtx m68hc11_soft_tmp_reg;
107 static GTY(()) rtx stack_push_word;
108 static GTY(()) rtx stack_pop_word;
109 static GTY(()) rtx z_reg;
110 static GTY(()) rtx z_reg_qi;
111 static int regs_inited = 0;
113 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
114 int current_function_interrupt;
116 /* Set to 1 by expand_prologue() when the function is a trap handler. */
117 int current_function_trap;
119 /* Set to 1 when the current function is placed in 68HC12 banked
120 memory and must return with rtc. */
121 int current_function_far;
123 /* Min offset that is valid for the indirect addressing mode. */
124 HOST_WIDE_INT m68hc11_min_offset = 0;
126 /* Max offset that is valid for the indirect addressing mode. */
127 HOST_WIDE_INT m68hc11_max_offset = 256;
129 /* The class value for base registers. */
130 enum reg_class m68hc11_base_reg_class = A_REGS;
132 /* The class value for index registers. This is NO_REGS for 68HC11. */
133 enum reg_class m68hc11_index_reg_class = NO_REGS;
135 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
137 /* Tables that tell whether a given hard register is valid for
138 a base or an index register. It is filled at init time depending
139 on the target processor. */
140 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
141 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
143 /* A correction offset which is applied to the stack pointer.
144 This is 1 for 68HC11 and 0 for 68HC12. */
145 int m68hc11_sp_correction;
147 int m68hc11_addr_mode;
148 int m68hc11_mov_addr_mode;
151 const struct processor_costs *m68hc11_cost;
153 /* Costs for a 68HC11. */
154 static const struct processor_costs m6811_cost = {
155 /* add */
156 COSTS_N_INSNS (2),
157 /* logical */
158 COSTS_N_INSNS (2),
159 /* non-constant shift */
160 COSTS_N_INSNS (20),
161 /* shiftQI const */
162 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
163 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
164 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
166 /* shiftHI const */
167 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
168 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
169 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
170 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
171 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
172 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
174 /* mulQI */
175 COSTS_N_INSNS (20),
176 /* mulHI */
177 COSTS_N_INSNS (20 * 4),
178 /* mulSI */
179 COSTS_N_INSNS (20 * 16),
180 /* divQI */
181 COSTS_N_INSNS (20),
182 /* divHI */
183 COSTS_N_INSNS (80),
184 /* divSI */
185 COSTS_N_INSNS (100)
188 /* Costs for a 68HC12. */
189 static const struct processor_costs m6812_cost = {
190 /* add */
191 COSTS_N_INSNS (2),
192 /* logical */
193 COSTS_N_INSNS (2),
194 /* non-constant shift */
195 COSTS_N_INSNS (20),
196 /* shiftQI const */
197 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
198 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
199 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
201 /* shiftHI const */
202 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
203 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
204 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
205 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
206 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
207 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
209 /* mulQI */
210 COSTS_N_INSNS (3),
211 /* mulHI */
212 COSTS_N_INSNS (3),
213 /* mulSI */
214 COSTS_N_INSNS (3 * 4),
215 /* divQI */
216 COSTS_N_INSNS (12),
217 /* divHI */
218 COSTS_N_INSNS (12),
219 /* divSI */
220 COSTS_N_INSNS (100)
223 /* M68HC11 specific attributes. */
225 static const struct attribute_spec m68hc11_attribute_table[] =
227 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
228 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
229 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
230 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
231 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
232 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
233 { NULL, 0, 0, false, false, false, NULL }
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_PRINT_OPERAND
244 #define TARGET_PRINT_OPERAND m68hc11_print_operand
245 #undef TARGET_PRINT_OPERAND_ADDRESS
246 #define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
248 #undef TARGET_ASM_FUNCTION_EPILOGUE
249 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
251 #undef TARGET_ASM_FILE_START
252 #define TARGET_ASM_FILE_START m68hc11_file_start
253 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
254 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
256 #undef TARGET_DEFAULT_TARGET_FLAGS
257 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
259 #undef TARGET_ENCODE_SECTION_INFO
260 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
262 #undef TARGET_SECTION_TYPE_FLAGS
263 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
265 #undef TARGET_RTX_COSTS
266 #define TARGET_RTX_COSTS m68hc11_rtx_costs
267 #undef TARGET_ADDRESS_COST
268 #define TARGET_ADDRESS_COST m68hc11_address_cost
270 #undef TARGET_MACHINE_DEPENDENT_REORG
271 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
273 #undef TARGET_INIT_LIBFUNCS
274 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
276 #undef TARGET_STRUCT_VALUE_RTX
277 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
278 #undef TARGET_RETURN_IN_MEMORY
279 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
280 #undef TARGET_CALLEE_COPIES
281 #define TARGET_CALLEE_COPIES hook_callee_copies_named
283 #undef TARGET_STRIP_NAME_ENCODING
284 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
286 #undef TARGET_LEGITIMATE_ADDRESS_P
287 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
289 #undef TARGET_CAN_ELIMINATE
290 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
292 #undef TARGET_TRAMPOLINE_INIT
293 #define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
295 struct gcc_target targetm = TARGET_INITIALIZER;
298 m68hc11_override_options (void)
300 memset (m68hc11_reg_valid_for_index, 0,
301 sizeof (m68hc11_reg_valid_for_index));
302 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
304 /* Compilation with -fpic generates a wrong code. */
305 if (flag_pic)
307 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
308 (flag_pic > 1) ? "PIC" : "pic");
309 flag_pic = 0;
312 /* Do not enable -fweb because it breaks the 32-bit shift patterns
313 by breaking the match_dup of those patterns. The shift patterns
314 will no longer be recognized after that. */
315 flag_web = 0;
317 /* Configure for a 68hc11 processor. */
318 if (TARGET_M6811)
320 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
321 m68hc11_cost = &m6811_cost;
322 m68hc11_min_offset = 0;
323 m68hc11_max_offset = 256;
324 m68hc11_index_reg_class = NO_REGS;
325 m68hc11_base_reg_class = A_REGS;
326 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
327 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
328 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
329 m68hc11_sp_correction = 1;
330 m68hc11_tmp_regs_class = D_REGS;
331 m68hc11_addr_mode = ADDR_OFFSET;
332 m68hc11_mov_addr_mode = 0;
333 if (m68hc11_soft_reg_count < 0)
334 m68hc11_soft_reg_count = 4;
337 /* Configure for a 68hc12 processor. */
338 if (TARGET_M6812)
340 m68hc11_cost = &m6812_cost;
341 m68hc11_min_offset = -65536;
342 m68hc11_max_offset = 65536;
343 m68hc11_index_reg_class = D_REGS;
344 m68hc11_base_reg_class = A_OR_SP_REGS;
345 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
346 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
347 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
348 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
349 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
350 m68hc11_sp_correction = 0;
351 m68hc11_tmp_regs_class = TMP_REGS;
352 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
353 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
354 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
355 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
356 target_flags |= MASK_NO_DIRECT_MODE;
357 if (m68hc11_soft_reg_count < 0)
358 m68hc11_soft_reg_count = 0;
360 if (TARGET_LONG_CALLS)
361 current_function_far = 1;
363 return 0;
367 void
368 m68hc11_conditional_register_usage (void)
370 int i;
372 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
373 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
375 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
377 fixed_regs[i] = 1;
378 call_used_regs[i] = 1;
381 /* For 68HC12, the Z register emulation is not necessary when the
382 frame pointer is not used. The frame pointer is eliminated and
383 replaced by the stack register (which is a BASE_REG_CLASS). */
384 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
386 fixed_regs[HARD_Z_REGNUM] = 1;
391 /* Reload and register operations. */
394 void
395 create_regs_rtx (void)
397 /* regs_inited = 1; */
398 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
399 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
400 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
401 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
403 stack_push_word = gen_rtx_MEM (HImode,
404 gen_rtx_PRE_DEC (HImode,
405 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
406 stack_pop_word = gen_rtx_MEM (HImode,
407 gen_rtx_POST_INC (HImode,
408 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
412 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
413 - 8-bit values are stored anywhere (except the SP register).
414 - 16-bit values can be stored in any register whose mode is 16
415 - 32-bit values can be stored in D, X registers or in a soft register
416 (except the last one because we need 2 soft registers)
417 - Values whose size is > 32 bit are not stored in real hard
418 registers. They may be stored in soft registers if there are
419 enough of them. */
421 hard_regno_mode_ok (int regno, enum machine_mode mode)
423 switch (GET_MODE_SIZE (mode))
425 case 8:
426 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
428 case 4:
429 return (X_REGNO_P (regno)
430 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
432 case 2:
433 return G_REGNO_P (regno);
435 case 1:
436 /* We have to accept a QImode in X or Y registers. Otherwise, the
437 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
438 in the insns. Reload fails if the insn rejects the register class 'a'
439 as well as if it accepts it. Patterns that failed were
440 zero_extend_qihi2 and iorqi3. */
442 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
444 default:
445 return 0;
450 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
452 /* Don't accept renaming to Z register. We will replace it to
453 X,Y or D during machine reorg pass. */
454 if (reg2 == HARD_Z_REGNUM)
455 return 0;
457 /* Don't accept renaming D,X to Y register as the code will be bigger. */
458 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
459 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
460 return 0;
462 return 1;
465 enum reg_class
466 preferred_reload_class (rtx operand, enum reg_class rclass)
468 enum machine_mode mode;
470 mode = GET_MODE (operand);
472 if (debug_m6811)
474 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
477 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
478 return m68hc11_base_reg_class;
480 if (rclass >= S_REGS && (GET_CODE (operand) == MEM
481 || GET_CODE (operand) == CONST_INT))
483 /* S_REGS class must not be used. The movhi template does not
484 work to move a memory to a soft register.
485 Restrict to a hard reg. */
486 switch (rclass)
488 default:
489 case G_REGS:
490 case D_OR_A_OR_S_REGS:
491 rclass = A_OR_D_REGS;
492 break;
493 case A_OR_S_REGS:
494 rclass = A_REGS;
495 break;
496 case D_OR_SP_OR_S_REGS:
497 rclass = D_OR_SP_REGS;
498 break;
499 case D_OR_Y_OR_S_REGS:
500 rclass = D_OR_Y_REGS;
501 break;
502 case D_OR_X_OR_S_REGS:
503 rclass = D_OR_X_REGS;
504 break;
505 case SP_OR_S_REGS:
506 rclass = SP_REGS;
507 break;
508 case Y_OR_S_REGS:
509 rclass = Y_REGS;
510 break;
511 case X_OR_S_REGS:
512 rclass = X_REGS;
513 break;
514 case D_OR_S_REGS:
515 rclass = D_REGS;
518 else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
520 rclass = Y_REGS;
522 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
524 rclass = D_OR_X_REGS;
526 else if (rclass >= S_REGS && S_REG_P (operand))
528 switch (rclass)
530 default:
531 case G_REGS:
532 case D_OR_A_OR_S_REGS:
533 rclass = A_OR_D_REGS;
534 break;
535 case A_OR_S_REGS:
536 rclass = A_REGS;
537 break;
538 case D_OR_SP_OR_S_REGS:
539 rclass = D_OR_SP_REGS;
540 break;
541 case D_OR_Y_OR_S_REGS:
542 rclass = D_OR_Y_REGS;
543 break;
544 case D_OR_X_OR_S_REGS:
545 rclass = D_OR_X_REGS;
546 break;
547 case SP_OR_S_REGS:
548 rclass = SP_REGS;
549 break;
550 case Y_OR_S_REGS:
551 rclass = Y_REGS;
552 break;
553 case X_OR_S_REGS:
554 rclass = X_REGS;
555 break;
556 case D_OR_S_REGS:
557 rclass = D_REGS;
560 else if (rclass >= S_REGS)
562 if (debug_m6811)
564 printf ("Class = %s for: ", reg_class_names[rclass]);
565 fflush (stdout);
566 debug_rtx (operand);
570 if (debug_m6811)
572 printf (" => class=%s\n", reg_class_names[rclass]);
573 fflush (stdout);
574 debug_rtx (operand);
577 return rclass;
580 /* Return 1 if the operand is a valid indexed addressing mode.
581 For 68hc11: n,r with n in [0..255] and r in A_REGS class
582 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
584 m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
586 rtx base, offset;
588 switch (GET_CODE (operand))
590 case MEM:
591 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
592 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
593 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
594 return 0;
596 case POST_INC:
597 case PRE_INC:
598 case POST_DEC:
599 case PRE_DEC:
600 if (addr_mode & ADDR_INCDEC)
601 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
602 addr_mode & ADDR_STRICT);
603 return 0;
605 case PLUS:
606 base = XEXP (operand, 0);
607 if (GET_CODE (base) == MEM)
608 return 0;
610 offset = XEXP (operand, 1);
611 if (GET_CODE (offset) == MEM)
612 return 0;
614 /* Indexed addressing mode with 2 registers. */
615 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
617 if (!(addr_mode & ADDR_INDEXED))
618 return 0;
620 addr_mode &= ADDR_STRICT;
621 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
622 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
623 return 1;
625 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
626 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
627 return 1;
629 return 0;
632 if (!(addr_mode & ADDR_OFFSET))
633 return 0;
635 if (GET_CODE (base) == REG)
637 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
638 return 0;
640 if (!(addr_mode & ADDR_STRICT))
641 return 1;
643 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
646 if (GET_CODE (offset) == REG)
648 if (!VALID_CONSTANT_OFFSET_P (base, mode))
649 return 0;
651 if (!(addr_mode & ADDR_STRICT))
652 return 1;
654 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
656 return 0;
658 case REG:
659 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
661 case CONST_INT:
662 if (addr_mode & ADDR_CONST)
663 return VALID_CONSTANT_OFFSET_P (operand, mode);
664 return 0;
666 default:
667 return 0;
671 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
672 a 68HC12 1-byte index addressing mode. */
674 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
676 rtx base, offset;
677 int addr_mode;
679 if (GET_CODE (operand) == REG && reload_in_progress
680 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
681 && reg_equiv_memory_loc[REGNO (operand)])
683 operand = reg_equiv_memory_loc[REGNO (operand)];
684 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
687 if (GET_CODE (operand) != MEM)
688 return 0;
690 operand = XEXP (operand, 0);
691 if (CONSTANT_ADDRESS_P (operand))
692 return 1;
694 if (PUSH_POP_ADDRESS_P (operand))
695 return 1;
697 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
698 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
699 return 0;
701 if (TARGET_M6812 && GET_CODE (operand) == PLUS
702 && (reload_completed | reload_in_progress))
704 base = XEXP (operand, 0);
705 offset = XEXP (operand, 1);
707 /* The offset can be a symbol address and this is too big
708 for the operand constraint. */
709 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
710 return 0;
712 if (GET_CODE (base) == CONST_INT)
713 offset = base;
715 switch (GET_MODE_SIZE (mode))
717 case 8:
718 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
719 return 0;
720 break;
722 case 4:
723 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
724 return 0;
725 break;
727 default:
728 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
729 return 0;
730 break;
733 return 1;
737 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
739 int addr_mode;
741 if (GET_CODE (operand) == REG && reload_in_progress
742 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
743 && reg_equiv_memory_loc[REGNO (operand)])
745 operand = reg_equiv_memory_loc[REGNO (operand)];
746 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
748 if (GET_CODE (operand) != MEM)
749 return 0;
751 operand = XEXP (operand, 0);
752 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
753 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
756 static bool
757 m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
758 bool strict)
760 int addr_mode;
762 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
764 /* Reject the global variables if they are too wide. This forces
765 a load of their address in a register and generates smaller code. */
766 if (GET_MODE_SIZE (mode) == 8)
767 return 0;
769 return 1;
771 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
772 if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
774 return 1;
776 if (PUSH_POP_ADDRESS_P (operand))
778 return 1;
780 if (symbolic_memory_operand (operand, mode))
782 return 1;
784 return 0;
787 bool
788 m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
789 bool strict)
791 int result;
793 if (debug_m6811)
795 printf ("Checking: ");
796 fflush (stdout);
797 debug_rtx (operand);
800 result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
802 if (debug_m6811)
804 printf (" -> %s\n", result == 0 ? "NO" : "YES");
807 if (result == 0)
809 if (debug_m6811)
811 printf ("go_if_legitimate%s, ret 0: %d:",
812 (strict ? "_strict" : ""), mode);
813 fflush (stdout);
814 debug_rtx (operand);
817 return result;
822 m68hc11_reload_operands (rtx operands[])
824 enum machine_mode mode;
826 if (regs_inited == 0)
827 create_regs_rtx ();
829 mode = GET_MODE (operands[1]);
831 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
832 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
834 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
835 rtx base = XEXP (XEXP (operands[1], 0), 0);
837 if (GET_CODE (base) != REG)
839 rtx tmp = base;
840 base = big_offset;
841 big_offset = tmp;
844 /* If the offset is out of range, we have to compute the address
845 with a separate add instruction. We try to do this with an 8-bit
846 add on the A register. This is possible only if the lowest part
847 of the offset (i.e., big_offset % 256) is a valid constant offset
848 with respect to the mode. If it's not, we have to generate a
849 16-bit add on the D register. From:
851 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
853 we generate:
855 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
856 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
857 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
858 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
860 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
861 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
864 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
866 int vh, vl;
867 rtx reg = operands[0];
868 rtx offset;
869 int val = INTVAL (big_offset);
872 /* We use the 'operands[0]' as a scratch register to compute the
873 address. Make sure 'base' is in that register. */
874 if (!rtx_equal_p (base, operands[0]))
876 emit_move_insn (reg, base);
879 if (val > 0)
881 vh = val >> 8;
882 vl = val & 0x0FF;
884 else
886 vh = (val >> 8) & 0x0FF;
887 vl = val & 0x0FF;
890 /* Create the lowest part offset that still remains to be added.
891 If it's not a valid offset, do a 16-bit add. */
892 offset = GEN_INT (vl);
893 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
895 emit_insn (gen_rtx_SET (VOIDmode, reg,
896 gen_rtx_PLUS (HImode, reg, big_offset)));
897 offset = const0_rtx;
899 else
901 emit_insn (gen_rtx_SET (VOIDmode, reg,
902 gen_rtx_PLUS (HImode, reg,
903 GEN_INT (vh << 8))));
905 emit_move_insn (operands[0],
906 gen_rtx_MEM (GET_MODE (operands[1]),
907 gen_rtx_PLUS (Pmode, reg, offset)));
908 return 1;
912 /* Use the normal gen_movhi pattern. */
913 return 0;
916 void
917 m68hc11_emit_libcall (const char *name, enum rtx_code code,
918 enum machine_mode dmode, enum machine_mode smode,
919 int noperands, rtx *operands)
921 rtx ret;
922 rtx insns;
923 rtx libcall;
924 rtx equiv;
926 start_sequence ();
927 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
928 switch (noperands)
930 case 2:
931 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
932 dmode, 1, operands[1], smode);
933 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
934 break;
936 case 3:
937 ret = emit_library_call_value (libcall, NULL_RTX,
938 LCT_CONST, dmode, 2,
939 operands[1], smode, operands[2],
940 smode);
941 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
942 break;
944 default:
945 gcc_unreachable ();
948 insns = get_insns ();
949 end_sequence ();
950 emit_libcall_block (insns, operands[0], ret, equiv);
953 /* Returns true if X is a PRE/POST increment decrement
954 (same as auto_inc_p() in rtlanal.c but do not take into
955 account the stack). */
957 m68hc11_auto_inc_p (rtx x)
959 return GET_CODE (x) == PRE_DEC
960 || GET_CODE (x) == POST_INC
961 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
965 /* Predicates for machine description. */
968 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
970 return GET_CODE (operand) == MEM
971 && GET_CODE (XEXP (operand, 0)) == PLUS
972 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
973 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
974 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
975 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
979 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
981 if (GET_CODE (operand) == MEM)
983 rtx op = XEXP (operand, 0);
985 if (symbolic_memory_operand (op, mode))
986 return 1;
988 return 0;
992 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
994 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
996 rtx op = XEXP (operand, 0);
997 int addr_mode;
999 if (m68hc11_page0_symbol_p (op))
1000 return 1;
1002 if (symbolic_memory_operand (op, mode))
1003 return TARGET_M6812;
1005 if (reload_in_progress)
1006 return 1;
1008 operand = XEXP (operand, 0);
1009 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1010 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
1012 return 0;
1016 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1018 if (GET_CODE (operand) != MEM)
1019 return 0;
1021 operand = XEXP (operand, 0);
1022 if (GET_CODE (operand) == PLUS)
1024 if (GET_CODE (XEXP (operand, 0)) == REG)
1025 operand = XEXP (operand, 0);
1026 else if (GET_CODE (XEXP (operand, 1)) == REG)
1027 operand = XEXP (operand, 1);
1029 return GET_CODE (operand) == REG
1030 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1031 || A_REGNO_P (REGNO (operand)));
1035 push_pop_operand_p (rtx operand)
1037 if (GET_CODE (operand) != MEM)
1039 return 0;
1041 operand = XEXP (operand, 0);
1042 return PUSH_POP_ADDRESS_P (operand);
1045 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1046 reference and a constant. */
1049 symbolic_memory_operand (rtx op, enum machine_mode mode)
1051 switch (GET_CODE (op))
1053 case SYMBOL_REF:
1054 case LABEL_REF:
1055 return 1;
1057 case CONST:
1058 op = XEXP (op, 0);
1059 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1060 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1061 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1063 /* ??? This clause seems to be irrelevant. */
1064 case CONST_DOUBLE:
1065 return GET_MODE (op) == mode;
1067 case PLUS:
1068 return symbolic_memory_operand (XEXP (op, 0), mode)
1069 && symbolic_memory_operand (XEXP (op, 1), mode);
1071 default:
1072 return 0;
1076 /* Emit the code to build the trampoline used to call a nested function.
1078 68HC11 68HC12
1080 ldy #&CXT movw #&CXT,*_.d1
1081 sty *_.d1 jmp FNADDR
1082 jmp FNADDR
1085 static void
1086 m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
1088 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1089 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
1090 rtx mem;
1092 /* Skip the '*'. */
1093 if (*static_chain_reg == '*')
1094 static_chain_reg++;
1095 if (TARGET_M6811)
1097 mem = adjust_address (m_tramp, HImode, 0);
1098 emit_move_insn (mem, GEN_INT (0x18ce));
1099 mem = adjust_address (m_tramp, HImode, 2);
1100 emit_move_insn (mem, cxt);
1101 mem = adjust_address (m_tramp, HImode, 4);
1102 emit_move_insn (mem, GEN_INT (0x18df));
1103 mem = adjust_address (m_tramp, QImode, 6);
1104 emit_move_insn (mem,
1105 gen_rtx_CONST (QImode,
1106 gen_rtx_SYMBOL_REF (Pmode,
1107 static_chain_reg)));
1108 mem = adjust_address (m_tramp, QImode, 7);
1109 emit_move_insn (mem, GEN_INT (0x7e));
1110 mem = adjust_address (m_tramp, HImode, 8);
1111 emit_move_insn (mem, fnaddr);
1113 else
1115 mem = adjust_address (m_tramp, HImode, 0);
1116 emit_move_insn (mem, GEN_INT (0x1803));
1117 mem = adjust_address (m_tramp, HImode, 2);
1118 emit_move_insn (mem, cxt);
1119 mem = adjust_address (m_tramp, HImode, 4);
1120 emit_move_insn (mem,
1121 gen_rtx_CONST (HImode,
1122 gen_rtx_SYMBOL_REF (Pmode,
1123 static_chain_reg)));
1124 mem = adjust_address (m_tramp, QImode, 6);
1125 emit_move_insn (mem, GEN_INT (0x06));
1126 mem = adjust_address (m_tramp, HImode, 7);
1127 emit_move_insn (mem, fnaddr);
1131 /* Declaration of types. */
1133 /* Handle an "tiny_data" attribute; arguments as in
1134 struct attribute_spec.handler. */
1135 static tree
1136 m68hc11_handle_page0_attribute (tree *node, tree name,
1137 tree args ATTRIBUTE_UNUSED,
1138 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1140 tree decl = *node;
1142 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1144 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1146 else
1148 warning (OPT_Wattributes, "%qE attribute ignored",
1149 name);
1150 *no_add_attrs = true;
1153 return NULL_TREE;
1156 /* Keep track of the symbol which has a `trap' attribute and which uses
1157 the `swi' calling convention. Since there is only one trap, we only
1158 record one such symbol. If there are several, a warning is reported. */
1159 static rtx trap_handler_symbol = 0;
1161 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1162 arguments as in struct attribute_spec.handler. */
1163 static tree
1164 m68hc11_handle_fntype_attribute (tree *node, tree name,
1165 tree args ATTRIBUTE_UNUSED,
1166 int flags ATTRIBUTE_UNUSED,
1167 bool *no_add_attrs)
1169 if (TREE_CODE (*node) != FUNCTION_TYPE
1170 && TREE_CODE (*node) != METHOD_TYPE
1171 && TREE_CODE (*node) != FIELD_DECL
1172 && TREE_CODE (*node) != TYPE_DECL)
1174 warning (OPT_Wattributes, "%qE attribute only applies to functions",
1175 name);
1176 *no_add_attrs = true;
1179 return NULL_TREE;
1181 /* Undo the effects of the above. */
1183 static const char *
1184 m68hc11_strip_name_encoding (const char *str)
1186 return str + (*str == '*' || *str == '@' || *str == '&');
1189 static void
1190 m68hc11_encode_label (tree decl)
1192 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1193 int len = strlen (str);
1194 char *newstr = XALLOCAVEC (char, len + 2);
1196 newstr[0] = '@';
1197 strcpy (&newstr[1], str);
1199 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1202 /* Return 1 if this is a symbol in page0 */
1204 m68hc11_page0_symbol_p (rtx x)
1206 switch (GET_CODE (x))
1208 case SYMBOL_REF:
1209 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1211 case CONST:
1212 return m68hc11_page0_symbol_p (XEXP (x, 0));
1214 case PLUS:
1215 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1216 return 0;
1218 return GET_CODE (XEXP (x, 1)) == CONST_INT
1219 && INTVAL (XEXP (x, 1)) < 256
1220 && INTVAL (XEXP (x, 1)) >= 0;
1222 default:
1223 return 0;
1227 /* We want to recognize trap handlers so that we handle calls to traps
1228 in a special manner (by issuing the trap). This information is stored
1229 in SYMBOL_REF_FLAG. */
1231 static void
1232 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1234 tree func_attr;
1235 int trap_handler;
1236 int is_far = 0;
1238 if (TREE_CODE (decl) == VAR_DECL)
1240 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1241 m68hc11_encode_label (decl);
1242 return;
1245 if (TREE_CODE (decl) != FUNCTION_DECL)
1246 return;
1248 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1251 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1252 is_far = 1;
1253 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1254 is_far = TARGET_LONG_CALLS != 0;
1256 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1257 if (trap_handler && is_far)
1259 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1260 "not compatible, ignoring %<far%>");
1261 trap_handler = 0;
1263 if (trap_handler)
1265 if (trap_handler_symbol != 0)
1266 warning (OPT_Wattributes, "%<trap%> attribute is already used");
1267 else
1268 trap_handler_symbol = XEXP (rtl, 0);
1270 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1273 static unsigned int
1274 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1276 unsigned int flags = default_section_type_flags (decl, name, reloc);
1278 if (strncmp (name, ".eeprom", 7) == 0)
1280 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1283 return flags;
1287 m68hc11_is_far_symbol (rtx sym)
1289 if (GET_CODE (sym) == MEM)
1290 sym = XEXP (sym, 0);
1292 return SYMBOL_REF_FLAG (sym);
1296 m68hc11_is_trap_symbol (rtx sym)
1298 if (GET_CODE (sym) == MEM)
1299 sym = XEXP (sym, 0);
1301 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1305 /* Argument support functions. */
1307 /* Given FROM and TO register numbers, say whether this elimination is
1308 allowed. Frame pointer elimination is automatically handled.
1310 All other eliminations are valid. */
1312 bool
1313 m68hc11_can_eliminate (const int from, const int to)
1315 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
1316 ? ! frame_pointer_needed
1317 : true);
1320 /* Define the offset between two registers, one to be eliminated, and the
1321 other its replacement, at the start of a routine. */
1323 m68hc11_initial_elimination_offset (int from, int to)
1325 int trap_handler;
1326 tree func_attr;
1327 int size;
1328 int regno;
1330 /* For a trap handler, we must take into account the registers which
1331 are pushed on the stack during the trap (except the PC). */
1332 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1333 current_function_interrupt = lookup_attribute ("interrupt",
1334 func_attr) != NULL_TREE;
1335 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1337 if (lookup_attribute ("far", func_attr) != 0)
1338 current_function_far = 1;
1339 else if (lookup_attribute ("near", func_attr) != 0)
1340 current_function_far = 0;
1341 else
1342 current_function_far = (TARGET_LONG_CALLS != 0
1343 && !current_function_interrupt
1344 && !trap_handler);
1346 if (trap_handler && from == ARG_POINTER_REGNUM)
1347 size = 7;
1349 /* For a function using 'call/rtc' we must take into account the
1350 page register which is pushed in the call. */
1351 else if (current_function_far && from == ARG_POINTER_REGNUM)
1352 size = 1;
1353 else
1354 size = 0;
1356 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1358 /* 2 is for the saved frame.
1359 1 is for the 'sts' correction when creating the frame. */
1360 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1363 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1365 return m68hc11_sp_correction;
1368 /* Push any 2 byte pseudo hard registers that we need to save. */
1369 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1371 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1373 size += 2;
1377 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1379 return get_frame_size () + size;
1382 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1384 return size;
1386 return 0;
1389 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1390 for a call to a function whose data type is FNTYPE.
1391 For a library call, FNTYPE is 0. */
1393 void
1394 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1396 tree ret_type;
1398 z_replacement_completed = 0;
1399 cum->words = 0;
1400 cum->nregs = 0;
1402 /* For a library call, we must find out the type of the return value.
1403 When the return value is bigger than 4 bytes, it is returned in
1404 memory. In that case, the first argument of the library call is a
1405 pointer to the memory location. Because the first argument is passed in
1406 register D, we have to identify this, so that the first function
1407 parameter is not passed in D either. */
1408 if (fntype == 0)
1410 const char *name;
1411 size_t len;
1413 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1414 return;
1416 /* If the library ends in 'di' or in 'df', we assume it's
1417 returning some DImode or some DFmode which are 64-bit wide. */
1418 name = XSTR (libname, 0);
1419 len = strlen (name);
1420 if (len > 3
1421 && ((name[len - 2] == 'd'
1422 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1423 || (name[len - 3] == 'd'
1424 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1426 /* We are in. Mark the first parameter register as already used. */
1427 cum->words = 1;
1428 cum->nregs = 1;
1430 return;
1433 ret_type = TREE_TYPE (fntype);
1435 if (ret_type && aggregate_value_p (ret_type, fntype))
1437 cum->words = 1;
1438 cum->nregs = 1;
1442 /* Update the data in CUM to advance over an argument
1443 of mode MODE and data type TYPE.
1444 (TYPE is null for libcalls where that information may not be available.) */
1446 void
1447 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1448 tree type, int named ATTRIBUTE_UNUSED)
1450 if (mode != BLKmode)
1452 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1454 cum->nregs = 2;
1455 cum->words = GET_MODE_SIZE (mode);
1457 else
1459 cum->words += GET_MODE_SIZE (mode);
1460 if (cum->words <= HARD_REG_SIZE)
1461 cum->nregs = 1;
1464 else
1466 cum->words += int_size_in_bytes (type);
1468 return;
1471 /* Define where to put the arguments to a function.
1472 Value is zero to push the argument on the stack,
1473 or a hard register in which to store the argument.
1475 MODE is the argument's machine mode.
1476 TYPE is the data type of the argument (as a tree).
1477 This is null for libcalls where that information may
1478 not be available.
1479 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1480 the preceding args and about the function being called.
1481 NAMED is nonzero if this argument is a named parameter
1482 (otherwise it is an extra parameter matching an ellipsis). */
1484 struct rtx_def *
1485 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1486 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1488 if (cum->words != 0)
1490 return NULL_RTX;
1493 if (mode != BLKmode)
1495 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1496 return gen_rtx_REG (mode, HARD_X_REGNUM);
1498 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1500 return NULL_RTX;
1502 return gen_rtx_REG (mode, HARD_D_REGNUM);
1504 return NULL_RTX;
1507 /* If defined, a C expression which determines whether, and in which direction,
1508 to pad out an argument with extra space. The value should be of type
1509 `enum direction': either `upward' to pad above the argument,
1510 `downward' to pad below, or `none' to inhibit padding.
1512 Structures are stored left shifted in their argument slot. */
1513 enum direction
1514 m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
1516 if (type != 0 && AGGREGATE_TYPE_P (type))
1517 return upward;
1519 /* Fall back to the default. */
1520 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1524 /* Function prologue and epilogue. */
1526 /* Emit a move after the reload pass has completed. This is used to
1527 emit the prologue and epilogue. */
1528 static void
1529 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1531 rtx insn;
1533 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1535 insn = emit_move_insn (to, from);
1537 else
1539 emit_move_insn (scratch, from);
1540 insn = emit_move_insn (to, scratch);
1543 /* Put a REG_INC note to tell the flow analysis that the instruction
1544 is necessary. */
1545 if (IS_STACK_PUSH (to))
1546 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
1547 else if (IS_STACK_POP (from))
1548 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
1550 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1551 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1552 The problem is that we are lying to gcc and use `txs' for x = sp
1553 (which is not really true because txs is really x = sp + 1). */
1554 else if (TARGET_M6811 && SP_REG_P (from))
1555 add_reg_note (insn, REG_INC, from);
1559 m68hc11_total_frame_size (void)
1561 int size;
1562 int regno;
1564 size = get_frame_size ();
1565 if (current_function_interrupt)
1567 size += 3 * HARD_REG_SIZE;
1569 if (frame_pointer_needed)
1570 size += HARD_REG_SIZE;
1572 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1573 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1574 size += HARD_REG_SIZE;
1576 return size;
1579 static void
1580 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1581 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1583 /* We catch the function epilogue generation to have a chance
1584 to clear the z_replacement_completed flag. */
1585 z_replacement_completed = 0;
1588 void
1589 expand_prologue (void)
1591 tree func_attr;
1592 int size;
1593 int regno;
1594 rtx scratch;
1596 gcc_assert (reload_completed == 1);
1598 size = get_frame_size ();
1600 create_regs_rtx ();
1602 /* Generate specific prologue for interrupt handlers. */
1603 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1604 current_function_interrupt = lookup_attribute ("interrupt",
1605 func_attr) != NULL_TREE;
1606 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1607 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1608 current_function_far = 1;
1609 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1610 current_function_far = 0;
1611 else
1612 current_function_far = (TARGET_LONG_CALLS != 0
1613 && !current_function_interrupt
1614 && !current_function_trap);
1616 /* Get the scratch register to build the frame and push registers.
1617 If the first argument is a 32-bit quantity, the D+X registers
1618 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1619 For 68HC12, this scratch register is not used. */
1620 if (crtl->args.info.nregs == 2)
1621 scratch = iy_reg;
1622 else
1623 scratch = ix_reg;
1625 /* Save current stack frame. */
1626 if (frame_pointer_needed)
1627 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1629 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1630 Other soft registers in page0 need not to be saved because they
1631 will be restored by C functions. For a trap handler, we don't
1632 need to preserve these registers because this is a synchronous call. */
1633 if (current_function_interrupt)
1635 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1636 emit_move_after_reload (stack_push_word,
1637 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1638 emit_move_after_reload (stack_push_word,
1639 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1640 scratch);
1643 /* Allocate local variables. */
1644 if (TARGET_M6812 && (size > 4 || size == 3))
1646 emit_insn (gen_addhi3 (stack_pointer_rtx,
1647 stack_pointer_rtx, GEN_INT (-size)));
1649 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1651 rtx insn;
1653 insn = gen_rtx_PARALLEL
1654 (VOIDmode,
1655 gen_rtvec (2,
1656 gen_rtx_SET (VOIDmode,
1657 stack_pointer_rtx,
1658 gen_rtx_PLUS (HImode,
1659 stack_pointer_rtx,
1660 GEN_INT (-size))),
1661 gen_rtx_CLOBBER (VOIDmode, scratch)));
1662 emit_insn (insn);
1664 else
1666 int i;
1668 /* Allocate by pushing scratch values. */
1669 for (i = 2; i <= size; i += 2)
1670 emit_move_after_reload (stack_push_word, ix_reg, 0);
1672 if (size & 1)
1673 emit_insn (gen_addhi3 (stack_pointer_rtx,
1674 stack_pointer_rtx, constm1_rtx));
1677 /* Create the frame pointer. */
1678 if (frame_pointer_needed)
1679 emit_move_after_reload (hard_frame_pointer_rtx,
1680 stack_pointer_rtx, scratch);
1682 /* Push any 2 byte pseudo hard registers that we need to save. */
1683 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1685 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1687 emit_move_after_reload (stack_push_word,
1688 gen_rtx_REG (HImode, regno), scratch);
1693 void
1694 expand_epilogue (void)
1696 int size;
1697 register int regno;
1698 int return_size;
1699 rtx scratch;
1701 gcc_assert (reload_completed == 1);
1703 size = get_frame_size ();
1705 /* If we are returning a value in two registers, we have to preserve the
1706 X register and use the Y register to restore the stack and the saved
1707 registers. Otherwise, use X because it's faster (and smaller). */
1708 if (crtl->return_rtx == 0)
1709 return_size = 0;
1710 else if (GET_CODE (crtl->return_rtx) == MEM)
1711 return_size = HARD_REG_SIZE;
1712 else
1713 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
1715 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1716 scratch = iy_reg;
1717 else
1718 scratch = ix_reg;
1720 /* Pop any 2 byte pseudo hard registers that we saved. */
1721 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1723 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1725 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1726 stack_pop_word, scratch);
1730 /* de-allocate auto variables */
1731 if (TARGET_M6812 && (size > 4 || size == 3))
1733 emit_insn (gen_addhi3 (stack_pointer_rtx,
1734 stack_pointer_rtx, GEN_INT (size)));
1736 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1738 rtx insn;
1740 insn = gen_rtx_PARALLEL
1741 (VOIDmode,
1742 gen_rtvec (2,
1743 gen_rtx_SET (VOIDmode,
1744 stack_pointer_rtx,
1745 gen_rtx_PLUS (HImode,
1746 stack_pointer_rtx,
1747 GEN_INT (size))),
1748 gen_rtx_CLOBBER (VOIDmode, scratch)));
1749 emit_insn (insn);
1751 else
1753 int i;
1755 for (i = 2; i <= size; i += 2)
1756 emit_move_after_reload (scratch, stack_pop_word, scratch);
1757 if (size & 1)
1758 emit_insn (gen_addhi3 (stack_pointer_rtx,
1759 stack_pointer_rtx, const1_rtx));
1762 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1763 if (current_function_interrupt)
1765 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1766 stack_pop_word, scratch);
1767 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1768 stack_pop_word, scratch);
1769 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1772 /* Restore previous frame pointer. */
1773 if (frame_pointer_needed)
1774 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1776 /* If the trap handler returns some value, copy the value
1777 in D, X onto the stack so that the rti will pop the return value
1778 correctly. */
1779 else if (current_function_trap && return_size != 0)
1781 rtx addr_reg = stack_pointer_rtx;
1783 if (!TARGET_M6812)
1785 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1786 addr_reg = scratch;
1788 emit_move_after_reload (gen_rtx_MEM (HImode,
1789 gen_rtx_PLUS (HImode, addr_reg,
1790 const1_rtx)), d_reg, 0);
1791 if (return_size > HARD_REG_SIZE)
1792 emit_move_after_reload (gen_rtx_MEM (HImode,
1793 gen_rtx_PLUS (HImode, addr_reg,
1794 GEN_INT (3))), ix_reg, 0);
1797 emit_jump_insn (gen_return ());
1801 /* Low and High part extraction for 68HC11. These routines are
1802 similar to gen_lowpart and gen_highpart but they have been
1803 fixed to work for constants and 68HC11 specific registers. */
1806 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1808 /* We assume that the low part of an auto-inc mode is the same with
1809 the mode changed and that the caller split the larger mode in the
1810 correct order. */
1811 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1813 return gen_rtx_MEM (mode, XEXP (x, 0));
1816 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1817 floating-point constant. A CONST_DOUBLE is used whenever the
1818 constant requires more than one word in order to be adequately
1819 represented. */
1820 if (GET_CODE (x) == CONST_DOUBLE)
1822 long l[2];
1824 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1826 REAL_VALUE_TYPE r;
1828 if (GET_MODE (x) == SFmode)
1830 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1831 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1833 else
1835 rtx first, second;
1837 split_double (x, &first, &second);
1838 return second;
1840 if (mode == SImode)
1841 return GEN_INT (l[0]);
1843 return gen_int_mode (l[0], HImode);
1845 else
1847 l[0] = CONST_DOUBLE_LOW (x);
1849 switch (mode)
1851 case SImode:
1852 return GEN_INT (l[0]);
1853 case HImode:
1854 gcc_assert (GET_MODE (x) == SFmode);
1855 return gen_int_mode (l[0], HImode);
1856 default:
1857 gcc_unreachable ();
1861 if (mode == QImode && D_REG_P (x))
1862 return gen_rtx_REG (mode, HARD_B_REGNUM);
1864 /* gen_lowpart crashes when it is called with a SUBREG. */
1865 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1867 switch (mode)
1869 case SImode:
1870 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1871 case HImode:
1872 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1873 default:
1874 gcc_unreachable ();
1877 x = gen_lowpart (mode, x);
1879 /* Return a different rtx to avoid to share it in several insns
1880 (when used by a split pattern). Sharing addresses within
1881 a MEM breaks the Z register replacement (and reloading). */
1882 if (GET_CODE (x) == MEM)
1883 x = copy_rtx (x);
1884 return x;
1888 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1890 /* We assume that the high part of an auto-inc mode is the same with
1891 the mode changed and that the caller split the larger mode in the
1892 correct order. */
1893 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1895 return gen_rtx_MEM (mode, XEXP (x, 0));
1898 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1899 floating-point constant. A CONST_DOUBLE is used whenever the
1900 constant requires more than one word in order to be adequately
1901 represented. */
1902 if (GET_CODE (x) == CONST_DOUBLE)
1904 long l[2];
1906 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1908 REAL_VALUE_TYPE r;
1910 if (GET_MODE (x) == SFmode)
1912 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1913 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1915 else
1917 rtx first, second;
1919 split_double (x, &first, &second);
1920 return first;
1922 if (mode == SImode)
1923 return GEN_INT (l[1]);
1925 return gen_int_mode ((l[1] >> 16), HImode);
1927 else
1929 l[1] = CONST_DOUBLE_HIGH (x);
1932 switch (mode)
1934 case SImode:
1935 return GEN_INT (l[1]);
1936 case HImode:
1937 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1938 return gen_int_mode ((l[0] >> 16), HImode);
1939 default:
1940 gcc_unreachable ();
1943 if (GET_CODE (x) == CONST_INT)
1945 HOST_WIDE_INT val = INTVAL (x);
1947 if (mode == QImode)
1949 return gen_int_mode (val >> 8, QImode);
1951 else if (mode == HImode)
1953 return gen_int_mode (val >> 16, HImode);
1955 else if (mode == SImode)
1957 return gen_int_mode (val >> 32, SImode);
1960 if (mode == QImode && D_REG_P (x))
1961 return gen_rtx_REG (mode, HARD_A_REGNUM);
1963 /* There is no way in GCC to represent the upper part of a word register.
1964 To obtain the 8-bit upper part of a soft register, we change the
1965 reg into a mem rtx. This is possible because they are physically
1966 located in memory. There is no offset because we are big-endian. */
1967 if (mode == QImode && S_REG_P (x))
1969 int pos;
1971 /* Avoid the '*' for direct addressing mode when this
1972 addressing mode is disabled. */
1973 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1974 return gen_rtx_MEM (QImode,
1975 gen_rtx_SYMBOL_REF (Pmode,
1976 &reg_names[REGNO (x)][pos]));
1979 /* gen_highpart crashes when it is called with a SUBREG. */
1980 switch (GET_CODE (x))
1982 case SUBREG:
1983 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
1984 case REG:
1985 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1986 return gen_rtx_REG (mode, REGNO (x));
1987 else
1988 return gen_rtx_SUBREG (mode, x, 0);
1989 case MEM:
1990 x = change_address (x, mode, 0);
1992 /* Return a different rtx to avoid to share it in several insns
1993 (when used by a split pattern). Sharing addresses within
1994 a MEM breaks the Z register replacement (and reloading). */
1995 if (GET_CODE (x) == MEM)
1996 x = copy_rtx (x);
1997 return x;
1999 default:
2000 gcc_unreachable ();
2005 /* Obscure register manipulation. */
2007 /* Finds backward in the instructions to see if register 'reg' is
2008 dead. This is used when generating code to see if we can use 'reg'
2009 as a scratch register. This allows us to choose a better generation
2010 of code when we know that some register dies or can be clobbered. */
2013 dead_register_here (rtx x, rtx reg)
2015 rtx x_reg;
2016 rtx p;
2018 if (D_REG_P (reg))
2019 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2020 else
2021 x_reg = 0;
2023 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2024 if (INSN_P (p))
2026 rtx body;
2028 body = PATTERN (p);
2030 if (GET_CODE (body) == CALL_INSN)
2031 break;
2032 if (GET_CODE (body) == JUMP_INSN)
2033 break;
2035 if (GET_CODE (body) == SET)
2037 rtx dst = XEXP (body, 0);
2039 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2040 break;
2041 if (x_reg && rtx_equal_p (dst, x_reg))
2042 break;
2044 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2045 return 1;
2047 else if (reg_mentioned_p (reg, p)
2048 || (x_reg && reg_mentioned_p (x_reg, p)))
2049 break;
2052 /* Scan forward to see if the register is set in some insns and never
2053 used since then. */
2054 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2056 rtx body;
2058 if (GET_CODE (p) == CODE_LABEL
2059 || GET_CODE (p) == JUMP_INSN
2060 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2061 break;
2063 if (GET_CODE (p) != INSN)
2064 continue;
2066 body = PATTERN (p);
2067 if (GET_CODE (body) == SET)
2069 rtx src = XEXP (body, 1);
2070 rtx dst = XEXP (body, 0);
2072 if (GET_CODE (dst) == REG
2073 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2074 return 1;
2077 /* Register is used (may be in source or in dest). */
2078 if (reg_mentioned_p (reg, p)
2079 || (x_reg != 0 && GET_MODE (p) == SImode
2080 && reg_mentioned_p (x_reg, p)))
2081 break;
2083 return p == 0 ? 1 : 0;
2087 /* Code generation operations called from machine description file. */
2089 /* Print the name of register 'regno' in the assembly file. */
2090 static void
2091 asm_print_register (FILE *file, int regno)
2093 const char *name = reg_names[regno];
2095 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2096 name++;
2098 fprintf (file, "%s", name);
2101 /* A C compound statement to output to stdio stream STREAM the
2102 assembler syntax for an instruction operand X. X is an RTL
2103 expression.
2105 CODE is a value that can be used to specify one of several ways
2106 of printing the operand. It is used when identical operands
2107 must be printed differently depending on the context. CODE
2108 comes from the `%' specification that was used to request
2109 printing of the operand. If the specification was just `%DIGIT'
2110 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2111 is the ASCII code for LTR.
2113 If X is a register, this macro should print the register's name.
2114 The names can be found in an array `reg_names' whose type is
2115 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2117 When the machine description has a specification `%PUNCT' (a `%'
2118 followed by a punctuation character), this macro is called with
2119 a null pointer for X and the punctuation character for CODE.
2121 The M68HC11 specific codes are:
2123 'b' for the low part of the operand.
2124 'h' for the high part of the operand
2125 The 'b' or 'h' modifiers have no effect if the operand has
2126 the QImode and is not a S_REG_P (soft register). If the
2127 operand is a hard register, these two modifiers have no effect.
2128 't' generate the temporary scratch register. The operand is
2129 ignored.
2130 'T' generate the low-part temporary scratch register. The operand is
2131 ignored. */
2133 static void
2134 m68hc11_print_operand (FILE *file, rtx op, int letter)
2136 if (letter == 't')
2138 asm_print_register (file, SOFT_TMP_REGNUM);
2139 return;
2141 else if (letter == 'T')
2143 asm_print_register (file, SOFT_TMP_REGNUM);
2144 fprintf (file, "+1");
2145 return;
2147 else if (letter == '#')
2149 asm_fprintf (file, "%I");
2152 if (GET_CODE (op) == REG)
2154 if (letter == 'b' && S_REG_P (op))
2156 asm_print_register (file, REGNO (op));
2157 fprintf (file, "+1");
2159 else if (letter == 'b' && D_REG_P (op))
2161 asm_print_register (file, HARD_B_REGNUM);
2163 else
2165 asm_print_register (file, REGNO (op));
2167 return;
2170 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2172 if (letter == 'b')
2173 asm_fprintf (file, "%I%%lo(");
2174 else
2175 asm_fprintf (file, "%I%%hi(");
2177 output_addr_const (file, op);
2178 fprintf (file, ")");
2179 return;
2182 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2183 are specified. If we already have a QImode, there is nothing to do. */
2184 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2186 if (letter == 'b')
2188 op = m68hc11_gen_lowpart (QImode, op);
2190 else if (letter == 'h')
2192 op = m68hc11_gen_highpart (QImode, op);
2196 if (GET_CODE (op) == MEM)
2198 rtx base = XEXP (op, 0);
2199 switch (GET_CODE (base))
2201 case PRE_DEC:
2202 gcc_assert (TARGET_M6812);
2203 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2204 asm_print_register (file, REGNO (XEXP (base, 0)));
2205 break;
2207 case POST_DEC:
2208 gcc_assert (TARGET_M6812);
2209 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2210 asm_print_register (file, REGNO (XEXP (base, 0)));
2211 fprintf (file, "-");
2212 break;
2214 case POST_INC:
2215 gcc_assert (TARGET_M6812);
2216 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2217 asm_print_register (file, REGNO (XEXP (base, 0)));
2218 fprintf (file, "+");
2219 break;
2221 case PRE_INC:
2222 gcc_assert (TARGET_M6812);
2223 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2224 asm_print_register (file, REGNO (XEXP (base, 0)));
2225 break;
2227 case MEM:
2228 gcc_assert (TARGET_M6812);
2229 fprintf (file, "[");
2230 print_operand_address (file, XEXP (base, 0));
2231 fprintf (file, "]");
2232 break;
2234 default:
2235 if (m68hc11_page0_symbol_p (base))
2236 fprintf (file, "*");
2238 output_address (base);
2239 break;
2242 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2244 REAL_VALUE_TYPE r;
2245 long l;
2247 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2248 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2249 asm_fprintf (file, "%I0x%lx", l);
2251 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2253 char dstr[30];
2255 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2256 sizeof (dstr), 0, 1);
2257 asm_fprintf (file, "%I0r%s", dstr);
2259 else
2261 int need_parenthesize = 0;
2263 if (letter != 'i')
2264 asm_fprintf (file, "%I");
2265 else
2266 need_parenthesize = must_parenthesize (op);
2268 if (need_parenthesize)
2269 fprintf (file, "(");
2271 output_addr_const (file, op);
2272 if (need_parenthesize)
2273 fprintf (file, ")");
2277 /* Returns true if the operand 'op' must be printed with parenthesis
2278 around it. This must be done only if there is a symbol whose name
2279 is a processor register. */
2280 static int
2281 must_parenthesize (rtx op)
2283 const char *name;
2285 switch (GET_CODE (op))
2287 case SYMBOL_REF:
2288 name = XSTR (op, 0);
2289 /* Avoid a conflict between symbol name and a possible
2290 register. */
2291 return (strcasecmp (name, "a") == 0
2292 || strcasecmp (name, "b") == 0
2293 || strcasecmp (name, "d") == 0
2294 || strcasecmp (name, "x") == 0
2295 || strcasecmp (name, "y") == 0
2296 || strcasecmp (name, "ix") == 0
2297 || strcasecmp (name, "iy") == 0
2298 || strcasecmp (name, "pc") == 0
2299 || strcasecmp (name, "sp") == 0
2300 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2302 case PLUS:
2303 case MINUS:
2304 return must_parenthesize (XEXP (op, 0))
2305 || must_parenthesize (XEXP (op, 1));
2307 case MEM:
2308 case CONST:
2309 case ZERO_EXTEND:
2310 case SIGN_EXTEND:
2311 return must_parenthesize (XEXP (op, 0));
2313 case CONST_DOUBLE:
2314 case CONST_INT:
2315 case LABEL_REF:
2316 case CODE_LABEL:
2317 default:
2318 return 0;
2322 /* A C compound statement to output to stdio stream STREAM the
2323 assembler syntax for an instruction operand that is a memory
2324 reference whose address is ADDR. ADDR is an RTL expression. */
2326 static void
2327 m68hc11_print_operand_address (FILE *file, rtx addr)
2329 rtx base;
2330 rtx offset;
2331 int need_parenthesis = 0;
2333 switch (GET_CODE (addr))
2335 case REG:
2336 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2338 fprintf (file, "0,");
2339 asm_print_register (file, REGNO (addr));
2340 break;
2342 case MEM:
2343 base = XEXP (addr, 0);
2344 switch (GET_CODE (base))
2346 case PRE_DEC:
2347 gcc_assert (TARGET_M6812);
2348 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2349 asm_print_register (file, REGNO (XEXP (base, 0)));
2350 break;
2352 case POST_DEC:
2353 gcc_assert (TARGET_M6812);
2354 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2355 asm_print_register (file, REGNO (XEXP (base, 0)));
2356 fprintf (file, "-");
2357 break;
2359 case POST_INC:
2360 gcc_assert (TARGET_M6812);
2361 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2362 asm_print_register (file, REGNO (XEXP (base, 0)));
2363 fprintf (file, "+");
2364 break;
2366 case PRE_INC:
2367 gcc_assert (TARGET_M6812);
2368 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2369 asm_print_register (file, REGNO (XEXP (base, 0)));
2370 break;
2372 default:
2373 need_parenthesis = must_parenthesize (base);
2374 if (need_parenthesis)
2375 fprintf (file, "(");
2377 output_addr_const (file, base);
2378 if (need_parenthesis)
2379 fprintf (file, ")");
2380 break;
2382 break;
2384 case PLUS:
2385 base = XEXP (addr, 0);
2386 offset = XEXP (addr, 1);
2387 if (!G_REG_P (base) && G_REG_P (offset))
2389 base = XEXP (addr, 1);
2390 offset = XEXP (addr, 0);
2392 if (CONSTANT_ADDRESS_P (base))
2394 need_parenthesis = must_parenthesize (addr);
2396 gcc_assert (CONSTANT_ADDRESS_P (offset));
2397 if (need_parenthesis)
2398 fprintf (file, "(");
2400 output_addr_const (file, base);
2401 fprintf (file, "+");
2402 output_addr_const (file, offset);
2403 if (need_parenthesis)
2404 fprintf (file, ")");
2406 else
2408 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2409 if (REG_P (offset))
2411 gcc_assert (TARGET_M6812);
2412 asm_print_register (file, REGNO (offset));
2413 fprintf (file, ",");
2414 asm_print_register (file, REGNO (base));
2416 else
2418 need_parenthesis = must_parenthesize (offset);
2419 if (need_parenthesis)
2420 fprintf (file, "(");
2422 output_addr_const (file, offset);
2423 if (need_parenthesis)
2424 fprintf (file, ")");
2425 fprintf (file, ",");
2426 asm_print_register (file, REGNO (base));
2429 break;
2431 default:
2432 if (GET_CODE (addr) == CONST_INT
2433 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2435 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2437 else
2439 need_parenthesis = must_parenthesize (addr);
2440 if (need_parenthesis)
2441 fprintf (file, "(");
2443 output_addr_const (file, addr);
2444 if (need_parenthesis)
2445 fprintf (file, ")");
2447 break;
2452 /* Splitting of some instructions. */
2454 static rtx
2455 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2457 rtx ret = 0;
2459 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2460 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2461 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2462 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2464 return ret;
2468 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2469 rtx label)
2471 rtx tmp;
2473 switch (GET_MODE (op0))
2475 case QImode:
2476 case HImode:
2477 tmp = m68hc11_expand_compare (code, op0, op1);
2478 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2479 gen_rtx_LABEL_REF (VOIDmode, label),
2480 pc_rtx);
2481 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2482 return 0;
2483 #if 0
2485 /* SCz: from i386.c */
2486 case SFmode:
2487 case DFmode:
2488 /* Don't expand the comparison early, so that we get better code
2489 when jump or whoever decides to reverse the comparison. */
2491 rtvec vec;
2492 int use_fcomi;
2494 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2495 &m68hc11_compare_op1);
2497 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2498 m68hc11_compare_op0, m68hc11_compare_op1);
2499 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2500 gen_rtx_LABEL_REF (VOIDmode, label),
2501 pc_rtx);
2502 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2504 use_fcomi = ix86_use_fcomi_compare (code);
2505 vec = rtvec_alloc (3 + !use_fcomi);
2506 RTVEC_ELT (vec, 0) = tmp;
2507 RTVEC_ELT (vec, 1)
2508 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2509 RTVEC_ELT (vec, 2)
2510 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2511 if (!use_fcomi)
2512 RTVEC_ELT (vec, 3)
2513 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2515 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2516 return;
2518 #endif
2520 case SImode:
2521 /* Expand SImode branch into multiple compare+branch. */
2523 rtx lo[2], hi[2], label2;
2524 enum rtx_code code1, code2, code3;
2526 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2528 tmp = op0;
2529 op0 = op1;
2530 op1 = tmp;
2531 code = swap_condition (code);
2533 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2534 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2535 hi[0] = m68hc11_gen_highpart (HImode, op0);
2536 hi[1] = m68hc11_gen_highpart (HImode, op1);
2538 /* Otherwise, if we are doing less-than, op1 is a constant and the
2539 low word is zero, then we can just examine the high word. */
2541 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2542 && (code == LT || code == LTU))
2544 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2545 label);
2548 /* Otherwise, we need two or three jumps. */
2550 label2 = gen_label_rtx ();
2552 code1 = code;
2553 code2 = swap_condition (code);
2554 code3 = unsigned_condition (code);
2556 switch (code)
2558 case LT:
2559 case GT:
2560 case LTU:
2561 case GTU:
2562 break;
2564 case LE:
2565 code1 = LT;
2566 code2 = GT;
2567 break;
2568 case GE:
2569 code1 = GT;
2570 code2 = LT;
2571 break;
2572 case LEU:
2573 code1 = LTU;
2574 code2 = GTU;
2575 break;
2576 case GEU:
2577 code1 = GTU;
2578 code2 = LTU;
2579 break;
2581 case EQ:
2582 code1 = UNKNOWN;
2583 code2 = NE;
2584 break;
2585 case NE:
2586 code2 = UNKNOWN;
2587 break;
2589 default:
2590 gcc_unreachable ();
2594 * a < b =>
2595 * if (hi(a) < hi(b)) goto true;
2596 * if (hi(a) > hi(b)) goto false;
2597 * if (lo(a) < lo(b)) goto true;
2598 * false:
2600 if (code1 != UNKNOWN)
2601 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2602 if (code2 != UNKNOWN)
2603 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2605 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2607 if (code2 != UNKNOWN)
2608 emit_label (label2);
2609 return 0;
2612 default:
2613 gcc_unreachable ();
2615 return 0;
2618 /* Return the increment/decrement mode of a MEM if it is such.
2619 Return CONST if it is anything else. */
2620 static int
2621 autoinc_mode (rtx x)
2623 if (GET_CODE (x) != MEM)
2624 return CONST;
2626 x = XEXP (x, 0);
2627 if (GET_CODE (x) == PRE_INC
2628 || GET_CODE (x) == PRE_DEC
2629 || GET_CODE (x) == POST_INC
2630 || GET_CODE (x) == POST_DEC)
2631 return GET_CODE (x);
2633 return CONST;
2636 static int
2637 m68hc11_make_autoinc_notes (rtx *x, void *data)
2639 rtx insn;
2641 switch (GET_CODE (*x))
2643 case PRE_DEC:
2644 case PRE_INC:
2645 case POST_DEC:
2646 case POST_INC:
2647 insn = (rtx) data;
2648 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2649 REG_NOTES (insn));
2650 return -1;
2652 default:
2653 return 0;
2657 /* Split a DI, SI or HI move into several smaller move operations.
2658 The scratch register 'scratch' is used as a temporary to load
2659 store intermediate values. It must be a hard register. */
2660 void
2661 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2663 rtx low_to, low_from;
2664 rtx high_to, high_from;
2665 rtx insn;
2666 enum machine_mode mode;
2667 int offset = 0;
2668 int autoinc_from = autoinc_mode (from);
2669 int autoinc_to = autoinc_mode (to);
2671 mode = GET_MODE (to);
2673 /* If the TO and FROM contain autoinc modes that are not compatible
2674 together (one pop and the other a push), we must change one to
2675 an offsetable operand and generate an appropriate add at the end. */
2676 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2678 rtx reg;
2679 int code;
2681 /* The source uses an autoinc mode which is not compatible with
2682 a split (this would result in a word swap). */
2683 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2685 code = GET_CODE (XEXP (from, 0));
2686 reg = XEXP (XEXP (from, 0), 0);
2687 offset = GET_MODE_SIZE (GET_MODE (from));
2688 if (code == POST_DEC)
2689 offset = -offset;
2691 if (code == PRE_INC)
2692 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2694 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2695 if (code == POST_DEC)
2696 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2697 return;
2700 /* Likewise for destination. */
2701 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2703 code = GET_CODE (XEXP (to, 0));
2704 reg = XEXP (XEXP (to, 0), 0);
2705 offset = GET_MODE_SIZE (GET_MODE (to));
2706 if (code == POST_DEC)
2707 offset = -offset;
2709 if (code == PRE_INC)
2710 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2712 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2713 if (code == POST_DEC)
2714 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2715 return;
2718 /* The source and destination auto increment modes must be compatible
2719 with each other: same direction. */
2720 if ((autoinc_to != autoinc_from
2721 && autoinc_to != CONST && autoinc_from != CONST)
2722 /* The destination address register must not be used within
2723 the source operand because the source address would change
2724 while doing the copy. */
2725 || (autoinc_to != CONST
2726 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2727 && !IS_STACK_PUSH (to)))
2729 /* Must change the destination. */
2730 code = GET_CODE (XEXP (to, 0));
2731 reg = XEXP (XEXP (to, 0), 0);
2732 offset = GET_MODE_SIZE (GET_MODE (to));
2733 if (code == PRE_DEC || code == POST_DEC)
2734 offset = -offset;
2736 if (code == PRE_DEC || code == PRE_INC)
2737 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2738 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2739 if (code == POST_DEC || code == POST_INC)
2740 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2742 return;
2745 /* Likewise, the source address register must not be used within
2746 the destination operand. */
2747 if (autoinc_from != CONST
2748 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2749 && !IS_STACK_PUSH (to))
2751 /* Must change the source. */
2752 code = GET_CODE (XEXP (from, 0));
2753 reg = XEXP (XEXP (from, 0), 0);
2754 offset = GET_MODE_SIZE (GET_MODE (from));
2755 if (code == PRE_DEC || code == POST_DEC)
2756 offset = -offset;
2758 if (code == PRE_DEC || code == PRE_INC)
2759 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2760 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2761 if (code == POST_DEC || code == POST_INC)
2762 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2764 return;
2768 if (GET_MODE_SIZE (mode) == 8)
2769 mode = SImode;
2770 else if (GET_MODE_SIZE (mode) == 4)
2771 mode = HImode;
2772 else
2773 mode = QImode;
2775 if (TARGET_M6812
2776 && IS_STACK_PUSH (to)
2777 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2779 if (mode == SImode)
2781 offset = 4;
2783 else if (mode == HImode)
2785 offset = 2;
2787 else
2788 offset = 0;
2791 low_to = m68hc11_gen_lowpart (mode, to);
2792 high_to = m68hc11_gen_highpart (mode, to);
2794 low_from = m68hc11_gen_lowpart (mode, from);
2795 high_from = m68hc11_gen_highpart (mode, from);
2797 if (offset)
2799 high_from = adjust_address (high_from, mode, offset);
2800 low_from = high_from;
2803 /* When copying with a POST_INC mode, we must copy the
2804 high part and then the low part to guarantee a correct
2805 32/64-bit copy. */
2806 if (TARGET_M6812
2807 && GET_MODE_SIZE (mode) >= 2
2808 && autoinc_from != autoinc_to
2809 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2811 rtx swap;
2813 swap = low_to;
2814 low_to = high_to;
2815 high_to = swap;
2817 swap = low_from;
2818 low_from = high_from;
2819 high_from = swap;
2821 if (mode == SImode)
2823 m68hc11_split_move (low_to, low_from, scratch);
2824 m68hc11_split_move (high_to, high_from, scratch);
2826 else if (H_REG_P (to) || H_REG_P (from)
2827 || (low_from == const0_rtx
2828 && high_from == const0_rtx
2829 && ! push_operand (to, GET_MODE (to))
2830 && ! H_REG_P (scratch))
2831 || (TARGET_M6812
2832 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2833 || m68hc11_small_indexed_indirect_p (from,
2834 GET_MODE (from)))
2835 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2836 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2838 insn = emit_move_insn (low_to, low_from);
2839 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2841 insn = emit_move_insn (high_to, high_from);
2842 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2844 else
2846 insn = emit_move_insn (scratch, low_from);
2847 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2848 insn = emit_move_insn (low_to, scratch);
2849 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2851 insn = emit_move_insn (scratch, high_from);
2852 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2853 insn = emit_move_insn (high_to, scratch);
2854 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2858 static rtx
2859 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2861 int val;
2862 int mask;
2864 *result = 0;
2865 if (GET_CODE (operand) != CONST_INT)
2866 return operand;
2868 if (mode == HImode)
2869 mask = 0x0ffff;
2870 else
2871 mask = 0x0ff;
2873 val = INTVAL (operand);
2874 switch (code)
2876 case IOR:
2877 if ((val & mask) == 0)
2878 return 0;
2879 if ((val & mask) == mask)
2880 *result = constm1_rtx;
2881 break;
2883 case AND:
2884 if ((val & mask) == 0)
2885 *result = const0_rtx;
2886 if ((val & mask) == mask)
2887 return 0;
2888 break;
2890 case XOR:
2891 if ((val & mask) == 0)
2892 return 0;
2893 break;
2895 return operand;
2898 static void
2899 m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
2901 rtx result;
2902 int need_copy;
2904 need_copy = (rtx_equal_p (operands[0], operands[1])
2905 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2907 operands[1] = simplify_logical (mode, code, operands[1], &result);
2908 operands[2] = simplify_logical (mode, code, operands[2], &result);
2910 if (result && GET_CODE (result) == CONST_INT)
2912 if (!H_REG_P (operands[0]) && operands[3]
2913 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2915 emit_move_insn (operands[3], result);
2916 emit_move_insn (operands[0], operands[3]);
2918 else
2920 emit_move_insn (operands[0], result);
2923 else if (operands[1] != 0 && operands[2] != 0)
2925 rtx insn;
2927 if (!H_REG_P (operands[0]) && operands[3])
2929 emit_move_insn (operands[3], operands[1]);
2930 emit_insn (gen_rtx_SET (mode,
2931 operands[3],
2932 gen_rtx_fmt_ee (code, mode,
2933 operands[3], operands[2])));
2934 insn = emit_move_insn (operands[0], operands[3]);
2936 else
2938 insn = emit_insn (gen_rtx_SET (mode,
2939 operands[0],
2940 gen_rtx_fmt_ee (code, mode,
2941 operands[0],
2942 operands[2])));
2946 /* The logical operation is similar to a copy. */
2947 else if (need_copy)
2949 rtx src;
2951 if (GET_CODE (operands[1]) == CONST_INT)
2952 src = operands[2];
2953 else
2954 src = operands[1];
2956 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2958 emit_move_insn (operands[3], src);
2959 emit_move_insn (operands[0], operands[3]);
2961 else
2963 emit_move_insn (operands[0], src);
2968 void
2969 m68hc11_split_logical (enum machine_mode mode, enum rtx_code code,
2970 rtx *operands)
2972 rtx low[4];
2973 rtx high[4];
2975 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2976 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2977 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2979 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2980 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2981 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2983 low[3] = operands[3];
2984 high[3] = operands[3];
2985 if (mode == SImode)
2987 m68hc11_split_logical (HImode, code, low);
2988 m68hc11_split_logical (HImode, code, high);
2989 return;
2992 m68hc11_emit_logical (mode, code, low);
2993 m68hc11_emit_logical (mode, code, high);
2997 /* Code generation. */
2999 void
3000 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3002 /* We have to be careful with the cc_status. An address register swap
3003 is generated for some comparison. The comparison is made with D
3004 but the branch really uses the address register. See the split
3005 pattern for compare. The xgdx/xgdy preserve the flags but after
3006 the exchange, the flags will reflect to the value of X and not D.
3007 Tell this by setting the cc_status according to the cc_prev_status. */
3008 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3010 if (cc_prev_status.value1 != 0
3011 && (D_REG_P (cc_prev_status.value1)
3012 || X_REG_P (cc_prev_status.value1)))
3014 cc_status = cc_prev_status;
3015 if (D_REG_P (cc_status.value1))
3016 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3017 HARD_X_REGNUM);
3018 else
3019 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3020 HARD_D_REGNUM);
3022 else
3023 CC_STATUS_INIT;
3025 output_asm_insn ("xgdx", operands);
3027 else
3029 if (cc_prev_status.value1 != 0
3030 && (D_REG_P (cc_prev_status.value1)
3031 || Y_REG_P (cc_prev_status.value1)))
3033 cc_status = cc_prev_status;
3034 if (D_REG_P (cc_status.value1))
3035 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3036 HARD_Y_REGNUM);
3037 else
3038 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3039 HARD_D_REGNUM);
3041 else
3042 CC_STATUS_INIT;
3044 output_asm_insn ("xgdy", operands);
3048 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3049 This is used to decide whether a move that set flags should be used
3050 instead. */
3052 next_insn_test_reg (rtx insn, rtx reg)
3054 rtx body;
3056 insn = next_nonnote_insn (insn);
3057 if (GET_CODE (insn) != INSN)
3058 return 0;
3060 body = PATTERN (insn);
3061 if (sets_cc0_p (body) != 1)
3062 return 0;
3064 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3065 return 0;
3067 return 1;
3070 /* Generate the code to move a 16-bit operand into another one. */
3072 void
3073 m68hc11_gen_movhi (rtx insn, rtx *operands)
3075 int reg;
3077 /* Move a register or memory to the same location.
3078 This is possible because such insn can appear
3079 in a non-optimizing mode. */
3080 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3082 cc_status = cc_prev_status;
3083 return;
3086 if (TARGET_M6812)
3088 rtx from = operands[1];
3089 rtx to = operands[0];
3091 if (IS_STACK_PUSH (to) && H_REG_P (from))
3093 cc_status = cc_prev_status;
3094 switch (REGNO (from))
3096 case HARD_X_REGNUM:
3097 case HARD_Y_REGNUM:
3098 case HARD_D_REGNUM:
3099 output_asm_insn ("psh%1", operands);
3100 break;
3101 case HARD_SP_REGNUM:
3102 output_asm_insn ("sts\t2,-sp", operands);
3103 break;
3104 default:
3105 gcc_unreachable ();
3107 return;
3109 if (IS_STACK_POP (from) && H_REG_P (to))
3111 cc_status = cc_prev_status;
3112 switch (REGNO (to))
3114 case HARD_X_REGNUM:
3115 case HARD_Y_REGNUM:
3116 case HARD_D_REGNUM:
3117 output_asm_insn ("pul%0", operands);
3118 break;
3119 default:
3120 gcc_unreachable ();
3122 return;
3124 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3126 m68hc11_notice_keep_cc (operands[0]);
3127 output_asm_insn ("tfr\t%1,%0", operands);
3129 else if (H_REG_P (operands[0]))
3131 if (SP_REG_P (operands[0]))
3132 output_asm_insn ("lds\t%1", operands);
3133 else
3134 output_asm_insn ("ld%0\t%1", operands);
3136 else if (H_REG_P (operands[1]))
3138 if (SP_REG_P (operands[1]))
3139 output_asm_insn ("sts\t%0", operands);
3140 else
3141 output_asm_insn ("st%1\t%0", operands);
3144 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3145 instruction. We have to use a scratch register as temporary location.
3146 Trying to use a specific pattern or constrain failed. */
3147 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3149 rtx ops[4];
3151 ops[0] = to;
3152 ops[2] = from;
3153 ops[3] = 0;
3154 if (dead_register_here (insn, d_reg))
3155 ops[1] = d_reg;
3156 else if (dead_register_here (insn, ix_reg))
3157 ops[1] = ix_reg;
3158 else if (dead_register_here (insn, iy_reg))
3159 ops[1] = iy_reg;
3160 else
3162 ops[1] = d_reg;
3163 ops[3] = d_reg;
3164 output_asm_insn ("psh%3", ops);
3167 ops[0] = to;
3168 ops[2] = from;
3169 output_asm_insn ("ld%1\t%2", ops);
3170 output_asm_insn ("st%1\t%0", ops);
3171 if (ops[3])
3172 output_asm_insn ("pul%3", ops);
3175 /* Use movw for non-null constants or when we are clearing
3176 a volatile memory reference. However, this is possible
3177 only if the memory reference has a small offset or is an
3178 absolute address. */
3179 else if (GET_CODE (from) == CONST_INT
3180 && INTVAL (from) == 0
3181 && (MEM_VOLATILE_P (to) == 0
3182 || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3184 output_asm_insn ("clr\t%h0", operands);
3185 output_asm_insn ("clr\t%b0", operands);
3187 else
3189 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3190 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3191 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3192 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3194 rtx ops[3];
3196 if (operands[2])
3198 ops[0] = operands[2];
3199 ops[1] = from;
3200 ops[2] = 0;
3201 m68hc11_gen_movhi (insn, ops);
3202 ops[0] = to;
3203 ops[1] = operands[2];
3204 m68hc11_gen_movhi (insn, ops);
3205 return;
3207 else
3209 /* !!!! SCz wrong here. */
3210 fatal_insn ("move insn not handled", insn);
3213 else
3215 m68hc11_notice_keep_cc (operands[0]);
3216 output_asm_insn ("movw\t%1,%0", operands);
3219 return;
3222 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3224 cc_status = cc_prev_status;
3225 switch (REGNO (operands[0]))
3227 case HARD_X_REGNUM:
3228 case HARD_Y_REGNUM:
3229 output_asm_insn ("pul%0", operands);
3230 break;
3231 case HARD_D_REGNUM:
3232 output_asm_insn ("pula", operands);
3233 output_asm_insn ("pulb", operands);
3234 break;
3235 default:
3236 gcc_unreachable ();
3238 return;
3240 /* Some moves to a hard register are special. Not all of them
3241 are really supported and we have to use a temporary
3242 location to provide them (either the stack of a temp var). */
3243 if (H_REG_P (operands[0]))
3245 switch (REGNO (operands[0]))
3247 case HARD_D_REGNUM:
3248 if (X_REG_P (operands[1]))
3250 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3252 m68hc11_output_swap (insn, operands);
3254 else if (next_insn_test_reg (insn, operands[0]))
3256 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3258 else
3260 m68hc11_notice_keep_cc (operands[0]);
3261 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3264 else if (Y_REG_P (operands[1]))
3266 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3268 m68hc11_output_swap (insn, operands);
3270 else
3272 /* %t means *ZTMP scratch register. */
3273 output_asm_insn ("sty\t%t1", operands);
3274 output_asm_insn ("ldd\t%t1", operands);
3277 else if (SP_REG_P (operands[1]))
3279 CC_STATUS_INIT;
3280 if (ix_reg == 0)
3281 create_regs_rtx ();
3282 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3283 output_asm_insn ("xgdx", operands);
3284 output_asm_insn ("tsx", operands);
3285 output_asm_insn ("xgdx", operands);
3287 else if (IS_STACK_POP (operands[1]))
3289 output_asm_insn ("pula\n\tpulb", operands);
3291 else if (GET_CODE (operands[1]) == CONST_INT
3292 && INTVAL (operands[1]) == 0)
3294 output_asm_insn ("clra\n\tclrb", operands);
3296 else
3298 output_asm_insn ("ldd\t%1", operands);
3300 break;
3302 case HARD_X_REGNUM:
3303 if (D_REG_P (operands[1]))
3305 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3307 m68hc11_output_swap (insn, operands);
3309 else if (next_insn_test_reg (insn, operands[0]))
3311 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3313 else
3315 m68hc11_notice_keep_cc (operands[0]);
3316 output_asm_insn ("pshb", operands);
3317 output_asm_insn ("psha", operands);
3318 output_asm_insn ("pulx", operands);
3321 else if (Y_REG_P (operands[1]))
3323 /* When both D and Y are dead, use the sequence xgdy, xgdx
3324 to move Y into X. The D and Y registers are modified. */
3325 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3326 && dead_register_here (insn, d_reg))
3328 output_asm_insn ("xgdy", operands);
3329 output_asm_insn ("xgdx", operands);
3330 CC_STATUS_INIT;
3332 else if (!optimize_size)
3334 output_asm_insn ("sty\t%t1", operands);
3335 output_asm_insn ("ldx\t%t1", operands);
3337 else
3339 CC_STATUS_INIT;
3340 output_asm_insn ("pshy", operands);
3341 output_asm_insn ("pulx", operands);
3344 else if (SP_REG_P (operands[1]))
3346 /* tsx, tsy preserve the flags */
3347 cc_status = cc_prev_status;
3348 output_asm_insn ("tsx", operands);
3350 else
3352 output_asm_insn ("ldx\t%1", operands);
3354 break;
3356 case HARD_Y_REGNUM:
3357 if (D_REG_P (operands[1]))
3359 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3361 m68hc11_output_swap (insn, operands);
3363 else
3365 output_asm_insn ("std\t%t1", operands);
3366 output_asm_insn ("ldy\t%t1", operands);
3369 else if (X_REG_P (operands[1]))
3371 /* When both D and X are dead, use the sequence xgdx, xgdy
3372 to move X into Y. The D and X registers are modified. */
3373 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3374 && dead_register_here (insn, d_reg))
3376 output_asm_insn ("xgdx", operands);
3377 output_asm_insn ("xgdy", operands);
3378 CC_STATUS_INIT;
3380 else if (!optimize_size)
3382 output_asm_insn ("stx\t%t1", operands);
3383 output_asm_insn ("ldy\t%t1", operands);
3385 else
3387 CC_STATUS_INIT;
3388 output_asm_insn ("pshx", operands);
3389 output_asm_insn ("puly", operands);
3392 else if (SP_REG_P (operands[1]))
3394 /* tsx, tsy preserve the flags */
3395 cc_status = cc_prev_status;
3396 output_asm_insn ("tsy", operands);
3398 else
3400 output_asm_insn ("ldy\t%1", operands);
3402 break;
3404 case HARD_SP_REGNUM:
3405 if (D_REG_P (operands[1]))
3407 m68hc11_notice_keep_cc (operands[0]);
3408 output_asm_insn ("xgdx", operands);
3409 output_asm_insn ("txs", operands);
3410 output_asm_insn ("xgdx", operands);
3412 else if (X_REG_P (operands[1]))
3414 /* tys, txs preserve the flags */
3415 cc_status = cc_prev_status;
3416 output_asm_insn ("txs", operands);
3418 else if (Y_REG_P (operands[1]))
3420 /* tys, txs preserve the flags */
3421 cc_status = cc_prev_status;
3422 output_asm_insn ("tys", operands);
3424 else
3426 /* lds sets the flags but the des does not. */
3427 CC_STATUS_INIT;
3428 output_asm_insn ("lds\t%1", operands);
3429 output_asm_insn ("des", operands);
3431 break;
3433 default:
3434 fatal_insn ("invalid register in the move instruction", insn);
3435 break;
3437 return;
3439 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3440 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3442 output_asm_insn ("sts\t%0", operands);
3443 return;
3446 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3448 cc_status = cc_prev_status;
3449 switch (REGNO (operands[1]))
3451 case HARD_X_REGNUM:
3452 case HARD_Y_REGNUM:
3453 output_asm_insn ("psh%1", operands);
3454 break;
3455 case HARD_D_REGNUM:
3456 output_asm_insn ("pshb", operands);
3457 output_asm_insn ("psha", operands);
3458 break;
3459 default:
3460 gcc_unreachable ();
3462 return;
3465 /* Operand 1 must be a hard register. */
3466 if (!H_REG_P (operands[1]))
3468 fatal_insn ("invalid operand in the instruction", insn);
3471 reg = REGNO (operands[1]);
3472 switch (reg)
3474 case HARD_D_REGNUM:
3475 output_asm_insn ("std\t%0", operands);
3476 break;
3478 case HARD_X_REGNUM:
3479 output_asm_insn ("stx\t%0", operands);
3480 break;
3482 case HARD_Y_REGNUM:
3483 output_asm_insn ("sty\t%0", operands);
3484 break;
3486 case HARD_SP_REGNUM:
3487 if (ix_reg == 0)
3488 create_regs_rtx ();
3490 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3492 output_asm_insn ("pshx", operands);
3493 output_asm_insn ("tsx", operands);
3494 output_asm_insn ("inx", operands);
3495 output_asm_insn ("inx", operands);
3496 output_asm_insn ("stx\t%0", operands);
3497 output_asm_insn ("pulx", operands);
3500 else if (reg_mentioned_p (ix_reg, operands[0]))
3502 output_asm_insn ("sty\t%t0", operands);
3503 output_asm_insn ("tsy", operands);
3504 output_asm_insn ("sty\t%0", operands);
3505 output_asm_insn ("ldy\t%t0", operands);
3507 else
3509 output_asm_insn ("stx\t%t0", operands);
3510 output_asm_insn ("tsx", operands);
3511 output_asm_insn ("stx\t%0", operands);
3512 output_asm_insn ("ldx\t%t0", operands);
3514 CC_STATUS_INIT;
3515 break;
3517 default:
3518 fatal_insn ("invalid register in the move instruction", insn);
3519 break;
3523 void
3524 m68hc11_gen_movqi (rtx insn, rtx *operands)
3526 /* Move a register or memory to the same location.
3527 This is possible because such insn can appear
3528 in a non-optimizing mode. */
3529 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3531 cc_status = cc_prev_status;
3532 return;
3535 if (TARGET_M6812)
3538 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3540 m68hc11_notice_keep_cc (operands[0]);
3541 output_asm_insn ("tfr\t%1,%0", operands);
3543 else if (H_REG_P (operands[0]))
3545 if (IS_STACK_POP (operands[1]))
3546 output_asm_insn ("pul%b0", operands);
3547 else if (Q_REG_P (operands[0]))
3548 output_asm_insn ("lda%0\t%b1", operands);
3549 else if (D_REG_P (operands[0]))
3550 output_asm_insn ("ldab\t%b1", operands);
3551 else
3552 goto m6811_move;
3554 else if (H_REG_P (operands[1]))
3556 if (Q_REG_P (operands[1]))
3557 output_asm_insn ("sta%1\t%b0", operands);
3558 else if (D_REG_P (operands[1]))
3559 output_asm_insn ("stab\t%b0", operands);
3560 else
3561 goto m6811_move;
3563 else
3565 rtx from = operands[1];
3566 rtx to = operands[0];
3568 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3569 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3570 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3571 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3573 rtx ops[3];
3575 if (operands[2])
3577 ops[0] = operands[2];
3578 ops[1] = from;
3579 ops[2] = 0;
3580 m68hc11_gen_movqi (insn, ops);
3581 ops[0] = to;
3582 ops[1] = operands[2];
3583 m68hc11_gen_movqi (insn, ops);
3585 else
3587 /* !!!! SCz wrong here. */
3588 fatal_insn ("move insn not handled", insn);
3591 else
3593 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3595 output_asm_insn ("clr\t%b0", operands);
3597 else
3599 m68hc11_notice_keep_cc (operands[0]);
3600 output_asm_insn ("movb\t%b1,%b0", operands);
3604 return;
3607 m6811_move:
3608 if (H_REG_P (operands[0]))
3610 switch (REGNO (operands[0]))
3612 case HARD_B_REGNUM:
3613 case HARD_D_REGNUM:
3614 if (X_REG_P (operands[1]))
3616 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3618 m68hc11_output_swap (insn, operands);
3620 else
3622 output_asm_insn ("stx\t%t1", operands);
3623 output_asm_insn ("ldab\t%T0", operands);
3626 else if (Y_REG_P (operands[1]))
3628 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3630 m68hc11_output_swap (insn, operands);
3632 else
3634 output_asm_insn ("sty\t%t1", operands);
3635 output_asm_insn ("ldab\t%T0", operands);
3638 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3639 && !DA_REG_P (operands[1]))
3641 output_asm_insn ("ldab\t%b1", operands);
3643 else if (DA_REG_P (operands[1]))
3645 output_asm_insn ("tab", operands);
3647 else
3649 cc_status = cc_prev_status;
3650 return;
3652 break;
3654 case HARD_A_REGNUM:
3655 if (X_REG_P (operands[1]))
3657 output_asm_insn ("stx\t%t1", operands);
3658 output_asm_insn ("ldaa\t%T0", operands);
3660 else if (Y_REG_P (operands[1]))
3662 output_asm_insn ("sty\t%t1", operands);
3663 output_asm_insn ("ldaa\t%T0", operands);
3665 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3666 && !DA_REG_P (operands[1]))
3668 output_asm_insn ("ldaa\t%b1", operands);
3670 else if (!DA_REG_P (operands[1]))
3672 output_asm_insn ("tba", operands);
3674 else
3676 cc_status = cc_prev_status;
3678 break;
3680 case HARD_X_REGNUM:
3681 if (D_REG_P (operands[1]))
3683 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3685 m68hc11_output_swap (insn, operands);
3687 else
3689 output_asm_insn ("stab\t%T1", operands);
3690 output_asm_insn ("ldx\t%t1", operands);
3692 CC_STATUS_INIT;
3694 else if (Y_REG_P (operands[1]))
3696 output_asm_insn ("sty\t%t0", operands);
3697 output_asm_insn ("ldx\t%t0", operands);
3699 else if (GET_CODE (operands[1]) == CONST_INT)
3701 output_asm_insn ("ldx\t%1", operands);
3703 else if (dead_register_here (insn, d_reg))
3705 output_asm_insn ("ldab\t%b1", operands);
3706 output_asm_insn ("xgdx", operands);
3708 else if (!reg_mentioned_p (operands[0], operands[1]))
3710 output_asm_insn ("xgdx", operands);
3711 output_asm_insn ("ldab\t%b1", operands);
3712 output_asm_insn ("xgdx", operands);
3714 else
3716 output_asm_insn ("pshb", operands);
3717 output_asm_insn ("ldab\t%b1", operands);
3718 output_asm_insn ("stab\t%T1", operands);
3719 output_asm_insn ("ldx\t%t1", operands);
3720 output_asm_insn ("pulb", operands);
3721 CC_STATUS_INIT;
3723 break;
3725 case HARD_Y_REGNUM:
3726 if (D_REG_P (operands[1]))
3728 output_asm_insn ("stab\t%T1", operands);
3729 output_asm_insn ("ldy\t%t1", operands);
3730 CC_STATUS_INIT;
3732 else if (X_REG_P (operands[1]))
3734 output_asm_insn ("stx\t%t1", operands);
3735 output_asm_insn ("ldy\t%t1", operands);
3736 CC_STATUS_INIT;
3738 else if (GET_CODE (operands[1]) == CONST_INT)
3740 output_asm_insn ("ldy\t%1", operands);
3742 else if (dead_register_here (insn, d_reg))
3744 output_asm_insn ("ldab\t%b1", operands);
3745 output_asm_insn ("xgdy", operands);
3747 else if (!reg_mentioned_p (operands[0], operands[1]))
3749 output_asm_insn ("xgdy", operands);
3750 output_asm_insn ("ldab\t%b1", operands);
3751 output_asm_insn ("xgdy", operands);
3753 else
3755 output_asm_insn ("pshb", operands);
3756 output_asm_insn ("ldab\t%b1", operands);
3757 output_asm_insn ("stab\t%T1", operands);
3758 output_asm_insn ("ldy\t%t1", operands);
3759 output_asm_insn ("pulb", operands);
3760 CC_STATUS_INIT;
3762 break;
3764 default:
3765 fatal_insn ("invalid register in the instruction", insn);
3766 break;
3769 else if (H_REG_P (operands[1]))
3771 switch (REGNO (operands[1]))
3773 case HARD_D_REGNUM:
3774 case HARD_B_REGNUM:
3775 output_asm_insn ("stab\t%b0", operands);
3776 break;
3778 case HARD_A_REGNUM:
3779 output_asm_insn ("staa\t%b0", operands);
3780 break;
3782 case HARD_X_REGNUM:
3783 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3784 break;
3786 case HARD_Y_REGNUM:
3787 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3788 break;
3790 default:
3791 fatal_insn ("invalid register in the move instruction", insn);
3792 break;
3794 return;
3796 else
3798 fatal_insn ("operand 1 must be a hard register", insn);
3802 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3803 The source and destination must be D or A and the shift must
3804 be a constant. */
3805 void
3806 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3808 int val;
3810 if (GET_CODE (operands[2]) != CONST_INT
3811 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3812 fatal_insn ("invalid rotate insn", insn);
3814 val = INTVAL (operands[2]);
3815 if (code == ROTATERT)
3816 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3818 if (GET_MODE (operands[0]) != QImode)
3819 CC_STATUS_INIT;
3821 /* Rotate by 8-bits if the shift is within [5..11]. */
3822 if (val >= 5 && val <= 11)
3824 if (TARGET_M6812)
3825 output_asm_insn ("exg\ta,b", operands);
3826 else
3828 output_asm_insn ("psha", operands);
3829 output_asm_insn ("tba", operands);
3830 output_asm_insn ("pulb", operands);
3832 val -= 8;
3835 /* If the shift is big, invert the rotation. */
3836 else if (val >= 12)
3838 val = val - 16;
3841 if (val > 0)
3843 while (--val >= 0)
3845 /* Set the carry to bit-15, but don't change D yet. */
3846 if (GET_MODE (operands[0]) != QImode)
3848 output_asm_insn ("asra", operands);
3849 output_asm_insn ("rola", operands);
3852 /* Rotate B first to move the carry to bit-0. */
3853 if (D_REG_P (operands[0]))
3854 output_asm_insn ("rolb", operands);
3856 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3857 output_asm_insn ("rola", operands);
3860 else
3862 while (++val <= 0)
3864 /* Set the carry to bit-8 of D. */
3865 if (GET_MODE (operands[0]) != QImode)
3866 output_asm_insn ("tap", operands);
3868 /* Rotate B first to move the carry to bit-7. */
3869 if (D_REG_P (operands[0]))
3870 output_asm_insn ("rorb", operands);
3872 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3873 output_asm_insn ("rora", operands);
3880 /* Store in cc_status the expressions that the condition codes will
3881 describe after execution of an instruction whose pattern is EXP.
3882 Do not alter them if the instruction would not alter the cc's. */
3884 void
3885 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3887 /* recognize SET insn's. */
3888 if (GET_CODE (exp) == SET)
3890 /* Jumps do not alter the cc's. */
3891 if (SET_DEST (exp) == pc_rtx)
3894 /* NOTE: most instructions don't affect the carry bit, but the
3895 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3896 the conditions.h header. */
3898 /* Function calls clobber the cc's. */
3899 else if (GET_CODE (SET_SRC (exp)) == CALL)
3901 CC_STATUS_INIT;
3904 /* Tests and compares set the cc's in predictable ways. */
3905 else if (SET_DEST (exp) == cc0_rtx)
3907 cc_status.flags = 0;
3908 cc_status.value1 = XEXP (exp, 0);
3909 if (GET_CODE (XEXP (exp, 1)) == COMPARE
3910 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
3911 cc_status.value2 = XEXP (XEXP (exp, 1), 0);
3912 else
3913 cc_status.value2 = XEXP (exp, 1);
3915 else
3917 /* All other instructions affect the condition codes. */
3918 cc_status.flags = 0;
3919 cc_status.value1 = XEXP (exp, 0);
3920 cc_status.value2 = XEXP (exp, 1);
3923 else
3925 /* Default action if we haven't recognized something
3926 and returned earlier. */
3927 CC_STATUS_INIT;
3930 if (cc_status.value2 != 0)
3931 switch (GET_CODE (cc_status.value2))
3933 /* These logical operations can generate several insns.
3934 The flags are setup according to what is generated. */
3935 case IOR:
3936 case XOR:
3937 case AND:
3938 break;
3940 /* The (not ...) generates several 'com' instructions for
3941 non QImode. We have to invalidate the flags. */
3942 case NOT:
3943 if (GET_MODE (cc_status.value2) != QImode)
3944 CC_STATUS_INIT;
3945 break;
3947 case PLUS:
3948 case MINUS:
3949 case MULT:
3950 case DIV:
3951 case UDIV:
3952 case MOD:
3953 case UMOD:
3954 case NEG:
3955 if (GET_MODE (cc_status.value2) != VOIDmode)
3956 cc_status.flags |= CC_NO_OVERFLOW;
3957 break;
3959 /* The asl sets the overflow bit in such a way that this
3960 makes the flags unusable for a next compare insn. */
3961 case ASHIFT:
3962 case ROTATE:
3963 case ROTATERT:
3964 if (GET_MODE (cc_status.value2) != VOIDmode)
3965 cc_status.flags |= CC_NO_OVERFLOW;
3966 break;
3968 /* A load/store instruction does not affect the carry. */
3969 case MEM:
3970 case SYMBOL_REF:
3971 case REG:
3972 case CONST_INT:
3973 cc_status.flags |= CC_NO_OVERFLOW;
3974 break;
3976 default:
3977 break;
3979 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3980 && cc_status.value2
3981 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3982 cc_status.value2 = 0;
3984 else if (cc_status.value1 && side_effects_p (cc_status.value1))
3985 cc_status.value1 = 0;
3987 else if (cc_status.value2 && side_effects_p (cc_status.value2))
3988 cc_status.value2 = 0;
3991 /* The current instruction does not affect the flags but changes
3992 the register 'reg'. See if the previous flags can be kept for the
3993 next instruction to avoid a comparison. */
3994 void
3995 m68hc11_notice_keep_cc (rtx reg)
3997 if (reg == 0
3998 || cc_prev_status.value1 == 0
3999 || rtx_equal_p (reg, cc_prev_status.value1)
4000 || (cc_prev_status.value2
4001 && reg_mentioned_p (reg, cc_prev_status.value2)))
4002 CC_STATUS_INIT;
4003 else
4004 cc_status = cc_prev_status;
4009 /* Machine Specific Reorg. */
4011 /* Z register replacement:
4013 GCC treats the Z register as an index base address register like
4014 X or Y. In general, it uses it during reload to compute the address
4015 of some operand. This helps the reload pass to avoid to fall into the
4016 register spill failure.
4018 The Z register is in the A_REGS class. In the machine description,
4019 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4021 It can appear everywhere an X or Y register can appear, except for
4022 some templates in the clobber section (when a clobber of X or Y is asked).
4023 For a given instruction, the template must ensure that no more than
4024 2 'A' registers are used. Otherwise, the register replacement is not
4025 possible.
4027 To replace the Z register, the algorithm is not terrific:
4028 1. Insns that do not use the Z register are not changed
4029 2. When a Z register is used, we scan forward the insns to see
4030 a potential register to use: either X or Y and sometimes D.
4031 We stop when a call, a label or a branch is seen, or when we
4032 detect that both X and Y are used (probably at different times, but it does
4033 not matter).
4034 3. The register that will be used for the replacement of Z is saved
4035 in a .page0 register or on the stack. If the first instruction that
4036 used Z, uses Z as an input, the value is loaded from another .page0
4037 register. The replacement register is pushed on the stack in the
4038 rare cases where a compare insn uses Z and we couldn't find if X/Y
4039 are dead.
4040 4. The Z register is replaced in all instructions until we reach
4041 the end of the Z-block, as detected by step 2.
4042 5. If we detect that Z is still alive, its value is saved.
4043 If the replacement register is alive, its old value is loaded.
4045 The Z register can be disabled with -ffixed-z.
4048 struct replace_info
4050 rtx first;
4051 rtx replace_reg;
4052 int need_save_z;
4053 int must_load_z;
4054 int must_save_reg;
4055 int must_restore_reg;
4056 rtx last;
4057 int regno;
4058 int x_used;
4059 int y_used;
4060 int can_use_d;
4061 int found_call;
4062 int z_died;
4063 int z_set_count;
4064 rtx z_value;
4065 int must_push_reg;
4066 int save_before_last;
4067 int z_loaded_with_sp;
4070 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4071 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4072 static void m68hc11_z_replacement (rtx);
4073 static void m68hc11_reassign_regs (rtx);
4075 int z_replacement_completed = 0;
4077 /* Analyze the insn to find out which replacement register to use and
4078 the boundaries of the replacement.
4079 Returns 0 if we reached the last insn to be replaced, 1 if we can
4080 continue replacement in next insns. */
4082 static int
4083 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4085 int this_insn_uses_ix;
4086 int this_insn_uses_iy;
4087 int this_insn_uses_z;
4088 int this_insn_uses_z_in_dst;
4089 int this_insn_uses_d;
4090 rtx body;
4091 int z_dies_here;
4093 /* A call is said to clobber the Z register, we don't need
4094 to save the value of Z. We also don't need to restore
4095 the replacement register (unless it is used by the call). */
4096 if (GET_CODE (insn) == CALL_INSN)
4098 body = PATTERN (insn);
4100 info->can_use_d = 0;
4102 /* If the call is an indirect call with Z, we have to use the
4103 Y register because X can be used as an input (D+X).
4104 We also must not save Z nor restore Y. */
4105 if (reg_mentioned_p (z_reg, body))
4107 insn = NEXT_INSN (insn);
4108 info->x_used = 1;
4109 info->y_used = 0;
4110 info->found_call = 1;
4111 info->must_restore_reg = 0;
4112 info->last = NEXT_INSN (insn);
4114 info->need_save_z = 0;
4115 return 0;
4117 if (GET_CODE (insn) == CODE_LABEL
4118 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4119 return 0;
4121 if (GET_CODE (insn) == JUMP_INSN)
4123 if (reg_mentioned_p (z_reg, insn) == 0)
4124 return 0;
4126 info->can_use_d = 0;
4127 info->must_save_reg = 0;
4128 info->must_restore_reg = 0;
4129 info->need_save_z = 0;
4130 info->last = NEXT_INSN (insn);
4131 return 0;
4133 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4135 return 1;
4138 /* Z register dies here. */
4139 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4141 body = PATTERN (insn);
4142 if (GET_CODE (body) == SET)
4144 rtx src = XEXP (body, 1);
4145 rtx dst = XEXP (body, 0);
4147 /* Condition code is set here. We have to restore the X/Y and
4148 save into Z before any test/compare insn because once we save/restore
4149 we can change the condition codes. When the compare insn uses Z and
4150 we can't use X/Y, the comparison is made with the *ZREG soft register
4151 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4152 if (dst == cc0_rtx)
4154 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4155 || (GET_CODE (src) == COMPARE &&
4156 ((rtx_equal_p (XEXP (src, 0), z_reg)
4157 && H_REG_P (XEXP (src, 1)))
4158 || (rtx_equal_p (XEXP (src, 1), z_reg)
4159 && H_REG_P (XEXP (src, 0))))))
4161 if (insn == info->first)
4163 info->must_load_z = 0;
4164 info->must_save_reg = 0;
4165 info->must_restore_reg = 0;
4166 info->need_save_z = 0;
4167 info->found_call = 1;
4168 info->regno = SOFT_Z_REGNUM;
4169 info->last = NEXT_INSN (insn);
4171 return 0;
4173 if (reg_mentioned_p (z_reg, src) == 0)
4175 info->can_use_d = 0;
4176 return 0;
4179 if (insn != info->first)
4180 return 0;
4182 /* Compare insn which uses Z. We have to save/restore the X/Y
4183 register without modifying the condition codes. For this
4184 we have to use a push/pop insn. */
4185 info->must_push_reg = 1;
4186 info->last = insn;
4189 /* Z reg is set to something new. We don't need to load it. */
4190 if (Z_REG_P (dst))
4192 if (!reg_mentioned_p (z_reg, src))
4194 /* Z reg is used before being set. Treat this as
4195 a new sequence of Z register replacement. */
4196 if (insn != info->first)
4198 return 0;
4200 info->must_load_z = 0;
4202 info->z_set_count++;
4203 info->z_value = src;
4204 if (SP_REG_P (src))
4205 info->z_loaded_with_sp = 1;
4207 else if (reg_mentioned_p (z_reg, dst))
4208 info->can_use_d = 0;
4210 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4211 | reg_mentioned_p (d_reg, dst);
4212 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4213 | reg_mentioned_p (ix_reg, dst);
4214 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4215 | reg_mentioned_p (iy_reg, dst);
4216 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4218 /* If z is used as an address operand (like (MEM (reg z))),
4219 we can't replace it with d. */
4220 if (this_insn_uses_z && !Z_REG_P (src)
4221 && !(m68hc11_arith_operator (src, GET_MODE (src))
4222 && Z_REG_P (XEXP (src, 0))
4223 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4224 && insn == info->first
4225 && dead_register_here (insn, d_reg)))
4226 info->can_use_d = 0;
4228 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4229 if (TARGET_M6812 && !z_dies_here
4230 && ((this_insn_uses_z && side_effects_p (src))
4231 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4233 info->need_save_z = 1;
4234 info->z_set_count++;
4236 this_insn_uses_z |= this_insn_uses_z_in_dst;
4238 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4240 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4243 if (this_insn_uses_d)
4244 info->can_use_d = 0;
4246 /* IX and IY are used at the same time, we have to restore
4247 the value of the scratch register before this insn. */
4248 if (this_insn_uses_ix && this_insn_uses_iy)
4250 return 0;
4253 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4254 info->can_use_d = 0;
4256 if (info->x_used == 0 && this_insn_uses_ix)
4258 if (info->y_used)
4260 /* We have a (set (REG:HI X) (REG:HI Z)).
4261 Since we use Z as the replacement register, this insn
4262 is no longer necessary. We turn it into a note. We must
4263 not reload the old value of X. */
4264 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4266 if (z_dies_here)
4268 info->need_save_z = 0;
4269 info->z_died = 1;
4271 info->must_save_reg = 0;
4272 info->must_restore_reg = 0;
4273 info->found_call = 1;
4274 info->can_use_d = 0;
4275 SET_INSN_DELETED (insn);
4276 info->last = NEXT_INSN (insn);
4277 return 0;
4280 if (X_REG_P (dst)
4281 && (rtx_equal_p (src, z_reg)
4282 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4284 if (z_dies_here)
4286 info->need_save_z = 0;
4287 info->z_died = 1;
4289 info->last = NEXT_INSN (insn);
4290 info->must_save_reg = 0;
4291 info->must_restore_reg = 0;
4293 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4294 && !reg_mentioned_p (ix_reg, src))
4296 if (z_dies_here)
4298 info->z_died = 1;
4299 info->need_save_z = 0;
4301 else if (TARGET_M6812 && side_effects_p (src))
4303 info->last = 0;
4304 info->must_restore_reg = 0;
4305 return 0;
4307 else
4309 info->save_before_last = 1;
4311 info->must_restore_reg = 0;
4312 info->last = NEXT_INSN (insn);
4314 else if (info->can_use_d)
4316 info->last = NEXT_INSN (insn);
4317 info->x_used = 1;
4319 return 0;
4321 info->x_used = 1;
4322 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4323 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4325 info->need_save_z = 0;
4326 info->z_died = 1;
4327 info->last = NEXT_INSN (insn);
4328 info->regno = HARD_X_REGNUM;
4329 info->must_save_reg = 0;
4330 info->must_restore_reg = 0;
4331 return 0;
4333 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4335 info->regno = HARD_X_REGNUM;
4336 info->must_restore_reg = 0;
4337 info->must_save_reg = 0;
4338 return 0;
4341 if (info->y_used == 0 && this_insn_uses_iy)
4343 if (info->x_used)
4345 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4347 if (z_dies_here)
4349 info->need_save_z = 0;
4350 info->z_died = 1;
4352 info->must_save_reg = 0;
4353 info->must_restore_reg = 0;
4354 info->found_call = 1;
4355 info->can_use_d = 0;
4356 SET_INSN_DELETED (insn);
4357 info->last = NEXT_INSN (insn);
4358 return 0;
4361 if (Y_REG_P (dst)
4362 && (rtx_equal_p (src, z_reg)
4363 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4365 if (z_dies_here)
4367 info->z_died = 1;
4368 info->need_save_z = 0;
4370 info->last = NEXT_INSN (insn);
4371 info->must_save_reg = 0;
4372 info->must_restore_reg = 0;
4374 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4375 && !reg_mentioned_p (iy_reg, src))
4377 if (z_dies_here)
4379 info->z_died = 1;
4380 info->need_save_z = 0;
4382 else if (TARGET_M6812 && side_effects_p (src))
4384 info->last = 0;
4385 info->must_restore_reg = 0;
4386 return 0;
4388 else
4390 info->save_before_last = 1;
4392 info->must_restore_reg = 0;
4393 info->last = NEXT_INSN (insn);
4395 else if (info->can_use_d)
4397 info->last = NEXT_INSN (insn);
4398 info->y_used = 1;
4401 return 0;
4403 info->y_used = 1;
4404 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4405 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4407 info->need_save_z = 0;
4408 info->z_died = 1;
4409 info->last = NEXT_INSN (insn);
4410 info->regno = HARD_Y_REGNUM;
4411 info->must_save_reg = 0;
4412 info->must_restore_reg = 0;
4413 return 0;
4415 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4417 info->regno = HARD_Y_REGNUM;
4418 info->must_restore_reg = 0;
4419 info->must_save_reg = 0;
4420 return 0;
4423 if (z_dies_here)
4425 info->need_save_z = 0;
4426 info->z_died = 1;
4427 if (info->last == 0)
4428 info->last = NEXT_INSN (insn);
4429 return 0;
4431 return info->last != NULL_RTX ? 0 : 1;
4433 if (GET_CODE (body) == PARALLEL)
4435 int i;
4436 char ix_clobber = 0;
4437 char iy_clobber = 0;
4438 char z_clobber = 0;
4439 this_insn_uses_iy = 0;
4440 this_insn_uses_ix = 0;
4441 this_insn_uses_z = 0;
4443 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4445 rtx x;
4446 int uses_ix, uses_iy, uses_z;
4448 x = XVECEXP (body, 0, i);
4450 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4451 info->can_use_d = 0;
4453 uses_ix = reg_mentioned_p (ix_reg, x);
4454 uses_iy = reg_mentioned_p (iy_reg, x);
4455 uses_z = reg_mentioned_p (z_reg, x);
4456 if (GET_CODE (x) == CLOBBER)
4458 ix_clobber |= uses_ix;
4459 iy_clobber |= uses_iy;
4460 z_clobber |= uses_z;
4462 else
4464 this_insn_uses_ix |= uses_ix;
4465 this_insn_uses_iy |= uses_iy;
4466 this_insn_uses_z |= uses_z;
4468 if (uses_z && GET_CODE (x) == SET)
4470 rtx dst = XEXP (x, 0);
4472 if (Z_REG_P (dst))
4473 info->z_set_count++;
4475 if (TARGET_M6812 && uses_z && side_effects_p (x))
4476 info->need_save_z = 1;
4478 if (z_clobber)
4479 info->need_save_z = 0;
4481 if (debug_m6811)
4483 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4484 this_insn_uses_ix, this_insn_uses_iy,
4485 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4486 debug_rtx (insn);
4488 if (this_insn_uses_z)
4489 info->can_use_d = 0;
4491 if (z_clobber && info->first != insn)
4493 info->need_save_z = 0;
4494 info->last = insn;
4495 return 0;
4497 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4499 if (this_insn_uses_z == 0 && insn == info->first)
4501 info->must_load_z = 0;
4503 if (dead_register_here (insn, d_reg))
4505 info->regno = HARD_D_REGNUM;
4506 info->must_save_reg = 0;
4507 info->must_restore_reg = 0;
4509 else if (dead_register_here (insn, ix_reg))
4511 info->regno = HARD_X_REGNUM;
4512 info->must_save_reg = 0;
4513 info->must_restore_reg = 0;
4515 else if (dead_register_here (insn, iy_reg))
4517 info->regno = HARD_Y_REGNUM;
4518 info->must_save_reg = 0;
4519 info->must_restore_reg = 0;
4521 if (info->regno >= 0)
4523 info->last = NEXT_INSN (insn);
4524 return 0;
4526 if (this_insn_uses_ix == 0)
4528 info->regno = HARD_X_REGNUM;
4529 info->must_save_reg = 1;
4530 info->must_restore_reg = 1;
4532 else if (this_insn_uses_iy == 0)
4534 info->regno = HARD_Y_REGNUM;
4535 info->must_save_reg = 1;
4536 info->must_restore_reg = 1;
4538 else
4540 info->regno = HARD_D_REGNUM;
4541 info->must_save_reg = 1;
4542 info->must_restore_reg = 1;
4544 info->last = NEXT_INSN (insn);
4545 return 0;
4548 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4549 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4551 if (this_insn_uses_z)
4553 if (info->y_used == 0 && iy_clobber)
4555 info->regno = HARD_Y_REGNUM;
4556 info->must_save_reg = 0;
4557 info->must_restore_reg = 0;
4559 if (info->first != insn
4560 && ((info->y_used && ix_clobber)
4561 || (info->x_used && iy_clobber)))
4562 info->last = insn;
4563 else
4564 info->last = NEXT_INSN (insn);
4565 info->save_before_last = 1;
4567 return 0;
4569 if (this_insn_uses_ix && this_insn_uses_iy)
4571 if (this_insn_uses_z)
4573 fatal_insn ("cannot do z-register replacement", insn);
4575 return 0;
4577 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4579 if (info->y_used)
4581 return 0;
4583 info->x_used = 1;
4584 if (iy_clobber || z_clobber)
4586 info->last = NEXT_INSN (insn);
4587 info->save_before_last = 1;
4588 return 0;
4592 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4594 if (info->x_used)
4596 return 0;
4598 info->y_used = 1;
4599 if (ix_clobber || z_clobber)
4601 info->last = NEXT_INSN (insn);
4602 info->save_before_last = 1;
4603 return 0;
4606 if (z_dies_here)
4608 info->z_died = 1;
4609 info->need_save_z = 0;
4611 return 1;
4613 if (GET_CODE (body) == CLOBBER)
4616 /* IX and IY are used at the same time, we have to restore
4617 the value of the scratch register before this insn. */
4618 if (this_insn_uses_ix && this_insn_uses_iy)
4620 return 0;
4622 if (info->x_used == 0 && this_insn_uses_ix)
4624 if (info->y_used)
4626 return 0;
4628 info->x_used = 1;
4630 if (info->y_used == 0 && this_insn_uses_iy)
4632 if (info->x_used)
4634 return 0;
4636 info->y_used = 1;
4638 return 1;
4640 return 1;
4643 static void
4644 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4646 int reg;
4648 info->replace_reg = NULL_RTX;
4649 info->must_load_z = 1;
4650 info->need_save_z = 1;
4651 info->must_save_reg = 1;
4652 info->must_restore_reg = 1;
4653 info->first = insn;
4654 info->x_used = 0;
4655 info->y_used = 0;
4656 info->can_use_d = TARGET_M6811 ? 1 : 0;
4657 info->found_call = 0;
4658 info->z_died = 0;
4659 info->last = 0;
4660 info->regno = -1;
4661 info->z_set_count = 0;
4662 info->z_value = NULL_RTX;
4663 info->must_push_reg = 0;
4664 info->save_before_last = 0;
4665 info->z_loaded_with_sp = 0;
4667 /* Scan the insn forward to find an address register that is not used.
4668 Stop when:
4669 - the flow of the program changes,
4670 - when we detect that both X and Y are necessary,
4671 - when the Z register dies,
4672 - when the condition codes are set. */
4674 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4676 if (m68hc11_check_z_replacement (insn, info) == 0)
4677 break;
4680 /* May be we can use Y or X if they contain the same value as Z.
4681 This happens very often after the reload. */
4682 if (info->z_set_count == 1)
4684 rtx p = info->first;
4685 rtx v = 0;
4687 if (info->x_used)
4689 v = find_last_value (iy_reg, &p, insn, 1);
4691 else if (info->y_used)
4693 v = find_last_value (ix_reg, &p, insn, 1);
4695 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4697 if (info->x_used)
4698 info->regno = HARD_Y_REGNUM;
4699 else
4700 info->regno = HARD_X_REGNUM;
4701 info->must_load_z = 0;
4702 info->must_save_reg = 0;
4703 info->must_restore_reg = 0;
4704 info->found_call = 1;
4707 if (info->z_set_count == 0)
4708 info->need_save_z = 0;
4710 if (insn == 0)
4711 info->need_save_z = 0;
4713 if (info->last == 0)
4714 info->last = insn;
4716 if (info->regno >= 0)
4718 reg = info->regno;
4719 info->replace_reg = gen_rtx_REG (HImode, reg);
4721 else if (info->can_use_d)
4723 reg = HARD_D_REGNUM;
4724 info->replace_reg = d_reg;
4726 else if (info->x_used)
4728 reg = HARD_Y_REGNUM;
4729 info->replace_reg = iy_reg;
4731 else
4733 reg = HARD_X_REGNUM;
4734 info->replace_reg = ix_reg;
4736 info->regno = reg;
4738 if (info->must_save_reg && info->must_restore_reg)
4740 if (insn && dead_register_here (insn, info->replace_reg))
4742 info->must_save_reg = 0;
4743 info->must_restore_reg = 0;
4748 /* The insn uses the Z register. Find a replacement register for it
4749 (either X or Y) and replace it in the insn and the next ones until
4750 the flow changes or the replacement register is used. Instructions
4751 are emitted before and after the Z-block to preserve the value of
4752 Z and of the replacement register. */
4754 static void
4755 m68hc11_z_replacement (rtx insn)
4757 rtx replace_reg_qi;
4758 rtx replace_reg;
4759 struct replace_info info;
4761 /* Find trivial case where we only need to replace z with the
4762 equivalent soft register. */
4763 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4765 rtx body = PATTERN (insn);
4766 rtx src = XEXP (body, 1);
4767 rtx dst = XEXP (body, 0);
4769 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4771 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4772 return;
4774 else if (Z_REG_P (src)
4775 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4777 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4778 return;
4780 else if (D_REG_P (dst)
4781 && m68hc11_arith_operator (src, GET_MODE (src))
4782 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4784 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4785 return;
4787 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4788 && INTVAL (src) == 0)
4790 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4791 /* Force it to be re-recognized. */
4792 INSN_CODE (insn) = -1;
4793 return;
4797 m68hc11_find_z_replacement (insn, &info);
4799 replace_reg = info.replace_reg;
4800 replace_reg_qi = NULL_RTX;
4802 /* Save the X register in a .page0 location. */
4803 if (info.must_save_reg && !info.must_push_reg)
4805 rtx dst;
4807 if (info.must_push_reg && 0)
4808 dst = gen_rtx_MEM (HImode,
4809 gen_rtx_PRE_DEC (HImode,
4810 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4811 else
4812 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4814 emit_insn_before (gen_movhi (dst,
4815 gen_rtx_REG (HImode, info.regno)), insn);
4817 if (info.must_load_z && !info.must_push_reg)
4819 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4820 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4821 insn);
4825 /* Replace all occurrence of Z by replace_reg.
4826 Stop when the last instruction to replace is reached.
4827 Also stop when we detect a change in the flow (but it's not
4828 necessary; just safeguard). */
4830 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4832 rtx body;
4834 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4835 break;
4837 if (GET_CODE (insn) != INSN
4838 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4839 continue;
4841 body = PATTERN (insn);
4842 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4843 || GET_CODE (body) == ASM_OPERANDS
4844 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4846 rtx note;
4848 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4850 printf ("Reg mentioned here...:\n");
4851 fflush (stdout);
4852 debug_rtx (insn);
4855 /* Stack pointer was decremented by 2 due to the push.
4856 Correct that by adding 2 to the destination. */
4857 if (info.must_push_reg
4858 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4860 rtx src, dst;
4862 src = SET_SRC (body);
4863 dst = SET_DEST (body);
4864 if (SP_REG_P (src) && Z_REG_P (dst))
4865 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4868 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4869 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4871 INSN_CODE (insn) = -1;
4872 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4873 fatal_insn ("cannot do z-register replacement", insn);
4876 /* Likewise for (REG:QI Z). */
4877 if (reg_mentioned_p (z_reg, insn))
4879 if (replace_reg_qi == NULL_RTX)
4880 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4881 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4884 /* If there is a REG_INC note on Z, replace it with a
4885 REG_INC note on the replacement register. This is necessary
4886 to make sure that the flow pass will identify the change
4887 and it will not remove a possible insn that saves Z. */
4888 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4890 if (REG_NOTE_KIND (note) == REG_INC
4891 && GET_CODE (XEXP (note, 0)) == REG
4892 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4894 XEXP (note, 0) = replace_reg;
4898 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4899 break;
4902 /* Save Z before restoring the old value. */
4903 if (insn && info.need_save_z && !info.must_push_reg)
4905 rtx save_pos_insn = insn;
4907 /* If Z is clobber by the last insn, we have to save its value
4908 before the last instruction. */
4909 if (info.save_before_last)
4910 save_pos_insn = PREV_INSN (save_pos_insn);
4912 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4913 gen_rtx_REG (HImode, info.regno)),
4914 save_pos_insn);
4917 if (info.must_push_reg && info.last)
4919 rtx new_body, body;
4921 body = PATTERN (info.last);
4922 new_body = gen_rtx_PARALLEL (VOIDmode,
4923 gen_rtvec (3, body,
4924 gen_rtx_USE (VOIDmode,
4925 replace_reg),
4926 gen_rtx_USE (VOIDmode,
4927 gen_rtx_REG (HImode,
4928 SOFT_Z_REGNUM))));
4929 PATTERN (info.last) = new_body;
4931 /* Force recognition on insn since we changed it. */
4932 INSN_CODE (insn) = -1;
4934 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4936 fatal_insn ("invalid Z register replacement for insn", insn);
4938 insn = NEXT_INSN (info.last);
4941 /* Restore replacement register unless it was died. */
4942 if (insn && info.must_restore_reg && !info.must_push_reg)
4944 rtx dst;
4946 if (info.must_push_reg && 0)
4947 dst = gen_rtx_MEM (HImode,
4948 gen_rtx_POST_INC (HImode,
4949 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4950 else
4951 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4953 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4954 dst), insn);
4960 /* Scan all the insn and re-affects some registers
4961 - The Z register (if it was used), is affected to X or Y depending
4962 on the instruction. */
4964 static void
4965 m68hc11_reassign_regs (rtx first)
4967 rtx insn;
4969 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4970 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4971 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4972 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4974 /* Scan all insns to replace Z by X or Y preserving the old value
4975 of X/Y and restoring it afterward. */
4977 for (insn = first; insn; insn = NEXT_INSN (insn))
4979 rtx body;
4981 if (GET_CODE (insn) == CODE_LABEL
4982 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4983 continue;
4985 if (!INSN_P (insn))
4986 continue;
4988 body = PATTERN (insn);
4989 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4990 continue;
4992 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4993 || GET_CODE (body) == ASM_OPERANDS
4994 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4995 continue;
4997 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4998 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5001 /* If Z appears in this insn, replace it in the current insn
5002 and the next ones until the flow changes or we have to
5003 restore back the replacement register. */
5005 if (reg_mentioned_p (z_reg, body))
5007 m68hc11_z_replacement (insn);
5010 else
5012 printf ("insn not handled by Z replacement:\n");
5013 fflush (stdout);
5014 debug_rtx (insn);
5020 /* Machine-dependent reorg pass.
5021 Specific optimizations are defined here:
5022 - this pass changes the Z register into either X or Y
5023 (it preserves X/Y previous values in a memory slot in page0).
5025 When this pass is finished, the global variable
5026 'z_replacement_completed' is set to 2. */
5028 static void
5029 m68hc11_reorg (void)
5031 int split_done = 0;
5032 rtx first;
5034 z_replacement_completed = 0;
5035 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5036 first = get_insns ();
5038 /* Some RTX are shared at this point. This breaks the Z register
5039 replacement, unshare everything. */
5040 unshare_all_rtl_again (first);
5042 /* Force a split of all splittable insn. This is necessary for the
5043 Z register replacement mechanism because we end up with basic insns. */
5044 split_all_insns_noflow ();
5045 split_done = 1;
5047 z_replacement_completed = 1;
5048 m68hc11_reassign_regs (first);
5050 if (optimize)
5051 compute_bb_for_insn ();
5053 /* After some splitting, there are some opportunities for CSE pass.
5054 This happens quite often when 32-bit or above patterns are split. */
5055 if (optimize > 0 && split_done)
5057 reload_cse_regs (first);
5060 /* Re-create the REG_DEAD notes. These notes are used in the machine
5061 description to use the best assembly directives. */
5062 if (optimize)
5064 df_note_add_problem ();
5065 df_analyze ();
5066 df_remove_problem (df_note);
5069 z_replacement_completed = 2;
5071 /* If optimizing, then go ahead and split insns that must be
5072 split after Z register replacement. This gives more opportunities
5073 for peephole (in particular for consecutives xgdx/xgdy). */
5074 if (optimize > 0)
5075 split_all_insns_noflow ();
5077 /* Once insns are split after the z_replacement_completed == 2,
5078 we must not re-run the life_analysis. The xgdx/xgdy patterns
5079 are not recognized and the life_analysis pass removes some
5080 insns because it thinks some (SETs) are noops or made to dead
5081 stores (which is false due to the swap).
5083 Do a simple pass to eliminate the noop set that the final
5084 split could generate (because it was easier for split definition). */
5086 rtx insn;
5088 for (insn = first; insn; insn = NEXT_INSN (insn))
5090 rtx body;
5092 if (INSN_DELETED_P (insn))
5093 continue;
5094 if (!INSN_P (insn))
5095 continue;
5097 /* Remove the (set (R) (R)) insns generated by some splits. */
5098 body = PATTERN (insn);
5099 if (GET_CODE (body) == SET
5100 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5102 SET_INSN_DELETED (insn);
5103 continue;
5109 /* Override memcpy */
5111 static void
5112 m68hc11_init_libfuncs (void)
5114 memcpy_libfunc = init_one_libfunc ("__memcpy");
5115 memcmp_libfunc = init_one_libfunc ("__memcmp");
5116 memset_libfunc = init_one_libfunc ("__memset");
5121 /* Cost functions. */
5123 /* Cost of moving memory. */
5125 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
5126 int in ATTRIBUTE_UNUSED)
5128 if (rclass <= H_REGS && rclass > NO_REGS)
5130 if (GET_MODE_SIZE (mode) <= 2)
5131 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5132 else
5133 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5135 else
5137 if (GET_MODE_SIZE (mode) <= 2)
5138 return COSTS_N_INSNS (3);
5139 else
5140 return COSTS_N_INSNS (4);
5145 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5146 Reload does not check the constraint of set insns when the two registers
5147 have a move cost of 2. Setting a higher cost will force reload to check
5148 the constraints. */
5150 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5151 enum reg_class to)
5153 /* All costs are symmetric, so reduce cases by putting the
5154 lower number class as the destination. */
5155 if (from < to)
5157 enum reg_class tmp = to;
5158 to = from, from = tmp;
5160 if (to >= S_REGS)
5161 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5162 else if (from <= S_REGS)
5163 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5164 else
5165 return COSTS_N_INSNS (2);
5169 /* Provide the costs of an addressing mode that contains ADDR.
5170 If ADDR is not a valid address, its cost is irrelevant. */
5172 static int
5173 m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
5175 int cost = 4;
5177 switch (GET_CODE (addr))
5179 case REG:
5180 /* Make the cost of hard registers and specially SP, FP small. */
5181 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5182 cost = 0;
5183 else
5184 cost = 1;
5185 break;
5187 case SYMBOL_REF:
5188 cost = 8;
5189 break;
5191 case LABEL_REF:
5192 case CONST:
5193 cost = 0;
5194 break;
5196 case PLUS:
5198 register rtx plus0 = XEXP (addr, 0);
5199 register rtx plus1 = XEXP (addr, 1);
5201 if (GET_CODE (plus0) != REG)
5202 break;
5204 switch (GET_CODE (plus1))
5206 case CONST_INT:
5207 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5208 || INTVAL (plus1) < m68hc11_min_offset)
5209 cost = 3;
5210 else if (INTVAL (plus1) >= m68hc11_max_offset)
5211 cost = 2;
5212 else
5213 cost = 1;
5214 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5215 cost += 0;
5216 else
5217 cost += 1;
5218 break;
5220 case SYMBOL_REF:
5221 cost = 8;
5222 break;
5224 case CONST:
5225 case LABEL_REF:
5226 cost = 0;
5227 break;
5229 default:
5230 break;
5232 break;
5234 case PRE_DEC:
5235 case PRE_INC:
5236 if (SP_REG_P (XEXP (addr, 0)))
5237 cost = 1;
5238 break;
5240 default:
5241 break;
5243 if (debug_m6811)
5245 printf ("Address cost: %d for :", cost);
5246 fflush (stdout);
5247 debug_rtx (addr);
5250 return cost;
5253 static int
5254 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5256 int total;
5258 total = rtx_cost (x, SET, !optimize_size);
5259 if (mode == QImode)
5260 total += m68hc11_cost->shiftQI_const[shift % 8];
5261 else if (mode == HImode)
5262 total += m68hc11_cost->shiftHI_const[shift % 16];
5263 else if (shift == 8 || shift == 16 || shift == 32)
5264 total += m68hc11_cost->shiftHI_const[8];
5265 else if (shift != 0 && shift != 16 && shift != 32)
5267 total += m68hc11_cost->shiftHI_const[1] * shift;
5270 /* For SI and others, the cost is higher. */
5271 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5272 total *= GET_MODE_SIZE (mode) / 2;
5274 /* When optimizing for size, make shift more costly so that
5275 multiplications are preferred. */
5276 if (optimize_size && (shift % 8) != 0)
5277 total *= 2;
5279 return total;
5282 static int
5283 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5284 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5286 enum machine_mode mode = GET_MODE (x);
5287 int extra_cost = 0;
5288 int total;
5290 switch (code)
5292 case ROTATE:
5293 case ROTATERT:
5294 case ASHIFT:
5295 case LSHIFTRT:
5296 case ASHIFTRT:
5297 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5299 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5302 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5303 total += m68hc11_cost->shift_var;
5304 return total;
5306 case AND:
5307 case XOR:
5308 case IOR:
5309 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5310 total += m68hc11_cost->logical;
5312 /* Logical instructions are byte instructions only. */
5313 total *= GET_MODE_SIZE (mode);
5314 return total;
5316 case MINUS:
5317 case PLUS:
5318 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5319 total += m68hc11_cost->add;
5320 if (GET_MODE_SIZE (mode) > 2)
5322 total *= GET_MODE_SIZE (mode) / 2;
5324 return total;
5326 case UDIV:
5327 case DIV:
5328 case MOD:
5329 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5330 switch (mode)
5332 case QImode:
5333 total += m68hc11_cost->divQI;
5334 break;
5336 case HImode:
5337 total += m68hc11_cost->divHI;
5338 break;
5340 case SImode:
5341 default:
5342 total += m68hc11_cost->divSI;
5343 break;
5345 return total;
5347 case MULT:
5348 /* mul instruction produces 16-bit result. */
5349 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5350 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5351 return m68hc11_cost->multQI
5352 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5353 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5355 /* emul instruction produces 32-bit result for 68HC12. */
5356 if (TARGET_M6812 && mode == SImode
5357 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5358 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5359 return m68hc11_cost->multHI
5360 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5361 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5363 total = rtx_cost (XEXP (x, 0), code, !optimize_size)
5364 + rtx_cost (XEXP (x, 1), code, !optimize_size);
5365 switch (mode)
5367 case QImode:
5368 total += m68hc11_cost->multQI;
5369 break;
5371 case HImode:
5372 total += m68hc11_cost->multHI;
5373 break;
5375 case SImode:
5376 default:
5377 total += m68hc11_cost->multSI;
5378 break;
5380 return total;
5382 case NEG:
5383 case SIGN_EXTEND:
5384 extra_cost = COSTS_N_INSNS (2);
5386 /* Fall through */
5387 case NOT:
5388 case COMPARE:
5389 case ABS:
5390 case ZERO_EXTEND:
5391 case ZERO_EXTRACT:
5392 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
5393 if (mode == QImode)
5395 return total + COSTS_N_INSNS (1);
5397 if (mode == HImode)
5399 return total + COSTS_N_INSNS (2);
5401 if (mode == SImode)
5403 return total + COSTS_N_INSNS (4);
5405 return total + COSTS_N_INSNS (8);
5407 case IF_THEN_ELSE:
5408 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5409 return COSTS_N_INSNS (1);
5411 return COSTS_N_INSNS (1);
5413 default:
5414 return COSTS_N_INSNS (4);
5418 static bool
5419 m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
5420 bool speed ATTRIBUTE_UNUSED)
5422 enum rtx_code code = (enum rtx_code) codearg;
5423 enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
5425 switch (code)
5427 /* Constants are cheap. Moving them in registers must be avoided
5428 because most instructions do not handle two register operands. */
5429 case CONST_INT:
5430 case CONST:
5431 case LABEL_REF:
5432 case SYMBOL_REF:
5433 case CONST_DOUBLE:
5434 /* Logical and arithmetic operations with a constant operand are
5435 better because they are not supported with two registers. */
5436 /* 'clr' is slow */
5437 if (outer_code == SET && x == const0_rtx)
5438 /* After reload, the reload_cse pass checks the cost to change
5439 a SET into a PLUS. Make const0 cheap then. */
5440 *total = 1 - reload_completed;
5441 else
5442 *total = 0;
5443 return true;
5445 case ZERO_EXTRACT:
5446 if (outer_code != COMPARE)
5447 return false;
5449 case ROTATE:
5450 case ROTATERT:
5451 case ASHIFT:
5452 case LSHIFTRT:
5453 case ASHIFTRT:
5454 case MINUS:
5455 case PLUS:
5456 case AND:
5457 case XOR:
5458 case IOR:
5459 case UDIV:
5460 case DIV:
5461 case MOD:
5462 case MULT:
5463 case NEG:
5464 case SIGN_EXTEND:
5465 case NOT:
5466 case COMPARE:
5467 case ZERO_EXTEND:
5468 case IF_THEN_ELSE:
5469 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5470 return true;
5472 default:
5473 return false;
5478 /* Worker function for TARGET_ASM_FILE_START. */
5480 static void
5481 m68hc11_file_start (void)
5483 default_file_start ();
5485 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5489 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5491 static void
5492 m68hc11_asm_out_constructor (rtx symbol, int priority)
5494 default_ctor_section_asm_out_constructor (symbol, priority);
5495 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5498 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5500 static void
5501 m68hc11_asm_out_destructor (rtx symbol, int priority)
5503 default_dtor_section_asm_out_destructor (symbol, priority);
5504 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5507 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5509 static rtx
5510 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5511 int incoming ATTRIBUTE_UNUSED)
5513 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5516 /* Return true if type TYPE should be returned in memory.
5517 Blocks and data types largers than 4 bytes cannot be returned
5518 in the register (D + X = 4). */
5520 static bool
5521 m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
5523 if (TYPE_MODE (type) == BLKmode)
5525 HOST_WIDE_INT size = int_size_in_bytes (type);
5526 return (size == -1 || size > 4);
5528 else
5529 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5532 #include "gt-m68hc11.h"