2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / gcc / config / m68hc11 / m68hc11.c
blob9a8651dd4409ba7368a59d59cb817109e6d80fe3
1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@nerim.fr)
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GCC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
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 "tm_p.h"
43 #include "regs.h"
44 #include "hard-reg-set.h"
45 #include "real.h"
46 #include "insn-config.h"
47 #include "conditions.h"
48 #include "output.h"
49 #include "insn-attr.h"
50 #include "flags.h"
51 #include "recog.h"
52 #include "expr.h"
53 #include "libfuncs.h"
54 #include "toplev.h"
55 #include "basic-block.h"
56 #include "function.h"
57 #include "ggc.h"
58 #include "reload.h"
59 #include "target.h"
60 #include "target-def.h"
62 static void emit_move_after_reload (rtx, rtx, rtx);
63 static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
64 static void m68hc11_emit_logical (enum machine_mode, int, rtx *);
65 static void m68hc11_reorg (void);
66 static int go_if_legitimate_address_internal (rtx, enum machine_mode, int);
67 static int register_indirect_p (rtx, enum machine_mode, int);
68 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
69 static int must_parenthesize (rtx);
70 static int m68hc11_address_cost (rtx);
71 static int m68hc11_shift_cost (enum machine_mode, rtx, int);
72 static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
73 static bool m68hc11_rtx_costs (rtx, int, int, int *);
74 static int m68hc11_auto_inc_p (rtx);
75 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
76 const struct attribute_spec m68hc11_attribute_table[];
78 void create_regs_rtx (void);
80 static void asm_print_register (FILE *, int);
81 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
82 static void m68hc11_asm_out_constructor (rtx, int);
83 static void m68hc11_asm_out_destructor (rtx, int);
84 static void m68hc11_file_start (void);
85 static void m68hc11_encode_section_info (tree, rtx, int);
86 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
87 static int autoinc_mode (rtx);
88 static int m68hc11_make_autoinc_notes (rtx *, void *);
89 static void m68hc11_init_libfuncs (void);
91 /* Must be set to 1 to produce debug messages. */
92 int debug_m6811 = 0;
94 extern FILE *asm_out_file;
96 rtx ix_reg;
97 rtx iy_reg;
98 rtx d_reg;
99 rtx m68hc11_soft_tmp_reg;
100 static GTY(()) rtx stack_push_word;
101 static GTY(()) rtx stack_pop_word;
102 static GTY(()) rtx z_reg;
103 static GTY(()) rtx z_reg_qi;
104 static int regs_inited = 0;
106 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
107 int current_function_interrupt;
109 /* Set to 1 by expand_prologue() when the function is a trap handler. */
110 int current_function_trap;
112 /* Set to 1 when the current function is placed in 68HC12 banked
113 memory and must return with rtc. */
114 int current_function_far;
116 /* Min offset that is valid for the indirect addressing mode. */
117 HOST_WIDE_INT m68hc11_min_offset = 0;
119 /* Max offset that is valid for the indirect addressing mode. */
120 HOST_WIDE_INT m68hc11_max_offset = 256;
122 /* The class value for base registers. */
123 enum reg_class m68hc11_base_reg_class = A_REGS;
125 /* The class value for index registers. This is NO_REGS for 68HC11. */
126 enum reg_class m68hc11_index_reg_class = NO_REGS;
128 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
130 /* Tables that tell whether a given hard register is valid for
131 a base or an index register. It is filled at init time depending
132 on the target processor. */
133 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
134 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
136 /* A correction offset which is applied to the stack pointer.
137 This is 1 for 68HC11 and 0 for 68HC12. */
138 int m68hc11_sp_correction;
140 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
141 rtx m68hc11_compare_op0;
142 rtx m68hc11_compare_op1;
145 const struct processor_costs *m68hc11_cost;
147 /* Costs for a 68HC11. */
148 static const struct processor_costs m6811_cost = {
149 /* add */
150 COSTS_N_INSNS (2),
151 /* logical */
152 COSTS_N_INSNS (2),
153 /* non-constant shift */
154 COSTS_N_INSNS (20),
155 /* shiftQI const */
156 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
157 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
158 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
160 /* shiftHI const */
161 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
162 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
163 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
164 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
165 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
166 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
168 /* mulQI */
169 COSTS_N_INSNS (20),
170 /* mulHI */
171 COSTS_N_INSNS (20 * 4),
172 /* mulSI */
173 COSTS_N_INSNS (20 * 16),
174 /* divQI */
175 COSTS_N_INSNS (20),
176 /* divHI */
177 COSTS_N_INSNS (80),
178 /* divSI */
179 COSTS_N_INSNS (100)
182 /* Costs for a 68HC12. */
183 static const struct processor_costs m6812_cost = {
184 /* add */
185 COSTS_N_INSNS (2),
186 /* logical */
187 COSTS_N_INSNS (2),
188 /* non-constant shift */
189 COSTS_N_INSNS (20),
190 /* shiftQI const */
191 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
192 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
193 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
195 /* shiftHI const */
196 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
197 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
198 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
199 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
200 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
201 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
203 /* mulQI */
204 COSTS_N_INSNS (3),
205 /* mulHI */
206 COSTS_N_INSNS (3),
207 /* mulSI */
208 COSTS_N_INSNS (3 * 4),
209 /* divQI */
210 COSTS_N_INSNS (12),
211 /* divHI */
212 COSTS_N_INSNS (12),
213 /* divSI */
214 COSTS_N_INSNS (100)
217 /* Machine specific options */
219 const char *m68hc11_regparm_string;
220 const char *m68hc11_reg_alloc_order;
221 const char *m68hc11_soft_reg_count;
223 static int nb_soft_regs;
225 /* Initialize the GCC target structure. */
226 #undef TARGET_ATTRIBUTE_TABLE
227 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
229 #undef TARGET_ASM_ALIGNED_HI_OP
230 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
232 #undef TARGET_ASM_FUNCTION_EPILOGUE
233 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
235 #undef TARGET_ASM_FILE_START
236 #define TARGET_ASM_FILE_START m68hc11_file_start
237 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
238 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
240 #undef TARGET_ENCODE_SECTION_INFO
241 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
243 #undef TARGET_SECTION_TYPE_FLAGS
244 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
246 #undef TARGET_RTX_COSTS
247 #define TARGET_RTX_COSTS m68hc11_rtx_costs
248 #undef TARGET_ADDRESS_COST
249 #define TARGET_ADDRESS_COST m68hc11_address_cost
251 #undef TARGET_MACHINE_DEPENDENT_REORG
252 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
254 #undef TARGET_INIT_LIBFUNCS
255 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
257 struct gcc_target targetm = TARGET_INITIALIZER;
260 m68hc11_override_options (void)
262 memset (m68hc11_reg_valid_for_index, 0,
263 sizeof (m68hc11_reg_valid_for_index));
264 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
266 /* Compilation with -fpic generates a wrong code. */
267 if (flag_pic)
269 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
270 (flag_pic > 1) ? "PIC" : "pic");
271 flag_pic = 0;
274 /* Configure for a 68hc11 processor. */
275 if (TARGET_M6811)
277 /* If gcc was built for a 68hc12, invalidate that because
278 a -m68hc11 option was specified on the command line. */
279 if (TARGET_DEFAULT != MASK_M6811)
280 target_flags &= ~TARGET_DEFAULT;
282 if (!TARGET_M6812)
283 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
284 m68hc11_cost = &m6811_cost;
285 m68hc11_min_offset = 0;
286 m68hc11_max_offset = 256;
287 m68hc11_index_reg_class = NO_REGS;
288 m68hc11_base_reg_class = A_REGS;
289 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
290 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
291 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
292 m68hc11_sp_correction = 1;
293 m68hc11_tmp_regs_class = D_REGS;
294 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
295 m68hc11_soft_reg_count = "4";
298 /* Configure for a 68hc12 processor. */
299 if (TARGET_M6812)
301 m68hc11_cost = &m6812_cost;
302 m68hc11_min_offset = -65536;
303 m68hc11_max_offset = 65536;
304 m68hc11_index_reg_class = D_REGS;
305 m68hc11_base_reg_class = A_OR_SP_REGS;
306 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
307 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
308 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
309 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
310 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
311 m68hc11_sp_correction = 0;
312 m68hc11_tmp_regs_class = TMP_REGS;
313 target_flags &= ~MASK_M6811;
314 target_flags |= MASK_NO_DIRECT_MODE;
315 if (m68hc11_soft_reg_count == 0)
316 m68hc11_soft_reg_count = "0";
318 if (TARGET_LONG_CALLS)
319 current_function_far = 1;
321 return 0;
325 void
326 m68hc11_conditional_register_usage (void)
328 int i;
329 int cnt = atoi (m68hc11_soft_reg_count);
331 if (cnt < 0)
332 cnt = 0;
333 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
334 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
336 nb_soft_regs = cnt;
337 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
339 fixed_regs[i] = 1;
340 call_used_regs[i] = 1;
343 /* For 68HC12, the Z register emulation is not necessary when the
344 frame pointer is not used. The frame pointer is eliminated and
345 replaced by the stack register (which is a BASE_REG_CLASS). */
346 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
348 fixed_regs[HARD_Z_REGNUM] = 1;
353 /* Reload and register operations. */
355 static const char *const reg_class_names[] = REG_CLASS_NAMES;
358 void
359 create_regs_rtx (void)
361 /* regs_inited = 1; */
362 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
363 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
364 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
365 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
367 stack_push_word = gen_rtx (MEM, HImode,
368 gen_rtx (PRE_DEC, HImode,
369 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
370 stack_pop_word = gen_rtx (MEM, HImode,
371 gen_rtx (POST_INC, HImode,
372 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
376 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
377 - 8 bit values are stored anywhere (except the SP register).
378 - 16 bit values can be stored in any register whose mode is 16
379 - 32 bit values can be stored in D, X registers or in a soft register
380 (except the last one because we need 2 soft registers)
381 - Values whose size is > 32 bit are not stored in real hard
382 registers. They may be stored in soft registers if there are
383 enough of them. */
385 hard_regno_mode_ok (int regno, enum machine_mode mode)
387 switch (GET_MODE_SIZE (mode))
389 case 8:
390 return S_REGNO_P (regno) && nb_soft_regs >= 4;
392 case 4:
393 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
395 case 2:
396 return G_REGNO_P (regno);
398 case 1:
399 /* We have to accept a QImode in X or Y registers. Otherwise, the
400 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
401 in the insns. Reload fails if the insn rejects the register class 'a'
402 as well as if it accepts it. Patterns that failed were
403 zero_extend_qihi2 and iorqi3. */
405 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
407 default:
408 return 0;
413 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
415 /* Don't accept renaming to Z register. We will replace it to
416 X,Y or D during machine reorg pass. */
417 if (reg2 == HARD_Z_REGNUM)
418 return 0;
420 /* Don't accept renaming D,X to Y register as the code will be bigger. */
421 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
422 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
423 return 0;
425 return 1;
428 enum reg_class
429 preferred_reload_class (rtx operand, enum reg_class class)
431 enum machine_mode mode;
433 mode = GET_MODE (operand);
435 if (debug_m6811)
437 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
440 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
441 return m68hc11_base_reg_class;
443 if (class >= S_REGS && (GET_CODE (operand) == MEM
444 || GET_CODE (operand) == CONST_INT))
446 /* S_REGS class must not be used. The movhi template does not
447 work to move a memory to a soft register.
448 Restrict to a hard reg. */
449 switch (class)
451 default:
452 case G_REGS:
453 case D_OR_A_OR_S_REGS:
454 class = A_OR_D_REGS;
455 break;
456 case A_OR_S_REGS:
457 class = A_REGS;
458 break;
459 case D_OR_SP_OR_S_REGS:
460 class = D_OR_SP_REGS;
461 break;
462 case D_OR_Y_OR_S_REGS:
463 class = D_OR_Y_REGS;
464 break;
465 case D_OR_X_OR_S_REGS:
466 class = D_OR_X_REGS;
467 break;
468 case SP_OR_S_REGS:
469 class = SP_REGS;
470 break;
471 case Y_OR_S_REGS:
472 class = Y_REGS;
473 break;
474 case X_OR_S_REGS:
475 class = X_REGS;
476 break;
477 case D_OR_S_REGS:
478 class = D_REGS;
481 else if (class == Y_REGS && GET_CODE (operand) == MEM)
483 class = Y_REGS;
485 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
487 class = D_OR_X_REGS;
489 else if (class >= S_REGS && S_REG_P (operand))
491 switch (class)
493 default:
494 case G_REGS:
495 case D_OR_A_OR_S_REGS:
496 class = A_OR_D_REGS;
497 break;
498 case A_OR_S_REGS:
499 class = A_REGS;
500 break;
501 case D_OR_SP_OR_S_REGS:
502 class = D_OR_SP_REGS;
503 break;
504 case D_OR_Y_OR_S_REGS:
505 class = D_OR_Y_REGS;
506 break;
507 case D_OR_X_OR_S_REGS:
508 class = D_OR_X_REGS;
509 break;
510 case SP_OR_S_REGS:
511 class = SP_REGS;
512 break;
513 case Y_OR_S_REGS:
514 class = Y_REGS;
515 break;
516 case X_OR_S_REGS:
517 class = X_REGS;
518 break;
519 case D_OR_S_REGS:
520 class = D_REGS;
523 else if (class >= S_REGS)
525 if (debug_m6811)
527 printf ("Class = %s for: ", reg_class_names[class]);
528 fflush (stdout);
529 debug_rtx (operand);
533 if (debug_m6811)
535 printf (" => class=%s\n", reg_class_names[class]);
536 fflush (stdout);
537 debug_rtx (operand);
540 return class;
543 /* Return 1 if the operand is a valid indexed addressing mode.
544 For 68hc11: n,r with n in [0..255] and r in A_REGS class
545 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
546 static int
547 register_indirect_p (rtx operand, enum machine_mode mode, int strict)
549 rtx base, offset;
551 switch (GET_CODE (operand))
553 case POST_INC:
554 case PRE_INC:
555 case POST_DEC:
556 case PRE_DEC:
557 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
558 return register_indirect_p (XEXP (operand, 0), mode, strict);
559 return 0;
561 case PLUS:
562 base = XEXP (operand, 0);
563 if (GET_CODE (base) == MEM)
564 return 0;
566 offset = XEXP (operand, 1);
567 if (GET_CODE (offset) == MEM)
568 return 0;
570 if (GET_CODE (base) == REG)
572 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
573 return 0;
575 if (strict == 0)
576 return 1;
578 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
580 if (GET_CODE (offset) == REG)
582 if (!VALID_CONSTANT_OFFSET_P (base, mode))
583 return 0;
585 if (strict == 0)
586 return 1;
588 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
590 return 0;
592 case REG:
593 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
595 case CONST_INT:
596 if (TARGET_M6811)
597 return 0;
599 return VALID_CONSTANT_OFFSET_P (operand, mode);
601 default:
602 return 0;
606 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
607 a 68HC12 1-byte index addressing mode. */
609 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
611 rtx base, offset;
613 if (GET_CODE (operand) == REG && reload_in_progress
614 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
615 && reg_equiv_memory_loc[REGNO (operand)])
617 operand = reg_equiv_memory_loc[REGNO (operand)];
618 operand = eliminate_regs (operand, 0, NULL_RTX);
621 if (GET_CODE (operand) != MEM)
622 return 0;
624 operand = XEXP (operand, 0);
625 if (CONSTANT_ADDRESS_P (operand))
626 return 1;
628 if (PUSH_POP_ADDRESS_P (operand))
629 return 1;
631 if (!register_indirect_p (operand, mode, reload_completed))
632 return 0;
634 if (TARGET_M6812 && GET_CODE (operand) == PLUS
635 && (reload_completed | reload_in_progress))
637 base = XEXP (operand, 0);
638 offset = XEXP (operand, 1);
640 /* The offset can be a symbol address and this is too big
641 for the operand constraint. */
642 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
643 return 0;
645 if (GET_CODE (base) == CONST_INT)
646 offset = base;
648 switch (GET_MODE_SIZE (mode))
650 case 8:
651 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
652 return 0;
653 break;
655 case 4:
656 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
657 return 0;
658 break;
660 default:
661 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
662 return 0;
663 break;
666 return 1;
670 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
672 if (GET_CODE (operand) != MEM)
673 return 0;
675 operand = XEXP (operand, 0);
676 return register_indirect_p (operand, mode,
677 (reload_completed | reload_in_progress));
680 static int
681 go_if_legitimate_address_internal (rtx operand, enum machine_mode mode,
682 int strict)
684 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
686 /* Reject the global variables if they are too wide. This forces
687 a load of their address in a register and generates smaller code. */
688 if (GET_MODE_SIZE (mode) == 8)
689 return 0;
691 return 1;
693 if (register_indirect_p (operand, mode, strict))
695 return 1;
697 if (PUSH_POP_ADDRESS_P (operand))
699 return 1;
701 if (symbolic_memory_operand (operand, mode))
703 return 1;
705 return 0;
709 m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode,
710 int strict)
712 int result;
714 if (debug_m6811)
716 printf ("Checking: ");
717 fflush (stdout);
718 debug_rtx (operand);
721 result = go_if_legitimate_address_internal (operand, mode, strict);
723 if (debug_m6811)
725 printf (" -> %s\n", result == 0 ? "NO" : "YES");
728 if (result == 0)
730 if (debug_m6811)
732 printf ("go_if_legitimate%s, ret 0: %d:",
733 (strict ? "_strict" : ""), mode);
734 fflush (stdout);
735 debug_rtx (operand);
738 return result;
742 m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED,
743 rtx old_operand ATTRIBUTE_UNUSED,
744 enum machine_mode mode ATTRIBUTE_UNUSED)
746 return 0;
751 m68hc11_reload_operands (rtx operands[])
753 enum machine_mode mode;
755 if (regs_inited == 0)
756 create_regs_rtx ();
758 mode = GET_MODE (operands[1]);
760 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
761 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
763 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
764 rtx base = XEXP (XEXP (operands[1], 0), 0);
766 if (GET_CODE (base) != REG)
768 rtx tmp = base;
769 base = big_offset;
770 big_offset = tmp;
773 /* If the offset is out of range, we have to compute the address
774 with a separate add instruction. We try to do with with an 8-bit
775 add on the A register. This is possible only if the lowest part
776 of the offset (ie, big_offset % 256) is a valid constant offset
777 with respect to the mode. If it's not, we have to generate a
778 16-bit add on the D register. From:
780 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
782 we generate:
784 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
785 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
786 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
787 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
789 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
790 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
793 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
795 int vh, vl;
796 rtx reg = operands[0];
797 rtx offset;
798 int val = INTVAL (big_offset);
801 /* We use the 'operands[0]' as a scratch register to compute the
802 address. Make sure 'base' is in that register. */
803 if (!rtx_equal_p (base, operands[0]))
805 emit_move_insn (reg, base);
808 if (val > 0)
810 vh = val >> 8;
811 vl = val & 0x0FF;
813 else
815 vh = (val >> 8) & 0x0FF;
816 vl = val & 0x0FF;
819 /* Create the lowest part offset that still remains to be added.
820 If it's not a valid offset, do a 16-bit add. */
821 offset = GEN_INT (vl);
822 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
824 emit_insn (gen_rtx (SET, VOIDmode, reg,
825 gen_rtx (PLUS, HImode, reg, big_offset)));
826 offset = const0_rtx;
828 else
830 emit_insn (gen_rtx (SET, VOIDmode, reg,
831 gen_rtx (PLUS, HImode, reg,
832 GEN_INT (vh << 8))));
834 emit_move_insn (operands[0],
835 gen_rtx (MEM, GET_MODE (operands[1]),
836 gen_rtx (PLUS, Pmode, reg, offset)));
837 return 1;
841 /* Use the normal gen_movhi pattern. */
842 return 0;
845 void
846 m68hc11_emit_libcall (const char *name, enum rtx_code code,
847 enum machine_mode dmode, enum machine_mode smode,
848 int noperands, rtx *operands)
850 rtx ret;
851 rtx insns;
852 rtx libcall;
853 rtx equiv;
855 start_sequence ();
856 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
857 switch (noperands)
859 case 2:
860 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
861 dmode, 1, operands[1], smode);
862 equiv = gen_rtx (code, dmode, operands[1]);
863 break;
865 case 3:
866 ret = emit_library_call_value (libcall, NULL_RTX,
867 LCT_CONST, dmode, 2,
868 operands[1], smode, operands[2],
869 smode);
870 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
871 break;
873 default:
874 abort ();
877 insns = get_insns ();
878 end_sequence ();
879 emit_libcall_block (insns, operands[0], ret, equiv);
882 /* Returns true if X is a PRE/POST increment decrement
883 (same as auto_inc_p() in rtlanal.c but do not take into
884 account the stack). */
885 static int
886 m68hc11_auto_inc_p (rtx x)
888 return GET_CODE (x) == PRE_DEC
889 || GET_CODE (x) == POST_INC
890 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
894 /* Predicates for machine description. */
897 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
899 return GET_CODE (operand) == MEM
900 && GET_CODE (XEXP (operand, 0)) == PLUS
901 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
902 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
903 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
904 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
908 tst_operand (rtx operand, enum machine_mode mode)
910 if (GET_CODE (operand) == MEM && reload_completed == 0)
912 rtx addr = XEXP (operand, 0);
913 if (m68hc11_auto_inc_p (addr))
914 return 0;
916 return nonimmediate_operand (operand, mode);
920 cmp_operand (rtx operand, enum machine_mode mode)
922 if (GET_CODE (operand) == MEM)
924 rtx addr = XEXP (operand, 0);
925 if (m68hc11_auto_inc_p (addr))
926 return 0;
928 return general_operand (operand, mode);
932 non_push_operand (rtx operand, enum machine_mode mode)
934 if (general_operand (operand, mode) == 0)
935 return 0;
937 if (push_operand (operand, mode) == 1)
938 return 0;
939 return 1;
943 reg_or_some_mem_operand (rtx operand, enum machine_mode mode)
945 if (GET_CODE (operand) == MEM)
947 rtx op = XEXP (operand, 0);
949 if (symbolic_memory_operand (op, mode))
950 return 1;
952 if (IS_STACK_PUSH (operand))
953 return 1;
955 if (m68hc11_register_indirect_p (operand, mode))
956 return 1;
958 return 0;
961 return register_operand (operand, mode);
965 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
967 if (GET_CODE (operand) == MEM)
969 rtx op = XEXP (operand, 0);
971 if (symbolic_memory_operand (op, mode))
972 return 1;
974 return 0;
978 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
980 if (GET_CODE (operand) == MEM)
982 rtx op = XEXP (operand, 0);
984 if (symbolic_memory_operand (op, mode))
985 return 0;
987 if (reload_in_progress)
988 return 1;
990 operand = XEXP (operand, 0);
991 return register_indirect_p (operand, mode, reload_completed);
993 return 0;
997 stack_register_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
999 return SP_REG_P (operand);
1003 d_register_operand (rtx operand, enum machine_mode mode)
1005 if (GET_MODE (operand) != mode && mode != VOIDmode)
1006 return 0;
1008 if (GET_CODE (operand) == SUBREG)
1009 operand = XEXP (operand, 0);
1011 return GET_CODE (operand) == REG
1012 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1013 || REGNO (operand) == HARD_D_REGNUM
1014 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
1018 hard_addr_reg_operand (rtx operand, enum machine_mode mode)
1020 if (GET_MODE (operand) != mode && mode != VOIDmode)
1021 return 0;
1023 if (GET_CODE (operand) == SUBREG)
1024 operand = XEXP (operand, 0);
1026 return GET_CODE (operand) == REG
1027 && (REGNO (operand) == HARD_X_REGNUM
1028 || REGNO (operand) == HARD_Y_REGNUM
1029 || REGNO (operand) == HARD_Z_REGNUM);
1033 hard_reg_operand (rtx operand, enum machine_mode mode)
1035 if (GET_MODE (operand) != mode && mode != VOIDmode)
1036 return 0;
1038 if (GET_CODE (operand) == SUBREG)
1039 operand = XEXP (operand, 0);
1041 return GET_CODE (operand) == REG
1042 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1043 || H_REGNO_P (REGNO (operand)));
1047 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1049 if (GET_CODE (operand) != MEM)
1050 return 0;
1052 operand = XEXP (operand, 0);
1053 if (GET_CODE (operand) == PLUS)
1055 if (GET_CODE (XEXP (operand, 0)) == REG)
1056 operand = XEXP (operand, 0);
1057 else if (GET_CODE (XEXP (operand, 1)) == REG)
1058 operand = XEXP (operand, 1);
1060 return GET_CODE (operand) == REG
1061 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1062 || A_REGNO_P (REGNO (operand)));
1066 push_pop_operand_p (rtx operand)
1068 if (GET_CODE (operand) != MEM)
1070 return 0;
1072 operand = XEXP (operand, 0);
1073 return PUSH_POP_ADDRESS_P (operand);
1076 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1077 reference and a constant. */
1080 symbolic_memory_operand (rtx op, enum machine_mode mode)
1082 switch (GET_CODE (op))
1084 case SYMBOL_REF:
1085 case LABEL_REF:
1086 return 1;
1088 case CONST:
1089 op = XEXP (op, 0);
1090 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1091 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1092 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1094 /* ??? This clause seems to be irrelevant. */
1095 case CONST_DOUBLE:
1096 return GET_MODE (op) == mode;
1098 case PLUS:
1099 return symbolic_memory_operand (XEXP (op, 0), mode)
1100 && symbolic_memory_operand (XEXP (op, 1), mode);
1102 default:
1103 return 0;
1108 m68hc11_eq_compare_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1110 return GET_CODE (op) == EQ || GET_CODE (op) == NE;
1114 m68hc11_logical_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1116 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1120 m68hc11_arith_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1122 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1123 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1124 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1125 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1126 || GET_CODE (op) == ROTATERT;
1130 m68hc11_non_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1132 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1133 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1136 /* Return true if op is a shift operator. */
1138 m68hc11_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1140 return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
1141 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
1142 || GET_CODE (op) == ASHIFTRT;
1146 m68hc11_unary_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1148 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1149 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1152 /* Emit the code to build the trampoline used to call a nested function.
1154 68HC11 68HC12
1156 ldy #&CXT movw #&CXT,*_.d1
1157 sty *_.d1 jmp FNADDR
1158 jmp FNADDR
1161 void
1162 m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1164 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1166 /* Skip the '*'. */
1167 if (*static_chain_reg == '*')
1168 static_chain_reg++;
1169 if (TARGET_M6811)
1171 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1172 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1173 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1174 GEN_INT (0x18df));
1175 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1176 gen_rtx_CONST (QImode,
1177 gen_rtx_SYMBOL_REF (Pmode,
1178 static_chain_reg)));
1179 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1180 GEN_INT (0x7e));
1181 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1183 else
1185 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1186 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1187 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1188 gen_rtx_CONST (HImode,
1189 gen_rtx_SYMBOL_REF (Pmode,
1190 static_chain_reg)));
1191 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1192 GEN_INT (0x06));
1193 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1197 /* Declaration of types. */
1199 const struct attribute_spec m68hc11_attribute_table[] =
1201 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1202 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1203 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1204 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1205 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1206 { NULL, 0, 0, false, false, false, NULL }
1209 /* Keep track of the symbol which has a `trap' attribute and which uses
1210 the `swi' calling convention. Since there is only one trap, we only
1211 record one such symbol. If there are several, a warning is reported. */
1212 static rtx trap_handler_symbol = 0;
1214 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1215 arguments as in struct attribute_spec.handler. */
1216 static tree
1217 m68hc11_handle_fntype_attribute (tree *node, tree name,
1218 tree args ATTRIBUTE_UNUSED,
1219 int flags ATTRIBUTE_UNUSED,
1220 bool *no_add_attrs)
1222 if (TREE_CODE (*node) != FUNCTION_TYPE
1223 && TREE_CODE (*node) != METHOD_TYPE
1224 && TREE_CODE (*node) != FIELD_DECL
1225 && TREE_CODE (*node) != TYPE_DECL)
1227 warning ("`%s' attribute only applies to functions",
1228 IDENTIFIER_POINTER (name));
1229 *no_add_attrs = true;
1232 return NULL_TREE;
1235 /* We want to recognize trap handlers so that we handle calls to traps
1236 in a special manner (by issuing the trap). This information is stored
1237 in SYMBOL_REF_FLAG. */
1239 static void
1240 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1242 tree func_attr;
1243 int trap_handler;
1244 int is_far = 0;
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 ("`trap' and `far' attributes are not compatible, ignoring `far'");
1261 trap_handler = 0;
1263 if (trap_handler)
1265 if (trap_handler_symbol != 0)
1266 warning ("`trap' attribute is already used");
1267 else
1268 trap_handler_symbol = XEXP (rtl, 0);
1270 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1273 static unsigned int
1274 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1276 unsigned int flags = default_section_type_flags (decl, name, reloc);
1278 if (strncmp (name, ".eeprom", 7) == 0)
1280 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1283 return flags;
1287 m68hc11_is_far_symbol (rtx sym)
1289 if (GET_CODE (sym) == MEM)
1290 sym = XEXP (sym, 0);
1292 return SYMBOL_REF_FLAG (sym);
1296 m68hc11_is_trap_symbol (rtx sym)
1298 if (GET_CODE (sym) == MEM)
1299 sym = XEXP (sym, 0);
1301 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1305 /* Argument support functions. */
1307 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1308 Arrays are passed by references and other types by value.
1310 SCz: I tried to pass DImode by reference but it seems that this
1311 does not work very well. */
1313 m68hc11_function_arg_pass_by_reference (const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1314 enum machine_mode mode ATTRIBUTE_UNUSED,
1315 tree type,
1316 int named ATTRIBUTE_UNUSED)
1318 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1319 /* Consider complex values as aggregates, so care for TCmode. */
1320 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1321 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1325 /* Define the offset between two registers, one to be eliminated, and the
1326 other its replacement, at the start of a routine. */
1328 m68hc11_initial_elimination_offset (int from, int to)
1330 int trap_handler;
1331 tree func_attr;
1332 int size;
1333 int regno;
1335 /* For a trap handler, we must take into account the registers which
1336 are pushed on the stack during the trap (except the PC). */
1337 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1339 if (lookup_attribute ("far", func_attr) != 0)
1340 current_function_far = 1;
1341 else if (lookup_attribute ("near", func_attr) != 0)
1342 current_function_far = 0;
1343 else
1344 current_function_far = TARGET_LONG_CALLS != 0;
1346 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
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 (regs_ever_live[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. */
1515 m68hc11_function_arg_padding (enum machine_mode mode, 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))
1548 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1549 XEXP (XEXP (to, 0), 0),
1550 REG_NOTES (insn));
1552 else if (IS_STACK_POP (from))
1554 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1555 XEXP (XEXP (from, 0), 0),
1556 REG_NOTES (insn));
1559 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1560 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1561 The problem is that we are lying to gcc and use `txs' for x = sp
1562 (which is not really true because txs is really x = sp + 1). */
1563 else if (TARGET_M6811 && SP_REG_P (from))
1565 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1566 from,
1567 REG_NOTES (insn));
1572 m68hc11_total_frame_size (void)
1574 int size;
1575 int regno;
1577 size = get_frame_size ();
1578 if (current_function_interrupt)
1580 size += 3 * HARD_REG_SIZE;
1582 if (frame_pointer_needed)
1583 size += HARD_REG_SIZE;
1585 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1586 if (regs_ever_live[regno] && !call_used_regs[regno])
1587 size += HARD_REG_SIZE;
1589 return size;
1592 static void
1593 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1594 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1596 /* We catch the function epilogue generation to have a chance
1597 to clear the z_replacement_completed flag. */
1598 z_replacement_completed = 0;
1601 void
1602 expand_prologue (void)
1604 tree func_attr;
1605 int size;
1606 int regno;
1607 rtx scratch;
1609 if (reload_completed != 1)
1610 abort ();
1612 size = get_frame_size ();
1614 create_regs_rtx ();
1616 /* Generate specific prologue for interrupt handlers. */
1617 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1618 current_function_interrupt = lookup_attribute ("interrupt",
1619 func_attr) != NULL_TREE;
1620 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1621 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1622 current_function_far = 1;
1623 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1624 current_function_far = 0;
1625 else
1626 current_function_far = TARGET_LONG_CALLS != 0;
1628 /* Get the scratch register to build the frame and push registers.
1629 If the first argument is a 32-bit quantity, the D+X registers
1630 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1631 For 68HC12, this scratch register is not used. */
1632 if (current_function_args_info.nregs == 2)
1633 scratch = iy_reg;
1634 else
1635 scratch = ix_reg;
1637 /* Save current stack frame. */
1638 if (frame_pointer_needed)
1639 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1641 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1642 Other soft registers in page0 need not to be saved because they
1643 will be restored by C functions. For a trap handler, we don't
1644 need to preserve these registers because this is a synchronous call. */
1645 if (current_function_interrupt)
1647 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1648 emit_move_after_reload (stack_push_word,
1649 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1650 emit_move_after_reload (stack_push_word,
1651 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1652 scratch);
1655 /* Allocate local variables. */
1656 if (TARGET_M6812 && (size > 4 || size == 3))
1658 emit_insn (gen_addhi3 (stack_pointer_rtx,
1659 stack_pointer_rtx, GEN_INT (-size)));
1661 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1663 rtx insn;
1665 insn = gen_rtx_PARALLEL
1666 (VOIDmode,
1667 gen_rtvec (2,
1668 gen_rtx_SET (VOIDmode,
1669 stack_pointer_rtx,
1670 gen_rtx_PLUS (HImode,
1671 stack_pointer_rtx,
1672 GEN_INT (-size))),
1673 gen_rtx_CLOBBER (VOIDmode, scratch)));
1674 emit_insn (insn);
1676 else
1678 int i;
1680 /* Allocate by pushing scratch values. */
1681 for (i = 2; i <= size; i += 2)
1682 emit_move_after_reload (stack_push_word, ix_reg, 0);
1684 if (size & 1)
1685 emit_insn (gen_addhi3 (stack_pointer_rtx,
1686 stack_pointer_rtx, GEN_INT (-1)));
1689 /* Create the frame pointer. */
1690 if (frame_pointer_needed)
1691 emit_move_after_reload (hard_frame_pointer_rtx,
1692 stack_pointer_rtx, scratch);
1694 /* Push any 2 byte pseudo hard registers that we need to save. */
1695 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1697 if (regs_ever_live[regno] && !call_used_regs[regno])
1699 emit_move_after_reload (stack_push_word,
1700 gen_rtx (REG, HImode, regno), scratch);
1705 void
1706 expand_epilogue (void)
1708 int size;
1709 register int regno;
1710 int return_size;
1711 rtx scratch;
1713 if (reload_completed != 1)
1714 abort ();
1716 size = get_frame_size ();
1718 /* If we are returning a value in two registers, we have to preserve the
1719 X register and use the Y register to restore the stack and the saved
1720 registers. Otherwise, use X because it's faster (and smaller). */
1721 if (current_function_return_rtx == 0)
1722 return_size = 0;
1723 else if (GET_CODE (current_function_return_rtx) == MEM)
1724 return_size = HARD_REG_SIZE;
1725 else
1726 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1728 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1729 scratch = iy_reg;
1730 else
1731 scratch = ix_reg;
1733 /* Pop any 2 byte pseudo hard registers that we saved. */
1734 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1736 if (regs_ever_live[regno] && !call_used_regs[regno])
1738 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1739 stack_pop_word, scratch);
1743 /* de-allocate auto variables */
1744 if (TARGET_M6812 && (size > 4 || size == 3))
1746 emit_insn (gen_addhi3 (stack_pointer_rtx,
1747 stack_pointer_rtx, GEN_INT (size)));
1749 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1751 rtx insn;
1753 insn = gen_rtx_PARALLEL
1754 (VOIDmode,
1755 gen_rtvec (2,
1756 gen_rtx_SET (VOIDmode,
1757 stack_pointer_rtx,
1758 gen_rtx_PLUS (HImode,
1759 stack_pointer_rtx,
1760 GEN_INT (size))),
1761 gen_rtx_CLOBBER (VOIDmode, scratch)));
1762 emit_insn (insn);
1764 else
1766 int i;
1768 for (i = 2; i <= size; i += 2)
1769 emit_move_after_reload (scratch, stack_pop_word, scratch);
1770 if (size & 1)
1771 emit_insn (gen_addhi3 (stack_pointer_rtx,
1772 stack_pointer_rtx, GEN_INT (1)));
1775 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1776 if (current_function_interrupt)
1778 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1779 stack_pop_word, scratch);
1780 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1781 stack_pop_word, scratch);
1782 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1785 /* Restore previous frame pointer. */
1786 if (frame_pointer_needed)
1787 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1789 /* If the trap handler returns some value, copy the value
1790 in D, X onto the stack so that the rti will pop the return value
1791 correctly. */
1792 else if (current_function_trap && return_size != 0)
1794 rtx addr_reg = stack_pointer_rtx;
1796 if (!TARGET_M6812)
1798 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1799 addr_reg = scratch;
1801 emit_move_after_reload (gen_rtx (MEM, HImode,
1802 gen_rtx (PLUS, HImode, addr_reg,
1803 GEN_INT (1))), d_reg, 0);
1804 if (return_size > HARD_REG_SIZE)
1805 emit_move_after_reload (gen_rtx (MEM, HImode,
1806 gen_rtx (PLUS, HImode, addr_reg,
1807 GEN_INT (3))), ix_reg, 0);
1810 emit_jump_insn (gen_return ());
1814 /* Low and High part extraction for 68HC11. These routines are
1815 similar to gen_lowpart and gen_highpart but they have been
1816 fixed to work for constants and 68HC11 specific registers. */
1819 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1821 /* We assume that the low part of an auto-inc mode is the same with
1822 the mode changed and that the caller split the larger mode in the
1823 correct order. */
1824 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1826 return gen_rtx (MEM, mode, XEXP (x, 0));
1829 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1830 floating-point constant. A CONST_DOUBLE is used whenever the
1831 constant requires more than one word in order to be adequately
1832 represented. */
1833 if (GET_CODE (x) == CONST_DOUBLE)
1835 long l[2];
1837 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1839 REAL_VALUE_TYPE r;
1841 if (GET_MODE (x) == SFmode)
1843 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1844 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1846 else
1848 rtx first, second;
1850 split_double (x, &first, &second);
1851 return second;
1853 if (mode == SImode)
1854 return GEN_INT (l[0]);
1856 return gen_int_mode (l[0], HImode);
1858 else
1860 l[0] = CONST_DOUBLE_LOW (x);
1862 if (mode == SImode)
1863 return GEN_INT (l[0]);
1864 else if (mode == HImode && GET_MODE (x) == SFmode)
1865 return gen_int_mode (l[0], HImode);
1866 else
1867 abort ();
1870 if (mode == QImode && D_REG_P (x))
1871 return gen_rtx (REG, mode, HARD_B_REGNUM);
1873 /* gen_lowpart crashes when it is called with a SUBREG. */
1874 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1876 if (mode == SImode)
1877 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1878 else if (mode == HImode)
1879 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1880 else
1881 abort ();
1883 x = gen_lowpart (mode, x);
1885 /* Return a different rtx to avoid to share it in several insns
1886 (when used by a split pattern). Sharing addresses within
1887 a MEM breaks the Z register replacement (and reloading). */
1888 if (GET_CODE (x) == MEM)
1889 x = copy_rtx (x);
1890 return x;
1894 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1896 /* We assume that the high part of an auto-inc mode is the same with
1897 the mode changed and that the caller split the larger mode in the
1898 correct order. */
1899 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1901 return gen_rtx (MEM, mode, XEXP (x, 0));
1904 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1905 floating-point constant. A CONST_DOUBLE is used whenever the
1906 constant requires more than one word in order to be adequately
1907 represented. */
1908 if (GET_CODE (x) == CONST_DOUBLE)
1910 long l[2];
1912 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1914 REAL_VALUE_TYPE r;
1916 if (GET_MODE (x) == SFmode)
1918 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1919 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1921 else
1923 rtx first, second;
1925 split_double (x, &first, &second);
1926 return first;
1928 if (mode == SImode)
1929 return GEN_INT (l[1]);
1931 return gen_int_mode ((l[1] >> 16), HImode);
1933 else
1935 l[1] = CONST_DOUBLE_HIGH (x);
1938 if (mode == SImode)
1939 return GEN_INT (l[1]);
1940 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1941 return gen_int_mode ((l[0] >> 16), HImode);
1942 else
1943 abort ();
1945 if (GET_CODE (x) == CONST_INT)
1947 HOST_WIDE_INT val = INTVAL (x);
1949 if (mode == QImode)
1951 return gen_int_mode (val >> 8, QImode);
1953 else if (mode == HImode)
1955 return gen_int_mode (val >> 16, HImode);
1958 if (mode == QImode && D_REG_P (x))
1959 return gen_rtx (REG, mode, HARD_A_REGNUM);
1961 /* There is no way in GCC to represent the upper part of a word register.
1962 To obtain the 8-bit upper part of a soft register, we change the
1963 reg into a mem rtx. This is possible because they are physically
1964 located in memory. There is no offset because we are big-endian. */
1965 if (mode == QImode && S_REG_P (x))
1967 int pos;
1969 /* Avoid the '*' for direct addressing mode when this
1970 addressing mode is disabled. */
1971 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1972 return gen_rtx (MEM, QImode,
1973 gen_rtx (SYMBOL_REF, Pmode,
1974 &reg_names[REGNO (x)][pos]));
1977 /* gen_highpart crashes when it is called with a SUBREG. */
1978 if (GET_CODE (x) == SUBREG)
1980 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1982 if (GET_CODE (x) == REG)
1984 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1985 return gen_rtx (REG, mode, REGNO (x));
1986 else
1987 return gen_rtx_SUBREG (mode, x, 0);
1990 if (GET_CODE (x) == MEM)
1992 x = change_address (x, mode, 0);
1994 /* Return a different rtx to avoid to share it in several insns
1995 (when used by a split pattern). Sharing addresses within
1996 a MEM breaks the Z register replacement (and reloading). */
1997 if (GET_CODE (x) == MEM)
1998 x = copy_rtx (x);
1999 return x;
2001 abort ();
2005 /* Obscure register manipulation. */
2007 /* Finds backward in the instructions to see if register 'reg' is
2008 dead. This is used when generating code to see if we can use 'reg'
2009 as a scratch register. This allows us to choose a better generation
2010 of code when we know that some register dies or can be clobbered. */
2013 dead_register_here (rtx x, rtx reg)
2015 rtx x_reg;
2016 rtx p;
2018 if (D_REG_P (reg))
2019 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
2020 else
2021 x_reg = 0;
2023 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2024 if (INSN_P (p))
2026 rtx body;
2028 body = PATTERN (p);
2030 if (GET_CODE (body) == CALL_INSN)
2031 break;
2032 if (GET_CODE (body) == JUMP_INSN)
2033 break;
2035 if (GET_CODE (body) == SET)
2037 rtx dst = XEXP (body, 0);
2039 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2040 break;
2041 if (x_reg && rtx_equal_p (dst, x_reg))
2042 break;
2044 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2045 return 1;
2047 else if (reg_mentioned_p (reg, p)
2048 || (x_reg && reg_mentioned_p (x_reg, p)))
2049 break;
2052 /* Scan forward to see if the register is set in some insns and never
2053 used since then. */
2054 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2056 rtx body;
2058 if (GET_CODE (p) == CODE_LABEL
2059 || GET_CODE (p) == JUMP_INSN
2060 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2061 break;
2063 if (GET_CODE (p) != INSN)
2064 continue;
2066 body = PATTERN (p);
2067 if (GET_CODE (body) == SET)
2069 rtx src = XEXP (body, 1);
2070 rtx dst = XEXP (body, 0);
2072 if (GET_CODE (dst) == REG
2073 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2074 return 1;
2077 /* Register is used (may be in source or in dest). */
2078 if (reg_mentioned_p (reg, p)
2079 || (x_reg != 0 && GET_MODE (p) == SImode
2080 && reg_mentioned_p (x_reg, p)))
2081 break;
2083 return p == 0 ? 1 : 0;
2087 /* Code generation operations called from machine description file. */
2089 /* Print the name of register 'regno' in the assembly file. */
2090 static void
2091 asm_print_register (FILE *file, int regno)
2093 const char *name = reg_names[regno];
2095 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2096 name++;
2098 fprintf (file, "%s", name);
2101 /* A C compound statement to output to stdio stream STREAM the
2102 assembler syntax for an instruction operand X. X is an RTL
2103 expression.
2105 CODE is a value that can be used to specify one of several ways
2106 of printing the operand. It is used when identical operands
2107 must be printed differently depending on the context. CODE
2108 comes from the `%' specification that was used to request
2109 printing of the operand. If the specification was just `%DIGIT'
2110 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2111 is the ASCII code for LTR.
2113 If X is a register, this macro should print the register's name.
2114 The names can be found in an array `reg_names' whose type is
2115 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2117 When the machine description has a specification `%PUNCT' (a `%'
2118 followed by a punctuation character), this macro is called with
2119 a null pointer for X and the punctuation character for CODE.
2121 The M68HC11 specific codes are:
2123 'b' for the low part of the operand.
2124 'h' for the high part of the operand
2125 The 'b' or 'h' modifiers have no effect if the operand has
2126 the QImode and is not a S_REG_P (soft register). If the
2127 operand is a hard register, these two modifiers have no effect.
2128 't' generate the temporary scratch register. The operand is
2129 ignored.
2130 'T' generate the low-part temporary scratch register. The operand is
2131 ignored. */
2133 void
2134 print_operand (FILE *file, rtx op, int letter)
2136 if (letter == 't')
2138 asm_print_register (file, SOFT_TMP_REGNUM);
2139 return;
2141 else if (letter == 'T')
2143 asm_print_register (file, SOFT_TMP_REGNUM);
2144 fprintf (file, "+1");
2145 return;
2147 else if (letter == '#')
2149 asm_fprintf (file, "%I");
2152 if (GET_CODE (op) == REG)
2154 if (letter == 'b' && S_REG_P (op))
2156 asm_print_register (file, REGNO (op));
2157 fprintf (file, "+1");
2159 else if (letter == 'b' && D_REG_P (op))
2161 asm_print_register (file, HARD_B_REGNUM);
2163 else
2165 asm_print_register (file, REGNO (op));
2167 return;
2170 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2172 if (letter == 'b')
2173 asm_fprintf (file, "%I%%lo(");
2174 else
2175 asm_fprintf (file, "%I%%hi(");
2177 output_addr_const (file, op);
2178 fprintf (file, ")");
2179 return;
2182 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2183 are specified. If we already have a QImode, there is nothing to do. */
2184 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2186 if (letter == 'b')
2188 op = m68hc11_gen_lowpart (QImode, op);
2190 else if (letter == 'h')
2192 op = m68hc11_gen_highpart (QImode, op);
2196 if (GET_CODE (op) == MEM)
2198 rtx base = XEXP (op, 0);
2199 switch (GET_CODE (base))
2201 case PRE_DEC:
2202 if (TARGET_M6812)
2204 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2205 asm_print_register (file, REGNO (XEXP (base, 0)));
2207 else
2208 abort ();
2209 break;
2211 case POST_DEC:
2212 if (TARGET_M6812)
2214 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2215 asm_print_register (file, REGNO (XEXP (base, 0)));
2216 fprintf (file, "-");
2218 else
2219 abort ();
2220 break;
2222 case POST_INC:
2223 if (TARGET_M6812)
2225 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2226 asm_print_register (file, REGNO (XEXP (base, 0)));
2227 fprintf (file, "+");
2229 else
2230 abort ();
2231 break;
2233 case PRE_INC:
2234 if (TARGET_M6812)
2236 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2237 asm_print_register (file, REGNO (XEXP (base, 0)));
2239 else
2240 abort ();
2241 break;
2243 default:
2244 output_address (base);
2245 break;
2248 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2250 REAL_VALUE_TYPE r;
2251 long l;
2253 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2254 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2255 asm_fprintf (file, "%I0x%lx", l);
2257 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2259 char dstr[30];
2261 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2262 sizeof (dstr), 0, 1);
2263 asm_fprintf (file, "%I0r%s", dstr);
2265 else
2267 int need_parenthesize = 0;
2269 if (letter != 'i')
2270 asm_fprintf (file, "%I");
2271 else
2272 need_parenthesize = must_parenthesize (op);
2274 if (need_parenthesize)
2275 fprintf (file, "(");
2277 output_addr_const (file, op);
2278 if (need_parenthesize)
2279 fprintf (file, ")");
2283 /* Returns true if the operand 'op' must be printed with parenthesis
2284 around it. This must be done only if there is a symbol whose name
2285 is a processor register. */
2286 static int
2287 must_parenthesize (rtx op)
2289 const char *name;
2291 switch (GET_CODE (op))
2293 case SYMBOL_REF:
2294 name = XSTR (op, 0);
2295 /* Avoid a conflict between symbol name and a possible
2296 register. */
2297 return (strcasecmp (name, "a") == 0
2298 || strcasecmp (name, "b") == 0
2299 || strcasecmp (name, "d") == 0
2300 || strcasecmp (name, "x") == 0
2301 || strcasecmp (name, "y") == 0
2302 || strcasecmp (name, "ix") == 0
2303 || strcasecmp (name, "iy") == 0
2304 || strcasecmp (name, "pc") == 0
2305 || strcasecmp (name, "sp") == 0
2306 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2308 case PLUS:
2309 case MINUS:
2310 return must_parenthesize (XEXP (op, 0))
2311 || must_parenthesize (XEXP (op, 1));
2313 case MEM:
2314 case CONST:
2315 case ZERO_EXTEND:
2316 case SIGN_EXTEND:
2317 return must_parenthesize (XEXP (op, 0));
2319 case CONST_DOUBLE:
2320 case CONST_INT:
2321 case LABEL_REF:
2322 case CODE_LABEL:
2323 default:
2324 return 0;
2328 /* A C compound statement to output to stdio stream STREAM the
2329 assembler syntax for an instruction operand that is a memory
2330 reference whose address is ADDR. ADDR is an RTL expression. */
2332 void
2333 print_operand_address (FILE *file, rtx addr)
2335 rtx base;
2336 rtx offset;
2337 int need_parenthesis = 0;
2339 switch (GET_CODE (addr))
2341 case REG:
2342 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2343 abort ();
2345 fprintf (file, "0,");
2346 asm_print_register (file, REGNO (addr));
2347 break;
2349 case MEM:
2350 base = XEXP (addr, 0);
2351 switch (GET_CODE (base))
2353 case PRE_DEC:
2354 if (TARGET_M6812)
2356 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2357 asm_print_register (file, REGNO (XEXP (base, 0)));
2359 else
2360 abort ();
2361 break;
2363 case POST_DEC:
2364 if (TARGET_M6812)
2366 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2367 asm_print_register (file, REGNO (XEXP (base, 0)));
2368 fprintf (file, "-");
2370 else
2371 abort ();
2372 break;
2374 case POST_INC:
2375 if (TARGET_M6812)
2377 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2378 asm_print_register (file, REGNO (XEXP (base, 0)));
2379 fprintf (file, "+");
2381 else
2382 abort ();
2383 break;
2385 case PRE_INC:
2386 if (TARGET_M6812)
2388 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2389 asm_print_register (file, REGNO (XEXP (base, 0)));
2391 else
2392 abort ();
2393 break;
2395 default:
2396 need_parenthesis = must_parenthesize (base);
2397 if (need_parenthesis)
2398 fprintf (file, "(");
2400 output_addr_const (file, base);
2401 if (need_parenthesis)
2402 fprintf (file, ")");
2403 break;
2405 break;
2407 case PLUS:
2408 base = XEXP (addr, 0);
2409 offset = XEXP (addr, 1);
2410 if (!G_REG_P (base) && G_REG_P (offset))
2412 base = XEXP (addr, 1);
2413 offset = XEXP (addr, 0);
2415 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2417 need_parenthesis = must_parenthesize (addr);
2419 if (need_parenthesis)
2420 fprintf (file, "(");
2422 output_addr_const (file, base);
2423 fprintf (file, "+");
2424 output_addr_const (file, offset);
2425 if (need_parenthesis)
2426 fprintf (file, ")");
2428 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2430 if (REG_P (offset))
2432 if (TARGET_M6812)
2434 asm_print_register (file, REGNO (offset));
2435 fprintf (file, ",");
2436 asm_print_register (file, REGNO (base));
2438 else
2439 abort ();
2441 else
2443 need_parenthesis = must_parenthesize (offset);
2444 if (need_parenthesis)
2445 fprintf (file, "(");
2447 output_addr_const (file, offset);
2448 if (need_parenthesis)
2449 fprintf (file, ")");
2450 fprintf (file, ",");
2451 asm_print_register (file, REGNO (base));
2454 else
2456 abort ();
2458 break;
2460 default:
2461 if (GET_CODE (addr) == CONST_INT
2462 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2464 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2466 else
2468 need_parenthesis = must_parenthesize (addr);
2469 if (need_parenthesis)
2470 fprintf (file, "(");
2472 output_addr_const (file, addr);
2473 if (need_parenthesis)
2474 fprintf (file, ")");
2476 break;
2481 /* Splitting of some instructions. */
2483 static rtx
2484 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2486 rtx ret = 0;
2488 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2489 abort ();
2490 else
2492 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2493 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2494 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2497 return ret;
2501 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2502 rtx label)
2504 rtx tmp;
2506 switch (GET_MODE (op0))
2508 case QImode:
2509 case HImode:
2510 tmp = m68hc11_expand_compare (code, op0, op1);
2511 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2512 gen_rtx_LABEL_REF (VOIDmode, label),
2513 pc_rtx);
2514 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2515 return 0;
2516 #if 0
2518 /* SCz: from i386.c */
2519 case SFmode:
2520 case DFmode:
2521 /* Don't expand the comparison early, so that we get better code
2522 when jump or whoever decides to reverse the comparison. */
2524 rtvec vec;
2525 int use_fcomi;
2527 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2528 &m68hc11_compare_op1);
2530 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2531 m68hc11_compare_op0, m68hc11_compare_op1);
2532 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2533 gen_rtx_LABEL_REF (VOIDmode, label),
2534 pc_rtx);
2535 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2537 use_fcomi = ix86_use_fcomi_compare (code);
2538 vec = rtvec_alloc (3 + !use_fcomi);
2539 RTVEC_ELT (vec, 0) = tmp;
2540 RTVEC_ELT (vec, 1)
2541 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2542 RTVEC_ELT (vec, 2)
2543 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2544 if (!use_fcomi)
2545 RTVEC_ELT (vec, 3)
2546 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2548 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2549 return;
2551 #endif
2553 case SImode:
2554 /* Expand SImode branch into multiple compare+branch. */
2556 rtx lo[2], hi[2], label2;
2557 enum rtx_code code1, code2, code3;
2559 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2561 tmp = op0;
2562 op0 = op1;
2563 op1 = tmp;
2564 code = swap_condition (code);
2566 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2567 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2568 hi[0] = m68hc11_gen_highpart (HImode, op0);
2569 hi[1] = m68hc11_gen_highpart (HImode, op1);
2571 /* Otherwise, if we are doing less-than, op1 is a constant and the
2572 low word is zero, then we can just examine the high word. */
2574 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2575 && (code == LT || code == LTU))
2577 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2578 label);
2581 /* Otherwise, we need two or three jumps. */
2583 label2 = gen_label_rtx ();
2585 code1 = code;
2586 code2 = swap_condition (code);
2587 code3 = unsigned_condition (code);
2589 switch (code)
2591 case LT:
2592 case GT:
2593 case LTU:
2594 case GTU:
2595 break;
2597 case LE:
2598 code1 = LT;
2599 code2 = GT;
2600 break;
2601 case GE:
2602 code1 = GT;
2603 code2 = LT;
2604 break;
2605 case LEU:
2606 code1 = LTU;
2607 code2 = GTU;
2608 break;
2609 case GEU:
2610 code1 = GTU;
2611 code2 = LTU;
2612 break;
2614 case EQ:
2615 code1 = NIL;
2616 code2 = NE;
2617 break;
2618 case NE:
2619 code2 = NIL;
2620 break;
2622 default:
2623 abort ();
2627 * a < b =>
2628 * if (hi(a) < hi(b)) goto true;
2629 * if (hi(a) > hi(b)) goto false;
2630 * if (lo(a) < lo(b)) goto true;
2631 * false:
2633 if (code1 != NIL)
2634 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2635 if (code2 != NIL)
2636 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2638 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2640 if (code2 != NIL)
2641 emit_label (label2);
2642 return 0;
2645 default:
2646 abort ();
2648 return 0;
2651 /* Return the increment/decrement mode of a MEM if it is such.
2652 Return CONST if it is anything else. */
2653 static int
2654 autoinc_mode (rtx x)
2656 if (GET_CODE (x) != MEM)
2657 return CONST;
2659 x = XEXP (x, 0);
2660 if (GET_CODE (x) == PRE_INC
2661 || GET_CODE (x) == PRE_DEC
2662 || GET_CODE (x) == POST_INC
2663 || GET_CODE (x) == POST_DEC)
2664 return GET_CODE (x);
2666 return CONST;
2669 static int
2670 m68hc11_make_autoinc_notes (rtx *x, void *data)
2672 rtx insn;
2674 switch (GET_CODE (*x))
2676 case PRE_DEC:
2677 case PRE_INC:
2678 case POST_DEC:
2679 case POST_INC:
2680 insn = (rtx) data;
2681 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2682 REG_NOTES (insn));
2683 return -1;
2685 default:
2686 return 0;
2690 /* Split a DI, SI or HI move into several smaller move operations.
2691 The scratch register 'scratch' is used as a temporary to load
2692 store intermediate values. It must be a hard register. */
2693 void
2694 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2696 rtx low_to, low_from;
2697 rtx high_to, high_from;
2698 rtx insn;
2699 enum machine_mode mode;
2700 int offset = 0;
2701 int autoinc_from = autoinc_mode (from);
2702 int autoinc_to = autoinc_mode (to);
2704 mode = GET_MODE (to);
2706 /* If the TO and FROM contain autoinc modes that are not compatible
2707 together (one pop and the other a push), we must change one to
2708 an offsetable operand and generate an appropriate add at the end. */
2709 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2711 rtx reg;
2712 int code;
2714 /* The source uses an autoinc mode which is not compatible with
2715 a split (this would result in a word swap). */
2716 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2718 code = GET_CODE (XEXP (from, 0));
2719 reg = XEXP (XEXP (from, 0), 0);
2720 offset = GET_MODE_SIZE (GET_MODE (from));
2721 if (code == POST_DEC)
2722 offset = -offset;
2724 if (code == PRE_INC)
2725 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2727 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2728 if (code == POST_DEC)
2729 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2730 return;
2733 /* Likewise for destination. */
2734 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2736 code = GET_CODE (XEXP (to, 0));
2737 reg = XEXP (XEXP (to, 0), 0);
2738 offset = GET_MODE_SIZE (GET_MODE (to));
2739 if (code == POST_DEC)
2740 offset = -offset;
2742 if (code == PRE_INC)
2743 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2745 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2746 if (code == POST_DEC)
2747 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2748 return;
2751 /* The source and destination auto increment modes must be compatible
2752 with each other: same direction. */
2753 if ((autoinc_to != autoinc_from
2754 && autoinc_to != CONST && autoinc_from != CONST)
2755 /* The destination address register must not be used within
2756 the source operand because the source address would change
2757 while doing the copy. */
2758 || (autoinc_to != CONST
2759 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2760 && !IS_STACK_PUSH (to)))
2762 /* Must change the destination. */
2763 code = GET_CODE (XEXP (to, 0));
2764 reg = XEXP (XEXP (to, 0), 0);
2765 offset = GET_MODE_SIZE (GET_MODE (to));
2766 if (code == PRE_DEC || code == POST_DEC)
2767 offset = -offset;
2769 if (code == PRE_DEC || code == PRE_INC)
2770 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2771 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2772 if (code == POST_DEC || code == POST_INC)
2773 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2775 return;
2778 /* Likewise, the source address register must not be used within
2779 the destination operand. */
2780 if (autoinc_from != CONST
2781 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2782 && !IS_STACK_PUSH (to))
2784 /* Must change the source. */
2785 code = GET_CODE (XEXP (from, 0));
2786 reg = XEXP (XEXP (from, 0), 0);
2787 offset = GET_MODE_SIZE (GET_MODE (from));
2788 if (code == PRE_DEC || code == POST_DEC)
2789 offset = -offset;
2791 if (code == PRE_DEC || code == PRE_INC)
2792 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2793 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2794 if (code == POST_DEC || code == POST_INC)
2795 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2797 return;
2801 if (GET_MODE_SIZE (mode) == 8)
2802 mode = SImode;
2803 else if (GET_MODE_SIZE (mode) == 4)
2804 mode = HImode;
2805 else
2806 mode = QImode;
2808 if (TARGET_M6812
2809 && IS_STACK_PUSH (to)
2810 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2812 if (mode == SImode)
2814 offset = 4;
2816 else if (mode == HImode)
2818 offset = 2;
2820 else
2821 offset = 0;
2824 low_to = m68hc11_gen_lowpart (mode, to);
2825 high_to = m68hc11_gen_highpart (mode, to);
2827 low_from = m68hc11_gen_lowpart (mode, from);
2828 if (mode == SImode && GET_CODE (from) == CONST_INT)
2830 if (INTVAL (from) >= 0)
2831 high_from = const0_rtx;
2832 else
2833 high_from = constm1_rtx;
2835 else
2836 high_from = m68hc11_gen_highpart (mode, from);
2838 if (offset)
2840 high_from = adjust_address (high_from, mode, offset);
2841 low_from = high_from;
2844 /* When copying with a POST_INC mode, we must copy the
2845 high part and then the low part to guarantee a correct
2846 32/64-bit copy. */
2847 if (TARGET_M6812
2848 && GET_MODE_SIZE (mode) >= 2
2849 && autoinc_from != autoinc_to
2850 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2852 rtx swap;
2854 swap = low_to;
2855 low_to = high_to;
2856 high_to = swap;
2858 swap = low_from;
2859 low_from = high_from;
2860 high_from = swap;
2862 if (mode == SImode)
2864 m68hc11_split_move (low_to, low_from, scratch);
2865 m68hc11_split_move (high_to, high_from, scratch);
2867 else if (H_REG_P (to) || H_REG_P (from)
2868 || (low_from == const0_rtx
2869 && high_from == const0_rtx
2870 && ! push_operand (to, GET_MODE (to))
2871 && ! H_REG_P (scratch))
2872 || (TARGET_M6812
2873 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2874 || m68hc11_small_indexed_indirect_p (from,
2875 GET_MODE (from)))
2876 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2877 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2879 insn = emit_move_insn (low_to, low_from);
2880 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2882 insn = emit_move_insn (high_to, high_from);
2883 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2885 else
2887 insn = emit_move_insn (scratch, low_from);
2888 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2889 insn = emit_move_insn (low_to, scratch);
2890 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2892 insn = emit_move_insn (scratch, high_from);
2893 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2894 insn = emit_move_insn (high_to, scratch);
2895 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2899 static rtx
2900 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2902 int val;
2903 int mask;
2905 *result = 0;
2906 if (GET_CODE (operand) != CONST_INT)
2907 return operand;
2909 if (mode == HImode)
2910 mask = 0x0ffff;
2911 else
2912 mask = 0x0ff;
2914 val = INTVAL (operand);
2915 switch (code)
2917 case IOR:
2918 if ((val & mask) == 0)
2919 return 0;
2920 if ((val & mask) == mask)
2921 *result = constm1_rtx;
2922 break;
2924 case AND:
2925 if ((val & mask) == 0)
2926 *result = const0_rtx;
2927 if ((val & mask) == mask)
2928 return 0;
2929 break;
2931 case XOR:
2932 if ((val & mask) == 0)
2933 return 0;
2934 break;
2936 return operand;
2939 static void
2940 m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
2942 rtx result;
2943 int need_copy;
2945 need_copy = (rtx_equal_p (operands[0], operands[1])
2946 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2948 operands[1] = simplify_logical (mode, code, operands[1], &result);
2949 operands[2] = simplify_logical (mode, code, operands[2], &result);
2951 if (result && GET_CODE (result) == CONST_INT)
2953 if (!H_REG_P (operands[0]) && operands[3]
2954 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2956 emit_move_insn (operands[3], result);
2957 emit_move_insn (operands[0], operands[3]);
2959 else
2961 emit_move_insn (operands[0], result);
2964 else if (operands[1] != 0 && operands[2] != 0)
2966 rtx insn;
2968 if (!H_REG_P (operands[0]) && operands[3])
2970 emit_move_insn (operands[3], operands[1]);
2971 emit_insn (gen_rtx (SET, mode,
2972 operands[3],
2973 gen_rtx (code, mode,
2974 operands[3], operands[2])));
2975 insn = emit_move_insn (operands[0], operands[3]);
2977 else
2979 insn = emit_insn (gen_rtx (SET, mode,
2980 operands[0],
2981 gen_rtx (code, mode,
2982 operands[0], operands[2])));
2986 /* The logical operation is similar to a copy. */
2987 else if (need_copy)
2989 rtx src;
2991 if (GET_CODE (operands[1]) == CONST_INT)
2992 src = operands[2];
2993 else
2994 src = operands[1];
2996 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2998 emit_move_insn (operands[3], src);
2999 emit_move_insn (operands[0], operands[3]);
3001 else
3003 emit_move_insn (operands[0], src);
3008 void
3009 m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
3011 rtx low[4];
3012 rtx high[4];
3014 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3015 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3016 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3018 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3020 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3022 if (INTVAL (operands[1]) >= 0)
3023 high[1] = const0_rtx;
3024 else
3025 high[1] = constm1_rtx;
3027 else
3028 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3030 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3032 if (INTVAL (operands[2]) >= 0)
3033 high[2] = const0_rtx;
3034 else
3035 high[2] = constm1_rtx;
3037 else
3038 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3040 low[3] = operands[3];
3041 high[3] = operands[3];
3042 if (mode == SImode)
3044 m68hc11_split_logical (HImode, code, low);
3045 m68hc11_split_logical (HImode, code, high);
3046 return;
3049 m68hc11_emit_logical (mode, code, low);
3050 m68hc11_emit_logical (mode, code, high);
3054 /* Code generation. */
3056 void
3057 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3059 /* We have to be careful with the cc_status. An address register swap
3060 is generated for some comparison. The comparison is made with D
3061 but the branch really uses the address register. See the split
3062 pattern for compare. The xgdx/xgdy preserve the flags but after
3063 the exchange, the flags will reflect to the value of X and not D.
3064 Tell this by setting the cc_status according to the cc_prev_status. */
3065 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3067 if (cc_prev_status.value1 != 0
3068 && (D_REG_P (cc_prev_status.value1)
3069 || X_REG_P (cc_prev_status.value1)))
3071 cc_status = cc_prev_status;
3072 if (D_REG_P (cc_status.value1))
3073 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3074 HARD_X_REGNUM);
3075 else
3076 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3077 HARD_D_REGNUM);
3079 else
3080 CC_STATUS_INIT;
3082 output_asm_insn ("xgdx", operands);
3084 else
3086 if (cc_prev_status.value1 != 0
3087 && (D_REG_P (cc_prev_status.value1)
3088 || Y_REG_P (cc_prev_status.value1)))
3090 cc_status = cc_prev_status;
3091 if (D_REG_P (cc_status.value1))
3092 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3093 HARD_Y_REGNUM);
3094 else
3095 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3096 HARD_D_REGNUM);
3098 else
3099 CC_STATUS_INIT;
3101 output_asm_insn ("xgdy", operands);
3105 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3106 This is used to decide whether a move that set flags should be used
3107 instead. */
3109 next_insn_test_reg (rtx insn, rtx reg)
3111 rtx body;
3113 insn = next_nonnote_insn (insn);
3114 if (GET_CODE (insn) != INSN)
3115 return 0;
3117 body = PATTERN (insn);
3118 if (sets_cc0_p (body) != 1)
3119 return 0;
3121 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3122 return 0;
3124 return 1;
3127 /* Generate the code to move a 16-bit operand into another one. */
3129 void
3130 m68hc11_gen_movhi (rtx insn, rtx *operands)
3132 int reg;
3134 /* Move a register or memory to the same location.
3135 This is possible because such insn can appear
3136 in a non-optimizing mode. */
3137 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3139 cc_status = cc_prev_status;
3140 return;
3143 if (TARGET_M6812)
3145 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3147 cc_status = cc_prev_status;
3148 switch (REGNO (operands[1]))
3150 case HARD_X_REGNUM:
3151 case HARD_Y_REGNUM:
3152 case HARD_D_REGNUM:
3153 output_asm_insn ("psh%1", operands);
3154 break;
3155 case HARD_SP_REGNUM:
3156 output_asm_insn ("sts\t-2,sp", operands);
3157 break;
3158 default:
3159 abort ();
3161 return;
3163 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3165 cc_status = cc_prev_status;
3166 switch (REGNO (operands[0]))
3168 case HARD_X_REGNUM:
3169 case HARD_Y_REGNUM:
3170 case HARD_D_REGNUM:
3171 output_asm_insn ("pul%0", operands);
3172 break;
3173 default:
3174 abort ();
3176 return;
3178 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3180 m68hc11_notice_keep_cc (operands[0]);
3181 output_asm_insn ("tfr\t%1,%0", operands);
3183 else if (H_REG_P (operands[0]))
3185 if (SP_REG_P (operands[0]))
3186 output_asm_insn ("lds\t%1", operands);
3187 else
3188 output_asm_insn ("ld%0\t%1", operands);
3190 else if (H_REG_P (operands[1]))
3192 if (SP_REG_P (operands[1]))
3193 output_asm_insn ("sts\t%0", operands);
3194 else
3195 output_asm_insn ("st%1\t%0", operands);
3197 else
3199 rtx from = operands[1];
3200 rtx to = operands[0];
3202 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3203 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3204 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3205 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3207 rtx ops[3];
3209 if (operands[2])
3211 ops[0] = operands[2];
3212 ops[1] = from;
3213 ops[2] = 0;
3214 m68hc11_gen_movhi (insn, ops);
3215 ops[0] = to;
3216 ops[1] = operands[2];
3217 m68hc11_gen_movhi (insn, ops);
3219 else
3221 /* !!!! SCz wrong here. */
3222 fatal_insn ("move insn not handled", insn);
3225 else
3227 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3229 output_asm_insn ("clr\t%h0", operands);
3230 output_asm_insn ("clr\t%b0", operands);
3232 else
3234 m68hc11_notice_keep_cc (operands[0]);
3235 output_asm_insn ("movw\t%1,%0", operands);
3239 return;
3242 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3244 cc_status = cc_prev_status;
3245 switch (REGNO (operands[0]))
3247 case HARD_X_REGNUM:
3248 case HARD_Y_REGNUM:
3249 output_asm_insn ("pul%0", operands);
3250 break;
3251 case HARD_D_REGNUM:
3252 output_asm_insn ("pula", operands);
3253 output_asm_insn ("pulb", operands);
3254 break;
3255 default:
3256 abort ();
3258 return;
3260 /* Some moves to a hard register are special. Not all of them
3261 are really supported and we have to use a temporary
3262 location to provide them (either the stack of a temp var). */
3263 if (H_REG_P (operands[0]))
3265 switch (REGNO (operands[0]))
3267 case HARD_D_REGNUM:
3268 if (X_REG_P (operands[1]))
3270 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3272 m68hc11_output_swap (insn, operands);
3274 else if (next_insn_test_reg (insn, operands[0]))
3276 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3278 else
3280 m68hc11_notice_keep_cc (operands[0]);
3281 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3284 else if (Y_REG_P (operands[1]))
3286 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3288 m68hc11_output_swap (insn, operands);
3290 else
3292 /* %t means *ZTMP scratch register. */
3293 output_asm_insn ("sty\t%t1", operands);
3294 output_asm_insn ("ldd\t%t1", operands);
3297 else if (SP_REG_P (operands[1]))
3299 CC_STATUS_INIT;
3300 if (ix_reg == 0)
3301 create_regs_rtx ();
3302 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3303 output_asm_insn ("xgdx", operands);
3304 output_asm_insn ("tsx", operands);
3305 output_asm_insn ("xgdx", operands);
3307 else if (IS_STACK_POP (operands[1]))
3309 output_asm_insn ("pula\n\tpulb", operands);
3311 else if (GET_CODE (operands[1]) == CONST_INT
3312 && INTVAL (operands[1]) == 0)
3314 output_asm_insn ("clra\n\tclrb", operands);
3316 else
3318 output_asm_insn ("ldd\t%1", operands);
3320 break;
3322 case HARD_X_REGNUM:
3323 if (D_REG_P (operands[1]))
3325 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3327 m68hc11_output_swap (insn, operands);
3329 else if (next_insn_test_reg (insn, operands[0]))
3331 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3333 else
3335 m68hc11_notice_keep_cc (operands[0]);
3336 output_asm_insn ("pshb", operands);
3337 output_asm_insn ("psha", operands);
3338 output_asm_insn ("pulx", operands);
3341 else if (Y_REG_P (operands[1]))
3343 /* When both D and Y are dead, use the sequence xgdy, xgdx
3344 to move Y into X. The D and Y registers are modified. */
3345 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3346 && dead_register_here (insn, d_reg))
3348 output_asm_insn ("xgdy", operands);
3349 output_asm_insn ("xgdx", operands);
3350 CC_STATUS_INIT;
3352 else if (!optimize_size)
3354 output_asm_insn ("sty\t%t1", operands);
3355 output_asm_insn ("ldx\t%t1", operands);
3357 else
3359 CC_STATUS_INIT;
3360 output_asm_insn ("pshy", operands);
3361 output_asm_insn ("pulx", operands);
3364 else if (SP_REG_P (operands[1]))
3366 /* tsx, tsy preserve the flags */
3367 cc_status = cc_prev_status;
3368 output_asm_insn ("tsx", operands);
3370 else
3372 output_asm_insn ("ldx\t%1", operands);
3374 break;
3376 case HARD_Y_REGNUM:
3377 if (D_REG_P (operands[1]))
3379 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3381 m68hc11_output_swap (insn, operands);
3383 else
3385 output_asm_insn ("std\t%t1", operands);
3386 output_asm_insn ("ldy\t%t1", operands);
3389 else if (X_REG_P (operands[1]))
3391 /* When both D and X are dead, use the sequence xgdx, xgdy
3392 to move X into Y. The D and X registers are modified. */
3393 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3394 && dead_register_here (insn, d_reg))
3396 output_asm_insn ("xgdx", operands);
3397 output_asm_insn ("xgdy", operands);
3398 CC_STATUS_INIT;
3400 else if (!optimize_size)
3402 output_asm_insn ("stx\t%t1", operands);
3403 output_asm_insn ("ldy\t%t1", operands);
3405 else
3407 CC_STATUS_INIT;
3408 output_asm_insn ("pshx", operands);
3409 output_asm_insn ("puly", operands);
3412 else if (SP_REG_P (operands[1]))
3414 /* tsx, tsy preserve the flags */
3415 cc_status = cc_prev_status;
3416 output_asm_insn ("tsy", operands);
3418 else
3420 output_asm_insn ("ldy\t%1", operands);
3422 break;
3424 case HARD_SP_REGNUM:
3425 if (D_REG_P (operands[1]))
3427 m68hc11_notice_keep_cc (operands[0]);
3428 output_asm_insn ("xgdx", operands);
3429 output_asm_insn ("txs", operands);
3430 output_asm_insn ("xgdx", operands);
3432 else if (X_REG_P (operands[1]))
3434 /* tys, txs preserve the flags */
3435 cc_status = cc_prev_status;
3436 output_asm_insn ("txs", operands);
3438 else if (Y_REG_P (operands[1]))
3440 /* tys, txs preserve the flags */
3441 cc_status = cc_prev_status;
3442 output_asm_insn ("tys", operands);
3444 else
3446 /* lds sets the flags but the des does not. */
3447 CC_STATUS_INIT;
3448 output_asm_insn ("lds\t%1", operands);
3449 output_asm_insn ("des", operands);
3451 break;
3453 default:
3454 fatal_insn ("invalid register in the move instruction", insn);
3455 break;
3457 return;
3459 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3460 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3462 output_asm_insn ("sts\t%0", operands);
3463 return;
3466 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3468 cc_status = cc_prev_status;
3469 switch (REGNO (operands[1]))
3471 case HARD_X_REGNUM:
3472 case HARD_Y_REGNUM:
3473 output_asm_insn ("psh%1", operands);
3474 break;
3475 case HARD_D_REGNUM:
3476 output_asm_insn ("pshb", operands);
3477 output_asm_insn ("psha", operands);
3478 break;
3479 default:
3480 abort ();
3482 return;
3485 /* Operand 1 must be a hard register. */
3486 if (!H_REG_P (operands[1]))
3488 fatal_insn ("invalid operand in the instruction", insn);
3491 reg = REGNO (operands[1]);
3492 switch (reg)
3494 case HARD_D_REGNUM:
3495 output_asm_insn ("std\t%0", operands);
3496 break;
3498 case HARD_X_REGNUM:
3499 output_asm_insn ("stx\t%0", operands);
3500 break;
3502 case HARD_Y_REGNUM:
3503 output_asm_insn ("sty\t%0", operands);
3504 break;
3506 case HARD_SP_REGNUM:
3507 if (ix_reg == 0)
3508 create_regs_rtx ();
3510 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3512 output_asm_insn ("pshx", operands);
3513 output_asm_insn ("tsx", operands);
3514 output_asm_insn ("inx", operands);
3515 output_asm_insn ("inx", operands);
3516 output_asm_insn ("stx\t%0", operands);
3517 output_asm_insn ("pulx", operands);
3520 else if (reg_mentioned_p (ix_reg, operands[0]))
3522 output_asm_insn ("sty\t%t0", operands);
3523 output_asm_insn ("tsy", operands);
3524 output_asm_insn ("sty\t%0", operands);
3525 output_asm_insn ("ldy\t%t0", operands);
3527 else
3529 output_asm_insn ("stx\t%t0", operands);
3530 output_asm_insn ("tsx", operands);
3531 output_asm_insn ("stx\t%0", operands);
3532 output_asm_insn ("ldx\t%t0", operands);
3534 CC_STATUS_INIT;
3535 break;
3537 default:
3538 fatal_insn ("invalid register in the move instruction", insn);
3539 break;
3543 void
3544 m68hc11_gen_movqi (rtx insn, rtx *operands)
3546 /* Move a register or memory to the same location.
3547 This is possible because such insn can appear
3548 in a non-optimizing mode. */
3549 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3551 cc_status = cc_prev_status;
3552 return;
3555 if (TARGET_M6812)
3558 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3560 m68hc11_notice_keep_cc (operands[0]);
3561 output_asm_insn ("tfr\t%1,%0", operands);
3563 else if (H_REG_P (operands[0]))
3565 if (Q_REG_P (operands[0]))
3566 output_asm_insn ("lda%0\t%b1", operands);
3567 else if (D_REG_P (operands[0]))
3568 output_asm_insn ("ldab\t%b1", operands);
3569 else
3570 goto m6811_move;
3572 else if (H_REG_P (operands[1]))
3574 if (Q_REG_P (operands[1]))
3575 output_asm_insn ("sta%1\t%b0", operands);
3576 else if (D_REG_P (operands[1]))
3577 output_asm_insn ("stab\t%b0", operands);
3578 else
3579 goto m6811_move;
3581 else
3583 rtx from = operands[1];
3584 rtx to = operands[0];
3586 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3587 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3588 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3589 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3591 rtx ops[3];
3593 if (operands[2])
3595 ops[0] = operands[2];
3596 ops[1] = from;
3597 ops[2] = 0;
3598 m68hc11_gen_movqi (insn, ops);
3599 ops[0] = to;
3600 ops[1] = operands[2];
3601 m68hc11_gen_movqi (insn, ops);
3603 else
3605 /* !!!! SCz wrong here. */
3606 fatal_insn ("move insn not handled", insn);
3609 else
3611 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3613 output_asm_insn ("clr\t%b0", operands);
3615 else
3617 m68hc11_notice_keep_cc (operands[0]);
3618 output_asm_insn ("movb\t%b1,%b0", operands);
3622 return;
3625 m6811_move:
3626 if (H_REG_P (operands[0]))
3628 switch (REGNO (operands[0]))
3630 case HARD_B_REGNUM:
3631 case HARD_D_REGNUM:
3632 if (X_REG_P (operands[1]))
3634 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3636 m68hc11_output_swap (insn, operands);
3638 else
3640 output_asm_insn ("stx\t%t1", operands);
3641 output_asm_insn ("ldab\t%T0", operands);
3644 else if (Y_REG_P (operands[1]))
3646 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3648 m68hc11_output_swap (insn, operands);
3650 else
3652 output_asm_insn ("sty\t%t1", operands);
3653 output_asm_insn ("ldab\t%T0", operands);
3656 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3657 && !DA_REG_P (operands[1]))
3659 output_asm_insn ("ldab\t%b1", operands);
3661 else if (DA_REG_P (operands[1]))
3663 output_asm_insn ("tab", operands);
3665 else
3667 cc_status = cc_prev_status;
3668 return;
3670 break;
3672 case HARD_A_REGNUM:
3673 if (X_REG_P (operands[1]))
3675 output_asm_insn ("stx\t%t1", operands);
3676 output_asm_insn ("ldaa\t%T0", operands);
3678 else if (Y_REG_P (operands[1]))
3680 output_asm_insn ("sty\t%t1", operands);
3681 output_asm_insn ("ldaa\t%T0", operands);
3683 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3684 && !DA_REG_P (operands[1]))
3686 output_asm_insn ("ldaa\t%b1", operands);
3688 else if (!DA_REG_P (operands[1]))
3690 output_asm_insn ("tba", operands);
3692 else
3694 cc_status = cc_prev_status;
3696 break;
3698 case HARD_X_REGNUM:
3699 if (D_REG_P (operands[1]))
3701 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3703 m68hc11_output_swap (insn, operands);
3705 else
3707 output_asm_insn ("stab\t%T1", operands);
3708 output_asm_insn ("ldx\t%t1", operands);
3710 CC_STATUS_INIT;
3712 else if (Y_REG_P (operands[1]))
3714 output_asm_insn ("sty\t%t0", operands);
3715 output_asm_insn ("ldx\t%t0", operands);
3717 else if (GET_CODE (operands[1]) == CONST_INT)
3719 output_asm_insn ("ldx\t%1", operands);
3721 else if (dead_register_here (insn, d_reg))
3723 output_asm_insn ("ldab\t%b1", operands);
3724 output_asm_insn ("xgdx", operands);
3726 else if (!reg_mentioned_p (operands[0], operands[1]))
3728 output_asm_insn ("xgdx", operands);
3729 output_asm_insn ("ldab\t%b1", operands);
3730 output_asm_insn ("xgdx", operands);
3732 else
3734 output_asm_insn ("pshb", operands);
3735 output_asm_insn ("ldab\t%b1", operands);
3736 output_asm_insn ("stab\t%T1", operands);
3737 output_asm_insn ("ldx\t%t1", operands);
3738 output_asm_insn ("pulb", operands);
3739 CC_STATUS_INIT;
3741 break;
3743 case HARD_Y_REGNUM:
3744 if (D_REG_P (operands[1]))
3746 output_asm_insn ("stab\t%T1", operands);
3747 output_asm_insn ("ldy\t%t1", operands);
3748 CC_STATUS_INIT;
3750 else if (X_REG_P (operands[1]))
3752 output_asm_insn ("stx\t%t1", operands);
3753 output_asm_insn ("ldy\t%t1", operands);
3754 CC_STATUS_INIT;
3756 else if (GET_CODE (operands[1]) == CONST_INT)
3758 output_asm_insn ("ldy\t%1", operands);
3760 else if (dead_register_here (insn, d_reg))
3762 output_asm_insn ("ldab\t%b1", operands);
3763 output_asm_insn ("xgdy", operands);
3765 else if (!reg_mentioned_p (operands[0], operands[1]))
3767 output_asm_insn ("xgdy", operands);
3768 output_asm_insn ("ldab\t%b1", operands);
3769 output_asm_insn ("xgdy", operands);
3771 else
3773 output_asm_insn ("pshb", operands);
3774 output_asm_insn ("ldab\t%b1", operands);
3775 output_asm_insn ("stab\t%T1", operands);
3776 output_asm_insn ("ldy\t%t1", operands);
3777 output_asm_insn ("pulb", operands);
3778 CC_STATUS_INIT;
3780 break;
3782 default:
3783 fatal_insn ("invalid register in the instruction", insn);
3784 break;
3787 else if (H_REG_P (operands[1]))
3789 switch (REGNO (operands[1]))
3791 case HARD_D_REGNUM:
3792 case HARD_B_REGNUM:
3793 output_asm_insn ("stab\t%b0", operands);
3794 break;
3796 case HARD_A_REGNUM:
3797 output_asm_insn ("staa\t%b0", operands);
3798 break;
3800 case HARD_X_REGNUM:
3801 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3802 break;
3804 case HARD_Y_REGNUM:
3805 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3806 break;
3808 default:
3809 fatal_insn ("invalid register in the move instruction", insn);
3810 break;
3812 return;
3814 else
3816 fatal_insn ("operand 1 must be a hard register", insn);
3820 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3821 The source and destination must be D or A and the shift must
3822 be a constant. */
3823 void
3824 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3826 int val;
3828 if (GET_CODE (operands[2]) != CONST_INT
3829 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3830 fatal_insn ("invalid rotate insn", insn);
3832 val = INTVAL (operands[2]);
3833 if (code == ROTATERT)
3834 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3836 if (GET_MODE (operands[0]) != QImode)
3837 CC_STATUS_INIT;
3839 /* Rotate by 8-bits if the shift is within [5..11]. */
3840 if (val >= 5 && val <= 11)
3842 if (TARGET_M6812)
3843 output_asm_insn ("exg\ta,b", operands);
3844 else
3846 output_asm_insn ("psha", operands);
3847 output_asm_insn ("tba", operands);
3848 output_asm_insn ("pulb", operands);
3850 val -= 8;
3853 /* If the shift is big, invert the rotation. */
3854 else if (val >= 12)
3856 val = val - 16;
3859 if (val > 0)
3861 while (--val >= 0)
3863 /* Set the carry to bit-15, but don't change D yet. */
3864 if (GET_MODE (operands[0]) != QImode)
3866 output_asm_insn ("asra", operands);
3867 output_asm_insn ("rola", operands);
3870 /* Rotate B first to move the carry to bit-0. */
3871 if (D_REG_P (operands[0]))
3872 output_asm_insn ("rolb", operands);
3874 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3875 output_asm_insn ("rola", operands);
3878 else
3880 while (++val <= 0)
3882 /* Set the carry to bit-8 of D. */
3883 if (GET_MODE (operands[0]) != QImode)
3884 output_asm_insn ("tap", operands);
3886 /* Rotate B first to move the carry to bit-7. */
3887 if (D_REG_P (operands[0]))
3888 output_asm_insn ("rorb", operands);
3890 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3891 output_asm_insn ("rora", operands);
3898 /* Store in cc_status the expressions that the condition codes will
3899 describe after execution of an instruction whose pattern is EXP.
3900 Do not alter them if the instruction would not alter the cc's. */
3902 void
3903 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3905 /* recognize SET insn's. */
3906 if (GET_CODE (exp) == SET)
3908 /* Jumps do not alter the cc's. */
3909 if (SET_DEST (exp) == pc_rtx)
3912 /* NOTE: most instructions don't affect the carry bit, but the
3913 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3914 the conditions.h header. */
3916 /* Function calls clobber the cc's. */
3917 else if (GET_CODE (SET_SRC (exp)) == CALL)
3919 CC_STATUS_INIT;
3922 /* Tests and compares set the cc's in predictable ways. */
3923 else if (SET_DEST (exp) == cc0_rtx)
3925 cc_status.flags = 0;
3926 cc_status.value1 = XEXP (exp, 0);
3927 cc_status.value2 = XEXP (exp, 1);
3929 else
3931 /* All other instructions affect the condition codes. */
3932 cc_status.flags = 0;
3933 cc_status.value1 = XEXP (exp, 0);
3934 cc_status.value2 = XEXP (exp, 1);
3937 else
3939 /* Default action if we haven't recognized something
3940 and returned earlier. */
3941 CC_STATUS_INIT;
3944 if (cc_status.value2 != 0)
3945 switch (GET_CODE (cc_status.value2))
3947 /* These logical operations can generate several insns.
3948 The flags are setup according to what is generated. */
3949 case IOR:
3950 case XOR:
3951 case AND:
3952 break;
3954 /* The (not ...) generates several 'com' instructions for
3955 non QImode. We have to invalidate the flags. */
3956 case NOT:
3957 if (GET_MODE (cc_status.value2) != QImode)
3958 CC_STATUS_INIT;
3959 break;
3961 case PLUS:
3962 case MINUS:
3963 case MULT:
3964 case DIV:
3965 case UDIV:
3966 case MOD:
3967 case UMOD:
3968 case NEG:
3969 if (GET_MODE (cc_status.value2) != VOIDmode)
3970 cc_status.flags |= CC_NO_OVERFLOW;
3971 break;
3973 /* The asl sets the overflow bit in such a way that this
3974 makes the flags unusable for a next compare insn. */
3975 case ASHIFT:
3976 case ROTATE:
3977 case ROTATERT:
3978 if (GET_MODE (cc_status.value2) != VOIDmode)
3979 cc_status.flags |= CC_NO_OVERFLOW;
3980 break;
3982 /* A load/store instruction does not affect the carry. */
3983 case MEM:
3984 case SYMBOL_REF:
3985 case REG:
3986 case CONST_INT:
3987 cc_status.flags |= CC_NO_OVERFLOW;
3988 break;
3990 default:
3991 break;
3993 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3994 && cc_status.value2
3995 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3996 cc_status.value2 = 0;
3999 /* The current instruction does not affect the flags but changes
4000 the register 'reg'. See if the previous flags can be kept for the
4001 next instruction to avoid a comparison. */
4002 void
4003 m68hc11_notice_keep_cc (rtx reg)
4005 if (reg == 0
4006 || cc_prev_status.value1 == 0
4007 || rtx_equal_p (reg, cc_prev_status.value1)
4008 || (cc_prev_status.value2
4009 && reg_mentioned_p (reg, cc_prev_status.value2)))
4010 CC_STATUS_INIT;
4011 else
4012 cc_status = cc_prev_status;
4017 /* Machine Specific Reorg. */
4019 /* Z register replacement:
4021 GCC treats the Z register as an index base address register like
4022 X or Y. In general, it uses it during reload to compute the address
4023 of some operand. This helps the reload pass to avoid to fall into the
4024 register spill failure.
4026 The Z register is in the A_REGS class. In the machine description,
4027 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4029 It can appear everywhere an X or Y register can appear, except for
4030 some templates in the clobber section (when a clobber of X or Y is asked).
4031 For a given instruction, the template must ensure that no more than
4032 2 'A' registers are used. Otherwise, the register replacement is not
4033 possible.
4035 To replace the Z register, the algorithm is not terrific:
4036 1. Insns that do not use the Z register are not changed
4037 2. When a Z register is used, we scan forward the insns to see
4038 a potential register to use: either X or Y and sometimes D.
4039 We stop when a call, a label or a branch is seen, or when we
4040 detect that both X and Y are used (probably at different times, but it does
4041 not matter).
4042 3. The register that will be used for the replacement of Z is saved
4043 in a .page0 register or on the stack. If the first instruction that
4044 used Z, uses Z as an input, the value is loaded from another .page0
4045 register. The replacement register is pushed on the stack in the
4046 rare cases where a compare insn uses Z and we couldn't find if X/Y
4047 are dead.
4048 4. The Z register is replaced in all instructions until we reach
4049 the end of the Z-block, as detected by step 2.
4050 5. If we detect that Z is still alive, its value is saved.
4051 If the replacement register is alive, its old value is loaded.
4053 The Z register can be disabled with -ffixed-z.
4056 struct replace_info
4058 rtx first;
4059 rtx replace_reg;
4060 int need_save_z;
4061 int must_load_z;
4062 int must_save_reg;
4063 int must_restore_reg;
4064 rtx last;
4065 int regno;
4066 int x_used;
4067 int y_used;
4068 int can_use_d;
4069 int found_call;
4070 int z_died;
4071 int z_set_count;
4072 rtx z_value;
4073 int must_push_reg;
4074 int save_before_last;
4075 int z_loaded_with_sp;
4078 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4079 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4080 static void m68hc11_z_replacement (rtx);
4081 static void m68hc11_reassign_regs (rtx);
4083 int z_replacement_completed = 0;
4085 /* Analyze the insn to find out which replacement register to use and
4086 the boundaries of the replacement.
4087 Returns 0 if we reached the last insn to be replaced, 1 if we can
4088 continue replacement in next insns. */
4090 static int
4091 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4093 int this_insn_uses_ix;
4094 int this_insn_uses_iy;
4095 int this_insn_uses_z;
4096 int this_insn_uses_z_in_dst;
4097 int this_insn_uses_d;
4098 rtx body;
4099 int z_dies_here;
4101 /* A call is said to clobber the Z register, we don't need
4102 to save the value of Z. We also don't need to restore
4103 the replacement register (unless it is used by the call). */
4104 if (GET_CODE (insn) == CALL_INSN)
4106 body = PATTERN (insn);
4108 info->can_use_d = 0;
4110 /* If the call is an indirect call with Z, we have to use the
4111 Y register because X can be used as an input (D+X).
4112 We also must not save Z nor restore Y. */
4113 if (reg_mentioned_p (z_reg, body))
4115 insn = NEXT_INSN (insn);
4116 info->x_used = 1;
4117 info->y_used = 0;
4118 info->found_call = 1;
4119 info->must_restore_reg = 0;
4120 info->last = NEXT_INSN (insn);
4122 info->need_save_z = 0;
4123 return 0;
4125 if (GET_CODE (insn) == CODE_LABEL
4126 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4127 return 0;
4129 if (GET_CODE (insn) == JUMP_INSN)
4131 if (reg_mentioned_p (z_reg, insn) == 0)
4132 return 0;
4134 info->can_use_d = 0;
4135 info->must_save_reg = 0;
4136 info->must_restore_reg = 0;
4137 info->need_save_z = 0;
4138 info->last = NEXT_INSN (insn);
4139 return 0;
4141 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4143 return 1;
4146 /* Z register dies here. */
4147 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4149 body = PATTERN (insn);
4150 if (GET_CODE (body) == SET)
4152 rtx src = XEXP (body, 1);
4153 rtx dst = XEXP (body, 0);
4155 /* Condition code is set here. We have to restore the X/Y and
4156 save into Z before any test/compare insn because once we save/restore
4157 we can change the condition codes. When the compare insn uses Z and
4158 we can't use X/Y, the comparison is made with the *ZREG soft register
4159 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4160 if (dst == cc0_rtx)
4162 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4163 || (GET_CODE (src) == COMPARE &&
4164 (rtx_equal_p (XEXP (src, 0), z_reg)
4165 || rtx_equal_p (XEXP (src, 1), z_reg))))
4167 if (insn == info->first)
4169 info->must_load_z = 0;
4170 info->must_save_reg = 0;
4171 info->must_restore_reg = 0;
4172 info->need_save_z = 0;
4173 info->found_call = 1;
4174 info->regno = SOFT_Z_REGNUM;
4175 info->last = NEXT_INSN (insn);
4177 return 0;
4179 if (reg_mentioned_p (z_reg, src) == 0)
4181 info->can_use_d = 0;
4182 return 0;
4185 if (insn != info->first)
4186 return 0;
4188 /* Compare insn which uses Z. We have to save/restore the X/Y
4189 register without modifying the condition codes. For this
4190 we have to use a push/pop insn. */
4191 info->must_push_reg = 1;
4192 info->last = insn;
4195 /* Z reg is set to something new. We don't need to load it. */
4196 if (Z_REG_P (dst))
4198 if (!reg_mentioned_p (z_reg, src))
4200 /* Z reg is used before being set. Treat this as
4201 a new sequence of Z register replacement. */
4202 if (insn != info->first)
4204 return 0;
4206 info->must_load_z = 0;
4208 info->z_set_count++;
4209 info->z_value = src;
4210 if (SP_REG_P (src))
4211 info->z_loaded_with_sp = 1;
4213 else if (reg_mentioned_p (z_reg, dst))
4214 info->can_use_d = 0;
4216 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4217 | reg_mentioned_p (d_reg, dst);
4218 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4219 | reg_mentioned_p (ix_reg, dst);
4220 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4221 | reg_mentioned_p (iy_reg, dst);
4222 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4224 /* If z is used as an address operand (like (MEM (reg z))),
4225 we can't replace it with d. */
4226 if (this_insn_uses_z && !Z_REG_P (src)
4227 && !(m68hc11_arith_operator (src, GET_MODE (src))
4228 && Z_REG_P (XEXP (src, 0))
4229 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4230 && insn == info->first
4231 && dead_register_here (insn, d_reg)))
4232 info->can_use_d = 0;
4234 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4235 if (TARGET_M6812 && !z_dies_here
4236 && ((this_insn_uses_z && side_effects_p (src))
4237 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4239 info->need_save_z = 1;
4240 info->z_set_count++;
4242 this_insn_uses_z |= this_insn_uses_z_in_dst;
4244 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4246 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4249 if (this_insn_uses_d)
4250 info->can_use_d = 0;
4252 /* IX and IY are used at the same time, we have to restore
4253 the value of the scratch register before this insn. */
4254 if (this_insn_uses_ix && this_insn_uses_iy)
4256 return 0;
4259 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4260 info->can_use_d = 0;
4262 if (info->x_used == 0 && this_insn_uses_ix)
4264 if (info->y_used)
4266 /* We have a (set (REG:HI X) (REG:HI Z)).
4267 Since we use Z as the replacement register, this insn
4268 is no longer necessary. We turn it into a note. We must
4269 not reload the old value of X. */
4270 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4272 if (z_dies_here)
4274 info->need_save_z = 0;
4275 info->z_died = 1;
4277 info->must_save_reg = 0;
4278 info->must_restore_reg = 0;
4279 info->found_call = 1;
4280 info->can_use_d = 0;
4281 PUT_CODE (insn, NOTE);
4282 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4283 NOTE_SOURCE_FILE (insn) = 0;
4284 info->last = NEXT_INSN (insn);
4285 return 0;
4288 if (X_REG_P (dst)
4289 && (rtx_equal_p (src, z_reg)
4290 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4292 if (z_dies_here)
4294 info->need_save_z = 0;
4295 info->z_died = 1;
4297 info->last = NEXT_INSN (insn);
4298 info->must_save_reg = 0;
4299 info->must_restore_reg = 0;
4301 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4302 && !reg_mentioned_p (ix_reg, src))
4304 if (z_dies_here)
4306 info->z_died = 1;
4307 info->need_save_z = 0;
4309 else if (TARGET_M6812 && side_effects_p (src))
4311 info->last = 0;
4312 info->must_restore_reg = 0;
4313 return 0;
4315 else
4317 info->save_before_last = 1;
4319 info->must_restore_reg = 0;
4320 info->last = NEXT_INSN (insn);
4322 else if (info->can_use_d)
4324 info->last = NEXT_INSN (insn);
4325 info->x_used = 1;
4327 return 0;
4329 info->x_used = 1;
4330 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4331 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4333 info->need_save_z = 0;
4334 info->z_died = 1;
4335 info->last = NEXT_INSN (insn);
4336 info->regno = HARD_X_REGNUM;
4337 info->must_save_reg = 0;
4338 info->must_restore_reg = 0;
4339 return 0;
4341 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4343 info->regno = HARD_X_REGNUM;
4344 info->must_restore_reg = 0;
4345 info->must_save_reg = 0;
4346 return 0;
4349 if (info->y_used == 0 && this_insn_uses_iy)
4351 if (info->x_used)
4353 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4355 if (z_dies_here)
4357 info->need_save_z = 0;
4358 info->z_died = 1;
4360 info->must_save_reg = 0;
4361 info->must_restore_reg = 0;
4362 info->found_call = 1;
4363 info->can_use_d = 0;
4364 PUT_CODE (insn, NOTE);
4365 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4366 NOTE_SOURCE_FILE (insn) = 0;
4367 info->last = NEXT_INSN (insn);
4368 return 0;
4371 if (Y_REG_P (dst)
4372 && (rtx_equal_p (src, z_reg)
4373 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4375 if (z_dies_here)
4377 info->z_died = 1;
4378 info->need_save_z = 0;
4380 info->last = NEXT_INSN (insn);
4381 info->must_save_reg = 0;
4382 info->must_restore_reg = 0;
4384 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4385 && !reg_mentioned_p (iy_reg, src))
4387 if (z_dies_here)
4389 info->z_died = 1;
4390 info->need_save_z = 0;
4392 else if (TARGET_M6812 && side_effects_p (src))
4394 info->last = 0;
4395 info->must_restore_reg = 0;
4396 return 0;
4398 else
4400 info->save_before_last = 1;
4402 info->must_restore_reg = 0;
4403 info->last = NEXT_INSN (insn);
4405 else if (info->can_use_d)
4407 info->last = NEXT_INSN (insn);
4408 info->y_used = 1;
4411 return 0;
4413 info->y_used = 1;
4414 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4415 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4417 info->need_save_z = 0;
4418 info->z_died = 1;
4419 info->last = NEXT_INSN (insn);
4420 info->regno = HARD_Y_REGNUM;
4421 info->must_save_reg = 0;
4422 info->must_restore_reg = 0;
4423 return 0;
4425 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4427 info->regno = HARD_Y_REGNUM;
4428 info->must_restore_reg = 0;
4429 info->must_save_reg = 0;
4430 return 0;
4433 if (z_dies_here)
4435 info->need_save_z = 0;
4436 info->z_died = 1;
4437 if (info->last == 0)
4438 info->last = NEXT_INSN (insn);
4439 return 0;
4441 return info->last != NULL_RTX ? 0 : 1;
4443 if (GET_CODE (body) == PARALLEL)
4445 int i;
4446 char ix_clobber = 0;
4447 char iy_clobber = 0;
4448 char z_clobber = 0;
4449 this_insn_uses_iy = 0;
4450 this_insn_uses_ix = 0;
4451 this_insn_uses_z = 0;
4453 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4455 rtx x;
4456 int uses_ix, uses_iy, uses_z;
4458 x = XVECEXP (body, 0, i);
4460 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4461 info->can_use_d = 0;
4463 uses_ix = reg_mentioned_p (ix_reg, x);
4464 uses_iy = reg_mentioned_p (iy_reg, x);
4465 uses_z = reg_mentioned_p (z_reg, x);
4466 if (GET_CODE (x) == CLOBBER)
4468 ix_clobber |= uses_ix;
4469 iy_clobber |= uses_iy;
4470 z_clobber |= uses_z;
4472 else
4474 this_insn_uses_ix |= uses_ix;
4475 this_insn_uses_iy |= uses_iy;
4476 this_insn_uses_z |= uses_z;
4478 if (uses_z && GET_CODE (x) == SET)
4480 rtx dst = XEXP (x, 0);
4482 if (Z_REG_P (dst))
4483 info->z_set_count++;
4485 if (TARGET_M6812 && uses_z && side_effects_p (x))
4486 info->need_save_z = 1;
4488 if (z_clobber)
4489 info->need_save_z = 0;
4491 if (debug_m6811)
4493 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4494 this_insn_uses_ix, this_insn_uses_iy,
4495 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4496 debug_rtx (insn);
4498 if (this_insn_uses_z)
4499 info->can_use_d = 0;
4501 if (z_clobber && info->first != insn)
4503 info->need_save_z = 0;
4504 info->last = insn;
4505 return 0;
4507 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4509 if (this_insn_uses_z == 0 && insn == info->first)
4511 info->must_load_z = 0;
4513 if (dead_register_here (insn, d_reg))
4515 info->regno = HARD_D_REGNUM;
4516 info->must_save_reg = 0;
4517 info->must_restore_reg = 0;
4519 else if (dead_register_here (insn, ix_reg))
4521 info->regno = HARD_X_REGNUM;
4522 info->must_save_reg = 0;
4523 info->must_restore_reg = 0;
4525 else if (dead_register_here (insn, iy_reg))
4527 info->regno = HARD_Y_REGNUM;
4528 info->must_save_reg = 0;
4529 info->must_restore_reg = 0;
4531 if (info->regno >= 0)
4533 info->last = NEXT_INSN (insn);
4534 return 0;
4536 if (this_insn_uses_ix == 0)
4538 info->regno = HARD_X_REGNUM;
4539 info->must_save_reg = 1;
4540 info->must_restore_reg = 1;
4542 else if (this_insn_uses_iy == 0)
4544 info->regno = HARD_Y_REGNUM;
4545 info->must_save_reg = 1;
4546 info->must_restore_reg = 1;
4548 else
4550 info->regno = HARD_D_REGNUM;
4551 info->must_save_reg = 1;
4552 info->must_restore_reg = 1;
4554 info->last = NEXT_INSN (insn);
4555 return 0;
4558 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4559 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4561 if (this_insn_uses_z)
4563 if (info->y_used == 0 && iy_clobber)
4565 info->regno = HARD_Y_REGNUM;
4566 info->must_save_reg = 0;
4567 info->must_restore_reg = 0;
4569 if (info->first != insn
4570 && ((info->y_used && ix_clobber)
4571 || (info->x_used && iy_clobber)))
4572 info->last = insn;
4573 else
4574 info->last = NEXT_INSN (insn);
4575 info->save_before_last = 1;
4577 return 0;
4579 if (this_insn_uses_ix && this_insn_uses_iy)
4581 if (this_insn_uses_z)
4583 fatal_insn ("cannot do z-register replacement", insn);
4585 return 0;
4587 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4589 if (info->y_used)
4591 return 0;
4593 info->x_used = 1;
4594 if (iy_clobber || z_clobber)
4596 info->last = NEXT_INSN (insn);
4597 info->save_before_last = 1;
4598 return 0;
4602 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4604 if (info->x_used)
4606 return 0;
4608 info->y_used = 1;
4609 if (ix_clobber || z_clobber)
4611 info->last = NEXT_INSN (insn);
4612 info->save_before_last = 1;
4613 return 0;
4616 if (z_dies_here)
4618 info->z_died = 1;
4619 info->need_save_z = 0;
4621 return 1;
4623 if (GET_CODE (body) == CLOBBER)
4626 /* IX and IY are used at the same time, we have to restore
4627 the value of the scratch register before this insn. */
4628 if (this_insn_uses_ix && this_insn_uses_iy)
4630 return 0;
4632 if (info->x_used == 0 && this_insn_uses_ix)
4634 if (info->y_used)
4636 return 0;
4638 info->x_used = 1;
4640 if (info->y_used == 0 && this_insn_uses_iy)
4642 if (info->x_used)
4644 return 0;
4646 info->y_used = 1;
4648 return 1;
4650 return 1;
4653 static void
4654 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4656 int reg;
4658 info->replace_reg = NULL_RTX;
4659 info->must_load_z = 1;
4660 info->need_save_z = 1;
4661 info->must_save_reg = 1;
4662 info->must_restore_reg = 1;
4663 info->first = insn;
4664 info->x_used = 0;
4665 info->y_used = 0;
4666 info->can_use_d = TARGET_M6811 ? 1 : 0;
4667 info->found_call = 0;
4668 info->z_died = 0;
4669 info->last = 0;
4670 info->regno = -1;
4671 info->z_set_count = 0;
4672 info->z_value = NULL_RTX;
4673 info->must_push_reg = 0;
4674 info->save_before_last = 0;
4675 info->z_loaded_with_sp = 0;
4677 /* Scan the insn forward to find an address register that is not used.
4678 Stop when:
4679 - the flow of the program changes,
4680 - when we detect that both X and Y are necessary,
4681 - when the Z register dies,
4682 - when the condition codes are set. */
4684 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4686 if (m68hc11_check_z_replacement (insn, info) == 0)
4687 break;
4690 /* May be we can use Y or X if they contain the same value as Z.
4691 This happens very often after the reload. */
4692 if (info->z_set_count == 1)
4694 rtx p = info->first;
4695 rtx v = 0;
4697 if (info->x_used)
4699 v = find_last_value (iy_reg, &p, insn, 1);
4701 else if (info->y_used)
4703 v = find_last_value (ix_reg, &p, insn, 1);
4705 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4707 if (info->x_used)
4708 info->regno = HARD_Y_REGNUM;
4709 else
4710 info->regno = HARD_X_REGNUM;
4711 info->must_load_z = 0;
4712 info->must_save_reg = 0;
4713 info->must_restore_reg = 0;
4714 info->found_call = 1;
4717 if (info->z_set_count == 0)
4718 info->need_save_z = 0;
4720 if (insn == 0)
4721 info->need_save_z = 0;
4723 if (info->last == 0)
4724 info->last = insn;
4726 if (info->regno >= 0)
4728 reg = info->regno;
4729 info->replace_reg = gen_rtx (REG, HImode, reg);
4731 else if (info->can_use_d)
4733 reg = HARD_D_REGNUM;
4734 info->replace_reg = d_reg;
4736 else if (info->x_used)
4738 reg = HARD_Y_REGNUM;
4739 info->replace_reg = iy_reg;
4741 else
4743 reg = HARD_X_REGNUM;
4744 info->replace_reg = ix_reg;
4746 info->regno = reg;
4748 if (info->must_save_reg && info->must_restore_reg)
4750 if (insn && dead_register_here (insn, info->replace_reg))
4752 info->must_save_reg = 0;
4753 info->must_restore_reg = 0;
4758 /* The insn uses the Z register. Find a replacement register for it
4759 (either X or Y) and replace it in the insn and the next ones until
4760 the flow changes or the replacement register is used. Instructions
4761 are emitted before and after the Z-block to preserve the value of
4762 Z and of the replacement register. */
4764 static void
4765 m68hc11_z_replacement (rtx insn)
4767 rtx replace_reg_qi;
4768 rtx replace_reg;
4769 struct replace_info info;
4771 /* Find trivial case where we only need to replace z with the
4772 equivalent soft register. */
4773 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4775 rtx body = PATTERN (insn);
4776 rtx src = XEXP (body, 1);
4777 rtx dst = XEXP (body, 0);
4779 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4781 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4782 return;
4784 else if (Z_REG_P (src)
4785 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4787 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4788 return;
4790 else if (D_REG_P (dst)
4791 && m68hc11_arith_operator (src, GET_MODE (src))
4792 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4794 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4795 return;
4797 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4798 && INTVAL (src) == 0)
4800 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4801 /* Force it to be re-recognized. */
4802 INSN_CODE (insn) = -1;
4803 return;
4807 m68hc11_find_z_replacement (insn, &info);
4809 replace_reg = info.replace_reg;
4810 replace_reg_qi = NULL_RTX;
4812 /* Save the X register in a .page0 location. */
4813 if (info.must_save_reg && !info.must_push_reg)
4815 rtx dst;
4817 if (info.must_push_reg && 0)
4818 dst = gen_rtx (MEM, HImode,
4819 gen_rtx (PRE_DEC, HImode,
4820 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4821 else
4822 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4824 emit_insn_before (gen_movhi (dst,
4825 gen_rtx (REG, HImode, info.regno)), insn);
4827 if (info.must_load_z && !info.must_push_reg)
4829 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4830 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4831 insn);
4835 /* Replace all occurrence of Z by replace_reg.
4836 Stop when the last instruction to replace is reached.
4837 Also stop when we detect a change in the flow (but it's not
4838 necessary; just safeguard). */
4840 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4842 rtx body;
4844 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4845 break;
4847 if (GET_CODE (insn) != INSN
4848 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4849 continue;
4851 body = PATTERN (insn);
4852 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4853 || GET_CODE (body) == ASM_OPERANDS
4854 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4856 rtx note;
4858 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4860 printf ("Reg mentioned here...:\n");
4861 fflush (stdout);
4862 debug_rtx (insn);
4865 /* Stack pointer was decremented by 2 due to the push.
4866 Correct that by adding 2 to the destination. */
4867 if (info.must_push_reg
4868 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4870 rtx src, dst;
4872 src = SET_SRC (body);
4873 dst = SET_DEST (body);
4874 if (SP_REG_P (src) && Z_REG_P (dst))
4875 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4878 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4879 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4881 INSN_CODE (insn) = -1;
4882 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4883 fatal_insn ("cannot do z-register replacement", insn);
4886 /* Likewise for (REG:QI Z). */
4887 if (reg_mentioned_p (z_reg, insn))
4889 if (replace_reg_qi == NULL_RTX)
4890 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4891 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4894 /* If there is a REG_INC note on Z, replace it with a
4895 REG_INC note on the replacement register. This is necessary
4896 to make sure that the flow pass will identify the change
4897 and it will not remove a possible insn that saves Z. */
4898 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4900 if (REG_NOTE_KIND (note) == REG_INC
4901 && GET_CODE (XEXP (note, 0)) == REG
4902 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4904 XEXP (note, 0) = replace_reg;
4908 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4909 break;
4912 /* Save Z before restoring the old value. */
4913 if (insn && info.need_save_z && !info.must_push_reg)
4915 rtx save_pos_insn = insn;
4917 /* If Z is clobber by the last insn, we have to save its value
4918 before the last instruction. */
4919 if (info.save_before_last)
4920 save_pos_insn = PREV_INSN (save_pos_insn);
4922 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4923 gen_rtx (REG, HImode, info.regno)),
4924 save_pos_insn);
4927 if (info.must_push_reg && info.last)
4929 rtx new_body, body;
4931 body = PATTERN (info.last);
4932 new_body = gen_rtx (PARALLEL, VOIDmode,
4933 gen_rtvec (3, body,
4934 gen_rtx (USE, VOIDmode,
4935 replace_reg),
4936 gen_rtx (USE, VOIDmode,
4937 gen_rtx (REG, HImode,
4938 SOFT_Z_REGNUM))));
4939 PATTERN (info.last) = new_body;
4941 /* Force recognition on insn since we changed it. */
4942 INSN_CODE (insn) = -1;
4944 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4946 fatal_insn ("invalid Z register replacement for insn", insn);
4948 insn = NEXT_INSN (info.last);
4951 /* Restore replacement register unless it was died. */
4952 if (insn && info.must_restore_reg && !info.must_push_reg)
4954 rtx dst;
4956 if (info.must_push_reg && 0)
4957 dst = gen_rtx (MEM, HImode,
4958 gen_rtx (POST_INC, HImode,
4959 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4960 else
4961 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4963 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4964 dst), insn);
4970 /* Scan all the insn and re-affects some registers
4971 - The Z register (if it was used), is affected to X or Y depending
4972 on the instruction. */
4974 static void
4975 m68hc11_reassign_regs (rtx first)
4977 rtx insn;
4979 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
4980 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
4981 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4982 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
4984 /* Scan all insns to replace Z by X or Y preserving the old value
4985 of X/Y and restoring it afterward. */
4987 for (insn = first; insn; insn = NEXT_INSN (insn))
4989 rtx body;
4991 if (GET_CODE (insn) == CODE_LABEL
4992 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4993 continue;
4995 if (!INSN_P (insn))
4996 continue;
4998 body = PATTERN (insn);
4999 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5000 continue;
5002 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5003 || GET_CODE (body) == ASM_OPERANDS
5004 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5005 continue;
5007 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5008 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5011 /* If Z appears in this insn, replace it in the current insn
5012 and the next ones until the flow changes or we have to
5013 restore back the replacement register. */
5015 if (reg_mentioned_p (z_reg, body))
5017 m68hc11_z_replacement (insn);
5020 else
5022 printf ("insn not handled by Z replacement:\n");
5023 fflush (stdout);
5024 debug_rtx (insn);
5030 /* Machine-dependent reorg pass.
5031 Specific optimizations are defined here:
5032 - this pass changes the Z register into either X or Y
5033 (it preserves X/Y previous values in a memory slot in page0).
5035 When this pass is finished, the global variable
5036 'z_replacement_completed' is set to 2. */
5038 static void
5039 m68hc11_reorg (void)
5041 int split_done = 0;
5042 rtx insn, first;
5044 z_replacement_completed = 0;
5045 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5046 first = get_insns ();
5048 /* Some RTX are shared at this point. This breaks the Z register
5049 replacement, unshare everything. */
5050 unshare_all_rtl_again (first);
5052 /* Force a split of all splitable insn. This is necessary for the
5053 Z register replacement mechanism because we end up with basic insns. */
5054 split_all_insns_noflow ();
5055 split_done = 1;
5057 z_replacement_completed = 1;
5058 m68hc11_reassign_regs (first);
5060 if (optimize)
5061 compute_bb_for_insn ();
5063 /* After some splitting, there are some opportunities for CSE pass.
5064 This happens quite often when 32-bit or above patterns are split. */
5065 if (optimize > 0 && split_done)
5067 reload_cse_regs (first);
5070 /* Re-create the REG_DEAD notes. These notes are used in the machine
5071 description to use the best assembly directives. */
5072 if (optimize)
5074 /* Before recomputing the REG_DEAD notes, remove all of them.
5075 This is necessary because the reload_cse_regs() pass can
5076 have replaced some (MEM) with a register. In that case,
5077 the REG_DEAD that could exist for that register may become
5078 wrong. */
5079 for (insn = first; insn; insn = NEXT_INSN (insn))
5081 if (INSN_P (insn))
5083 rtx *pnote;
5085 pnote = &REG_NOTES (insn);
5086 while (*pnote != 0)
5088 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5089 *pnote = XEXP (*pnote, 1);
5090 else
5091 pnote = &XEXP (*pnote, 1);
5096 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
5099 z_replacement_completed = 2;
5101 /* If optimizing, then go ahead and split insns that must be
5102 split after Z register replacement. This gives more opportunities
5103 for peephole (in particular for consecutives xgdx/xgdy). */
5104 if (optimize > 0)
5105 split_all_insns_noflow ();
5107 /* Once insns are split after the z_replacement_completed == 2,
5108 we must not re-run the life_analysis. The xgdx/xgdy patterns
5109 are not recognized and the life_analysis pass removes some
5110 insns because it thinks some (SETs) are noops or made to dead
5111 stores (which is false due to the swap).
5113 Do a simple pass to eliminate the noop set that the final
5114 split could generate (because it was easier for split definition). */
5116 rtx insn;
5118 for (insn = first; insn; insn = NEXT_INSN (insn))
5120 rtx body;
5122 if (INSN_DELETED_P (insn))
5123 continue;
5124 if (!INSN_P (insn))
5125 continue;
5127 /* Remove the (set (R) (R)) insns generated by some splits. */
5128 body = PATTERN (insn);
5129 if (GET_CODE (body) == SET
5130 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5132 PUT_CODE (insn, NOTE);
5133 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5134 NOTE_SOURCE_FILE (insn) = 0;
5135 continue;
5141 /* Override memcpy */
5143 static void
5144 m68hc11_init_libfuncs (void)
5146 memcpy_libfunc = init_one_libfunc ("__memcpy");
5147 memcmp_libfunc = init_one_libfunc ("__memcmp");
5148 memset_libfunc = init_one_libfunc ("__memset");
5153 /* Cost functions. */
5155 /* Cost of moving memory. */
5157 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class class,
5158 int in ATTRIBUTE_UNUSED)
5160 if (class <= H_REGS && class > NO_REGS)
5162 if (GET_MODE_SIZE (mode) <= 2)
5163 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5164 else
5165 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5167 else
5169 if (GET_MODE_SIZE (mode) <= 2)
5170 return COSTS_N_INSNS (3);
5171 else
5172 return COSTS_N_INSNS (4);
5177 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5178 Reload does not check the constraint of set insns when the two registers
5179 have a move cost of 2. Setting a higher cost will force reload to check
5180 the constraints. */
5182 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5183 enum reg_class to)
5185 /* All costs are symmetric, so reduce cases by putting the
5186 lower number class as the destination. */
5187 if (from < to)
5189 enum reg_class tmp = to;
5190 to = from, from = tmp;
5192 if (to >= S_REGS)
5193 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5194 else if (from <= S_REGS)
5195 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5196 else
5197 return COSTS_N_INSNS (2);
5201 /* Provide the costs of an addressing mode that contains ADDR.
5202 If ADDR is not a valid address, its cost is irrelevant. */
5204 static int
5205 m68hc11_address_cost (rtx addr)
5207 int cost = 4;
5209 switch (GET_CODE (addr))
5211 case REG:
5212 /* Make the cost of hard registers and specially SP, FP small. */
5213 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5214 cost = 0;
5215 else
5216 cost = 1;
5217 break;
5219 case SYMBOL_REF:
5220 cost = 8;
5221 break;
5223 case LABEL_REF:
5224 case CONST:
5225 cost = 0;
5226 break;
5228 case PLUS:
5230 register rtx plus0 = XEXP (addr, 0);
5231 register rtx plus1 = XEXP (addr, 1);
5233 if (GET_CODE (plus0) != REG)
5234 break;
5236 switch (GET_CODE (plus1))
5238 case CONST_INT:
5239 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5240 || INTVAL (plus1) < m68hc11_min_offset)
5241 cost = 3;
5242 else if (INTVAL (plus1) >= m68hc11_max_offset)
5243 cost = 2;
5244 else
5245 cost = 1;
5246 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5247 cost += 0;
5248 else
5249 cost += 1;
5250 break;
5252 case SYMBOL_REF:
5253 cost = 8;
5254 break;
5256 case CONST:
5257 case LABEL_REF:
5258 cost = 0;
5259 break;
5261 default:
5262 break;
5264 break;
5266 case PRE_DEC:
5267 case PRE_INC:
5268 if (SP_REG_P (XEXP (addr, 0)))
5269 cost = 1;
5270 break;
5272 default:
5273 break;
5275 if (debug_m6811)
5277 printf ("Address cost: %d for :", cost);
5278 fflush (stdout);
5279 debug_rtx (addr);
5282 return cost;
5285 static int
5286 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5288 int total;
5290 total = rtx_cost (x, SET);
5291 if (mode == QImode)
5292 total += m68hc11_cost->shiftQI_const[shift % 8];
5293 else if (mode == HImode)
5294 total += m68hc11_cost->shiftHI_const[shift % 16];
5295 else if (shift == 8 || shift == 16 || shift == 32)
5296 total += m68hc11_cost->shiftHI_const[8];
5297 else if (shift != 0 && shift != 16 && shift != 32)
5299 total += m68hc11_cost->shiftHI_const[1] * shift;
5302 /* For SI and others, the cost is higher. */
5303 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5304 total *= GET_MODE_SIZE (mode) / 2;
5306 /* When optimizing for size, make shift more costly so that
5307 multiplications are preferred. */
5308 if (optimize_size && (shift % 8) != 0)
5309 total *= 2;
5311 return total;
5314 static int
5315 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5316 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5318 enum machine_mode mode = GET_MODE (x);
5319 int extra_cost = 0;
5320 int total;
5322 switch (code)
5324 case ROTATE:
5325 case ROTATERT:
5326 case ASHIFT:
5327 case LSHIFTRT:
5328 case ASHIFTRT:
5329 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5331 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5334 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5335 total += m68hc11_cost->shift_var;
5336 return total;
5338 case AND:
5339 case XOR:
5340 case IOR:
5341 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5342 total += m68hc11_cost->logical;
5344 /* Logical instructions are byte instructions only. */
5345 total *= GET_MODE_SIZE (mode);
5346 return total;
5348 case MINUS:
5349 case PLUS:
5350 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5351 total += m68hc11_cost->add;
5352 if (GET_MODE_SIZE (mode) > 2)
5354 total *= GET_MODE_SIZE (mode) / 2;
5356 return total;
5358 case UDIV:
5359 case DIV:
5360 case MOD:
5361 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5362 switch (mode)
5364 case QImode:
5365 total += m68hc11_cost->divQI;
5366 break;
5368 case HImode:
5369 total += m68hc11_cost->divHI;
5370 break;
5372 case SImode:
5373 default:
5374 total += m68hc11_cost->divSI;
5375 break;
5377 return total;
5379 case MULT:
5380 /* mul instruction produces 16-bit result. */
5381 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5382 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5383 return m68hc11_cost->multQI
5384 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5385 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5387 /* emul instruction produces 32-bit result for 68HC12. */
5388 if (TARGET_M6812 && mode == SImode
5389 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5390 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5391 return m68hc11_cost->multHI
5392 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5393 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5395 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5396 switch (mode)
5398 case QImode:
5399 total += m68hc11_cost->multQI;
5400 break;
5402 case HImode:
5403 total += m68hc11_cost->multHI;
5404 break;
5406 case SImode:
5407 default:
5408 total += m68hc11_cost->multSI;
5409 break;
5411 return total;
5413 case NEG:
5414 case SIGN_EXTEND:
5415 extra_cost = COSTS_N_INSNS (2);
5417 /* Fall through */
5418 case NOT:
5419 case COMPARE:
5420 case ABS:
5421 case ZERO_EXTEND:
5422 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5423 if (mode == QImode)
5425 return total + COSTS_N_INSNS (1);
5427 if (mode == HImode)
5429 return total + COSTS_N_INSNS (2);
5431 if (mode == SImode)
5433 return total + COSTS_N_INSNS (4);
5435 return total + COSTS_N_INSNS (8);
5437 case IF_THEN_ELSE:
5438 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5439 return COSTS_N_INSNS (1);
5441 return COSTS_N_INSNS (1);
5443 default:
5444 return COSTS_N_INSNS (4);
5448 static bool
5449 m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total)
5451 switch (code)
5453 /* Constants are cheap. Moving them in registers must be avoided
5454 because most instructions do not handle two register operands. */
5455 case CONST_INT:
5456 case CONST:
5457 case LABEL_REF:
5458 case SYMBOL_REF:
5459 case CONST_DOUBLE:
5460 /* Logical and arithmetic operations with a constant operand are
5461 better because they are not supported with two registers. */
5462 /* 'clr' is slow */
5463 if (outer_code == SET && x == const0_rtx)
5464 /* After reload, the reload_cse pass checks the cost to change
5465 a SET into a PLUS. Make const0 cheap then. */
5466 *total = 1 - reload_completed;
5467 else
5468 *total = 0;
5469 return true;
5471 case ROTATE:
5472 case ROTATERT:
5473 case ASHIFT:
5474 case LSHIFTRT:
5475 case ASHIFTRT:
5476 case MINUS:
5477 case PLUS:
5478 case AND:
5479 case XOR:
5480 case IOR:
5481 case UDIV:
5482 case DIV:
5483 case MOD:
5484 case MULT:
5485 case NEG:
5486 case SIGN_EXTEND:
5487 case NOT:
5488 case COMPARE:
5489 case ZERO_EXTEND:
5490 case IF_THEN_ELSE:
5491 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5492 return true;
5494 default:
5495 return false;
5500 static void
5501 m68hc11_file_start (void)
5503 default_file_start ();
5505 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5509 static void
5510 m68hc11_asm_out_constructor (rtx symbol, int priority)
5512 default_ctor_section_asm_out_constructor (symbol, priority);
5513 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5516 static void
5517 m68hc11_asm_out_destructor (rtx symbol, int priority)
5519 default_dtor_section_asm_out_destructor (symbol, priority);
5520 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5523 #include "gt-m68hc11.h"