Merge from mainline (160224:163495).
[official-gcc/graphite-test-results.git] / gcc / config / m68hc11 / m68hc11.c
blob2056375b6a669cc546946462d0d91a34ee76facb
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 "diagnostic-core.h"
55 #include "toplev.h"
56 #include "basic-block.h"
57 #include "function.h"
58 #include "ggc.h"
59 #include "reload.h"
60 #include "target.h"
61 #include "target-def.h"
62 #include "df.h"
64 static void emit_move_after_reload (rtx, rtx, rtx);
65 static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
66 static void m68hc11_emit_logical (enum machine_mode, enum rtx_code, rtx *);
67 static void m68hc11_reorg (void);
68 static bool m68hc11_legitimate_address_p_1 (enum machine_mode, rtx, bool);
69 static bool m68hc11_legitimate_address_p (enum machine_mode, rtx, bool);
70 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
71 static int must_parenthesize (rtx);
72 static int m68hc11_address_cost (rtx, bool);
73 static int m68hc11_shift_cost (enum machine_mode, rtx, int);
74 static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
75 static bool m68hc11_rtx_costs (rtx, int, int, int *, bool);
76 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
77 static tree m68hc11_handle_page0_attribute (tree *, tree, tree, int, bool *);
79 void create_regs_rtx (void);
81 static void asm_print_register (FILE *, int);
82 static void m68hc11_print_operand (FILE *, rtx, int);
83 static void m68hc11_print_operand_address (FILE *, rtx);
84 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
85 static void m68hc11_asm_out_constructor (rtx, int);
86 static void m68hc11_asm_out_destructor (rtx, int);
87 static void m68hc11_file_start (void);
88 static void m68hc11_encode_section_info (tree, rtx, int);
89 static const char *m68hc11_strip_name_encoding (const char* str);
90 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
91 static int autoinc_mode (rtx);
92 static int m68hc11_make_autoinc_notes (rtx *, void *);
93 static void m68hc11_init_libfuncs (void);
94 static rtx m68hc11_struct_value_rtx (tree, int);
95 static bool m68hc11_return_in_memory (const_tree, const_tree);
96 static bool m68hc11_can_eliminate (const int, const int);
97 static void m68hc11_trampoline_init (rtx, tree, rtx);
99 /* Must be set to 1 to produce debug messages. */
100 int debug_m6811 = 0;
102 extern FILE *asm_out_file;
104 rtx ix_reg;
105 rtx iy_reg;
106 rtx d_reg;
107 rtx m68hc11_soft_tmp_reg;
108 static GTY(()) rtx stack_push_word;
109 static GTY(()) rtx stack_pop_word;
110 static GTY(()) rtx z_reg;
111 static GTY(()) rtx z_reg_qi;
112 static int regs_inited = 0;
114 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
115 int current_function_interrupt;
117 /* Set to 1 by expand_prologue() when the function is a trap handler. */
118 int current_function_trap;
120 /* Set to 1 when the current function is placed in 68HC12 banked
121 memory and must return with rtc. */
122 int current_function_far;
124 /* Min offset that is valid for the indirect addressing mode. */
125 HOST_WIDE_INT m68hc11_min_offset = 0;
127 /* Max offset that is valid for the indirect addressing mode. */
128 HOST_WIDE_INT m68hc11_max_offset = 256;
130 /* The class value for base registers. */
131 enum reg_class m68hc11_base_reg_class = A_REGS;
133 /* The class value for index registers. This is NO_REGS for 68HC11. */
134 enum reg_class m68hc11_index_reg_class = NO_REGS;
136 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
138 /* Tables that tell whether a given hard register is valid for
139 a base or an index register. It is filled at init time depending
140 on the target processor. */
141 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
142 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
144 /* A correction offset which is applied to the stack pointer.
145 This is 1 for 68HC11 and 0 for 68HC12. */
146 int m68hc11_sp_correction;
148 int m68hc11_addr_mode;
149 int m68hc11_mov_addr_mode;
152 const struct processor_costs *m68hc11_cost;
154 /* Costs for a 68HC11. */
155 static const struct processor_costs m6811_cost = {
156 /* add */
157 COSTS_N_INSNS (2),
158 /* logical */
159 COSTS_N_INSNS (2),
160 /* non-constant shift */
161 COSTS_N_INSNS (20),
162 /* shiftQI const */
163 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
164 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
165 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
167 /* shiftHI const */
168 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
169 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
170 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
171 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
172 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
173 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
175 /* mulQI */
176 COSTS_N_INSNS (20),
177 /* mulHI */
178 COSTS_N_INSNS (20 * 4),
179 /* mulSI */
180 COSTS_N_INSNS (20 * 16),
181 /* divQI */
182 COSTS_N_INSNS (20),
183 /* divHI */
184 COSTS_N_INSNS (80),
185 /* divSI */
186 COSTS_N_INSNS (100)
189 /* Costs for a 68HC12. */
190 static const struct processor_costs m6812_cost = {
191 /* add */
192 COSTS_N_INSNS (2),
193 /* logical */
194 COSTS_N_INSNS (2),
195 /* non-constant shift */
196 COSTS_N_INSNS (20),
197 /* shiftQI const */
198 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
199 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
200 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
202 /* shiftHI const */
203 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
204 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
205 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
206 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
207 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
208 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
210 /* mulQI */
211 COSTS_N_INSNS (3),
212 /* mulHI */
213 COSTS_N_INSNS (3),
214 /* mulSI */
215 COSTS_N_INSNS (3 * 4),
216 /* divQI */
217 COSTS_N_INSNS (12),
218 /* divHI */
219 COSTS_N_INSNS (12),
220 /* divSI */
221 COSTS_N_INSNS (100)
224 /* M68HC11 specific attributes. */
226 static const struct attribute_spec m68hc11_attribute_table[] =
228 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
229 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
230 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
231 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
232 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
233 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
234 { NULL, 0, 0, false, false, false, NULL }
237 /* Initialize the GCC target structure. */
238 #undef TARGET_ATTRIBUTE_TABLE
239 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
241 #undef TARGET_ASM_ALIGNED_HI_OP
242 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
244 #undef TARGET_PRINT_OPERAND
245 #define TARGET_PRINT_OPERAND m68hc11_print_operand
246 #undef TARGET_PRINT_OPERAND_ADDRESS
247 #define TARGET_PRINT_OPERAND_ADDRESS m68hc11_print_operand_address
249 #undef TARGET_ASM_FUNCTION_EPILOGUE
250 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
252 #undef TARGET_ASM_FILE_START
253 #define TARGET_ASM_FILE_START m68hc11_file_start
254 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
255 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
257 #undef TARGET_DEFAULT_TARGET_FLAGS
258 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
260 #undef TARGET_ENCODE_SECTION_INFO
261 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
263 #undef TARGET_SECTION_TYPE_FLAGS
264 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
266 #undef TARGET_RTX_COSTS
267 #define TARGET_RTX_COSTS m68hc11_rtx_costs
268 #undef TARGET_ADDRESS_COST
269 #define TARGET_ADDRESS_COST m68hc11_address_cost
271 #undef TARGET_MACHINE_DEPENDENT_REORG
272 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
274 #undef TARGET_INIT_LIBFUNCS
275 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
277 #undef TARGET_STRUCT_VALUE_RTX
278 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
279 #undef TARGET_RETURN_IN_MEMORY
280 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
281 #undef TARGET_CALLEE_COPIES
282 #define TARGET_CALLEE_COPIES hook_callee_copies_named
284 #undef TARGET_STRIP_NAME_ENCODING
285 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
287 #undef TARGET_LEGITIMATE_ADDRESS_P
288 #define TARGET_LEGITIMATE_ADDRESS_P m68hc11_legitimate_address_p
290 #undef TARGET_CAN_ELIMINATE
291 #define TARGET_CAN_ELIMINATE m68hc11_can_eliminate
293 #undef TARGET_TRAMPOLINE_INIT
294 #define TARGET_TRAMPOLINE_INIT m68hc11_trampoline_init
296 struct gcc_target targetm = TARGET_INITIALIZER;
299 m68hc11_override_options (void)
301 memset (m68hc11_reg_valid_for_index, 0,
302 sizeof (m68hc11_reg_valid_for_index));
303 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
305 /* Compilation with -fpic generates a wrong code. */
306 if (flag_pic)
308 warning (0, "-f%s ignored for 68HC11/68HC12 (not supported)",
309 (flag_pic > 1) ? "PIC" : "pic");
310 flag_pic = 0;
313 /* Do not enable -fweb because it breaks the 32-bit shift patterns
314 by breaking the match_dup of those patterns. The shift patterns
315 will no longer be recognized after that. */
316 flag_web = 0;
318 /* Configure for a 68hc11 processor. */
319 if (TARGET_M6811)
321 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
322 m68hc11_cost = &m6811_cost;
323 m68hc11_min_offset = 0;
324 m68hc11_max_offset = 256;
325 m68hc11_index_reg_class = NO_REGS;
326 m68hc11_base_reg_class = A_REGS;
327 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
328 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
329 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
330 m68hc11_sp_correction = 1;
331 m68hc11_tmp_regs_class = D_REGS;
332 m68hc11_addr_mode = ADDR_OFFSET;
333 m68hc11_mov_addr_mode = 0;
334 if (m68hc11_soft_reg_count < 0)
335 m68hc11_soft_reg_count = 4;
338 /* Configure for a 68hc12 processor. */
339 if (TARGET_M6812)
341 m68hc11_cost = &m6812_cost;
342 m68hc11_min_offset = -65536;
343 m68hc11_max_offset = 65536;
344 m68hc11_index_reg_class = D_REGS;
345 m68hc11_base_reg_class = A_OR_SP_REGS;
346 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
347 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
348 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
349 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
350 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
351 m68hc11_sp_correction = 0;
352 m68hc11_tmp_regs_class = TMP_REGS;
353 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
354 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
355 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
356 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
357 target_flags |= MASK_NO_DIRECT_MODE;
358 if (m68hc11_soft_reg_count < 0)
359 m68hc11_soft_reg_count = 0;
361 if (TARGET_LONG_CALLS)
362 current_function_far = 1;
364 return 0;
368 void
369 m68hc11_conditional_register_usage (void)
371 int i;
373 if (m68hc11_soft_reg_count > SOFT_REG_LAST - SOFT_REG_FIRST)
374 m68hc11_soft_reg_count = SOFT_REG_LAST - SOFT_REG_FIRST;
376 for (i = SOFT_REG_FIRST + m68hc11_soft_reg_count; i < SOFT_REG_LAST; i++)
378 fixed_regs[i] = 1;
379 call_used_regs[i] = 1;
382 /* For 68HC12, the Z register emulation is not necessary when the
383 frame pointer is not used. The frame pointer is eliminated and
384 replaced by the stack register (which is a BASE_REG_CLASS). */
385 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
387 fixed_regs[HARD_Z_REGNUM] = 1;
392 /* Reload and register operations. */
395 void
396 create_regs_rtx (void)
398 /* regs_inited = 1; */
399 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
400 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
401 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
402 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
404 stack_push_word = gen_rtx_MEM (HImode,
405 gen_rtx_PRE_DEC (HImode,
406 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
407 stack_pop_word = gen_rtx_MEM (HImode,
408 gen_rtx_POST_INC (HImode,
409 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
413 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
414 - 8-bit values are stored anywhere (except the SP register).
415 - 16-bit values can be stored in any register whose mode is 16
416 - 32-bit values can be stored in D, X registers or in a soft register
417 (except the last one because we need 2 soft registers)
418 - Values whose size is > 32 bit are not stored in real hard
419 registers. They may be stored in soft registers if there are
420 enough of them. */
422 hard_regno_mode_ok (int regno, enum machine_mode mode)
424 switch (GET_MODE_SIZE (mode))
426 case 8:
427 return S_REGNO_P (regno) && m68hc11_soft_reg_count >= 4;
429 case 4:
430 return (X_REGNO_P (regno)
431 || (S_REGNO_P (regno) && m68hc11_soft_reg_count >= 2));
433 case 2:
434 return G_REGNO_P (regno);
436 case 1:
437 /* We have to accept a QImode in X or Y registers. Otherwise, the
438 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
439 in the insns. Reload fails if the insn rejects the register class 'a'
440 as well as if it accepts it. Patterns that failed were
441 zero_extend_qihi2 and iorqi3. */
443 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
445 default:
446 return 0;
451 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
453 /* Don't accept renaming to Z register. We will replace it to
454 X,Y or D during machine reorg pass. */
455 if (reg2 == HARD_Z_REGNUM)
456 return 0;
458 /* Don't accept renaming D,X to Y register as the code will be bigger. */
459 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
460 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
461 return 0;
463 return 1;
466 enum reg_class
467 preferred_reload_class (rtx operand, enum reg_class rclass)
469 enum machine_mode mode;
471 mode = GET_MODE (operand);
473 if (debug_m6811)
475 printf ("Preferred reload: (class=%s): ", reg_class_names[rclass]);
478 if (rclass == D_OR_A_OR_S_REGS && SP_REG_P (operand))
479 return m68hc11_base_reg_class;
481 if (rclass >= S_REGS && (GET_CODE (operand) == MEM
482 || GET_CODE (operand) == CONST_INT))
484 /* S_REGS class must not be used. The movhi template does not
485 work to move a memory to a soft register.
486 Restrict to a hard reg. */
487 switch (rclass)
489 default:
490 case G_REGS:
491 case D_OR_A_OR_S_REGS:
492 rclass = A_OR_D_REGS;
493 break;
494 case A_OR_S_REGS:
495 rclass = A_REGS;
496 break;
497 case D_OR_SP_OR_S_REGS:
498 rclass = D_OR_SP_REGS;
499 break;
500 case D_OR_Y_OR_S_REGS:
501 rclass = D_OR_Y_REGS;
502 break;
503 case D_OR_X_OR_S_REGS:
504 rclass = D_OR_X_REGS;
505 break;
506 case SP_OR_S_REGS:
507 rclass = SP_REGS;
508 break;
509 case Y_OR_S_REGS:
510 rclass = Y_REGS;
511 break;
512 case X_OR_S_REGS:
513 rclass = X_REGS;
514 break;
515 case D_OR_S_REGS:
516 rclass = D_REGS;
519 else if (rclass == Y_REGS && GET_CODE (operand) == MEM)
521 rclass = Y_REGS;
523 else if (rclass == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
525 rclass = D_OR_X_REGS;
527 else if (rclass >= S_REGS && S_REG_P (operand))
529 switch (rclass)
531 default:
532 case G_REGS:
533 case D_OR_A_OR_S_REGS:
534 rclass = A_OR_D_REGS;
535 break;
536 case A_OR_S_REGS:
537 rclass = A_REGS;
538 break;
539 case D_OR_SP_OR_S_REGS:
540 rclass = D_OR_SP_REGS;
541 break;
542 case D_OR_Y_OR_S_REGS:
543 rclass = D_OR_Y_REGS;
544 break;
545 case D_OR_X_OR_S_REGS:
546 rclass = D_OR_X_REGS;
547 break;
548 case SP_OR_S_REGS:
549 rclass = SP_REGS;
550 break;
551 case Y_OR_S_REGS:
552 rclass = Y_REGS;
553 break;
554 case X_OR_S_REGS:
555 rclass = X_REGS;
556 break;
557 case D_OR_S_REGS:
558 rclass = D_REGS;
561 else if (rclass >= S_REGS)
563 if (debug_m6811)
565 printf ("Class = %s for: ", reg_class_names[rclass]);
566 fflush (stdout);
567 debug_rtx (operand);
571 if (debug_m6811)
573 printf (" => class=%s\n", reg_class_names[rclass]);
574 fflush (stdout);
575 debug_rtx (operand);
578 return rclass;
581 /* Return 1 if the operand is a valid indexed addressing mode.
582 For 68hc11: n,r with n in [0..255] and r in A_REGS class
583 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
585 m68hc11_valid_addressing_p (rtx operand, enum machine_mode mode, int addr_mode)
587 rtx base, offset;
589 switch (GET_CODE (operand))
591 case MEM:
592 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
593 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
594 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
595 return 0;
597 case POST_INC:
598 case PRE_INC:
599 case POST_DEC:
600 case PRE_DEC:
601 if (addr_mode & ADDR_INCDEC)
602 return m68hc11_valid_addressing_p (XEXP (operand, 0), mode,
603 addr_mode & ADDR_STRICT);
604 return 0;
606 case PLUS:
607 base = XEXP (operand, 0);
608 if (GET_CODE (base) == MEM)
609 return 0;
611 offset = XEXP (operand, 1);
612 if (GET_CODE (offset) == MEM)
613 return 0;
615 /* Indexed addressing mode with 2 registers. */
616 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
618 if (!(addr_mode & ADDR_INDEXED))
619 return 0;
621 addr_mode &= ADDR_STRICT;
622 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
623 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
624 return 1;
626 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
627 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
628 return 1;
630 return 0;
633 if (!(addr_mode & ADDR_OFFSET))
634 return 0;
636 if (GET_CODE (base) == REG)
638 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
639 return 0;
641 if (!(addr_mode & ADDR_STRICT))
642 return 1;
644 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
647 if (GET_CODE (offset) == REG)
649 if (!VALID_CONSTANT_OFFSET_P (base, mode))
650 return 0;
652 if (!(addr_mode & ADDR_STRICT))
653 return 1;
655 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
657 return 0;
659 case REG:
660 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
662 case CONST_INT:
663 if (addr_mode & ADDR_CONST)
664 return VALID_CONSTANT_OFFSET_P (operand, mode);
665 return 0;
667 default:
668 return 0;
672 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
673 a 68HC12 1-byte index addressing mode. */
675 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
677 rtx base, offset;
678 int addr_mode;
680 if (GET_CODE (operand) == REG && reload_in_progress
681 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
682 && reg_equiv_memory_loc[REGNO (operand)])
684 operand = reg_equiv_memory_loc[REGNO (operand)];
685 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
688 if (GET_CODE (operand) != MEM)
689 return 0;
691 operand = XEXP (operand, 0);
692 if (CONSTANT_ADDRESS_P (operand))
693 return 1;
695 if (PUSH_POP_ADDRESS_P (operand))
696 return 1;
698 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
699 if (!m68hc11_valid_addressing_p (operand, mode, addr_mode))
700 return 0;
702 if (TARGET_M6812 && GET_CODE (operand) == PLUS
703 && (reload_completed | reload_in_progress))
705 base = XEXP (operand, 0);
706 offset = XEXP (operand, 1);
708 /* The offset can be a symbol address and this is too big
709 for the operand constraint. */
710 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
711 return 0;
713 if (GET_CODE (base) == CONST_INT)
714 offset = base;
716 switch (GET_MODE_SIZE (mode))
718 case 8:
719 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
720 return 0;
721 break;
723 case 4:
724 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
725 return 0;
726 break;
728 default:
729 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
730 return 0;
731 break;
734 return 1;
738 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
740 int addr_mode;
742 if (GET_CODE (operand) == REG && reload_in_progress
743 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
744 && reg_equiv_memory_loc[REGNO (operand)])
746 operand = reg_equiv_memory_loc[REGNO (operand)];
747 operand = eliminate_regs (operand, VOIDmode, NULL_RTX);
749 if (GET_CODE (operand) != MEM)
750 return 0;
752 operand = XEXP (operand, 0);
753 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
754 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
757 static bool
758 m68hc11_legitimate_address_p_1 (enum machine_mode mode, rtx operand,
759 bool strict)
761 int addr_mode;
763 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
765 /* Reject the global variables if they are too wide. This forces
766 a load of their address in a register and generates smaller code. */
767 if (GET_MODE_SIZE (mode) == 8)
768 return 0;
770 return 1;
772 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
773 if (m68hc11_valid_addressing_p (operand, mode, addr_mode))
775 return 1;
777 if (PUSH_POP_ADDRESS_P (operand))
779 return 1;
781 if (symbolic_memory_operand (operand, mode))
783 return 1;
785 return 0;
788 bool
789 m68hc11_legitimate_address_p (enum machine_mode mode, rtx operand,
790 bool strict)
792 int result;
794 if (debug_m6811)
796 printf ("Checking: ");
797 fflush (stdout);
798 debug_rtx (operand);
801 result = m68hc11_legitimate_address_p_1 (mode, operand, strict);
803 if (debug_m6811)
805 printf (" -> %s\n", result == 0 ? "NO" : "YES");
808 if (result == 0)
810 if (debug_m6811)
812 printf ("go_if_legitimate%s, ret 0: %d:",
813 (strict ? "_strict" : ""), mode);
814 fflush (stdout);
815 debug_rtx (operand);
818 return result;
823 m68hc11_reload_operands (rtx operands[])
825 enum machine_mode mode;
827 if (regs_inited == 0)
828 create_regs_rtx ();
830 mode = GET_MODE (operands[1]);
832 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
833 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
835 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
836 rtx base = XEXP (XEXP (operands[1], 0), 0);
838 if (GET_CODE (base) != REG)
840 rtx tmp = base;
841 base = big_offset;
842 big_offset = tmp;
845 /* If the offset is out of range, we have to compute the address
846 with a separate add instruction. We try to do this with an 8-bit
847 add on the A register. This is possible only if the lowest part
848 of the offset (i.e., big_offset % 256) is a valid constant offset
849 with respect to the mode. If it's not, we have to generate a
850 16-bit add on the D register. From:
852 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
854 we generate:
856 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
857 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
858 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
859 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
861 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
862 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
865 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
867 int vh, vl;
868 rtx reg = operands[0];
869 rtx offset;
870 int val = INTVAL (big_offset);
873 /* We use the 'operands[0]' as a scratch register to compute the
874 address. Make sure 'base' is in that register. */
875 if (!rtx_equal_p (base, operands[0]))
877 emit_move_insn (reg, base);
880 if (val > 0)
882 vh = val >> 8;
883 vl = val & 0x0FF;
885 else
887 vh = (val >> 8) & 0x0FF;
888 vl = val & 0x0FF;
891 /* Create the lowest part offset that still remains to be added.
892 If it's not a valid offset, do a 16-bit add. */
893 offset = GEN_INT (vl);
894 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
896 emit_insn (gen_rtx_SET (VOIDmode, reg,
897 gen_rtx_PLUS (HImode, reg, big_offset)));
898 offset = const0_rtx;
900 else
902 emit_insn (gen_rtx_SET (VOIDmode, reg,
903 gen_rtx_PLUS (HImode, reg,
904 GEN_INT (vh << 8))));
906 emit_move_insn (operands[0],
907 gen_rtx_MEM (GET_MODE (operands[1]),
908 gen_rtx_PLUS (Pmode, reg, offset)));
909 return 1;
913 /* Use the normal gen_movhi pattern. */
914 return 0;
917 void
918 m68hc11_emit_libcall (const char *name, enum rtx_code code,
919 enum machine_mode dmode, enum machine_mode smode,
920 int noperands, rtx *operands)
922 rtx ret;
923 rtx insns;
924 rtx libcall;
925 rtx equiv;
927 start_sequence ();
928 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
929 switch (noperands)
931 case 2:
932 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
933 dmode, 1, operands[1], smode);
934 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
935 break;
937 case 3:
938 ret = emit_library_call_value (libcall, NULL_RTX,
939 LCT_CONST, dmode, 2,
940 operands[1], smode, operands[2],
941 smode);
942 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
943 break;
945 default:
946 gcc_unreachable ();
949 insns = get_insns ();
950 end_sequence ();
951 emit_libcall_block (insns, operands[0], ret, equiv);
954 /* Returns true if X is a PRE/POST increment decrement
955 (same as auto_inc_p() in rtlanal.c but do not take into
956 account the stack). */
958 m68hc11_auto_inc_p (rtx x)
960 return GET_CODE (x) == PRE_DEC
961 || GET_CODE (x) == POST_INC
962 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
966 /* Predicates for machine description. */
969 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
971 return GET_CODE (operand) == MEM
972 && GET_CODE (XEXP (operand, 0)) == PLUS
973 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
974 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
975 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
976 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
980 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
982 if (GET_CODE (operand) == MEM)
984 rtx op = XEXP (operand, 0);
986 if (symbolic_memory_operand (op, mode))
987 return 1;
989 return 0;
993 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
995 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
997 rtx op = XEXP (operand, 0);
998 int addr_mode;
1000 if (m68hc11_page0_symbol_p (op))
1001 return 1;
1003 if (symbolic_memory_operand (op, mode))
1004 return TARGET_M6812;
1006 if (reload_in_progress)
1007 return 1;
1009 operand = XEXP (operand, 0);
1010 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1011 return m68hc11_valid_addressing_p (operand, mode, addr_mode);
1013 return 0;
1017 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1019 if (GET_CODE (operand) != MEM)
1020 return 0;
1022 operand = XEXP (operand, 0);
1023 if (GET_CODE (operand) == PLUS)
1025 if (GET_CODE (XEXP (operand, 0)) == REG)
1026 operand = XEXP (operand, 0);
1027 else if (GET_CODE (XEXP (operand, 1)) == REG)
1028 operand = XEXP (operand, 1);
1030 return GET_CODE (operand) == REG
1031 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1032 || A_REGNO_P (REGNO (operand)));
1036 push_pop_operand_p (rtx operand)
1038 if (GET_CODE (operand) != MEM)
1040 return 0;
1042 operand = XEXP (operand, 0);
1043 return PUSH_POP_ADDRESS_P (operand);
1046 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1047 reference and a constant. */
1050 symbolic_memory_operand (rtx op, enum machine_mode mode)
1052 switch (GET_CODE (op))
1054 case SYMBOL_REF:
1055 case LABEL_REF:
1056 return 1;
1058 case CONST:
1059 op = XEXP (op, 0);
1060 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1061 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1062 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1064 /* ??? This clause seems to be irrelevant. */
1065 case CONST_DOUBLE:
1066 return GET_MODE (op) == mode;
1068 case PLUS:
1069 return symbolic_memory_operand (XEXP (op, 0), mode)
1070 && symbolic_memory_operand (XEXP (op, 1), mode);
1072 default:
1073 return 0;
1077 /* Emit the code to build the trampoline used to call a nested function.
1079 68HC11 68HC12
1081 ldy #&CXT movw #&CXT,*_.d1
1082 sty *_.d1 jmp FNADDR
1083 jmp FNADDR
1086 static void
1087 m68hc11_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
1089 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1090 rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
1091 rtx mem;
1093 /* Skip the '*'. */
1094 if (*static_chain_reg == '*')
1095 static_chain_reg++;
1096 if (TARGET_M6811)
1098 mem = adjust_address (m_tramp, HImode, 0);
1099 emit_move_insn (mem, GEN_INT (0x18ce));
1100 mem = adjust_address (m_tramp, HImode, 2);
1101 emit_move_insn (mem, cxt);
1102 mem = adjust_address (m_tramp, HImode, 4);
1103 emit_move_insn (mem, GEN_INT (0x18df));
1104 mem = adjust_address (m_tramp, QImode, 6);
1105 emit_move_insn (mem,
1106 gen_rtx_CONST (QImode,
1107 gen_rtx_SYMBOL_REF (Pmode,
1108 static_chain_reg)));
1109 mem = adjust_address (m_tramp, QImode, 7);
1110 emit_move_insn (mem, GEN_INT (0x7e));
1111 mem = adjust_address (m_tramp, HImode, 8);
1112 emit_move_insn (mem, fnaddr);
1114 else
1116 mem = adjust_address (m_tramp, HImode, 0);
1117 emit_move_insn (mem, GEN_INT (0x1803));
1118 mem = adjust_address (m_tramp, HImode, 2);
1119 emit_move_insn (mem, cxt);
1120 mem = adjust_address (m_tramp, HImode, 4);
1121 emit_move_insn (mem,
1122 gen_rtx_CONST (HImode,
1123 gen_rtx_SYMBOL_REF (Pmode,
1124 static_chain_reg)));
1125 mem = adjust_address (m_tramp, QImode, 6);
1126 emit_move_insn (mem, GEN_INT (0x06));
1127 mem = adjust_address (m_tramp, HImode, 7);
1128 emit_move_insn (mem, fnaddr);
1132 /* Declaration of types. */
1134 /* Handle an "tiny_data" attribute; arguments as in
1135 struct attribute_spec.handler. */
1136 static tree
1137 m68hc11_handle_page0_attribute (tree *node, tree name,
1138 tree args ATTRIBUTE_UNUSED,
1139 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1141 tree decl = *node;
1143 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1145 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1147 else
1149 warning (OPT_Wattributes, "%qE attribute ignored",
1150 name);
1151 *no_add_attrs = true;
1154 return NULL_TREE;
1157 /* Keep track of the symbol which has a `trap' attribute and which uses
1158 the `swi' calling convention. Since there is only one trap, we only
1159 record one such symbol. If there are several, a warning is reported. */
1160 static rtx trap_handler_symbol = 0;
1162 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1163 arguments as in struct attribute_spec.handler. */
1164 static tree
1165 m68hc11_handle_fntype_attribute (tree *node, tree name,
1166 tree args ATTRIBUTE_UNUSED,
1167 int flags ATTRIBUTE_UNUSED,
1168 bool *no_add_attrs)
1170 if (TREE_CODE (*node) != FUNCTION_TYPE
1171 && TREE_CODE (*node) != METHOD_TYPE
1172 && TREE_CODE (*node) != FIELD_DECL
1173 && TREE_CODE (*node) != TYPE_DECL)
1175 warning (OPT_Wattributes, "%qE attribute only applies to functions",
1176 name);
1177 *no_add_attrs = true;
1180 return NULL_TREE;
1182 /* Undo the effects of the above. */
1184 static const char *
1185 m68hc11_strip_name_encoding (const char *str)
1187 return str + (*str == '*' || *str == '@' || *str == '&');
1190 static void
1191 m68hc11_encode_label (tree decl)
1193 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1194 int len = strlen (str);
1195 char *newstr = XALLOCAVEC (char, len + 2);
1197 newstr[0] = '@';
1198 strcpy (&newstr[1], str);
1200 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1203 /* Return 1 if this is a symbol in page0 */
1205 m68hc11_page0_symbol_p (rtx x)
1207 switch (GET_CODE (x))
1209 case SYMBOL_REF:
1210 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1212 case CONST:
1213 return m68hc11_page0_symbol_p (XEXP (x, 0));
1215 case PLUS:
1216 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1217 return 0;
1219 return GET_CODE (XEXP (x, 1)) == CONST_INT
1220 && INTVAL (XEXP (x, 1)) < 256
1221 && INTVAL (XEXP (x, 1)) >= 0;
1223 default:
1224 return 0;
1228 /* We want to recognize trap handlers so that we handle calls to traps
1229 in a special manner (by issuing the trap). This information is stored
1230 in SYMBOL_REF_FLAG. */
1232 static void
1233 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1235 tree func_attr;
1236 int trap_handler;
1237 int is_far = 0;
1239 if (TREE_CODE (decl) == VAR_DECL)
1241 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1242 m68hc11_encode_label (decl);
1243 return;
1246 if (TREE_CODE (decl) != FUNCTION_DECL)
1247 return;
1249 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1252 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1253 is_far = 1;
1254 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1255 is_far = TARGET_LONG_CALLS != 0;
1257 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1258 if (trap_handler && is_far)
1260 warning (OPT_Wattributes, "%<trap%> and %<far%> attributes are "
1261 "not compatible, ignoring %<far%>");
1262 trap_handler = 0;
1264 if (trap_handler)
1266 if (trap_handler_symbol != 0)
1267 warning (OPT_Wattributes, "%<trap%> attribute is already used");
1268 else
1269 trap_handler_symbol = XEXP (rtl, 0);
1271 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1274 static unsigned int
1275 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1277 unsigned int flags = default_section_type_flags (decl, name, reloc);
1279 if (strncmp (name, ".eeprom", 7) == 0)
1281 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1284 return flags;
1288 m68hc11_is_far_symbol (rtx sym)
1290 if (GET_CODE (sym) == MEM)
1291 sym = XEXP (sym, 0);
1293 return SYMBOL_REF_FLAG (sym);
1297 m68hc11_is_trap_symbol (rtx sym)
1299 if (GET_CODE (sym) == MEM)
1300 sym = XEXP (sym, 0);
1302 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1306 /* Argument support functions. */
1308 /* Given FROM and TO register numbers, say whether this elimination is
1309 allowed. Frame pointer elimination is automatically handled.
1311 All other eliminations are valid. */
1313 bool
1314 m68hc11_can_eliminate (const int from, const int to)
1316 return (from == ARG_POINTER_REGNUM && to == STACK_POINTER_REGNUM
1317 ? ! frame_pointer_needed
1318 : true);
1321 /* Define the offset between two registers, one to be eliminated, and the
1322 other its replacement, at the start of a routine. */
1324 m68hc11_initial_elimination_offset (int from, int to)
1326 int trap_handler;
1327 tree func_attr;
1328 int size;
1329 int regno;
1331 /* For a trap handler, we must take into account the registers which
1332 are pushed on the stack during the trap (except the PC). */
1333 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1334 current_function_interrupt = lookup_attribute ("interrupt",
1335 func_attr) != NULL_TREE;
1336 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1338 if (lookup_attribute ("far", func_attr) != 0)
1339 current_function_far = 1;
1340 else if (lookup_attribute ("near", func_attr) != 0)
1341 current_function_far = 0;
1342 else
1343 current_function_far = (TARGET_LONG_CALLS != 0
1344 && !current_function_interrupt
1345 && !trap_handler);
1347 if (trap_handler && from == ARG_POINTER_REGNUM)
1348 size = 7;
1350 /* For a function using 'call/rtc' we must take into account the
1351 page register which is pushed in the call. */
1352 else if (current_function_far && from == ARG_POINTER_REGNUM)
1353 size = 1;
1354 else
1355 size = 0;
1357 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1359 /* 2 is for the saved frame.
1360 1 is for the 'sts' correction when creating the frame. */
1361 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1364 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1366 return m68hc11_sp_correction;
1369 /* Push any 2 byte pseudo hard registers that we need to save. */
1370 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1372 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1374 size += 2;
1378 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1380 return get_frame_size () + size;
1383 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1385 return size;
1387 return 0;
1390 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1391 for a call to a function whose data type is FNTYPE.
1392 For a library call, FNTYPE is 0. */
1394 void
1395 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1397 tree ret_type;
1399 z_replacement_completed = 0;
1400 cum->words = 0;
1401 cum->nregs = 0;
1403 /* For a library call, we must find out the type of the return value.
1404 When the return value is bigger than 4 bytes, it is returned in
1405 memory. In that case, the first argument of the library call is a
1406 pointer to the memory location. Because the first argument is passed in
1407 register D, we have to identify this, so that the first function
1408 parameter is not passed in D either. */
1409 if (fntype == 0)
1411 const char *name;
1412 size_t len;
1414 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1415 return;
1417 /* If the library ends in 'di' or in 'df', we assume it's
1418 returning some DImode or some DFmode which are 64-bit wide. */
1419 name = XSTR (libname, 0);
1420 len = strlen (name);
1421 if (len > 3
1422 && ((name[len - 2] == 'd'
1423 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1424 || (name[len - 3] == 'd'
1425 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1427 /* We are in. Mark the first parameter register as already used. */
1428 cum->words = 1;
1429 cum->nregs = 1;
1431 return;
1434 ret_type = TREE_TYPE (fntype);
1436 if (ret_type && aggregate_value_p (ret_type, fntype))
1438 cum->words = 1;
1439 cum->nregs = 1;
1443 /* Update the data in CUM to advance over an argument
1444 of mode MODE and data type TYPE.
1445 (TYPE is null for libcalls where that information may not be available.) */
1447 void
1448 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1449 tree type, int named ATTRIBUTE_UNUSED)
1451 if (mode != BLKmode)
1453 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1455 cum->nregs = 2;
1456 cum->words = GET_MODE_SIZE (mode);
1458 else
1460 cum->words += GET_MODE_SIZE (mode);
1461 if (cum->words <= HARD_REG_SIZE)
1462 cum->nregs = 1;
1465 else
1467 cum->words += int_size_in_bytes (type);
1469 return;
1472 /* Define where to put the arguments to a function.
1473 Value is zero to push the argument on the stack,
1474 or a hard register in which to store the argument.
1476 MODE is the argument's machine mode.
1477 TYPE is the data type of the argument (as a tree).
1478 This is null for libcalls where that information may
1479 not be available.
1480 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1481 the preceding args and about the function being called.
1482 NAMED is nonzero if this argument is a named parameter
1483 (otherwise it is an extra parameter matching an ellipsis). */
1485 struct rtx_def *
1486 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1487 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1489 if (cum->words != 0)
1491 return NULL_RTX;
1494 if (mode != BLKmode)
1496 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1497 return gen_rtx_REG (mode, HARD_X_REGNUM);
1499 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1501 return NULL_RTX;
1503 return gen_rtx_REG (mode, HARD_D_REGNUM);
1505 return NULL_RTX;
1508 /* If defined, a C expression which determines whether, and in which direction,
1509 to pad out an argument with extra space. The value should be of type
1510 `enum direction': either `upward' to pad above the argument,
1511 `downward' to pad below, or `none' to inhibit padding.
1513 Structures are stored left shifted in their argument slot. */
1514 enum direction
1515 m68hc11_function_arg_padding (enum machine_mode mode, const_tree type)
1517 if (type != 0 && AGGREGATE_TYPE_P (type))
1518 return upward;
1520 /* Fall back to the default. */
1521 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1525 /* Function prologue and epilogue. */
1527 /* Emit a move after the reload pass has completed. This is used to
1528 emit the prologue and epilogue. */
1529 static void
1530 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1532 rtx insn;
1534 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1536 insn = emit_move_insn (to, from);
1538 else
1540 emit_move_insn (scratch, from);
1541 insn = emit_move_insn (to, scratch);
1544 /* Put a REG_INC note to tell the flow analysis that the instruction
1545 is necessary. */
1546 if (IS_STACK_PUSH (to))
1547 add_reg_note (insn, REG_INC, XEXP (XEXP (to, 0), 0));
1548 else if (IS_STACK_POP (from))
1549 add_reg_note (insn, REG_INC, XEXP (XEXP (from, 0), 0));
1551 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1552 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1553 The problem is that we are lying to gcc and use `txs' for x = sp
1554 (which is not really true because txs is really x = sp + 1). */
1555 else if (TARGET_M6811 && SP_REG_P (from))
1556 add_reg_note (insn, REG_INC, from);
1560 m68hc11_total_frame_size (void)
1562 int size;
1563 int regno;
1565 size = get_frame_size ();
1566 if (current_function_interrupt)
1568 size += 3 * HARD_REG_SIZE;
1570 if (frame_pointer_needed)
1571 size += HARD_REG_SIZE;
1573 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1574 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1575 size += HARD_REG_SIZE;
1577 return size;
1580 static void
1581 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1582 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1584 /* We catch the function epilogue generation to have a chance
1585 to clear the z_replacement_completed flag. */
1586 z_replacement_completed = 0;
1589 void
1590 expand_prologue (void)
1592 tree func_attr;
1593 int size;
1594 int regno;
1595 rtx scratch;
1597 gcc_assert (reload_completed == 1);
1599 size = get_frame_size ();
1601 create_regs_rtx ();
1603 /* Generate specific prologue for interrupt handlers. */
1604 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1605 current_function_interrupt = lookup_attribute ("interrupt",
1606 func_attr) != NULL_TREE;
1607 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1608 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1609 current_function_far = 1;
1610 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1611 current_function_far = 0;
1612 else
1613 current_function_far = (TARGET_LONG_CALLS != 0
1614 && !current_function_interrupt
1615 && !current_function_trap);
1617 /* Get the scratch register to build the frame and push registers.
1618 If the first argument is a 32-bit quantity, the D+X registers
1619 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1620 For 68HC12, this scratch register is not used. */
1621 if (crtl->args.info.nregs == 2)
1622 scratch = iy_reg;
1623 else
1624 scratch = ix_reg;
1626 /* Save current stack frame. */
1627 if (frame_pointer_needed)
1628 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1630 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1631 Other soft registers in page0 need not to be saved because they
1632 will be restored by C functions. For a trap handler, we don't
1633 need to preserve these registers because this is a synchronous call. */
1634 if (current_function_interrupt)
1636 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1637 emit_move_after_reload (stack_push_word,
1638 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1639 emit_move_after_reload (stack_push_word,
1640 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1641 scratch);
1644 /* Allocate local variables. */
1645 if (TARGET_M6812 && (size > 4 || size == 3))
1647 emit_insn (gen_addhi3 (stack_pointer_rtx,
1648 stack_pointer_rtx, GEN_INT (-size)));
1650 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1652 rtx insn;
1654 insn = gen_rtx_PARALLEL
1655 (VOIDmode,
1656 gen_rtvec (2,
1657 gen_rtx_SET (VOIDmode,
1658 stack_pointer_rtx,
1659 gen_rtx_PLUS (HImode,
1660 stack_pointer_rtx,
1661 GEN_INT (-size))),
1662 gen_rtx_CLOBBER (VOIDmode, scratch)));
1663 emit_insn (insn);
1665 else
1667 int i;
1669 /* Allocate by pushing scratch values. */
1670 for (i = 2; i <= size; i += 2)
1671 emit_move_after_reload (stack_push_word, ix_reg, 0);
1673 if (size & 1)
1674 emit_insn (gen_addhi3 (stack_pointer_rtx,
1675 stack_pointer_rtx, constm1_rtx));
1678 /* Create the frame pointer. */
1679 if (frame_pointer_needed)
1680 emit_move_after_reload (hard_frame_pointer_rtx,
1681 stack_pointer_rtx, scratch);
1683 /* Push any 2 byte pseudo hard registers that we need to save. */
1684 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1686 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1688 emit_move_after_reload (stack_push_word,
1689 gen_rtx_REG (HImode, regno), scratch);
1694 void
1695 expand_epilogue (void)
1697 int size;
1698 register int regno;
1699 int return_size;
1700 rtx scratch;
1702 gcc_assert (reload_completed == 1);
1704 size = get_frame_size ();
1706 /* If we are returning a value in two registers, we have to preserve the
1707 X register and use the Y register to restore the stack and the saved
1708 registers. Otherwise, use X because it's faster (and smaller). */
1709 if (crtl->return_rtx == 0)
1710 return_size = 0;
1711 else if (GET_CODE (crtl->return_rtx) == MEM)
1712 return_size = HARD_REG_SIZE;
1713 else
1714 return_size = GET_MODE_SIZE (GET_MODE (crtl->return_rtx));
1716 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1717 scratch = iy_reg;
1718 else
1719 scratch = ix_reg;
1721 /* Pop any 2 byte pseudo hard registers that we saved. */
1722 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1724 if (df_regs_ever_live_p (regno) && !call_used_regs[regno])
1726 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1727 stack_pop_word, scratch);
1731 /* de-allocate auto variables */
1732 if (TARGET_M6812 && (size > 4 || size == 3))
1734 emit_insn (gen_addhi3 (stack_pointer_rtx,
1735 stack_pointer_rtx, GEN_INT (size)));
1737 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1739 rtx insn;
1741 insn = gen_rtx_PARALLEL
1742 (VOIDmode,
1743 gen_rtvec (2,
1744 gen_rtx_SET (VOIDmode,
1745 stack_pointer_rtx,
1746 gen_rtx_PLUS (HImode,
1747 stack_pointer_rtx,
1748 GEN_INT (size))),
1749 gen_rtx_CLOBBER (VOIDmode, scratch)));
1750 emit_insn (insn);
1752 else
1754 int i;
1756 for (i = 2; i <= size; i += 2)
1757 emit_move_after_reload (scratch, stack_pop_word, scratch);
1758 if (size & 1)
1759 emit_insn (gen_addhi3 (stack_pointer_rtx,
1760 stack_pointer_rtx, const1_rtx));
1763 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1764 if (current_function_interrupt)
1766 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1767 stack_pop_word, scratch);
1768 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1769 stack_pop_word, scratch);
1770 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1773 /* Restore previous frame pointer. */
1774 if (frame_pointer_needed)
1775 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1777 /* If the trap handler returns some value, copy the value
1778 in D, X onto the stack so that the rti will pop the return value
1779 correctly. */
1780 else if (current_function_trap && return_size != 0)
1782 rtx addr_reg = stack_pointer_rtx;
1784 if (!TARGET_M6812)
1786 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1787 addr_reg = scratch;
1789 emit_move_after_reload (gen_rtx_MEM (HImode,
1790 gen_rtx_PLUS (HImode, addr_reg,
1791 const1_rtx)), d_reg, 0);
1792 if (return_size > HARD_REG_SIZE)
1793 emit_move_after_reload (gen_rtx_MEM (HImode,
1794 gen_rtx_PLUS (HImode, addr_reg,
1795 GEN_INT (3))), ix_reg, 0);
1798 emit_jump_insn (gen_return ());
1802 /* Low and High part extraction for 68HC11. These routines are
1803 similar to gen_lowpart and gen_highpart but they have been
1804 fixed to work for constants and 68HC11 specific registers. */
1807 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1809 /* We assume that the low part of an auto-inc mode is the same with
1810 the mode changed and that the caller split the larger mode in the
1811 correct order. */
1812 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1814 return gen_rtx_MEM (mode, XEXP (x, 0));
1817 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1818 floating-point constant. A CONST_DOUBLE is used whenever the
1819 constant requires more than one word in order to be adequately
1820 represented. */
1821 if (GET_CODE (x) == CONST_DOUBLE)
1823 long l[2];
1825 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1827 REAL_VALUE_TYPE r;
1829 if (GET_MODE (x) == SFmode)
1831 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1832 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1834 else
1836 rtx first, second;
1838 split_double (x, &first, &second);
1839 return second;
1841 if (mode == SImode)
1842 return GEN_INT (l[0]);
1844 return gen_int_mode (l[0], HImode);
1846 else
1848 l[0] = CONST_DOUBLE_LOW (x);
1850 switch (mode)
1852 case SImode:
1853 return GEN_INT (l[0]);
1854 case HImode:
1855 gcc_assert (GET_MODE (x) == SFmode);
1856 return gen_int_mode (l[0], HImode);
1857 default:
1858 gcc_unreachable ();
1862 if (mode == QImode && D_REG_P (x))
1863 return gen_rtx_REG (mode, HARD_B_REGNUM);
1865 /* gen_lowpart crashes when it is called with a SUBREG. */
1866 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1868 switch (mode)
1870 case SImode:
1871 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1872 case HImode:
1873 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1874 default:
1875 gcc_unreachable ();
1878 x = gen_lowpart (mode, x);
1880 /* Return a different rtx to avoid to share it in several insns
1881 (when used by a split pattern). Sharing addresses within
1882 a MEM breaks the Z register replacement (and reloading). */
1883 if (GET_CODE (x) == MEM)
1884 x = copy_rtx (x);
1885 return x;
1889 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1891 /* We assume that the high part of an auto-inc mode is the same with
1892 the mode changed and that the caller split the larger mode in the
1893 correct order. */
1894 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1896 return gen_rtx_MEM (mode, XEXP (x, 0));
1899 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1900 floating-point constant. A CONST_DOUBLE is used whenever the
1901 constant requires more than one word in order to be adequately
1902 represented. */
1903 if (GET_CODE (x) == CONST_DOUBLE)
1905 long l[2];
1907 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1909 REAL_VALUE_TYPE r;
1911 if (GET_MODE (x) == SFmode)
1913 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1914 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1916 else
1918 rtx first, second;
1920 split_double (x, &first, &second);
1921 return first;
1923 if (mode == SImode)
1924 return GEN_INT (l[1]);
1926 return gen_int_mode ((l[1] >> 16), HImode);
1928 else
1930 l[1] = CONST_DOUBLE_HIGH (x);
1933 switch (mode)
1935 case SImode:
1936 return GEN_INT (l[1]);
1937 case HImode:
1938 gcc_assert (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT);
1939 return gen_int_mode ((l[0] >> 16), HImode);
1940 default:
1941 gcc_unreachable ();
1944 if (GET_CODE (x) == CONST_INT)
1946 HOST_WIDE_INT val = INTVAL (x);
1948 if (mode == QImode)
1950 return gen_int_mode (val >> 8, QImode);
1952 else if (mode == HImode)
1954 return gen_int_mode (val >> 16, HImode);
1956 else if (mode == SImode)
1958 return gen_int_mode (val >> 32, SImode);
1961 if (mode == QImode && D_REG_P (x))
1962 return gen_rtx_REG (mode, HARD_A_REGNUM);
1964 /* There is no way in GCC to represent the upper part of a word register.
1965 To obtain the 8-bit upper part of a soft register, we change the
1966 reg into a mem rtx. This is possible because they are physically
1967 located in memory. There is no offset because we are big-endian. */
1968 if (mode == QImode && S_REG_P (x))
1970 int pos;
1972 /* Avoid the '*' for direct addressing mode when this
1973 addressing mode is disabled. */
1974 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1975 return gen_rtx_MEM (QImode,
1976 gen_rtx_SYMBOL_REF (Pmode,
1977 &reg_names[REGNO (x)][pos]));
1980 /* gen_highpart crashes when it is called with a SUBREG. */
1981 switch (GET_CODE (x))
1983 case SUBREG:
1984 return gen_rtx_SUBREG (mode, XEXP (x, 0), XINT (x, 1));
1985 case REG:
1986 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1987 return gen_rtx_REG (mode, REGNO (x));
1988 else
1989 return gen_rtx_SUBREG (mode, x, 0);
1990 case MEM:
1991 x = change_address (x, mode, 0);
1993 /* Return a different rtx to avoid to share it in several insns
1994 (when used by a split pattern). Sharing addresses within
1995 a MEM breaks the Z register replacement (and reloading). */
1996 if (GET_CODE (x) == MEM)
1997 x = copy_rtx (x);
1998 return x;
2000 default:
2001 gcc_unreachable ();
2006 /* Obscure register manipulation. */
2008 /* Finds backward in the instructions to see if register 'reg' is
2009 dead. This is used when generating code to see if we can use 'reg'
2010 as a scratch register. This allows us to choose a better generation
2011 of code when we know that some register dies or can be clobbered. */
2014 dead_register_here (rtx x, rtx reg)
2016 rtx x_reg;
2017 rtx p;
2019 if (D_REG_P (reg))
2020 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2021 else
2022 x_reg = 0;
2024 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2025 if (INSN_P (p))
2027 rtx body;
2029 body = PATTERN (p);
2031 if (GET_CODE (body) == CALL_INSN)
2032 break;
2033 if (GET_CODE (body) == JUMP_INSN)
2034 break;
2036 if (GET_CODE (body) == SET)
2038 rtx dst = XEXP (body, 0);
2040 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2041 break;
2042 if (x_reg && rtx_equal_p (dst, x_reg))
2043 break;
2045 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2046 return 1;
2048 else if (reg_mentioned_p (reg, p)
2049 || (x_reg && reg_mentioned_p (x_reg, p)))
2050 break;
2053 /* Scan forward to see if the register is set in some insns and never
2054 used since then. */
2055 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2057 rtx body;
2059 if (GET_CODE (p) == CODE_LABEL
2060 || GET_CODE (p) == JUMP_INSN
2061 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2062 break;
2064 if (GET_CODE (p) != INSN)
2065 continue;
2067 body = PATTERN (p);
2068 if (GET_CODE (body) == SET)
2070 rtx src = XEXP (body, 1);
2071 rtx dst = XEXP (body, 0);
2073 if (GET_CODE (dst) == REG
2074 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2075 return 1;
2078 /* Register is used (may be in source or in dest). */
2079 if (reg_mentioned_p (reg, p)
2080 || (x_reg != 0 && GET_MODE (p) == SImode
2081 && reg_mentioned_p (x_reg, p)))
2082 break;
2084 return p == 0 ? 1 : 0;
2088 /* Code generation operations called from machine description file. */
2090 /* Print the name of register 'regno' in the assembly file. */
2091 static void
2092 asm_print_register (FILE *file, int regno)
2094 const char *name = reg_names[regno];
2096 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2097 name++;
2099 fprintf (file, "%s", name);
2102 /* A C compound statement to output to stdio stream STREAM the
2103 assembler syntax for an instruction operand X. X is an RTL
2104 expression.
2106 CODE is a value that can be used to specify one of several ways
2107 of printing the operand. It is used when identical operands
2108 must be printed differently depending on the context. CODE
2109 comes from the `%' specification that was used to request
2110 printing of the operand. If the specification was just `%DIGIT'
2111 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2112 is the ASCII code for LTR.
2114 If X is a register, this macro should print the register's name.
2115 The names can be found in an array `reg_names' whose type is
2116 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2118 When the machine description has a specification `%PUNCT' (a `%'
2119 followed by a punctuation character), this macro is called with
2120 a null pointer for X and the punctuation character for CODE.
2122 The M68HC11 specific codes are:
2124 'b' for the low part of the operand.
2125 'h' for the high part of the operand
2126 The 'b' or 'h' modifiers have no effect if the operand has
2127 the QImode and is not a S_REG_P (soft register). If the
2128 operand is a hard register, these two modifiers have no effect.
2129 't' generate the temporary scratch register. The operand is
2130 ignored.
2131 'T' generate the low-part temporary scratch register. The operand is
2132 ignored. */
2134 static void
2135 m68hc11_print_operand (FILE *file, rtx op, int letter)
2137 if (letter == 't')
2139 asm_print_register (file, SOFT_TMP_REGNUM);
2140 return;
2142 else if (letter == 'T')
2144 asm_print_register (file, SOFT_TMP_REGNUM);
2145 fprintf (file, "+1");
2146 return;
2148 else if (letter == '#')
2150 asm_fprintf (file, "%I");
2153 if (GET_CODE (op) == REG)
2155 if (letter == 'b' && S_REG_P (op))
2157 asm_print_register (file, REGNO (op));
2158 fprintf (file, "+1");
2160 else if (letter == 'b' && D_REG_P (op))
2162 asm_print_register (file, HARD_B_REGNUM);
2164 else
2166 asm_print_register (file, REGNO (op));
2168 return;
2171 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2173 if (letter == 'b')
2174 asm_fprintf (file, "%I%%lo(");
2175 else
2176 asm_fprintf (file, "%I%%hi(");
2178 output_addr_const (file, op);
2179 fprintf (file, ")");
2180 return;
2183 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2184 are specified. If we already have a QImode, there is nothing to do. */
2185 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2187 if (letter == 'b')
2189 op = m68hc11_gen_lowpart (QImode, op);
2191 else if (letter == 'h')
2193 op = m68hc11_gen_highpart (QImode, op);
2197 if (GET_CODE (op) == MEM)
2199 rtx base = XEXP (op, 0);
2200 switch (GET_CODE (base))
2202 case PRE_DEC:
2203 gcc_assert (TARGET_M6812);
2204 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2205 asm_print_register (file, REGNO (XEXP (base, 0)));
2206 break;
2208 case POST_DEC:
2209 gcc_assert (TARGET_M6812);
2210 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2211 asm_print_register (file, REGNO (XEXP (base, 0)));
2212 fprintf (file, "-");
2213 break;
2215 case POST_INC:
2216 gcc_assert (TARGET_M6812);
2217 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2218 asm_print_register (file, REGNO (XEXP (base, 0)));
2219 fprintf (file, "+");
2220 break;
2222 case PRE_INC:
2223 gcc_assert (TARGET_M6812);
2224 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2225 asm_print_register (file, REGNO (XEXP (base, 0)));
2226 break;
2228 case MEM:
2229 gcc_assert (TARGET_M6812);
2230 fprintf (file, "[");
2231 print_operand_address (file, XEXP (base, 0));
2232 fprintf (file, "]");
2233 break;
2235 default:
2236 if (m68hc11_page0_symbol_p (base))
2237 fprintf (file, "*");
2239 output_address (base);
2240 break;
2243 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2245 REAL_VALUE_TYPE r;
2246 long l;
2248 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2249 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2250 asm_fprintf (file, "%I0x%lx", l);
2252 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2254 char dstr[30];
2256 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2257 sizeof (dstr), 0, 1);
2258 asm_fprintf (file, "%I0r%s", dstr);
2260 else
2262 int need_parenthesize = 0;
2264 if (letter != 'i')
2265 asm_fprintf (file, "%I");
2266 else
2267 need_parenthesize = must_parenthesize (op);
2269 if (need_parenthesize)
2270 fprintf (file, "(");
2272 output_addr_const (file, op);
2273 if (need_parenthesize)
2274 fprintf (file, ")");
2278 /* Returns true if the operand 'op' must be printed with parenthesis
2279 around it. This must be done only if there is a symbol whose name
2280 is a processor register. */
2281 static int
2282 must_parenthesize (rtx op)
2284 const char *name;
2286 switch (GET_CODE (op))
2288 case SYMBOL_REF:
2289 name = XSTR (op, 0);
2290 /* Avoid a conflict between symbol name and a possible
2291 register. */
2292 return (strcasecmp (name, "a") == 0
2293 || strcasecmp (name, "b") == 0
2294 || strcasecmp (name, "d") == 0
2295 || strcasecmp (name, "x") == 0
2296 || strcasecmp (name, "y") == 0
2297 || strcasecmp (name, "ix") == 0
2298 || strcasecmp (name, "iy") == 0
2299 || strcasecmp (name, "pc") == 0
2300 || strcasecmp (name, "sp") == 0
2301 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2303 case PLUS:
2304 case MINUS:
2305 return must_parenthesize (XEXP (op, 0))
2306 || must_parenthesize (XEXP (op, 1));
2308 case MEM:
2309 case CONST:
2310 case ZERO_EXTEND:
2311 case SIGN_EXTEND:
2312 return must_parenthesize (XEXP (op, 0));
2314 case CONST_DOUBLE:
2315 case CONST_INT:
2316 case LABEL_REF:
2317 case CODE_LABEL:
2318 default:
2319 return 0;
2323 /* A C compound statement to output to stdio stream STREAM the
2324 assembler syntax for an instruction operand that is a memory
2325 reference whose address is ADDR. ADDR is an RTL expression. */
2327 static void
2328 m68hc11_print_operand_address (FILE *file, rtx addr)
2330 rtx base;
2331 rtx offset;
2332 int need_parenthesis = 0;
2334 switch (GET_CODE (addr))
2336 case REG:
2337 gcc_assert (REG_P (addr) && REG_OK_FOR_BASE_STRICT_P (addr));
2339 fprintf (file, "0,");
2340 asm_print_register (file, REGNO (addr));
2341 break;
2343 case MEM:
2344 base = XEXP (addr, 0);
2345 switch (GET_CODE (base))
2347 case PRE_DEC:
2348 gcc_assert (TARGET_M6812);
2349 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2350 asm_print_register (file, REGNO (XEXP (base, 0)));
2351 break;
2353 case POST_DEC:
2354 gcc_assert (TARGET_M6812);
2355 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2356 asm_print_register (file, REGNO (XEXP (base, 0)));
2357 fprintf (file, "-");
2358 break;
2360 case POST_INC:
2361 gcc_assert (TARGET_M6812);
2362 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2363 asm_print_register (file, REGNO (XEXP (base, 0)));
2364 fprintf (file, "+");
2365 break;
2367 case PRE_INC:
2368 gcc_assert (TARGET_M6812);
2369 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2370 asm_print_register (file, REGNO (XEXP (base, 0)));
2371 break;
2373 default:
2374 need_parenthesis = must_parenthesize (base);
2375 if (need_parenthesis)
2376 fprintf (file, "(");
2378 output_addr_const (file, base);
2379 if (need_parenthesis)
2380 fprintf (file, ")");
2381 break;
2383 break;
2385 case PLUS:
2386 base = XEXP (addr, 0);
2387 offset = XEXP (addr, 1);
2388 if (!G_REG_P (base) && G_REG_P (offset))
2390 base = XEXP (addr, 1);
2391 offset = XEXP (addr, 0);
2393 if (CONSTANT_ADDRESS_P (base))
2395 need_parenthesis = must_parenthesize (addr);
2397 gcc_assert (CONSTANT_ADDRESS_P (offset));
2398 if (need_parenthesis)
2399 fprintf (file, "(");
2401 output_addr_const (file, base);
2402 fprintf (file, "+");
2403 output_addr_const (file, offset);
2404 if (need_parenthesis)
2405 fprintf (file, ")");
2407 else
2409 gcc_assert (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base));
2410 if (REG_P (offset))
2412 gcc_assert (TARGET_M6812);
2413 asm_print_register (file, REGNO (offset));
2414 fprintf (file, ",");
2415 asm_print_register (file, REGNO (base));
2417 else
2419 need_parenthesis = must_parenthesize (offset);
2420 if (need_parenthesis)
2421 fprintf (file, "(");
2423 output_addr_const (file, offset);
2424 if (need_parenthesis)
2425 fprintf (file, ")");
2426 fprintf (file, ",");
2427 asm_print_register (file, REGNO (base));
2430 break;
2432 default:
2433 if (GET_CODE (addr) == CONST_INT
2434 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2436 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2438 else
2440 need_parenthesis = must_parenthesize (addr);
2441 if (need_parenthesis)
2442 fprintf (file, "(");
2444 output_addr_const (file, addr);
2445 if (need_parenthesis)
2446 fprintf (file, ")");
2448 break;
2453 /* Splitting of some instructions. */
2455 static rtx
2456 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2458 rtx ret = 0;
2460 gcc_assert (GET_MODE_CLASS (GET_MODE (op0)) != MODE_FLOAT);
2461 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2462 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2463 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2465 return ret;
2469 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2470 rtx label)
2472 rtx tmp;
2474 switch (GET_MODE (op0))
2476 case QImode:
2477 case HImode:
2478 tmp = m68hc11_expand_compare (code, op0, op1);
2479 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2480 gen_rtx_LABEL_REF (VOIDmode, label),
2481 pc_rtx);
2482 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2483 return 0;
2484 #if 0
2486 /* SCz: from i386.c */
2487 case SFmode:
2488 case DFmode:
2489 /* Don't expand the comparison early, so that we get better code
2490 when jump or whoever decides to reverse the comparison. */
2492 rtvec vec;
2493 int use_fcomi;
2495 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2496 &m68hc11_compare_op1);
2498 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2499 m68hc11_compare_op0, m68hc11_compare_op1);
2500 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2501 gen_rtx_LABEL_REF (VOIDmode, label),
2502 pc_rtx);
2503 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2505 use_fcomi = ix86_use_fcomi_compare (code);
2506 vec = rtvec_alloc (3 + !use_fcomi);
2507 RTVEC_ELT (vec, 0) = tmp;
2508 RTVEC_ELT (vec, 1)
2509 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2510 RTVEC_ELT (vec, 2)
2511 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2512 if (!use_fcomi)
2513 RTVEC_ELT (vec, 3)
2514 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2516 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2517 return;
2519 #endif
2521 case SImode:
2522 /* Expand SImode branch into multiple compare+branch. */
2524 rtx lo[2], hi[2], label2;
2525 enum rtx_code code1, code2, code3;
2527 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2529 tmp = op0;
2530 op0 = op1;
2531 op1 = tmp;
2532 code = swap_condition (code);
2534 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2535 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2536 hi[0] = m68hc11_gen_highpart (HImode, op0);
2537 hi[1] = m68hc11_gen_highpart (HImode, op1);
2539 /* Otherwise, if we are doing less-than, op1 is a constant and the
2540 low word is zero, then we can just examine the high word. */
2542 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2543 && (code == LT || code == LTU))
2545 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2546 label);
2549 /* Otherwise, we need two or three jumps. */
2551 label2 = gen_label_rtx ();
2553 code1 = code;
2554 code2 = swap_condition (code);
2555 code3 = unsigned_condition (code);
2557 switch (code)
2559 case LT:
2560 case GT:
2561 case LTU:
2562 case GTU:
2563 break;
2565 case LE:
2566 code1 = LT;
2567 code2 = GT;
2568 break;
2569 case GE:
2570 code1 = GT;
2571 code2 = LT;
2572 break;
2573 case LEU:
2574 code1 = LTU;
2575 code2 = GTU;
2576 break;
2577 case GEU:
2578 code1 = GTU;
2579 code2 = LTU;
2580 break;
2582 case EQ:
2583 code1 = UNKNOWN;
2584 code2 = NE;
2585 break;
2586 case NE:
2587 code2 = UNKNOWN;
2588 break;
2590 default:
2591 gcc_unreachable ();
2595 * a < b =>
2596 * if (hi(a) < hi(b)) goto true;
2597 * if (hi(a) > hi(b)) goto false;
2598 * if (lo(a) < lo(b)) goto true;
2599 * false:
2601 if (code1 != UNKNOWN)
2602 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2603 if (code2 != UNKNOWN)
2604 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2606 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2608 if (code2 != UNKNOWN)
2609 emit_label (label2);
2610 return 0;
2613 default:
2614 gcc_unreachable ();
2616 return 0;
2619 /* Return the increment/decrement mode of a MEM if it is such.
2620 Return CONST if it is anything else. */
2621 static int
2622 autoinc_mode (rtx x)
2624 if (GET_CODE (x) != MEM)
2625 return CONST;
2627 x = XEXP (x, 0);
2628 if (GET_CODE (x) == PRE_INC
2629 || GET_CODE (x) == PRE_DEC
2630 || GET_CODE (x) == POST_INC
2631 || GET_CODE (x) == POST_DEC)
2632 return GET_CODE (x);
2634 return CONST;
2637 static int
2638 m68hc11_make_autoinc_notes (rtx *x, void *data)
2640 rtx insn;
2642 switch (GET_CODE (*x))
2644 case PRE_DEC:
2645 case PRE_INC:
2646 case POST_DEC:
2647 case POST_INC:
2648 insn = (rtx) data;
2649 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2650 REG_NOTES (insn));
2651 return -1;
2653 default:
2654 return 0;
2658 /* Split a DI, SI or HI move into several smaller move operations.
2659 The scratch register 'scratch' is used as a temporary to load
2660 store intermediate values. It must be a hard register. */
2661 void
2662 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2664 rtx low_to, low_from;
2665 rtx high_to, high_from;
2666 rtx insn;
2667 enum machine_mode mode;
2668 int offset = 0;
2669 int autoinc_from = autoinc_mode (from);
2670 int autoinc_to = autoinc_mode (to);
2672 mode = GET_MODE (to);
2674 /* If the TO and FROM contain autoinc modes that are not compatible
2675 together (one pop and the other a push), we must change one to
2676 an offsetable operand and generate an appropriate add at the end. */
2677 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2679 rtx reg;
2680 int code;
2682 /* The source uses an autoinc mode which is not compatible with
2683 a split (this would result in a word swap). */
2684 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2686 code = GET_CODE (XEXP (from, 0));
2687 reg = XEXP (XEXP (from, 0), 0);
2688 offset = GET_MODE_SIZE (GET_MODE (from));
2689 if (code == POST_DEC)
2690 offset = -offset;
2692 if (code == PRE_INC)
2693 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2695 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2696 if (code == POST_DEC)
2697 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2698 return;
2701 /* Likewise for destination. */
2702 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2704 code = GET_CODE (XEXP (to, 0));
2705 reg = XEXP (XEXP (to, 0), 0);
2706 offset = GET_MODE_SIZE (GET_MODE (to));
2707 if (code == POST_DEC)
2708 offset = -offset;
2710 if (code == PRE_INC)
2711 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2713 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2714 if (code == POST_DEC)
2715 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2716 return;
2719 /* The source and destination auto increment modes must be compatible
2720 with each other: same direction. */
2721 if ((autoinc_to != autoinc_from
2722 && autoinc_to != CONST && autoinc_from != CONST)
2723 /* The destination address register must not be used within
2724 the source operand because the source address would change
2725 while doing the copy. */
2726 || (autoinc_to != CONST
2727 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2728 && !IS_STACK_PUSH (to)))
2730 /* Must change the destination. */
2731 code = GET_CODE (XEXP (to, 0));
2732 reg = XEXP (XEXP (to, 0), 0);
2733 offset = GET_MODE_SIZE (GET_MODE (to));
2734 if (code == PRE_DEC || code == POST_DEC)
2735 offset = -offset;
2737 if (code == PRE_DEC || code == PRE_INC)
2738 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2739 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2740 if (code == POST_DEC || code == POST_INC)
2741 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2743 return;
2746 /* Likewise, the source address register must not be used within
2747 the destination operand. */
2748 if (autoinc_from != CONST
2749 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2750 && !IS_STACK_PUSH (to))
2752 /* Must change the source. */
2753 code = GET_CODE (XEXP (from, 0));
2754 reg = XEXP (XEXP (from, 0), 0);
2755 offset = GET_MODE_SIZE (GET_MODE (from));
2756 if (code == PRE_DEC || code == POST_DEC)
2757 offset = -offset;
2759 if (code == PRE_DEC || code == PRE_INC)
2760 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2761 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2762 if (code == POST_DEC || code == POST_INC)
2763 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2765 return;
2769 if (GET_MODE_SIZE (mode) == 8)
2770 mode = SImode;
2771 else if (GET_MODE_SIZE (mode) == 4)
2772 mode = HImode;
2773 else
2774 mode = QImode;
2776 if (TARGET_M6812
2777 && IS_STACK_PUSH (to)
2778 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2780 if (mode == SImode)
2782 offset = 4;
2784 else if (mode == HImode)
2786 offset = 2;
2788 else
2789 offset = 0;
2792 low_to = m68hc11_gen_lowpart (mode, to);
2793 high_to = m68hc11_gen_highpart (mode, to);
2795 low_from = m68hc11_gen_lowpart (mode, from);
2796 high_from = m68hc11_gen_highpart (mode, from);
2798 if (offset)
2800 high_from = adjust_address (high_from, mode, offset);
2801 low_from = high_from;
2804 /* When copying with a POST_INC mode, we must copy the
2805 high part and then the low part to guarantee a correct
2806 32/64-bit copy. */
2807 if (TARGET_M6812
2808 && GET_MODE_SIZE (mode) >= 2
2809 && autoinc_from != autoinc_to
2810 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2812 rtx swap;
2814 swap = low_to;
2815 low_to = high_to;
2816 high_to = swap;
2818 swap = low_from;
2819 low_from = high_from;
2820 high_from = swap;
2822 if (mode == SImode)
2824 m68hc11_split_move (low_to, low_from, scratch);
2825 m68hc11_split_move (high_to, high_from, scratch);
2827 else if (H_REG_P (to) || H_REG_P (from)
2828 || (low_from == const0_rtx
2829 && high_from == const0_rtx
2830 && ! push_operand (to, GET_MODE (to))
2831 && ! H_REG_P (scratch))
2832 || (TARGET_M6812
2833 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2834 || m68hc11_small_indexed_indirect_p (from,
2835 GET_MODE (from)))
2836 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2837 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2839 insn = emit_move_insn (low_to, low_from);
2840 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2842 insn = emit_move_insn (high_to, high_from);
2843 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2845 else
2847 insn = emit_move_insn (scratch, low_from);
2848 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2849 insn = emit_move_insn (low_to, scratch);
2850 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2852 insn = emit_move_insn (scratch, high_from);
2853 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2854 insn = emit_move_insn (high_to, scratch);
2855 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2859 static rtx
2860 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2862 int val;
2863 int mask;
2865 *result = 0;
2866 if (GET_CODE (operand) != CONST_INT)
2867 return operand;
2869 if (mode == HImode)
2870 mask = 0x0ffff;
2871 else
2872 mask = 0x0ff;
2874 val = INTVAL (operand);
2875 switch (code)
2877 case IOR:
2878 if ((val & mask) == 0)
2879 return 0;
2880 if ((val & mask) == mask)
2881 *result = constm1_rtx;
2882 break;
2884 case AND:
2885 if ((val & mask) == 0)
2886 *result = const0_rtx;
2887 if ((val & mask) == mask)
2888 return 0;
2889 break;
2891 case XOR:
2892 if ((val & mask) == 0)
2893 return 0;
2894 break;
2896 return operand;
2899 static void
2900 m68hc11_emit_logical (enum machine_mode mode, enum rtx_code code, rtx *operands)
2902 rtx result;
2903 int need_copy;
2905 need_copy = (rtx_equal_p (operands[0], operands[1])
2906 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2908 operands[1] = simplify_logical (mode, code, operands[1], &result);
2909 operands[2] = simplify_logical (mode, code, operands[2], &result);
2911 if (result && GET_CODE (result) == CONST_INT)
2913 if (!H_REG_P (operands[0]) && operands[3]
2914 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2916 emit_move_insn (operands[3], result);
2917 emit_move_insn (operands[0], operands[3]);
2919 else
2921 emit_move_insn (operands[0], result);
2924 else if (operands[1] != 0 && operands[2] != 0)
2926 rtx insn;
2928 if (!H_REG_P (operands[0]) && operands[3])
2930 emit_move_insn (operands[3], operands[1]);
2931 emit_insn (gen_rtx_SET (mode,
2932 operands[3],
2933 gen_rtx_fmt_ee (code, mode,
2934 operands[3], operands[2])));
2935 insn = emit_move_insn (operands[0], operands[3]);
2937 else
2939 insn = emit_insn (gen_rtx_SET (mode,
2940 operands[0],
2941 gen_rtx_fmt_ee (code, mode,
2942 operands[0],
2943 operands[2])));
2947 /* The logical operation is similar to a copy. */
2948 else if (need_copy)
2950 rtx src;
2952 if (GET_CODE (operands[1]) == CONST_INT)
2953 src = operands[2];
2954 else
2955 src = operands[1];
2957 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2959 emit_move_insn (operands[3], src);
2960 emit_move_insn (operands[0], operands[3]);
2962 else
2964 emit_move_insn (operands[0], src);
2969 void
2970 m68hc11_split_logical (enum machine_mode mode, enum rtx_code code,
2971 rtx *operands)
2973 rtx low[4];
2974 rtx high[4];
2976 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2977 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2978 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2980 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2981 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2982 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2984 low[3] = operands[3];
2985 high[3] = operands[3];
2986 if (mode == SImode)
2988 m68hc11_split_logical (HImode, code, low);
2989 m68hc11_split_logical (HImode, code, high);
2990 return;
2993 m68hc11_emit_logical (mode, code, low);
2994 m68hc11_emit_logical (mode, code, high);
2998 /* Code generation. */
3000 void
3001 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3003 /* We have to be careful with the cc_status. An address register swap
3004 is generated for some comparison. The comparison is made with D
3005 but the branch really uses the address register. See the split
3006 pattern for compare. The xgdx/xgdy preserve the flags but after
3007 the exchange, the flags will reflect to the value of X and not D.
3008 Tell this by setting the cc_status according to the cc_prev_status. */
3009 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3011 if (cc_prev_status.value1 != 0
3012 && (D_REG_P (cc_prev_status.value1)
3013 || X_REG_P (cc_prev_status.value1)))
3015 cc_status = cc_prev_status;
3016 if (D_REG_P (cc_status.value1))
3017 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3018 HARD_X_REGNUM);
3019 else
3020 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3021 HARD_D_REGNUM);
3023 else
3024 CC_STATUS_INIT;
3026 output_asm_insn ("xgdx", operands);
3028 else
3030 if (cc_prev_status.value1 != 0
3031 && (D_REG_P (cc_prev_status.value1)
3032 || Y_REG_P (cc_prev_status.value1)))
3034 cc_status = cc_prev_status;
3035 if (D_REG_P (cc_status.value1))
3036 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3037 HARD_Y_REGNUM);
3038 else
3039 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3040 HARD_D_REGNUM);
3042 else
3043 CC_STATUS_INIT;
3045 output_asm_insn ("xgdy", operands);
3049 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3050 This is used to decide whether a move that set flags should be used
3051 instead. */
3053 next_insn_test_reg (rtx insn, rtx reg)
3055 rtx body;
3057 insn = next_nonnote_insn (insn);
3058 if (GET_CODE (insn) != INSN)
3059 return 0;
3061 body = PATTERN (insn);
3062 if (sets_cc0_p (body) != 1)
3063 return 0;
3065 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3066 return 0;
3068 return 1;
3071 /* Generate the code to move a 16-bit operand into another one. */
3073 void
3074 m68hc11_gen_movhi (rtx insn, rtx *operands)
3076 int reg;
3078 /* Move a register or memory to the same location.
3079 This is possible because such insn can appear
3080 in a non-optimizing mode. */
3081 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3083 cc_status = cc_prev_status;
3084 return;
3087 if (TARGET_M6812)
3089 rtx from = operands[1];
3090 rtx to = operands[0];
3092 if (IS_STACK_PUSH (to) && H_REG_P (from))
3094 cc_status = cc_prev_status;
3095 switch (REGNO (from))
3097 case HARD_X_REGNUM:
3098 case HARD_Y_REGNUM:
3099 case HARD_D_REGNUM:
3100 output_asm_insn ("psh%1", operands);
3101 break;
3102 case HARD_SP_REGNUM:
3103 output_asm_insn ("sts\t2,-sp", operands);
3104 break;
3105 default:
3106 gcc_unreachable ();
3108 return;
3110 if (IS_STACK_POP (from) && H_REG_P (to))
3112 cc_status = cc_prev_status;
3113 switch (REGNO (to))
3115 case HARD_X_REGNUM:
3116 case HARD_Y_REGNUM:
3117 case HARD_D_REGNUM:
3118 output_asm_insn ("pul%0", operands);
3119 break;
3120 default:
3121 gcc_unreachable ();
3123 return;
3125 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3127 m68hc11_notice_keep_cc (operands[0]);
3128 output_asm_insn ("tfr\t%1,%0", operands);
3130 else if (H_REG_P (operands[0]))
3132 if (SP_REG_P (operands[0]))
3133 output_asm_insn ("lds\t%1", operands);
3134 else
3135 output_asm_insn ("ld%0\t%1", operands);
3137 else if (H_REG_P (operands[1]))
3139 if (SP_REG_P (operands[1]))
3140 output_asm_insn ("sts\t%0", operands);
3141 else
3142 output_asm_insn ("st%1\t%0", operands);
3145 /* The 68hc12 does not support (MEM:HI (MEM:HI)) with the movw
3146 instruction. We have to use a scratch register as temporary location.
3147 Trying to use a specific pattern or constrain failed. */
3148 else if (GET_CODE (to) == MEM && GET_CODE (XEXP (to, 0)) == MEM)
3150 rtx ops[4];
3152 ops[0] = to;
3153 ops[2] = from;
3154 ops[3] = 0;
3155 if (dead_register_here (insn, d_reg))
3156 ops[1] = d_reg;
3157 else if (dead_register_here (insn, ix_reg))
3158 ops[1] = ix_reg;
3159 else if (dead_register_here (insn, iy_reg))
3160 ops[1] = iy_reg;
3161 else
3163 ops[1] = d_reg;
3164 ops[3] = d_reg;
3165 output_asm_insn ("psh%3", ops);
3168 ops[0] = to;
3169 ops[2] = from;
3170 output_asm_insn ("ld%1\t%2", ops);
3171 output_asm_insn ("st%1\t%0", ops);
3172 if (ops[3])
3173 output_asm_insn ("pul%3", ops);
3176 /* Use movw for non-null constants or when we are clearing
3177 a volatile memory reference. However, this is possible
3178 only if the memory reference has a small offset or is an
3179 absolute address. */
3180 else if (GET_CODE (from) == CONST_INT
3181 && INTVAL (from) == 0
3182 && (MEM_VOLATILE_P (to) == 0
3183 || m68hc11_small_indexed_indirect_p (to, HImode) == 0))
3185 output_asm_insn ("clr\t%h0", operands);
3186 output_asm_insn ("clr\t%b0", operands);
3188 else
3190 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3191 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3192 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3193 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3195 rtx ops[3];
3197 if (operands[2])
3199 ops[0] = operands[2];
3200 ops[1] = from;
3201 ops[2] = 0;
3202 m68hc11_gen_movhi (insn, ops);
3203 ops[0] = to;
3204 ops[1] = operands[2];
3205 m68hc11_gen_movhi (insn, ops);
3206 return;
3208 else
3210 /* !!!! SCz wrong here. */
3211 fatal_insn ("move insn not handled", insn);
3214 else
3216 m68hc11_notice_keep_cc (operands[0]);
3217 output_asm_insn ("movw\t%1,%0", operands);
3220 return;
3223 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3225 cc_status = cc_prev_status;
3226 switch (REGNO (operands[0]))
3228 case HARD_X_REGNUM:
3229 case HARD_Y_REGNUM:
3230 output_asm_insn ("pul%0", operands);
3231 break;
3232 case HARD_D_REGNUM:
3233 output_asm_insn ("pula", operands);
3234 output_asm_insn ("pulb", operands);
3235 break;
3236 default:
3237 gcc_unreachable ();
3239 return;
3241 /* Some moves to a hard register are special. Not all of them
3242 are really supported and we have to use a temporary
3243 location to provide them (either the stack of a temp var). */
3244 if (H_REG_P (operands[0]))
3246 switch (REGNO (operands[0]))
3248 case HARD_D_REGNUM:
3249 if (X_REG_P (operands[1]))
3251 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3253 m68hc11_output_swap (insn, operands);
3255 else if (next_insn_test_reg (insn, operands[0]))
3257 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3259 else
3261 m68hc11_notice_keep_cc (operands[0]);
3262 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3265 else if (Y_REG_P (operands[1]))
3267 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3269 m68hc11_output_swap (insn, operands);
3271 else
3273 /* %t means *ZTMP scratch register. */
3274 output_asm_insn ("sty\t%t1", operands);
3275 output_asm_insn ("ldd\t%t1", operands);
3278 else if (SP_REG_P (operands[1]))
3280 CC_STATUS_INIT;
3281 if (ix_reg == 0)
3282 create_regs_rtx ();
3283 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3284 output_asm_insn ("xgdx", operands);
3285 output_asm_insn ("tsx", operands);
3286 output_asm_insn ("xgdx", operands);
3288 else if (IS_STACK_POP (operands[1]))
3290 output_asm_insn ("pula\n\tpulb", operands);
3292 else if (GET_CODE (operands[1]) == CONST_INT
3293 && INTVAL (operands[1]) == 0)
3295 output_asm_insn ("clra\n\tclrb", operands);
3297 else
3299 output_asm_insn ("ldd\t%1", operands);
3301 break;
3303 case HARD_X_REGNUM:
3304 if (D_REG_P (operands[1]))
3306 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3308 m68hc11_output_swap (insn, operands);
3310 else if (next_insn_test_reg (insn, operands[0]))
3312 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3314 else
3316 m68hc11_notice_keep_cc (operands[0]);
3317 output_asm_insn ("pshb", operands);
3318 output_asm_insn ("psha", operands);
3319 output_asm_insn ("pulx", operands);
3322 else if (Y_REG_P (operands[1]))
3324 /* When both D and Y are dead, use the sequence xgdy, xgdx
3325 to move Y into X. The D and Y registers are modified. */
3326 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3327 && dead_register_here (insn, d_reg))
3329 output_asm_insn ("xgdy", operands);
3330 output_asm_insn ("xgdx", operands);
3331 CC_STATUS_INIT;
3333 else if (!optimize_size)
3335 output_asm_insn ("sty\t%t1", operands);
3336 output_asm_insn ("ldx\t%t1", operands);
3338 else
3340 CC_STATUS_INIT;
3341 output_asm_insn ("pshy", operands);
3342 output_asm_insn ("pulx", operands);
3345 else if (SP_REG_P (operands[1]))
3347 /* tsx, tsy preserve the flags */
3348 cc_status = cc_prev_status;
3349 output_asm_insn ("tsx", operands);
3351 else
3353 output_asm_insn ("ldx\t%1", operands);
3355 break;
3357 case HARD_Y_REGNUM:
3358 if (D_REG_P (operands[1]))
3360 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3362 m68hc11_output_swap (insn, operands);
3364 else
3366 output_asm_insn ("std\t%t1", operands);
3367 output_asm_insn ("ldy\t%t1", operands);
3370 else if (X_REG_P (operands[1]))
3372 /* When both D and X are dead, use the sequence xgdx, xgdy
3373 to move X into Y. The D and X registers are modified. */
3374 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3375 && dead_register_here (insn, d_reg))
3377 output_asm_insn ("xgdx", operands);
3378 output_asm_insn ("xgdy", operands);
3379 CC_STATUS_INIT;
3381 else if (!optimize_size)
3383 output_asm_insn ("stx\t%t1", operands);
3384 output_asm_insn ("ldy\t%t1", operands);
3386 else
3388 CC_STATUS_INIT;
3389 output_asm_insn ("pshx", operands);
3390 output_asm_insn ("puly", operands);
3393 else if (SP_REG_P (operands[1]))
3395 /* tsx, tsy preserve the flags */
3396 cc_status = cc_prev_status;
3397 output_asm_insn ("tsy", operands);
3399 else
3401 output_asm_insn ("ldy\t%1", operands);
3403 break;
3405 case HARD_SP_REGNUM:
3406 if (D_REG_P (operands[1]))
3408 m68hc11_notice_keep_cc (operands[0]);
3409 output_asm_insn ("xgdx", operands);
3410 output_asm_insn ("txs", operands);
3411 output_asm_insn ("xgdx", operands);
3413 else if (X_REG_P (operands[1]))
3415 /* tys, txs preserve the flags */
3416 cc_status = cc_prev_status;
3417 output_asm_insn ("txs", operands);
3419 else if (Y_REG_P (operands[1]))
3421 /* tys, txs preserve the flags */
3422 cc_status = cc_prev_status;
3423 output_asm_insn ("tys", operands);
3425 else
3427 /* lds sets the flags but the des does not. */
3428 CC_STATUS_INIT;
3429 output_asm_insn ("lds\t%1", operands);
3430 output_asm_insn ("des", operands);
3432 break;
3434 default:
3435 fatal_insn ("invalid register in the move instruction", insn);
3436 break;
3438 return;
3440 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3441 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3443 output_asm_insn ("sts\t%0", operands);
3444 return;
3447 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3449 cc_status = cc_prev_status;
3450 switch (REGNO (operands[1]))
3452 case HARD_X_REGNUM:
3453 case HARD_Y_REGNUM:
3454 output_asm_insn ("psh%1", operands);
3455 break;
3456 case HARD_D_REGNUM:
3457 output_asm_insn ("pshb", operands);
3458 output_asm_insn ("psha", operands);
3459 break;
3460 default:
3461 gcc_unreachable ();
3463 return;
3466 /* Operand 1 must be a hard register. */
3467 if (!H_REG_P (operands[1]))
3469 fatal_insn ("invalid operand in the instruction", insn);
3472 reg = REGNO (operands[1]);
3473 switch (reg)
3475 case HARD_D_REGNUM:
3476 output_asm_insn ("std\t%0", operands);
3477 break;
3479 case HARD_X_REGNUM:
3480 output_asm_insn ("stx\t%0", operands);
3481 break;
3483 case HARD_Y_REGNUM:
3484 output_asm_insn ("sty\t%0", operands);
3485 break;
3487 case HARD_SP_REGNUM:
3488 if (ix_reg == 0)
3489 create_regs_rtx ();
3491 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3493 output_asm_insn ("pshx", operands);
3494 output_asm_insn ("tsx", operands);
3495 output_asm_insn ("inx", operands);
3496 output_asm_insn ("inx", operands);
3497 output_asm_insn ("stx\t%0", operands);
3498 output_asm_insn ("pulx", operands);
3501 else if (reg_mentioned_p (ix_reg, operands[0]))
3503 output_asm_insn ("sty\t%t0", operands);
3504 output_asm_insn ("tsy", operands);
3505 output_asm_insn ("sty\t%0", operands);
3506 output_asm_insn ("ldy\t%t0", operands);
3508 else
3510 output_asm_insn ("stx\t%t0", operands);
3511 output_asm_insn ("tsx", operands);
3512 output_asm_insn ("stx\t%0", operands);
3513 output_asm_insn ("ldx\t%t0", operands);
3515 CC_STATUS_INIT;
3516 break;
3518 default:
3519 fatal_insn ("invalid register in the move instruction", insn);
3520 break;
3524 void
3525 m68hc11_gen_movqi (rtx insn, rtx *operands)
3527 /* Move a register or memory to the same location.
3528 This is possible because such insn can appear
3529 in a non-optimizing mode. */
3530 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3532 cc_status = cc_prev_status;
3533 return;
3536 if (TARGET_M6812)
3539 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3541 m68hc11_notice_keep_cc (operands[0]);
3542 output_asm_insn ("tfr\t%1,%0", operands);
3544 else if (H_REG_P (operands[0]))
3546 if (IS_STACK_POP (operands[1]))
3547 output_asm_insn ("pul%b0", operands);
3548 else if (Q_REG_P (operands[0]))
3549 output_asm_insn ("lda%0\t%b1", operands);
3550 else if (D_REG_P (operands[0]))
3551 output_asm_insn ("ldab\t%b1", operands);
3552 else
3553 goto m6811_move;
3555 else if (H_REG_P (operands[1]))
3557 if (Q_REG_P (operands[1]))
3558 output_asm_insn ("sta%1\t%b0", operands);
3559 else if (D_REG_P (operands[1]))
3560 output_asm_insn ("stab\t%b0", operands);
3561 else
3562 goto m6811_move;
3564 else
3566 rtx from = operands[1];
3567 rtx to = operands[0];
3569 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3570 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3571 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3572 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3574 rtx ops[3];
3576 if (operands[2])
3578 ops[0] = operands[2];
3579 ops[1] = from;
3580 ops[2] = 0;
3581 m68hc11_gen_movqi (insn, ops);
3582 ops[0] = to;
3583 ops[1] = operands[2];
3584 m68hc11_gen_movqi (insn, ops);
3586 else
3588 /* !!!! SCz wrong here. */
3589 fatal_insn ("move insn not handled", insn);
3592 else
3594 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3596 output_asm_insn ("clr\t%b0", operands);
3598 else
3600 m68hc11_notice_keep_cc (operands[0]);
3601 output_asm_insn ("movb\t%b1,%b0", operands);
3605 return;
3608 m6811_move:
3609 if (H_REG_P (operands[0]))
3611 switch (REGNO (operands[0]))
3613 case HARD_B_REGNUM:
3614 case HARD_D_REGNUM:
3615 if (X_REG_P (operands[1]))
3617 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3619 m68hc11_output_swap (insn, operands);
3621 else
3623 output_asm_insn ("stx\t%t1", operands);
3624 output_asm_insn ("ldab\t%T0", operands);
3627 else if (Y_REG_P (operands[1]))
3629 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3631 m68hc11_output_swap (insn, operands);
3633 else
3635 output_asm_insn ("sty\t%t1", operands);
3636 output_asm_insn ("ldab\t%T0", operands);
3639 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3640 && !DA_REG_P (operands[1]))
3642 output_asm_insn ("ldab\t%b1", operands);
3644 else if (DA_REG_P (operands[1]))
3646 output_asm_insn ("tab", operands);
3648 else
3650 cc_status = cc_prev_status;
3651 return;
3653 break;
3655 case HARD_A_REGNUM:
3656 if (X_REG_P (operands[1]))
3658 output_asm_insn ("stx\t%t1", operands);
3659 output_asm_insn ("ldaa\t%T0", operands);
3661 else if (Y_REG_P (operands[1]))
3663 output_asm_insn ("sty\t%t1", operands);
3664 output_asm_insn ("ldaa\t%T0", operands);
3666 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3667 && !DA_REG_P (operands[1]))
3669 output_asm_insn ("ldaa\t%b1", operands);
3671 else if (!DA_REG_P (operands[1]))
3673 output_asm_insn ("tba", operands);
3675 else
3677 cc_status = cc_prev_status;
3679 break;
3681 case HARD_X_REGNUM:
3682 if (D_REG_P (operands[1]))
3684 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3686 m68hc11_output_swap (insn, operands);
3688 else
3690 output_asm_insn ("stab\t%T1", operands);
3691 output_asm_insn ("ldx\t%t1", operands);
3693 CC_STATUS_INIT;
3695 else if (Y_REG_P (operands[1]))
3697 output_asm_insn ("sty\t%t0", operands);
3698 output_asm_insn ("ldx\t%t0", operands);
3700 else if (GET_CODE (operands[1]) == CONST_INT)
3702 output_asm_insn ("ldx\t%1", operands);
3704 else if (dead_register_here (insn, d_reg))
3706 output_asm_insn ("ldab\t%b1", operands);
3707 output_asm_insn ("xgdx", operands);
3709 else if (!reg_mentioned_p (operands[0], operands[1]))
3711 output_asm_insn ("xgdx", operands);
3712 output_asm_insn ("ldab\t%b1", operands);
3713 output_asm_insn ("xgdx", operands);
3715 else
3717 output_asm_insn ("pshb", operands);
3718 output_asm_insn ("ldab\t%b1", operands);
3719 output_asm_insn ("stab\t%T1", operands);
3720 output_asm_insn ("ldx\t%t1", operands);
3721 output_asm_insn ("pulb", operands);
3722 CC_STATUS_INIT;
3724 break;
3726 case HARD_Y_REGNUM:
3727 if (D_REG_P (operands[1]))
3729 output_asm_insn ("stab\t%T1", operands);
3730 output_asm_insn ("ldy\t%t1", operands);
3731 CC_STATUS_INIT;
3733 else if (X_REG_P (operands[1]))
3735 output_asm_insn ("stx\t%t1", operands);
3736 output_asm_insn ("ldy\t%t1", operands);
3737 CC_STATUS_INIT;
3739 else if (GET_CODE (operands[1]) == CONST_INT)
3741 output_asm_insn ("ldy\t%1", operands);
3743 else if (dead_register_here (insn, d_reg))
3745 output_asm_insn ("ldab\t%b1", operands);
3746 output_asm_insn ("xgdy", operands);
3748 else if (!reg_mentioned_p (operands[0], operands[1]))
3750 output_asm_insn ("xgdy", operands);
3751 output_asm_insn ("ldab\t%b1", operands);
3752 output_asm_insn ("xgdy", operands);
3754 else
3756 output_asm_insn ("pshb", operands);
3757 output_asm_insn ("ldab\t%b1", operands);
3758 output_asm_insn ("stab\t%T1", operands);
3759 output_asm_insn ("ldy\t%t1", operands);
3760 output_asm_insn ("pulb", operands);
3761 CC_STATUS_INIT;
3763 break;
3765 default:
3766 fatal_insn ("invalid register in the instruction", insn);
3767 break;
3770 else if (H_REG_P (operands[1]))
3772 switch (REGNO (operands[1]))
3774 case HARD_D_REGNUM:
3775 case HARD_B_REGNUM:
3776 output_asm_insn ("stab\t%b0", operands);
3777 break;
3779 case HARD_A_REGNUM:
3780 output_asm_insn ("staa\t%b0", operands);
3781 break;
3783 case HARD_X_REGNUM:
3784 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3785 break;
3787 case HARD_Y_REGNUM:
3788 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3789 break;
3791 default:
3792 fatal_insn ("invalid register in the move instruction", insn);
3793 break;
3795 return;
3797 else
3799 fatal_insn ("operand 1 must be a hard register", insn);
3803 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3804 The source and destination must be D or A and the shift must
3805 be a constant. */
3806 void
3807 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3809 int val;
3811 if (GET_CODE (operands[2]) != CONST_INT
3812 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3813 fatal_insn ("invalid rotate insn", insn);
3815 val = INTVAL (operands[2]);
3816 if (code == ROTATERT)
3817 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3819 if (GET_MODE (operands[0]) != QImode)
3820 CC_STATUS_INIT;
3822 /* Rotate by 8-bits if the shift is within [5..11]. */
3823 if (val >= 5 && val <= 11)
3825 if (TARGET_M6812)
3826 output_asm_insn ("exg\ta,b", operands);
3827 else
3829 output_asm_insn ("psha", operands);
3830 output_asm_insn ("tba", operands);
3831 output_asm_insn ("pulb", operands);
3833 val -= 8;
3836 /* If the shift is big, invert the rotation. */
3837 else if (val >= 12)
3839 val = val - 16;
3842 if (val > 0)
3844 while (--val >= 0)
3846 /* Set the carry to bit-15, but don't change D yet. */
3847 if (GET_MODE (operands[0]) != QImode)
3849 output_asm_insn ("asra", operands);
3850 output_asm_insn ("rola", operands);
3853 /* Rotate B first to move the carry to bit-0. */
3854 if (D_REG_P (operands[0]))
3855 output_asm_insn ("rolb", operands);
3857 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3858 output_asm_insn ("rola", operands);
3861 else
3863 while (++val <= 0)
3865 /* Set the carry to bit-8 of D. */
3866 if (GET_MODE (operands[0]) != QImode)
3867 output_asm_insn ("tap", operands);
3869 /* Rotate B first to move the carry to bit-7. */
3870 if (D_REG_P (operands[0]))
3871 output_asm_insn ("rorb", operands);
3873 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3874 output_asm_insn ("rora", operands);
3881 /* Store in cc_status the expressions that the condition codes will
3882 describe after execution of an instruction whose pattern is EXP.
3883 Do not alter them if the instruction would not alter the cc's. */
3885 void
3886 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3888 /* recognize SET insn's. */
3889 if (GET_CODE (exp) == SET)
3891 /* Jumps do not alter the cc's. */
3892 if (SET_DEST (exp) == pc_rtx)
3895 /* NOTE: most instructions don't affect the carry bit, but the
3896 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3897 the conditions.h header. */
3899 /* Function calls clobber the cc's. */
3900 else if (GET_CODE (SET_SRC (exp)) == CALL)
3902 CC_STATUS_INIT;
3905 /* Tests and compares set the cc's in predictable ways. */
3906 else if (SET_DEST (exp) == cc0_rtx)
3908 cc_status.flags = 0;
3909 cc_status.value1 = XEXP (exp, 0);
3910 if (GET_CODE (XEXP (exp, 1)) == COMPARE
3911 && XEXP (XEXP (exp, 1), 1) == CONST0_RTX (GET_MODE (XEXP (XEXP (exp, 1), 0))))
3912 cc_status.value2 = XEXP (XEXP (exp, 1), 0);
3913 else
3914 cc_status.value2 = XEXP (exp, 1);
3916 else
3918 /* All other instructions affect the condition codes. */
3919 cc_status.flags = 0;
3920 cc_status.value1 = XEXP (exp, 0);
3921 cc_status.value2 = XEXP (exp, 1);
3924 else
3926 /* Default action if we haven't recognized something
3927 and returned earlier. */
3928 CC_STATUS_INIT;
3931 if (cc_status.value2 != 0)
3932 switch (GET_CODE (cc_status.value2))
3934 /* These logical operations can generate several insns.
3935 The flags are setup according to what is generated. */
3936 case IOR:
3937 case XOR:
3938 case AND:
3939 break;
3941 /* The (not ...) generates several 'com' instructions for
3942 non QImode. We have to invalidate the flags. */
3943 case NOT:
3944 if (GET_MODE (cc_status.value2) != QImode)
3945 CC_STATUS_INIT;
3946 break;
3948 case PLUS:
3949 case MINUS:
3950 case MULT:
3951 case DIV:
3952 case UDIV:
3953 case MOD:
3954 case UMOD:
3955 case NEG:
3956 if (GET_MODE (cc_status.value2) != VOIDmode)
3957 cc_status.flags |= CC_NO_OVERFLOW;
3958 break;
3960 /* The asl sets the overflow bit in such a way that this
3961 makes the flags unusable for a next compare insn. */
3962 case ASHIFT:
3963 case ROTATE:
3964 case ROTATERT:
3965 if (GET_MODE (cc_status.value2) != VOIDmode)
3966 cc_status.flags |= CC_NO_OVERFLOW;
3967 break;
3969 /* A load/store instruction does not affect the carry. */
3970 case MEM:
3971 case SYMBOL_REF:
3972 case REG:
3973 case CONST_INT:
3974 cc_status.flags |= CC_NO_OVERFLOW;
3975 break;
3977 default:
3978 break;
3980 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3981 && cc_status.value2
3982 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3983 cc_status.value2 = 0;
3985 else if (cc_status.value1 && side_effects_p (cc_status.value1))
3986 cc_status.value1 = 0;
3988 else if (cc_status.value2 && side_effects_p (cc_status.value2))
3989 cc_status.value2 = 0;
3992 /* The current instruction does not affect the flags but changes
3993 the register 'reg'. See if the previous flags can be kept for the
3994 next instruction to avoid a comparison. */
3995 void
3996 m68hc11_notice_keep_cc (rtx reg)
3998 if (reg == 0
3999 || cc_prev_status.value1 == 0
4000 || rtx_equal_p (reg, cc_prev_status.value1)
4001 || (cc_prev_status.value2
4002 && reg_mentioned_p (reg, cc_prev_status.value2)))
4003 CC_STATUS_INIT;
4004 else
4005 cc_status = cc_prev_status;
4010 /* Machine Specific Reorg. */
4012 /* Z register replacement:
4014 GCC treats the Z register as an index base address register like
4015 X or Y. In general, it uses it during reload to compute the address
4016 of some operand. This helps the reload pass to avoid to fall into the
4017 register spill failure.
4019 The Z register is in the A_REGS class. In the machine description,
4020 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4022 It can appear everywhere an X or Y register can appear, except for
4023 some templates in the clobber section (when a clobber of X or Y is asked).
4024 For a given instruction, the template must ensure that no more than
4025 2 'A' registers are used. Otherwise, the register replacement is not
4026 possible.
4028 To replace the Z register, the algorithm is not terrific:
4029 1. Insns that do not use the Z register are not changed
4030 2. When a Z register is used, we scan forward the insns to see
4031 a potential register to use: either X or Y and sometimes D.
4032 We stop when a call, a label or a branch is seen, or when we
4033 detect that both X and Y are used (probably at different times, but it does
4034 not matter).
4035 3. The register that will be used for the replacement of Z is saved
4036 in a .page0 register or on the stack. If the first instruction that
4037 used Z, uses Z as an input, the value is loaded from another .page0
4038 register. The replacement register is pushed on the stack in the
4039 rare cases where a compare insn uses Z and we couldn't find if X/Y
4040 are dead.
4041 4. The Z register is replaced in all instructions until we reach
4042 the end of the Z-block, as detected by step 2.
4043 5. If we detect that Z is still alive, its value is saved.
4044 If the replacement register is alive, its old value is loaded.
4046 The Z register can be disabled with -ffixed-z.
4049 struct replace_info
4051 rtx first;
4052 rtx replace_reg;
4053 int need_save_z;
4054 int must_load_z;
4055 int must_save_reg;
4056 int must_restore_reg;
4057 rtx last;
4058 int regno;
4059 int x_used;
4060 int y_used;
4061 int can_use_d;
4062 int found_call;
4063 int z_died;
4064 int z_set_count;
4065 rtx z_value;
4066 int must_push_reg;
4067 int save_before_last;
4068 int z_loaded_with_sp;
4071 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4072 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4073 static void m68hc11_z_replacement (rtx);
4074 static void m68hc11_reassign_regs (rtx);
4076 int z_replacement_completed = 0;
4078 /* Analyze the insn to find out which replacement register to use and
4079 the boundaries of the replacement.
4080 Returns 0 if we reached the last insn to be replaced, 1 if we can
4081 continue replacement in next insns. */
4083 static int
4084 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4086 int this_insn_uses_ix;
4087 int this_insn_uses_iy;
4088 int this_insn_uses_z;
4089 int this_insn_uses_z_in_dst;
4090 int this_insn_uses_d;
4091 rtx body;
4092 int z_dies_here;
4094 /* A call is said to clobber the Z register, we don't need
4095 to save the value of Z. We also don't need to restore
4096 the replacement register (unless it is used by the call). */
4097 if (GET_CODE (insn) == CALL_INSN)
4099 body = PATTERN (insn);
4101 info->can_use_d = 0;
4103 /* If the call is an indirect call with Z, we have to use the
4104 Y register because X can be used as an input (D+X).
4105 We also must not save Z nor restore Y. */
4106 if (reg_mentioned_p (z_reg, body))
4108 insn = NEXT_INSN (insn);
4109 info->x_used = 1;
4110 info->y_used = 0;
4111 info->found_call = 1;
4112 info->must_restore_reg = 0;
4113 info->last = NEXT_INSN (insn);
4115 info->need_save_z = 0;
4116 return 0;
4118 if (GET_CODE (insn) == CODE_LABEL
4119 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4120 return 0;
4122 if (GET_CODE (insn) == JUMP_INSN)
4124 if (reg_mentioned_p (z_reg, insn) == 0)
4125 return 0;
4127 info->can_use_d = 0;
4128 info->must_save_reg = 0;
4129 info->must_restore_reg = 0;
4130 info->need_save_z = 0;
4131 info->last = NEXT_INSN (insn);
4132 return 0;
4134 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4136 return 1;
4139 /* Z register dies here. */
4140 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4142 body = PATTERN (insn);
4143 if (GET_CODE (body) == SET)
4145 rtx src = XEXP (body, 1);
4146 rtx dst = XEXP (body, 0);
4148 /* Condition code is set here. We have to restore the X/Y and
4149 save into Z before any test/compare insn because once we save/restore
4150 we can change the condition codes. When the compare insn uses Z and
4151 we can't use X/Y, the comparison is made with the *ZREG soft register
4152 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4153 if (dst == cc0_rtx)
4155 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4156 || (GET_CODE (src) == COMPARE &&
4157 ((rtx_equal_p (XEXP (src, 0), z_reg)
4158 && H_REG_P (XEXP (src, 1)))
4159 || (rtx_equal_p (XEXP (src, 1), z_reg)
4160 && H_REG_P (XEXP (src, 0))))))
4162 if (insn == info->first)
4164 info->must_load_z = 0;
4165 info->must_save_reg = 0;
4166 info->must_restore_reg = 0;
4167 info->need_save_z = 0;
4168 info->found_call = 1;
4169 info->regno = SOFT_Z_REGNUM;
4170 info->last = NEXT_INSN (insn);
4172 return 0;
4174 if (reg_mentioned_p (z_reg, src) == 0)
4176 info->can_use_d = 0;
4177 return 0;
4180 if (insn != info->first)
4181 return 0;
4183 /* Compare insn which uses Z. We have to save/restore the X/Y
4184 register without modifying the condition codes. For this
4185 we have to use a push/pop insn. */
4186 info->must_push_reg = 1;
4187 info->last = insn;
4190 /* Z reg is set to something new. We don't need to load it. */
4191 if (Z_REG_P (dst))
4193 if (!reg_mentioned_p (z_reg, src))
4195 /* Z reg is used before being set. Treat this as
4196 a new sequence of Z register replacement. */
4197 if (insn != info->first)
4199 return 0;
4201 info->must_load_z = 0;
4203 info->z_set_count++;
4204 info->z_value = src;
4205 if (SP_REG_P (src))
4206 info->z_loaded_with_sp = 1;
4208 else if (reg_mentioned_p (z_reg, dst))
4209 info->can_use_d = 0;
4211 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4212 | reg_mentioned_p (d_reg, dst);
4213 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4214 | reg_mentioned_p (ix_reg, dst);
4215 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4216 | reg_mentioned_p (iy_reg, dst);
4217 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4219 /* If z is used as an address operand (like (MEM (reg z))),
4220 we can't replace it with d. */
4221 if (this_insn_uses_z && !Z_REG_P (src)
4222 && !(m68hc11_arith_operator (src, GET_MODE (src))
4223 && Z_REG_P (XEXP (src, 0))
4224 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4225 && insn == info->first
4226 && dead_register_here (insn, d_reg)))
4227 info->can_use_d = 0;
4229 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4230 if (TARGET_M6812 && !z_dies_here
4231 && ((this_insn_uses_z && side_effects_p (src))
4232 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4234 info->need_save_z = 1;
4235 info->z_set_count++;
4237 this_insn_uses_z |= this_insn_uses_z_in_dst;
4239 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4241 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4244 if (this_insn_uses_d)
4245 info->can_use_d = 0;
4247 /* IX and IY are used at the same time, we have to restore
4248 the value of the scratch register before this insn. */
4249 if (this_insn_uses_ix && this_insn_uses_iy)
4251 return 0;
4254 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4255 info->can_use_d = 0;
4257 if (info->x_used == 0 && this_insn_uses_ix)
4259 if (info->y_used)
4261 /* We have a (set (REG:HI X) (REG:HI Z)).
4262 Since we use Z as the replacement register, this insn
4263 is no longer necessary. We turn it into a note. We must
4264 not reload the old value of X. */
4265 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4267 if (z_dies_here)
4269 info->need_save_z = 0;
4270 info->z_died = 1;
4272 info->must_save_reg = 0;
4273 info->must_restore_reg = 0;
4274 info->found_call = 1;
4275 info->can_use_d = 0;
4276 SET_INSN_DELETED (insn);
4277 info->last = NEXT_INSN (insn);
4278 return 0;
4281 if (X_REG_P (dst)
4282 && (rtx_equal_p (src, z_reg)
4283 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4285 if (z_dies_here)
4287 info->need_save_z = 0;
4288 info->z_died = 1;
4290 info->last = NEXT_INSN (insn);
4291 info->must_save_reg = 0;
4292 info->must_restore_reg = 0;
4294 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4295 && !reg_mentioned_p (ix_reg, src))
4297 if (z_dies_here)
4299 info->z_died = 1;
4300 info->need_save_z = 0;
4302 else if (TARGET_M6812 && side_effects_p (src))
4304 info->last = 0;
4305 info->must_restore_reg = 0;
4306 return 0;
4308 else
4310 info->save_before_last = 1;
4312 info->must_restore_reg = 0;
4313 info->last = NEXT_INSN (insn);
4315 else if (info->can_use_d)
4317 info->last = NEXT_INSN (insn);
4318 info->x_used = 1;
4320 return 0;
4322 info->x_used = 1;
4323 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4324 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4326 info->need_save_z = 0;
4327 info->z_died = 1;
4328 info->last = NEXT_INSN (insn);
4329 info->regno = HARD_X_REGNUM;
4330 info->must_save_reg = 0;
4331 info->must_restore_reg = 0;
4332 return 0;
4334 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4336 info->regno = HARD_X_REGNUM;
4337 info->must_restore_reg = 0;
4338 info->must_save_reg = 0;
4339 return 0;
4342 if (info->y_used == 0 && this_insn_uses_iy)
4344 if (info->x_used)
4346 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4348 if (z_dies_here)
4350 info->need_save_z = 0;
4351 info->z_died = 1;
4353 info->must_save_reg = 0;
4354 info->must_restore_reg = 0;
4355 info->found_call = 1;
4356 info->can_use_d = 0;
4357 SET_INSN_DELETED (insn);
4358 info->last = NEXT_INSN (insn);
4359 return 0;
4362 if (Y_REG_P (dst)
4363 && (rtx_equal_p (src, z_reg)
4364 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4366 if (z_dies_here)
4368 info->z_died = 1;
4369 info->need_save_z = 0;
4371 info->last = NEXT_INSN (insn);
4372 info->must_save_reg = 0;
4373 info->must_restore_reg = 0;
4375 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4376 && !reg_mentioned_p (iy_reg, src))
4378 if (z_dies_here)
4380 info->z_died = 1;
4381 info->need_save_z = 0;
4383 else if (TARGET_M6812 && side_effects_p (src))
4385 info->last = 0;
4386 info->must_restore_reg = 0;
4387 return 0;
4389 else
4391 info->save_before_last = 1;
4393 info->must_restore_reg = 0;
4394 info->last = NEXT_INSN (insn);
4396 else if (info->can_use_d)
4398 info->last = NEXT_INSN (insn);
4399 info->y_used = 1;
4402 return 0;
4404 info->y_used = 1;
4405 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4406 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4408 info->need_save_z = 0;
4409 info->z_died = 1;
4410 info->last = NEXT_INSN (insn);
4411 info->regno = HARD_Y_REGNUM;
4412 info->must_save_reg = 0;
4413 info->must_restore_reg = 0;
4414 return 0;
4416 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4418 info->regno = HARD_Y_REGNUM;
4419 info->must_restore_reg = 0;
4420 info->must_save_reg = 0;
4421 return 0;
4424 if (z_dies_here)
4426 info->need_save_z = 0;
4427 info->z_died = 1;
4428 if (info->last == 0)
4429 info->last = NEXT_INSN (insn);
4430 return 0;
4432 return info->last != NULL_RTX ? 0 : 1;
4434 if (GET_CODE (body) == PARALLEL)
4436 int i;
4437 char ix_clobber = 0;
4438 char iy_clobber = 0;
4439 char z_clobber = 0;
4440 this_insn_uses_iy = 0;
4441 this_insn_uses_ix = 0;
4442 this_insn_uses_z = 0;
4444 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4446 rtx x;
4447 int uses_ix, uses_iy, uses_z;
4449 x = XVECEXP (body, 0, i);
4451 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4452 info->can_use_d = 0;
4454 uses_ix = reg_mentioned_p (ix_reg, x);
4455 uses_iy = reg_mentioned_p (iy_reg, x);
4456 uses_z = reg_mentioned_p (z_reg, x);
4457 if (GET_CODE (x) == CLOBBER)
4459 ix_clobber |= uses_ix;
4460 iy_clobber |= uses_iy;
4461 z_clobber |= uses_z;
4463 else
4465 this_insn_uses_ix |= uses_ix;
4466 this_insn_uses_iy |= uses_iy;
4467 this_insn_uses_z |= uses_z;
4469 if (uses_z && GET_CODE (x) == SET)
4471 rtx dst = XEXP (x, 0);
4473 if (Z_REG_P (dst))
4474 info->z_set_count++;
4476 if (TARGET_M6812 && uses_z && side_effects_p (x))
4477 info->need_save_z = 1;
4479 if (z_clobber)
4480 info->need_save_z = 0;
4482 if (debug_m6811)
4484 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4485 this_insn_uses_ix, this_insn_uses_iy,
4486 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4487 debug_rtx (insn);
4489 if (this_insn_uses_z)
4490 info->can_use_d = 0;
4492 if (z_clobber && info->first != insn)
4494 info->need_save_z = 0;
4495 info->last = insn;
4496 return 0;
4498 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4500 if (this_insn_uses_z == 0 && insn == info->first)
4502 info->must_load_z = 0;
4504 if (dead_register_here (insn, d_reg))
4506 info->regno = HARD_D_REGNUM;
4507 info->must_save_reg = 0;
4508 info->must_restore_reg = 0;
4510 else if (dead_register_here (insn, ix_reg))
4512 info->regno = HARD_X_REGNUM;
4513 info->must_save_reg = 0;
4514 info->must_restore_reg = 0;
4516 else if (dead_register_here (insn, iy_reg))
4518 info->regno = HARD_Y_REGNUM;
4519 info->must_save_reg = 0;
4520 info->must_restore_reg = 0;
4522 if (info->regno >= 0)
4524 info->last = NEXT_INSN (insn);
4525 return 0;
4527 if (this_insn_uses_ix == 0)
4529 info->regno = HARD_X_REGNUM;
4530 info->must_save_reg = 1;
4531 info->must_restore_reg = 1;
4533 else if (this_insn_uses_iy == 0)
4535 info->regno = HARD_Y_REGNUM;
4536 info->must_save_reg = 1;
4537 info->must_restore_reg = 1;
4539 else
4541 info->regno = HARD_D_REGNUM;
4542 info->must_save_reg = 1;
4543 info->must_restore_reg = 1;
4545 info->last = NEXT_INSN (insn);
4546 return 0;
4549 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4550 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4552 if (this_insn_uses_z)
4554 if (info->y_used == 0 && iy_clobber)
4556 info->regno = HARD_Y_REGNUM;
4557 info->must_save_reg = 0;
4558 info->must_restore_reg = 0;
4560 if (info->first != insn
4561 && ((info->y_used && ix_clobber)
4562 || (info->x_used && iy_clobber)))
4563 info->last = insn;
4564 else
4565 info->last = NEXT_INSN (insn);
4566 info->save_before_last = 1;
4568 return 0;
4570 if (this_insn_uses_ix && this_insn_uses_iy)
4572 if (this_insn_uses_z)
4574 fatal_insn ("cannot do z-register replacement", insn);
4576 return 0;
4578 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4580 if (info->y_used)
4582 return 0;
4584 info->x_used = 1;
4585 if (iy_clobber || z_clobber)
4587 info->last = NEXT_INSN (insn);
4588 info->save_before_last = 1;
4589 return 0;
4593 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4595 if (info->x_used)
4597 return 0;
4599 info->y_used = 1;
4600 if (ix_clobber || z_clobber)
4602 info->last = NEXT_INSN (insn);
4603 info->save_before_last = 1;
4604 return 0;
4607 if (z_dies_here)
4609 info->z_died = 1;
4610 info->need_save_z = 0;
4612 return 1;
4614 if (GET_CODE (body) == CLOBBER)
4617 /* IX and IY are used at the same time, we have to restore
4618 the value of the scratch register before this insn. */
4619 if (this_insn_uses_ix && this_insn_uses_iy)
4621 return 0;
4623 if (info->x_used == 0 && this_insn_uses_ix)
4625 if (info->y_used)
4627 return 0;
4629 info->x_used = 1;
4631 if (info->y_used == 0 && this_insn_uses_iy)
4633 if (info->x_used)
4635 return 0;
4637 info->y_used = 1;
4639 return 1;
4641 return 1;
4644 static void
4645 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4647 int reg;
4649 info->replace_reg = NULL_RTX;
4650 info->must_load_z = 1;
4651 info->need_save_z = 1;
4652 info->must_save_reg = 1;
4653 info->must_restore_reg = 1;
4654 info->first = insn;
4655 info->x_used = 0;
4656 info->y_used = 0;
4657 info->can_use_d = TARGET_M6811 ? 1 : 0;
4658 info->found_call = 0;
4659 info->z_died = 0;
4660 info->last = 0;
4661 info->regno = -1;
4662 info->z_set_count = 0;
4663 info->z_value = NULL_RTX;
4664 info->must_push_reg = 0;
4665 info->save_before_last = 0;
4666 info->z_loaded_with_sp = 0;
4668 /* Scan the insn forward to find an address register that is not used.
4669 Stop when:
4670 - the flow of the program changes,
4671 - when we detect that both X and Y are necessary,
4672 - when the Z register dies,
4673 - when the condition codes are set. */
4675 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4677 if (m68hc11_check_z_replacement (insn, info) == 0)
4678 break;
4681 /* May be we can use Y or X if they contain the same value as Z.
4682 This happens very often after the reload. */
4683 if (info->z_set_count == 1)
4685 rtx p = info->first;
4686 rtx v = 0;
4688 if (info->x_used)
4690 v = find_last_value (iy_reg, &p, insn, 1);
4692 else if (info->y_used)
4694 v = find_last_value (ix_reg, &p, insn, 1);
4696 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4698 if (info->x_used)
4699 info->regno = HARD_Y_REGNUM;
4700 else
4701 info->regno = HARD_X_REGNUM;
4702 info->must_load_z = 0;
4703 info->must_save_reg = 0;
4704 info->must_restore_reg = 0;
4705 info->found_call = 1;
4708 if (info->z_set_count == 0)
4709 info->need_save_z = 0;
4711 if (insn == 0)
4712 info->need_save_z = 0;
4714 if (info->last == 0)
4715 info->last = insn;
4717 if (info->regno >= 0)
4719 reg = info->regno;
4720 info->replace_reg = gen_rtx_REG (HImode, reg);
4722 else if (info->can_use_d)
4724 reg = HARD_D_REGNUM;
4725 info->replace_reg = d_reg;
4727 else if (info->x_used)
4729 reg = HARD_Y_REGNUM;
4730 info->replace_reg = iy_reg;
4732 else
4734 reg = HARD_X_REGNUM;
4735 info->replace_reg = ix_reg;
4737 info->regno = reg;
4739 if (info->must_save_reg && info->must_restore_reg)
4741 if (insn && dead_register_here (insn, info->replace_reg))
4743 info->must_save_reg = 0;
4744 info->must_restore_reg = 0;
4749 /* The insn uses the Z register. Find a replacement register for it
4750 (either X or Y) and replace it in the insn and the next ones until
4751 the flow changes or the replacement register is used. Instructions
4752 are emitted before and after the Z-block to preserve the value of
4753 Z and of the replacement register. */
4755 static void
4756 m68hc11_z_replacement (rtx insn)
4758 rtx replace_reg_qi;
4759 rtx replace_reg;
4760 struct replace_info info;
4762 /* Find trivial case where we only need to replace z with the
4763 equivalent soft register. */
4764 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4766 rtx body = PATTERN (insn);
4767 rtx src = XEXP (body, 1);
4768 rtx dst = XEXP (body, 0);
4770 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4772 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4773 return;
4775 else if (Z_REG_P (src)
4776 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4778 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4779 return;
4781 else if (D_REG_P (dst)
4782 && m68hc11_arith_operator (src, GET_MODE (src))
4783 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4785 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4786 return;
4788 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4789 && INTVAL (src) == 0)
4791 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4792 /* Force it to be re-recognized. */
4793 INSN_CODE (insn) = -1;
4794 return;
4798 m68hc11_find_z_replacement (insn, &info);
4800 replace_reg = info.replace_reg;
4801 replace_reg_qi = NULL_RTX;
4803 /* Save the X register in a .page0 location. */
4804 if (info.must_save_reg && !info.must_push_reg)
4806 rtx dst;
4808 if (info.must_push_reg && 0)
4809 dst = gen_rtx_MEM (HImode,
4810 gen_rtx_PRE_DEC (HImode,
4811 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4812 else
4813 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4815 emit_insn_before (gen_movhi (dst,
4816 gen_rtx_REG (HImode, info.regno)), insn);
4818 if (info.must_load_z && !info.must_push_reg)
4820 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4821 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4822 insn);
4826 /* Replace all occurrence of Z by replace_reg.
4827 Stop when the last instruction to replace is reached.
4828 Also stop when we detect a change in the flow (but it's not
4829 necessary; just safeguard). */
4831 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4833 rtx body;
4835 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4836 break;
4838 if (GET_CODE (insn) != INSN
4839 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4840 continue;
4842 body = PATTERN (insn);
4843 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4844 || GET_CODE (body) == ASM_OPERANDS
4845 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4847 rtx note;
4849 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4851 printf ("Reg mentioned here...:\n");
4852 fflush (stdout);
4853 debug_rtx (insn);
4856 /* Stack pointer was decremented by 2 due to the push.
4857 Correct that by adding 2 to the destination. */
4858 if (info.must_push_reg
4859 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4861 rtx src, dst;
4863 src = SET_SRC (body);
4864 dst = SET_DEST (body);
4865 if (SP_REG_P (src) && Z_REG_P (dst))
4866 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4869 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4870 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4872 INSN_CODE (insn) = -1;
4873 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4874 fatal_insn ("cannot do z-register replacement", insn);
4877 /* Likewise for (REG:QI Z). */
4878 if (reg_mentioned_p (z_reg, insn))
4880 if (replace_reg_qi == NULL_RTX)
4881 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4882 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4885 /* If there is a REG_INC note on Z, replace it with a
4886 REG_INC note on the replacement register. This is necessary
4887 to make sure that the flow pass will identify the change
4888 and it will not remove a possible insn that saves Z. */
4889 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4891 if (REG_NOTE_KIND (note) == REG_INC
4892 && GET_CODE (XEXP (note, 0)) == REG
4893 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4895 XEXP (note, 0) = replace_reg;
4899 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4900 break;
4903 /* Save Z before restoring the old value. */
4904 if (insn && info.need_save_z && !info.must_push_reg)
4906 rtx save_pos_insn = insn;
4908 /* If Z is clobber by the last insn, we have to save its value
4909 before the last instruction. */
4910 if (info.save_before_last)
4911 save_pos_insn = PREV_INSN (save_pos_insn);
4913 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4914 gen_rtx_REG (HImode, info.regno)),
4915 save_pos_insn);
4918 if (info.must_push_reg && info.last)
4920 rtx new_body, body;
4922 body = PATTERN (info.last);
4923 new_body = gen_rtx_PARALLEL (VOIDmode,
4924 gen_rtvec (3, body,
4925 gen_rtx_USE (VOIDmode,
4926 replace_reg),
4927 gen_rtx_USE (VOIDmode,
4928 gen_rtx_REG (HImode,
4929 SOFT_Z_REGNUM))));
4930 PATTERN (info.last) = new_body;
4932 /* Force recognition on insn since we changed it. */
4933 INSN_CODE (insn) = -1;
4935 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4937 fatal_insn ("invalid Z register replacement for insn", insn);
4939 insn = NEXT_INSN (info.last);
4942 /* Restore replacement register unless it was died. */
4943 if (insn && info.must_restore_reg && !info.must_push_reg)
4945 rtx dst;
4947 if (info.must_push_reg && 0)
4948 dst = gen_rtx_MEM (HImode,
4949 gen_rtx_POST_INC (HImode,
4950 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4951 else
4952 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4954 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4955 dst), insn);
4961 /* Scan all the insn and re-affects some registers
4962 - The Z register (if it was used), is affected to X or Y depending
4963 on the instruction. */
4965 static void
4966 m68hc11_reassign_regs (rtx first)
4968 rtx insn;
4970 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4971 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4972 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4973 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4975 /* Scan all insns to replace Z by X or Y preserving the old value
4976 of X/Y and restoring it afterward. */
4978 for (insn = first; insn; insn = NEXT_INSN (insn))
4980 rtx body;
4982 if (GET_CODE (insn) == CODE_LABEL
4983 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4984 continue;
4986 if (!INSN_P (insn))
4987 continue;
4989 body = PATTERN (insn);
4990 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4991 continue;
4993 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4994 || GET_CODE (body) == ASM_OPERANDS
4995 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4996 continue;
4998 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4999 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5002 /* If Z appears in this insn, replace it in the current insn
5003 and the next ones until the flow changes or we have to
5004 restore back the replacement register. */
5006 if (reg_mentioned_p (z_reg, body))
5008 m68hc11_z_replacement (insn);
5011 else
5013 printf ("insn not handled by Z replacement:\n");
5014 fflush (stdout);
5015 debug_rtx (insn);
5021 /* Machine-dependent reorg pass.
5022 Specific optimizations are defined here:
5023 - this pass changes the Z register into either X or Y
5024 (it preserves X/Y previous values in a memory slot in page0).
5026 When this pass is finished, the global variable
5027 'z_replacement_completed' is set to 2. */
5029 static void
5030 m68hc11_reorg (void)
5032 int split_done = 0;
5033 rtx first;
5035 z_replacement_completed = 0;
5036 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5037 first = get_insns ();
5039 /* Some RTX are shared at this point. This breaks the Z register
5040 replacement, unshare everything. */
5041 unshare_all_rtl_again (first);
5043 /* Force a split of all splittable insn. This is necessary for the
5044 Z register replacement mechanism because we end up with basic insns. */
5045 split_all_insns_noflow ();
5046 split_done = 1;
5048 z_replacement_completed = 1;
5049 m68hc11_reassign_regs (first);
5051 if (optimize)
5052 compute_bb_for_insn ();
5054 /* After some splitting, there are some opportunities for CSE pass.
5055 This happens quite often when 32-bit or above patterns are split. */
5056 if (optimize > 0 && split_done)
5058 reload_cse_regs (first);
5061 /* Re-create the REG_DEAD notes. These notes are used in the machine
5062 description to use the best assembly directives. */
5063 if (optimize)
5065 df_note_add_problem ();
5066 df_analyze ();
5067 df_remove_problem (df_note);
5070 z_replacement_completed = 2;
5072 /* If optimizing, then go ahead and split insns that must be
5073 split after Z register replacement. This gives more opportunities
5074 for peephole (in particular for consecutives xgdx/xgdy). */
5075 if (optimize > 0)
5076 split_all_insns_noflow ();
5078 /* Once insns are split after the z_replacement_completed == 2,
5079 we must not re-run the life_analysis. The xgdx/xgdy patterns
5080 are not recognized and the life_analysis pass removes some
5081 insns because it thinks some (SETs) are noops or made to dead
5082 stores (which is false due to the swap).
5084 Do a simple pass to eliminate the noop set that the final
5085 split could generate (because it was easier for split definition). */
5087 rtx insn;
5089 for (insn = first; insn; insn = NEXT_INSN (insn))
5091 rtx body;
5093 if (INSN_DELETED_P (insn))
5094 continue;
5095 if (!INSN_P (insn))
5096 continue;
5098 /* Remove the (set (R) (R)) insns generated by some splits. */
5099 body = PATTERN (insn);
5100 if (GET_CODE (body) == SET
5101 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5103 SET_INSN_DELETED (insn);
5104 continue;
5110 /* Override memcpy */
5112 static void
5113 m68hc11_init_libfuncs (void)
5115 memcpy_libfunc = init_one_libfunc ("__memcpy");
5116 memcmp_libfunc = init_one_libfunc ("__memcmp");
5117 memset_libfunc = init_one_libfunc ("__memset");
5122 /* Cost functions. */
5124 /* Cost of moving memory. */
5126 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class rclass,
5127 int in ATTRIBUTE_UNUSED)
5129 if (rclass <= H_REGS && rclass > NO_REGS)
5131 if (GET_MODE_SIZE (mode) <= 2)
5132 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5133 else
5134 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5136 else
5138 if (GET_MODE_SIZE (mode) <= 2)
5139 return COSTS_N_INSNS (3);
5140 else
5141 return COSTS_N_INSNS (4);
5146 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5147 Reload does not check the constraint of set insns when the two registers
5148 have a move cost of 2. Setting a higher cost will force reload to check
5149 the constraints. */
5151 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5152 enum reg_class to)
5154 /* All costs are symmetric, so reduce cases by putting the
5155 lower number class as the destination. */
5156 if (from < to)
5158 enum reg_class tmp = to;
5159 to = from, from = tmp;
5161 if (to >= S_REGS)
5162 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5163 else if (from <= S_REGS)
5164 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5165 else
5166 return COSTS_N_INSNS (2);
5170 /* Provide the costs of an addressing mode that contains ADDR.
5171 If ADDR is not a valid address, its cost is irrelevant. */
5173 static int
5174 m68hc11_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
5176 int cost = 4;
5178 switch (GET_CODE (addr))
5180 case REG:
5181 /* Make the cost of hard registers and specially SP, FP small. */
5182 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5183 cost = 0;
5184 else
5185 cost = 1;
5186 break;
5188 case SYMBOL_REF:
5189 cost = 8;
5190 break;
5192 case LABEL_REF:
5193 case CONST:
5194 cost = 0;
5195 break;
5197 case PLUS:
5199 register rtx plus0 = XEXP (addr, 0);
5200 register rtx plus1 = XEXP (addr, 1);
5202 if (GET_CODE (plus0) != REG)
5203 break;
5205 switch (GET_CODE (plus1))
5207 case CONST_INT:
5208 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5209 || INTVAL (plus1) < m68hc11_min_offset)
5210 cost = 3;
5211 else if (INTVAL (plus1) >= m68hc11_max_offset)
5212 cost = 2;
5213 else
5214 cost = 1;
5215 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5216 cost += 0;
5217 else
5218 cost += 1;
5219 break;
5221 case SYMBOL_REF:
5222 cost = 8;
5223 break;
5225 case CONST:
5226 case LABEL_REF:
5227 cost = 0;
5228 break;
5230 default:
5231 break;
5233 break;
5235 case PRE_DEC:
5236 case PRE_INC:
5237 if (SP_REG_P (XEXP (addr, 0)))
5238 cost = 1;
5239 break;
5241 default:
5242 break;
5244 if (debug_m6811)
5246 printf ("Address cost: %d for :", cost);
5247 fflush (stdout);
5248 debug_rtx (addr);
5251 return cost;
5254 static int
5255 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5257 int total;
5259 total = rtx_cost (x, SET, !optimize_size);
5260 if (mode == QImode)
5261 total += m68hc11_cost->shiftQI_const[shift % 8];
5262 else if (mode == HImode)
5263 total += m68hc11_cost->shiftHI_const[shift % 16];
5264 else if (shift == 8 || shift == 16 || shift == 32)
5265 total += m68hc11_cost->shiftHI_const[8];
5266 else if (shift != 0 && shift != 16 && shift != 32)
5268 total += m68hc11_cost->shiftHI_const[1] * shift;
5271 /* For SI and others, the cost is higher. */
5272 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5273 total *= GET_MODE_SIZE (mode) / 2;
5275 /* When optimizing for size, make shift more costly so that
5276 multiplications are preferred. */
5277 if (optimize_size && (shift % 8) != 0)
5278 total *= 2;
5280 return total;
5283 static int
5284 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5285 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5287 enum machine_mode mode = GET_MODE (x);
5288 int extra_cost = 0;
5289 int total;
5291 switch (code)
5293 case ROTATE:
5294 case ROTATERT:
5295 case ASHIFT:
5296 case LSHIFTRT:
5297 case ASHIFTRT:
5298 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5300 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5303 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5304 total += m68hc11_cost->shift_var;
5305 return total;
5307 case AND:
5308 case XOR:
5309 case IOR:
5310 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5311 total += m68hc11_cost->logical;
5313 /* Logical instructions are byte instructions only. */
5314 total *= GET_MODE_SIZE (mode);
5315 return total;
5317 case MINUS:
5318 case PLUS:
5319 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5320 total += m68hc11_cost->add;
5321 if (GET_MODE_SIZE (mode) > 2)
5323 total *= GET_MODE_SIZE (mode) / 2;
5325 return total;
5327 case UDIV:
5328 case DIV:
5329 case MOD:
5330 total = rtx_cost (XEXP (x, 0), code, !optimize_size) + rtx_cost (XEXP (x, 1), code, !optimize_size);
5331 switch (mode)
5333 case QImode:
5334 total += m68hc11_cost->divQI;
5335 break;
5337 case HImode:
5338 total += m68hc11_cost->divHI;
5339 break;
5341 case SImode:
5342 default:
5343 total += m68hc11_cost->divSI;
5344 break;
5346 return total;
5348 case MULT:
5349 /* mul instruction produces 16-bit result. */
5350 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5351 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5352 return m68hc11_cost->multQI
5353 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5354 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5356 /* emul instruction produces 32-bit result for 68HC12. */
5357 if (TARGET_M6812 && mode == SImode
5358 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5359 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5360 return m68hc11_cost->multHI
5361 + rtx_cost (XEXP (XEXP (x, 0), 0), code, !optimize_size)
5362 + rtx_cost (XEXP (XEXP (x, 1), 0), code, !optimize_size);
5364 total = rtx_cost (XEXP (x, 0), code, !optimize_size)
5365 + rtx_cost (XEXP (x, 1), code, !optimize_size);
5366 switch (mode)
5368 case QImode:
5369 total += m68hc11_cost->multQI;
5370 break;
5372 case HImode:
5373 total += m68hc11_cost->multHI;
5374 break;
5376 case SImode:
5377 default:
5378 total += m68hc11_cost->multSI;
5379 break;
5381 return total;
5383 case NEG:
5384 case SIGN_EXTEND:
5385 extra_cost = COSTS_N_INSNS (2);
5387 /* Fall through */
5388 case NOT:
5389 case COMPARE:
5390 case ABS:
5391 case ZERO_EXTEND:
5392 case ZERO_EXTRACT:
5393 total = extra_cost + rtx_cost (XEXP (x, 0), code, !optimize_size);
5394 if (mode == QImode)
5396 return total + COSTS_N_INSNS (1);
5398 if (mode == HImode)
5400 return total + COSTS_N_INSNS (2);
5402 if (mode == SImode)
5404 return total + COSTS_N_INSNS (4);
5406 return total + COSTS_N_INSNS (8);
5408 case IF_THEN_ELSE:
5409 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5410 return COSTS_N_INSNS (1);
5412 return COSTS_N_INSNS (1);
5414 default:
5415 return COSTS_N_INSNS (4);
5419 static bool
5420 m68hc11_rtx_costs (rtx x, int codearg, int outer_code_arg, int *total,
5421 bool speed ATTRIBUTE_UNUSED)
5423 enum rtx_code code = (enum rtx_code) codearg;
5424 enum rtx_code outer_code = (enum rtx_code) outer_code_arg;
5426 switch (code)
5428 /* Constants are cheap. Moving them in registers must be avoided
5429 because most instructions do not handle two register operands. */
5430 case CONST_INT:
5431 case CONST:
5432 case LABEL_REF:
5433 case SYMBOL_REF:
5434 case CONST_DOUBLE:
5435 /* Logical and arithmetic operations with a constant operand are
5436 better because they are not supported with two registers. */
5437 /* 'clr' is slow */
5438 if (outer_code == SET && x == const0_rtx)
5439 /* After reload, the reload_cse pass checks the cost to change
5440 a SET into a PLUS. Make const0 cheap then. */
5441 *total = 1 - reload_completed;
5442 else
5443 *total = 0;
5444 return true;
5446 case ZERO_EXTRACT:
5447 if (outer_code != COMPARE)
5448 return false;
5450 case ROTATE:
5451 case ROTATERT:
5452 case ASHIFT:
5453 case LSHIFTRT:
5454 case ASHIFTRT:
5455 case MINUS:
5456 case PLUS:
5457 case AND:
5458 case XOR:
5459 case IOR:
5460 case UDIV:
5461 case DIV:
5462 case MOD:
5463 case MULT:
5464 case NEG:
5465 case SIGN_EXTEND:
5466 case NOT:
5467 case COMPARE:
5468 case ZERO_EXTEND:
5469 case IF_THEN_ELSE:
5470 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5471 return true;
5473 default:
5474 return false;
5479 /* Worker function for TARGET_ASM_FILE_START. */
5481 static void
5482 m68hc11_file_start (void)
5484 default_file_start ();
5486 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5490 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5492 static void
5493 m68hc11_asm_out_constructor (rtx symbol, int priority)
5495 default_ctor_section_asm_out_constructor (symbol, priority);
5496 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5499 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5501 static void
5502 m68hc11_asm_out_destructor (rtx symbol, int priority)
5504 default_dtor_section_asm_out_destructor (symbol, priority);
5505 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5508 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5510 static rtx
5511 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5512 int incoming ATTRIBUTE_UNUSED)
5514 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5517 /* Return true if type TYPE should be returned in memory.
5518 Blocks and data types largers than 4 bytes cannot be returned
5519 in the register (D + X = 4). */
5521 static bool
5522 m68hc11_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
5524 if (TYPE_MODE (type) == BLKmode)
5526 HOST_WIDE_INT size = int_size_in_bytes (type);
5527 return (size == -1 || size > 4);
5529 else
5530 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5533 #include "gt-m68hc11.h"