* varasm.c (assemble_real): Use REAL_VALUE_TO_x and assemble_integer
[official-gcc.git] / gcc / config / m68hc11 / m68hc11.c
blobf45d195e0203724ab187450035d3de4d5b3cdbaf
1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.
3 Contributed by Stephane Carrez (stcarrez@worldnet.fr)
5 This file is part of GNU CC.
7 GNU CC is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU CC is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU CC; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
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 "rtl.h"
39 #include "tree.h"
40 #include "tm_p.h"
41 #include "regs.h"
42 #include "hard-reg-set.h"
43 #include "real.h"
44 #include "insn-config.h"
45 #include "conditions.h"
46 #include "output.h"
47 #include "insn-attr.h"
48 #include "flags.h"
49 #include "recog.h"
50 #include "expr.h"
51 #include "toplev.h"
52 #include "basic-block.h"
53 #include "function.h"
54 #include "ggc.h"
55 #include "reload.h"
56 #include "target.h"
57 #include "target-def.h"
59 static void print_options PARAMS ((FILE *));
60 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
61 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
62 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
63 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
64 int));
65 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
66 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
67 static int must_parenthesize PARAMS ((rtx));
68 static int m68hc11_shift_cost PARAMS ((enum machine_mode, rtx, int));
69 static int m68hc11_auto_inc_p PARAMS ((rtx));
70 static tree m68hc11_handle_fntype_attribute PARAMS ((tree *, tree, tree, int, bool *));
71 const struct attribute_spec m68hc11_attribute_table[];
73 void create_regs_rtx PARAMS ((void));
74 static void m68hc11_add_gc_roots PARAMS ((void));
76 static void asm_print_register PARAMS ((FILE *, int));
77 static void m68hc11_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
78 static void m68hc11_asm_out_constructor PARAMS ((rtx, int));
79 static void m68hc11_asm_out_destructor PARAMS ((rtx, int));
81 rtx m68hc11_soft_tmp_reg;
83 /* Must be set to 1 to produce debug messages. */
84 int debug_m6811 = 0;
86 extern FILE *asm_out_file;
88 rtx ix_reg;
89 rtx iy_reg;
90 rtx d_reg;
91 rtx da_reg;
92 rtx stack_push_word;
93 rtx stack_pop_word;
94 static int regs_inited = 0;
95 static rtx z_reg;
97 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
98 int current_function_interrupt;
100 /* Set to 1 by expand_prologue() when the function is a trap handler. */
101 int current_function_trap;
103 /* Min offset that is valid for the indirect addressing mode. */
104 HOST_WIDE_INT m68hc11_min_offset = 0;
106 /* Max offset that is valid for the indirect addressing mode. */
107 HOST_WIDE_INT m68hc11_max_offset = 256;
109 /* The class value for base registers. */
110 enum reg_class m68hc11_base_reg_class = A_REGS;
112 /* The class value for index registers. This is NO_REGS for 68HC11. */
113 enum reg_class m68hc11_index_reg_class = NO_REGS;
115 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
117 /* Tables that tell whether a given hard register is valid for
118 a base or an index register. It is filled at init time depending
119 on the target processor. */
120 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
121 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
123 /* A correction offset which is applied to the stack pointer.
124 This is 1 for 68HC11 and 0 for 68HC12. */
125 int m68hc11_sp_correction;
127 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
128 rtx m68hc11_compare_op0;
129 rtx m68hc11_compare_op1;
132 const struct processor_costs *m68hc11_cost;
134 /* Costs for a 68HC11. */
135 static const struct processor_costs m6811_cost = {
136 /* add */
137 COSTS_N_INSNS (2),
138 /* logical */
139 COSTS_N_INSNS (2),
140 /* non-constant shift */
141 COSTS_N_INSNS (20),
142 /* shiftQI const */
143 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
144 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
145 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
147 /* shiftHI const */
148 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
149 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
150 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
151 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
152 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
153 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
155 /* mulQI */
156 COSTS_N_INSNS (20),
157 /* mulHI */
158 COSTS_N_INSNS (20 * 4),
159 /* mulSI */
160 COSTS_N_INSNS (20 * 16),
161 /* divQI */
162 COSTS_N_INSNS (20),
163 /* divHI */
164 COSTS_N_INSNS (80),
165 /* divSI */
166 COSTS_N_INSNS (100)
169 /* Costs for a 68HC12. */
170 static const struct processor_costs m6812_cost = {
171 /* add */
172 COSTS_N_INSNS (1),
173 /* logical */
174 COSTS_N_INSNS (1),
175 /* non-constant shift */
176 COSTS_N_INSNS (20),
177 /* shiftQI const */
178 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
179 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
180 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
182 /* shiftHI const */
183 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
184 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
185 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
186 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
187 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
188 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
190 /* mulQI */
191 COSTS_N_INSNS (3),
192 /* mulHI */
193 COSTS_N_INSNS (3),
194 /* mulSI */
195 COSTS_N_INSNS (3 * 4),
196 /* divQI */
197 COSTS_N_INSNS (12),
198 /* divHI */
199 COSTS_N_INSNS (12),
200 /* divSI */
201 COSTS_N_INSNS (100)
204 /* Machine specific options */
206 const char *m68hc11_regparm_string;
207 const char *m68hc11_reg_alloc_order;
208 const char *m68hc11_soft_reg_count;
210 static int nb_soft_regs;
212 /* Initialize the GCC target structure. */
213 #undef TARGET_ATTRIBUTE_TABLE
214 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
216 #undef TARGET_ASM_ALIGNED_HI_OP
217 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
219 #undef TARGET_ASM_FUNCTION_EPILOGUE
220 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
222 struct gcc_target targetm = TARGET_INITIALIZER;
225 m68hc11_override_options ()
227 m68hc11_add_gc_roots ();
229 memset (m68hc11_reg_valid_for_index, 0,
230 sizeof (m68hc11_reg_valid_for_index));
231 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
233 /* Compilation with -fpic generates a wrong code. */
234 if (flag_pic)
236 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
237 (flag_pic > 1) ? "PIC" : "pic");
238 flag_pic = 0;
241 /* Configure for a 68hc11 processor. */
242 if (TARGET_M6811)
244 /* If gcc was built for a 68hc12, invalidate that because
245 a -m68hc11 option was specified on the command line. */
246 if (TARGET_DEFAULT != MASK_M6811)
247 target_flags &= ~TARGET_DEFAULT;
249 m68hc11_cost = &m6811_cost;
250 m68hc11_min_offset = 0;
251 m68hc11_max_offset = 256;
252 m68hc11_index_reg_class = NO_REGS;
253 m68hc11_base_reg_class = A_REGS;
254 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
255 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
256 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
257 m68hc11_sp_correction = 1;
258 m68hc11_tmp_regs_class = D_REGS;
259 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
260 m68hc11_soft_reg_count = "4";
263 /* Configure for a 68hc12 processor. */
264 if (TARGET_M6812)
266 m68hc11_cost = &m6812_cost;
267 m68hc11_min_offset = -65536;
268 m68hc11_max_offset = 65536;
269 m68hc11_index_reg_class = D_REGS;
270 m68hc11_base_reg_class = A_OR_SP_REGS;
271 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
272 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
273 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
274 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
275 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
276 m68hc11_sp_correction = 0;
277 m68hc11_tmp_regs_class = TMP_REGS;
278 target_flags &= ~MASK_M6811;
279 if (m68hc11_soft_reg_count == 0)
280 m68hc11_soft_reg_count = "2";
282 return 0;
286 void
287 m68hc11_conditional_register_usage ()
289 int i;
290 int cnt = atoi (m68hc11_soft_reg_count);
292 if (cnt < 0)
293 cnt = 0;
294 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
295 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
297 nb_soft_regs = cnt;
298 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
300 fixed_regs[i] = 1;
301 call_used_regs[i] = 1;
306 /* Reload and register operations. */
308 static const char *const reg_class_names[] = REG_CLASS_NAMES;
311 void
312 create_regs_rtx ()
314 /* regs_inited = 1; */
315 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
316 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
317 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
318 da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
319 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
321 stack_push_word = gen_rtx (MEM, HImode,
322 gen_rtx (PRE_DEC, HImode,
323 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
324 stack_pop_word = gen_rtx (MEM, HImode,
325 gen_rtx (POST_INC, HImode,
326 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
330 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
331 - 8 bit values are stored anywhere (except the SP register).
332 - 16 bit values can be stored in any register whose mode is 16
333 - 32 bit values can be stored in D, X registers or in a soft register
334 (except the last one because we need 2 soft registers)
335 - Values whose size is > 32 bit are not stored in real hard
336 registers. They may be stored in soft registers if there are
337 enough of them. */
339 hard_regno_mode_ok (regno, mode)
340 int regno;
341 enum machine_mode mode;
343 switch (GET_MODE_SIZE (mode))
345 case 8:
346 return S_REGNO_P (regno) && nb_soft_regs >= 4;
348 case 4:
349 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
351 case 2:
352 return G_REGNO_P (regno);
354 case 1:
355 /* We have to accept a QImode in X or Y registers. Otherwise, the
356 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
357 in the insns. Reload fails if the insn rejects the register class 'a'
358 as well as if it accepts it. Patterns that failed were
359 zero_extend_qihi2 and iorqi3. */
361 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
363 default:
364 return 0;
368 enum reg_class
369 preferred_reload_class (operand, class)
370 rtx operand;
371 enum reg_class class;
373 enum machine_mode mode;
375 mode = GET_MODE (operand);
377 if (debug_m6811)
379 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
382 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
383 return m68hc11_base_reg_class;
385 if (class >= S_REGS && (GET_CODE (operand) == MEM
386 || GET_CODE (operand) == CONST_INT))
388 /* S_REGS class must not be used. The movhi template does not
389 work to move a memory to a soft register.
390 Restrict to a hard reg. */
391 switch (class)
393 default:
394 case G_REGS:
395 case D_OR_A_OR_S_REGS:
396 class = A_OR_D_REGS;
397 break;
398 case A_OR_S_REGS:
399 class = A_REGS;
400 break;
401 case D_OR_SP_OR_S_REGS:
402 class = D_OR_SP_REGS;
403 break;
404 case D_OR_Y_OR_S_REGS:
405 class = D_OR_Y_REGS;
406 break;
407 case D_OR_X_OR_S_REGS:
408 class = D_OR_X_REGS;
409 break;
410 case SP_OR_S_REGS:
411 class = SP_REGS;
412 break;
413 case Y_OR_S_REGS:
414 class = Y_REGS;
415 break;
416 case X_OR_S_REGS:
417 class = X_REGS;
418 break;
419 case D_OR_S_REGS:
420 class = D_REGS;
423 else if (class == Y_REGS && GET_CODE (operand) == MEM)
425 class = Y_REGS;
427 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
429 class = D_OR_X_REGS;
431 else if (class >= S_REGS && S_REG_P (operand))
433 switch (class)
435 default:
436 case G_REGS:
437 case D_OR_A_OR_S_REGS:
438 class = A_OR_D_REGS;
439 break;
440 case A_OR_S_REGS:
441 class = A_REGS;
442 break;
443 case D_OR_SP_OR_S_REGS:
444 class = D_OR_SP_REGS;
445 break;
446 case D_OR_Y_OR_S_REGS:
447 class = D_OR_Y_REGS;
448 break;
449 case D_OR_X_OR_S_REGS:
450 class = D_OR_X_REGS;
451 break;
452 case SP_OR_S_REGS:
453 class = SP_REGS;
454 break;
455 case Y_OR_S_REGS:
456 class = Y_REGS;
457 break;
458 case X_OR_S_REGS:
459 class = X_REGS;
460 break;
461 case D_OR_S_REGS:
462 class = D_REGS;
465 else if (class >= S_REGS)
467 if (debug_m6811)
469 printf ("Class = %s for: ", reg_class_names[class]);
470 fflush (stdout);
471 debug_rtx (operand);
475 if (debug_m6811)
477 printf (" => class=%s\n", reg_class_names[class]);
478 fflush (stdout);
479 debug_rtx (operand);
482 return class;
485 /* Return 1 if the operand is a valid indexed addressing mode.
486 For 68hc11: n,r with n in [0..255] and r in A_REGS class
487 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
488 static int
489 register_indirect_p (operand, mode, strict)
490 rtx operand;
491 enum machine_mode mode;
492 int strict;
494 rtx base, offset;
496 switch (GET_CODE (operand))
498 case POST_INC:
499 case PRE_INC:
500 case POST_DEC:
501 case PRE_DEC:
502 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
503 return register_indirect_p (XEXP (operand, 0), mode, strict);
504 return 0;
506 case PLUS:
507 base = XEXP (operand, 0);
508 if (GET_CODE (base) == MEM)
509 return 0;
511 offset = XEXP (operand, 1);
512 if (GET_CODE (offset) == MEM)
513 return 0;
515 if (GET_CODE (base) == REG)
517 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
518 return 0;
520 if (strict == 0)
521 return 1;
523 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
525 if (GET_CODE (offset) == REG)
527 if (!VALID_CONSTANT_OFFSET_P (base, mode))
528 return 0;
530 if (strict == 0)
531 return 1;
533 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
535 return 0;
537 case REG:
538 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
540 default:
541 return 0;
545 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
546 a 68HC12 1-byte index addressing mode. */
548 m68hc11_small_indexed_indirect_p (operand, mode)
549 rtx operand;
550 enum machine_mode mode;
552 rtx base, offset;
554 if (GET_CODE (operand) != MEM)
555 return 0;
557 operand = XEXP (operand, 0);
558 if (CONSTANT_ADDRESS_P (operand))
559 return 1;
561 if (PUSH_POP_ADDRESS_P (operand))
562 return 1;
564 if (!register_indirect_p (operand, mode,
565 (reload_completed | reload_in_progress)))
566 return 0;
568 if (TARGET_M6812 && GET_CODE (operand) == PLUS
569 && (reload_completed | reload_in_progress))
571 base = XEXP (operand, 0);
572 offset = XEXP (operand, 1);
573 if (GET_CODE (base) == CONST_INT)
574 offset = base;
576 switch (GET_MODE_SIZE (mode))
578 case 8:
579 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
580 return 0;
581 break;
583 case 4:
584 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
585 return 0;
586 break;
588 default:
589 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
590 return 0;
591 break;
594 return 1;
598 m68hc11_register_indirect_p (operand, mode)
599 rtx operand;
600 enum machine_mode mode;
602 if (GET_CODE (operand) != MEM)
603 return 0;
605 operand = XEXP (operand, 0);
606 return register_indirect_p (operand, mode,
607 (reload_completed | reload_in_progress));
610 static int
611 go_if_legitimate_address_internal (operand, mode, strict)
612 rtx operand;
613 enum machine_mode mode;
614 int strict;
616 if (CONSTANT_ADDRESS_P (operand))
618 /* Reject the global variables if they are too wide. This forces
619 a load of their address in a register and generates smaller code. */
620 if (GET_MODE_SIZE (mode) == 8)
621 return 0;
623 return 1;
625 if (register_indirect_p (operand, mode, strict))
627 return 1;
629 if (PUSH_POP_ADDRESS_P (operand))
631 return 1;
633 if (symbolic_memory_operand (operand, mode))
635 return 1;
637 return 0;
641 m68hc11_go_if_legitimate_address (operand, mode, strict)
642 rtx operand;
643 enum machine_mode mode;
644 int strict;
646 int result;
648 if (debug_m6811)
650 printf ("Checking: ");
651 fflush (stdout);
652 debug_rtx (operand);
655 result = go_if_legitimate_address_internal (operand, mode, strict);
657 if (debug_m6811)
659 printf (" -> %s\n", result == 0 ? "NO" : "YES");
662 if (result == 0)
664 if (debug_m6811)
666 printf ("go_if_legitimate%s, ret 0: %d:",
667 (strict ? "_strict" : ""), mode);
668 fflush (stdout);
669 debug_rtx (operand);
672 return result;
676 m68hc11_legitimize_address (operand, old_operand, mode)
677 rtx *operand ATTRIBUTE_UNUSED;
678 rtx old_operand ATTRIBUTE_UNUSED;
679 enum machine_mode mode ATTRIBUTE_UNUSED;
681 return 0;
686 m68hc11_reload_operands (operands)
687 rtx operands[];
689 enum machine_mode mode;
691 if (regs_inited == 0)
692 create_regs_rtx ();
694 mode = GET_MODE (operands[1]);
696 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
697 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
699 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
700 rtx base = XEXP (XEXP (operands[1], 0), 0);
702 if (GET_CODE (base) != REG)
704 rtx tmp = base;
705 base = big_offset;
706 big_offset = tmp;
709 /* If the offset is out of range, we have to compute the address
710 with a separate add instruction. We try to do with with an 8-bit
711 add on the A register. This is possible only if the lowest part
712 of the offset (ie, big_offset % 256) is a valid constant offset
713 with respect to the mode. If it's not, we have to generate a
714 16-bit add on the D register. From:
716 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
718 we generate:
720 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
721 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
722 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
723 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
725 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
726 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
729 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
731 int vh, vl;
732 rtx reg = operands[0];
733 rtx offset;
734 int val = INTVAL (big_offset);
737 /* We use the 'operands[0]' as a scratch register to compute the
738 address. Make sure 'base' is in that register. */
739 if (!rtx_equal_p (base, operands[0]))
741 emit_move_insn (reg, base);
744 if (val > 0)
746 vh = val >> 8;
747 vl = val & 0x0FF;
749 else
751 vh = (val >> 8) & 0x0FF;
752 vl = val & 0x0FF;
755 /* Create the lowest part offset that still remains to be added.
756 If it's not a valid offset, do a 16-bit add. */
757 offset = gen_rtx (CONST_INT, VOIDmode, vl);
758 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
760 emit_insn (gen_rtx (SET, VOIDmode, reg,
761 gen_rtx (PLUS, HImode, reg, big_offset)));
762 offset = const0_rtx;
764 else
766 emit_insn (gen_rtx (SET, VOIDmode, reg,
767 gen_rtx (PLUS, HImode, reg,
768 gen_rtx (CONST_INT,
769 VOIDmode, vh << 8))));
771 emit_move_insn (operands[0],
772 gen_rtx (MEM, GET_MODE (operands[1]),
773 gen_rtx (PLUS, Pmode, reg, offset)));
774 return 1;
778 /* Use the normal gen_movhi pattern. */
779 return 0;
782 void
783 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
784 const char *name;
785 enum rtx_code code;
786 enum machine_mode dmode;
787 enum machine_mode smode;
788 int noperands;
789 rtx *operands;
791 rtx ret;
792 rtx insns;
793 rtx libcall;
794 rtx equiv;
796 start_sequence ();
797 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
798 switch (noperands)
800 case 2:
801 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
802 dmode, 1, operands[1], smode);
803 equiv = gen_rtx (code, dmode, operands[1]);
804 break;
806 case 3:
807 ret = emit_library_call_value (libcall, NULL_RTX,
808 LCT_CONST, dmode, 2,
809 operands[1], smode, operands[2],
810 smode);
811 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
812 break;
814 default:
815 abort ();
818 insns = get_insns ();
819 end_sequence ();
820 emit_libcall_block (insns, operands[0], ret, equiv);
823 /* Returns true if X is a PRE/POST increment decrement
824 (same as auto_inc_p() in rtlanal.c but do not take into
825 account the stack). */
826 static int
827 m68hc11_auto_inc_p (x)
828 rtx x;
830 return GET_CODE (x) == PRE_DEC
831 || GET_CODE (x) == POST_INC
832 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
836 /* Predicates for machine description. */
839 memory_reload_operand (operand, mode)
840 rtx operand;
841 enum machine_mode mode ATTRIBUTE_UNUSED;
843 return GET_CODE (operand) == MEM
844 && GET_CODE (XEXP (operand, 0)) == PLUS
845 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
846 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
847 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
848 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
852 tst_operand (operand, mode)
853 rtx operand;
854 enum machine_mode mode;
856 if (GET_CODE (operand) == MEM)
858 rtx addr = XEXP (operand, 0);
859 if (m68hc11_auto_inc_p (addr))
860 return 0;
862 return nonimmediate_operand (operand, mode);
866 cmp_operand (operand, mode)
867 rtx operand;
868 enum machine_mode mode;
870 if (GET_CODE (operand) == MEM)
872 rtx addr = XEXP (operand, 0);
873 if (m68hc11_auto_inc_p (addr))
874 return 0;
876 return general_operand (operand, mode);
880 non_push_operand (operand, mode)
881 rtx operand;
882 enum machine_mode mode;
884 if (general_operand (operand, mode) == 0)
885 return 0;
887 if (push_operand (operand, mode) == 1)
888 return 0;
889 return 1;
893 reg_or_some_mem_operand (operand, mode)
894 rtx operand;
895 enum machine_mode mode;
897 if (GET_CODE (operand) == MEM)
899 rtx op = XEXP (operand, 0);
901 if (symbolic_memory_operand (op, mode))
902 return 1;
904 if (IS_STACK_PUSH (operand))
905 return 1;
907 if (m68hc11_register_indirect_p (operand, mode))
908 return 1;
910 return 0;
913 return register_operand (operand, mode);
917 stack_register_operand (operand, mode)
918 rtx operand;
919 enum machine_mode mode ATTRIBUTE_UNUSED;
921 return SP_REG_P (operand);
925 d_register_operand (operand, mode)
926 rtx operand;
927 enum machine_mode mode ATTRIBUTE_UNUSED;
929 if (GET_CODE (operand) == SUBREG)
930 operand = XEXP (operand, 0);
932 return GET_CODE (operand) == REG
933 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
934 || REGNO (operand) == HARD_D_REGNUM
935 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
939 hard_addr_reg_operand (operand, mode)
940 rtx operand;
941 enum machine_mode mode ATTRIBUTE_UNUSED;
943 if (GET_CODE (operand) == SUBREG)
944 operand = XEXP (operand, 0);
946 return GET_CODE (operand) == REG
947 && (REGNO (operand) == HARD_X_REGNUM
948 || REGNO (operand) == HARD_Y_REGNUM
949 || REGNO (operand) == HARD_Z_REGNUM);
953 hard_reg_operand (operand, mode)
954 rtx operand;
955 enum machine_mode mode ATTRIBUTE_UNUSED;
957 if (GET_CODE (operand) == SUBREG)
958 operand = XEXP (operand, 0);
960 return GET_CODE (operand) == REG
961 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
962 || H_REGNO_P (REGNO (operand)));
966 memory_indexed_operand (operand, mode)
967 rtx operand;
968 enum machine_mode mode ATTRIBUTE_UNUSED;
970 if (GET_CODE (operand) != MEM)
971 return 0;
973 operand = XEXP (operand, 0);
974 if (GET_CODE (operand) == PLUS)
976 if (GET_CODE (XEXP (operand, 0)) == REG)
977 operand = XEXP (operand, 0);
978 else if (GET_CODE (XEXP (operand, 1)) == REG)
979 operand = XEXP (operand, 1);
981 return GET_CODE (operand) == REG
982 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
983 || A_REGNO_P (REGNO (operand)));
987 push_pop_operand_p (operand)
988 rtx operand;
990 if (GET_CODE (operand) != MEM)
992 return 0;
994 operand = XEXP (operand, 0);
995 return PUSH_POP_ADDRESS_P (operand);
998 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
999 reference and a constant. */
1002 symbolic_memory_operand (op, mode)
1003 register rtx op;
1004 enum machine_mode mode;
1006 switch (GET_CODE (op))
1008 case SYMBOL_REF:
1009 case LABEL_REF:
1010 return 1;
1012 case CONST:
1013 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1014 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1015 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1017 /* ??? This clause seems to be irrelevant. */
1018 case CONST_DOUBLE:
1019 return GET_MODE (op) == mode;
1021 case PLUS:
1022 return symbolic_memory_operand (XEXP (op, 0), mode)
1023 && symbolic_memory_operand (XEXP (op, 1), mode);
1025 default:
1026 return 0;
1031 m68hc11_logical_operator (op, mode)
1032 register rtx op;
1033 enum machine_mode mode ATTRIBUTE_UNUSED;
1035 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1039 m68hc11_arith_operator (op, mode)
1040 register rtx op;
1041 enum machine_mode mode ATTRIBUTE_UNUSED;
1043 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1044 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1045 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1046 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1047 || GET_CODE (op) == ROTATERT;
1051 m68hc11_non_shift_operator (op, mode)
1052 register rtx op;
1053 enum machine_mode mode ATTRIBUTE_UNUSED;
1055 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1056 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1061 m68hc11_unary_operator (op, mode)
1062 register rtx op;
1063 enum machine_mode mode ATTRIBUTE_UNUSED;
1065 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1066 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1070 /* Profiling. */
1073 m68hc11_block_profiler (out, blockno)
1074 FILE *out ATTRIBUTE_UNUSED;
1075 int blockno ATTRIBUTE_UNUSED;
1077 return 0;
1081 m68hc11_function_block_profiler (out, block_or_label)
1082 FILE *out ATTRIBUTE_UNUSED;
1083 int block_or_label ATTRIBUTE_UNUSED;
1085 return 0;
1088 /* Emit the code to build the trampoline used to call a nested function.
1090 68HC11 68HC12
1092 ldy #&CXT movw #&CXT,*_.d1
1093 sty *_.d1 jmp FNADDR
1094 jmp FNADDR
1097 void
1098 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
1099 rtx tramp;
1100 rtx fnaddr;
1101 rtx cxt;
1103 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1105 /* Skip the '*'. */
1106 if (*static_chain_reg == '*')
1107 static_chain_reg++;
1108 if (TARGET_M6811)
1110 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1111 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1112 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1113 GEN_INT (0x18df));
1114 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1115 gen_rtx_CONST (QImode,
1116 gen_rtx_SYMBOL_REF (Pmode,
1117 static_chain_reg)));
1118 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1119 GEN_INT (0x7e));
1120 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1122 else
1124 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1125 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1126 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1127 gen_rtx_CONST (HImode,
1128 gen_rtx_SYMBOL_REF (Pmode,
1129 static_chain_reg)));
1130 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1131 GEN_INT (0x06));
1132 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1136 /* Declaration of types. */
1138 const struct attribute_spec m68hc11_attribute_table[] =
1140 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1141 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1142 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1143 { NULL, 0, 0, false, false, false, NULL }
1146 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1147 arguments as in struct attribute_spec.handler. */
1148 static tree
1149 m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
1150 tree *node;
1151 tree name;
1152 tree args ATTRIBUTE_UNUSED;
1153 int flags ATTRIBUTE_UNUSED;
1154 bool *no_add_attrs;
1156 if (TREE_CODE (*node) != FUNCTION_TYPE
1157 && TREE_CODE (*node) != FIELD_DECL
1158 && TREE_CODE (*node) != TYPE_DECL)
1160 warning ("`%s' attribute only applies to functions",
1161 IDENTIFIER_POINTER (name));
1162 *no_add_attrs = true;
1165 return NULL_TREE;
1168 /* Define this macro if references to a symbol must be treated
1169 differently depending on something about the variable or function
1170 named by the symbol (such as what section it is in).
1172 For the 68HC11, we want to recognize trap handlers so that we
1173 handle calls to traps in a special manner (by issuing the trap).
1174 This information is stored in SYMBOL_REF_FLAG. */
1175 void
1176 m68hc11_encode_section_info (decl)
1177 tree decl;
1179 tree func_attr;
1180 int trap_handler;
1181 rtx rtl;
1183 if (TREE_CODE (decl) != FUNCTION_DECL)
1184 return;
1186 rtl = DECL_RTL (decl);
1188 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1189 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1190 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
1194 /* Argument support functions. */
1196 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1197 Arrays are passed by references and other types by value.
1199 SCz: I tried to pass DImode by reference but it seems that this
1200 does not work very well. */
1202 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1203 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1204 enum machine_mode mode ATTRIBUTE_UNUSED;
1205 tree type;
1206 int named ATTRIBUTE_UNUSED;
1208 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1209 /* Consider complex values as aggregates, so care for TCmode. */
1210 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1211 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1215 /* Define the offset between two registers, one to be eliminated, and the
1216 other its replacement, at the start of a routine. */
1218 m68hc11_initial_elimination_offset (from, to)
1219 int from;
1220 int to;
1222 int trap_handler;
1223 tree func_attr;
1224 int size;
1225 int regno;
1227 /* For a trap handler, we must take into account the registers which
1228 are pushed on the stack during the trap (except the PC). */
1229 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1230 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1231 if (trap_handler && from == ARG_POINTER_REGNUM)
1232 size = 7;
1233 else
1234 size = 0;
1236 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1238 /* 2 is for the saved frame.
1239 1 is for the 'sts' correction when creating the frame. */
1240 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1243 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1245 return m68hc11_sp_correction;
1248 /* Push any 2 byte pseudo hard registers that we need to save. */
1249 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1251 if (regs_ever_live[regno] && !call_used_regs[regno])
1253 size += 2;
1257 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1259 return get_frame_size () + size;
1262 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1264 return size;
1266 return 0;
1269 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1270 for a call to a function whose data type is FNTYPE.
1271 For a library call, FNTYPE is 0. */
1273 void
1274 m68hc11_init_cumulative_args (cum, fntype, libname)
1275 CUMULATIVE_ARGS *cum;
1276 tree fntype;
1277 rtx libname;
1279 tree ret_type;
1281 z_replacement_completed = 0;
1282 cum->words = 0;
1283 cum->nregs = 0;
1285 /* For a library call, we must find out the type of the return value.
1286 When the return value is bigger than 4 bytes, it is returned in
1287 memory. In that case, the first argument of the library call is a
1288 pointer to the memory location. Because the first argument is passed in
1289 register D, we have to identify this, so that the first function
1290 parameter is not passed in D either. */
1291 if (fntype == 0)
1293 const char *name;
1294 size_t len;
1296 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1297 return;
1299 /* If the library ends in 'di' or in 'df', we assume it's
1300 returning some DImode or some DFmode which are 64-bit wide. */
1301 name = XSTR (libname, 0);
1302 len = strlen (name);
1303 if (len > 3
1304 && ((name[len - 2] == 'd'
1305 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1306 || (name[len - 3] == 'd'
1307 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1309 /* We are in. Mark the first parameter register as already used. */
1310 cum->words = 1;
1311 cum->nregs = 1;
1313 return;
1316 ret_type = TREE_TYPE (fntype);
1318 if (ret_type && aggregate_value_p (ret_type))
1320 cum->words = 1;
1321 cum->nregs = 1;
1325 /* Update the data in CUM to advance over an argument
1326 of mode MODE and data type TYPE.
1327 (TYPE is null for libcalls where that information may not be available.) */
1329 void
1330 m68hc11_function_arg_advance (cum, mode, type, named)
1331 CUMULATIVE_ARGS *cum;
1332 enum machine_mode mode;
1333 tree type;
1334 int named ATTRIBUTE_UNUSED;
1336 if (mode != BLKmode)
1338 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1340 cum->nregs = 2;
1341 cum->words = GET_MODE_SIZE (mode);
1343 else
1345 cum->words += GET_MODE_SIZE (mode);
1346 if (cum->words <= HARD_REG_SIZE)
1347 cum->nregs = 1;
1350 else
1352 cum->words += int_size_in_bytes (type);
1354 return;
1357 /* Define where to put the arguments to a function.
1358 Value is zero to push the argument on the stack,
1359 or a hard register in which to store the argument.
1361 MODE is the argument's machine mode.
1362 TYPE is the data type of the argument (as a tree).
1363 This is null for libcalls where that information may
1364 not be available.
1365 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1366 the preceding args and about the function being called.
1367 NAMED is nonzero if this argument is a named parameter
1368 (otherwise it is an extra parameter matching an ellipsis). */
1370 struct rtx_def *
1371 m68hc11_function_arg (cum, mode, type, named)
1372 const CUMULATIVE_ARGS *cum;
1373 enum machine_mode mode;
1374 tree type ATTRIBUTE_UNUSED;
1375 int named ATTRIBUTE_UNUSED;
1377 if (cum->words != 0)
1379 return NULL_RTX;
1382 if (mode != BLKmode)
1384 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1385 return gen_rtx (REG, mode, HARD_X_REGNUM);
1387 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1389 return NULL_RTX;
1391 return gen_rtx (REG, mode, HARD_D_REGNUM);
1393 return NULL_RTX;
1396 /* The "standard" implementation of va_start: just assign `nextarg' to
1397 the variable. */
1398 void
1399 m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
1400 int stdarg_p ATTRIBUTE_UNUSED;
1401 tree valist;
1402 rtx nextarg;
1404 tree t;
1406 /* SCz: the default implementation in builtins.c adjust the
1407 nextarg using UNITS_PER_WORD. This works only with -mshort
1408 and fails when integers are 32-bit. Here is the correct way. */
1409 if (!stdarg_p)
1410 nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
1412 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1413 make_tree (ptr_type_node, nextarg));
1414 TREE_SIDE_EFFECTS (t) = 1;
1416 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1420 m68hc11_va_arg (valist, type)
1421 tree valist;
1422 tree type;
1424 tree addr_tree, t;
1425 HOST_WIDE_INT align;
1426 HOST_WIDE_INT rounded_size;
1427 rtx addr;
1428 int pad_direction;
1430 /* Compute the rounded size of the type. */
1431 align = PARM_BOUNDARY / BITS_PER_UNIT;
1432 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1434 /* Get AP. */
1435 addr_tree = valist;
1436 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
1438 if (pad_direction == downward)
1440 /* Small args are padded downward. */
1442 HOST_WIDE_INT adj;
1443 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1444 if (rounded_size > align)
1445 adj = rounded_size;
1447 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1448 build_int_2 (rounded_size - adj, 0));
1451 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1452 addr = copy_to_reg (addr);
1454 /* Compute new value for AP. */
1455 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1456 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1457 build_int_2 (rounded_size, 0)));
1458 TREE_SIDE_EFFECTS (t) = 1;
1459 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1461 return addr;
1464 /* If defined, a C expression which determines whether, and in which direction,
1465 to pad out an argument with extra space. The value should be of type
1466 `enum direction': either `upward' to pad above the argument,
1467 `downward' to pad below, or `none' to inhibit padding.
1469 Structures are stored left shifted in their argument slot. */
1471 m68hc11_function_arg_padding (mode, type)
1472 enum machine_mode mode;
1473 tree type;
1475 if (type != 0 && AGGREGATE_TYPE_P (type))
1476 return upward;
1478 /* This is the default definition. */
1479 return (!BYTES_BIG_ENDIAN
1480 ? upward
1481 : ((mode == BLKmode
1482 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1483 && int_size_in_bytes (type) <
1484 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1485 PARM_BOUNDARY) ? downward : upward));
1489 /* Function prologue and epilogue. */
1491 /* Emit a move after the reload pass has completed. This is used to
1492 emit the prologue and epilogue. */
1493 static void
1494 emit_move_after_reload (to, from, scratch)
1495 rtx to, from, scratch;
1497 rtx insn;
1499 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1501 insn = emit_move_insn (to, from);
1503 else
1505 emit_move_insn (scratch, from);
1506 insn = emit_move_insn (to, scratch);
1509 /* Put a REG_INC note to tell the flow analysis that the instruction
1510 is necessary. */
1511 if (IS_STACK_PUSH (to))
1513 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1514 XEXP (XEXP (to, 0), 0),
1515 REG_NOTES (insn));
1517 else if (IS_STACK_POP (from))
1519 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1520 XEXP (XEXP (from, 0), 0),
1521 REG_NOTES (insn));
1526 m68hc11_total_frame_size ()
1528 int size;
1529 int regno;
1531 size = get_frame_size ();
1532 if (current_function_interrupt)
1534 size += 3 * HARD_REG_SIZE;
1536 if (frame_pointer_needed)
1537 size += HARD_REG_SIZE;
1539 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1540 if (regs_ever_live[regno] && !call_used_regs[regno])
1541 size += HARD_REG_SIZE;
1543 return size;
1546 static void
1547 m68hc11_output_function_epilogue (out, size)
1548 FILE *out ATTRIBUTE_UNUSED;
1549 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1551 /* We catch the function epilogue generation to have a chance
1552 to clear the z_replacement_completed flag. */
1553 z_replacement_completed = 0;
1556 void
1557 expand_prologue ()
1559 tree func_attr;
1560 int size;
1561 int regno;
1562 rtx scratch;
1564 if (reload_completed != 1)
1565 abort ();
1567 size = get_frame_size ();
1569 create_regs_rtx ();
1571 /* Generate specific prologue for interrupt handlers. */
1572 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1573 current_function_interrupt = lookup_attribute ("interrupt",
1574 func_attr) != NULL_TREE;
1575 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1577 /* Get the scratch register to build the frame and push registers.
1578 If the first argument is a 32-bit quantity, the D+X registers
1579 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1580 For 68HC12, this scratch register is not used. */
1581 if (current_function_args_info.nregs == 2)
1582 scratch = iy_reg;
1583 else
1584 scratch = ix_reg;
1586 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1587 Other soft registers in page0 need not to be saved because they
1588 will be restored by C functions. For a trap handler, we don't
1589 need to preserve these registers because this is a synchronous call. */
1590 if (current_function_interrupt)
1592 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1593 emit_move_after_reload (stack_push_word,
1594 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1595 emit_move_after_reload (stack_push_word,
1596 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1597 scratch);
1600 /* Save current stack frame. */
1601 if (frame_pointer_needed)
1602 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1604 /* Allocate local variables. */
1605 if (TARGET_M6812 && size >= 2)
1607 emit_insn (gen_addhi3 (stack_pointer_rtx,
1608 stack_pointer_rtx, GEN_INT (-size)));
1610 else if (size > 8)
1612 rtx insn;
1614 insn = gen_rtx_PARALLEL
1615 (VOIDmode,
1616 gen_rtvec (2,
1617 gen_rtx_SET (VOIDmode,
1618 stack_pointer_rtx,
1619 gen_rtx_PLUS (HImode,
1620 stack_pointer_rtx,
1621 GEN_INT (-size))),
1622 gen_rtx_CLOBBER (VOIDmode, scratch)));
1623 emit_insn (insn);
1625 else
1627 int i;
1629 /* Allocate by pushing scratch values. */
1630 for (i = 2; i <= size; i += 2)
1631 emit_move_after_reload (stack_push_word, ix_reg, 0);
1633 if (size & 1)
1634 emit_insn (gen_addhi3 (stack_pointer_rtx,
1635 stack_pointer_rtx, GEN_INT (-1)));
1638 /* Create the frame pointer. */
1639 if (frame_pointer_needed)
1640 emit_move_after_reload (hard_frame_pointer_rtx,
1641 stack_pointer_rtx, scratch);
1643 /* Push any 2 byte pseudo hard registers that we need to save. */
1644 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1646 if (regs_ever_live[regno] && !call_used_regs[regno])
1648 emit_move_after_reload (stack_push_word,
1649 gen_rtx (REG, HImode, regno), scratch);
1654 void
1655 expand_epilogue ()
1657 int size;
1658 register int regno;
1659 int return_size;
1660 rtx scratch;
1662 if (reload_completed != 1)
1663 abort ();
1665 size = get_frame_size ();
1667 /* If we are returning a value in two registers, we have to preserve the
1668 X register and use the Y register to restore the stack and the saved
1669 registers. Otherwise, use X because it's faster (and smaller). */
1670 if (current_function_return_rtx == 0)
1671 return_size = 0;
1672 else if (GET_CODE (current_function_return_rtx) == MEM)
1673 return_size = HARD_REG_SIZE;
1674 else
1675 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1677 if (return_size > HARD_REG_SIZE)
1678 scratch = iy_reg;
1679 else
1680 scratch = ix_reg;
1682 /* Pop any 2 byte pseudo hard registers that we saved. */
1683 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1685 if (regs_ever_live[regno] && !call_used_regs[regno])
1687 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1688 stack_pop_word, scratch);
1692 /* de-allocate auto variables */
1693 if (TARGET_M6812 && size >= 2)
1695 emit_insn (gen_addhi3 (stack_pointer_rtx,
1696 stack_pointer_rtx, GEN_INT (size)));
1698 else if (size > 8)
1700 rtx insn;
1702 insn = gen_rtx_PARALLEL
1703 (VOIDmode,
1704 gen_rtvec (2,
1705 gen_rtx_SET (VOIDmode,
1706 stack_pointer_rtx,
1707 gen_rtx_PLUS (HImode,
1708 stack_pointer_rtx,
1709 GEN_INT (size))),
1710 gen_rtx_CLOBBER (VOIDmode, scratch)));
1711 emit_insn (insn);
1713 else
1715 int i;
1717 for (i = 2; i <= size; i += 2)
1718 emit_move_after_reload (scratch, stack_pop_word, scratch);
1719 if (size & 1)
1720 emit_insn (gen_addhi3 (stack_pointer_rtx,
1721 stack_pointer_rtx, GEN_INT (1)));
1724 /* Restore previous frame pointer. */
1725 if (frame_pointer_needed)
1726 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1728 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1729 if (current_function_interrupt)
1731 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1732 stack_pop_word, scratch);
1733 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1734 stack_pop_word, scratch);
1735 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1738 /* If the trap handler returns some value, copy the value
1739 in D, X onto the stack so that the rti will pop the return value
1740 correctly. */
1741 else if (current_function_trap && return_size != 0)
1743 rtx addr_reg = stack_pointer_rtx;
1745 if (!TARGET_M6812)
1747 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1748 addr_reg = scratch;
1750 emit_move_after_reload (gen_rtx (MEM, HImode,
1751 gen_rtx (PLUS, HImode, addr_reg,
1752 GEN_INT (1))), d_reg, 0);
1753 if (return_size > HARD_REG_SIZE)
1754 emit_move_after_reload (gen_rtx (MEM, HImode,
1755 gen_rtx (PLUS, HImode, addr_reg,
1756 GEN_INT (3))), ix_reg, 0);
1759 emit_jump_insn (gen_return ());
1763 /* Low and High part extraction for 68HC11. These routines are
1764 similar to gen_lowpart and gen_highpart but they have been
1765 fixed to work for constants and 68HC11 specific registers. */
1768 m68hc11_gen_lowpart (mode, x)
1769 enum machine_mode mode;
1770 rtx x;
1772 /* We assume that the low part of an auto-inc mode is the same with
1773 the mode changed and that the caller split the larger mode in the
1774 correct order. */
1775 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1777 return gen_rtx (MEM, mode, XEXP (x, 0));
1780 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1781 floating-point constant. A CONST_DOUBLE is used whenever the
1782 constant requires more than one word in order to be adequately
1783 represented. */
1784 if (GET_CODE (x) == CONST_DOUBLE)
1786 long l[2];
1788 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1790 REAL_VALUE_TYPE r;
1792 if (GET_MODE (x) == SFmode)
1794 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1795 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1797 else
1799 rtx first, second;
1801 split_double (x, &first, &second);
1802 return second;
1804 if (mode == SImode)
1805 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1807 return gen_rtx (CONST_INT, VOIDmode,
1808 trunc_int_for_mode (l[0], HImode));
1810 else
1812 l[0] = CONST_DOUBLE_LOW (x);
1814 if (mode == SImode)
1815 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1816 else if (mode == HImode && GET_MODE (x) == SFmode)
1817 return gen_rtx (CONST_INT, VOIDmode,
1818 trunc_int_for_mode (l[0], HImode));
1819 else
1820 abort ();
1823 if (mode == QImode && D_REG_P (x))
1824 return gen_rtx (REG, mode, HARD_B_REGNUM);
1826 /* gen_lowpart crashes when it is called with a SUBREG. */
1827 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1829 if (mode == SImode)
1830 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1831 else if (mode == HImode)
1832 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1833 else
1834 abort ();
1836 x = gen_lowpart (mode, x);
1838 /* Return a different rtx to avoid to share it in several insns
1839 (when used by a split pattern). Sharing addresses within
1840 a MEM breaks the Z register replacement (and reloading). */
1841 if (GET_CODE (x) == MEM)
1842 x = copy_rtx (x);
1843 return x;
1847 m68hc11_gen_highpart (mode, x)
1848 enum machine_mode mode;
1849 rtx x;
1851 /* We assume that the high part of an auto-inc mode is the same with
1852 the mode changed and that the caller split the larger mode in the
1853 correct order. */
1854 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1856 return gen_rtx (MEM, mode, XEXP (x, 0));
1859 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1860 floating-point constant. A CONST_DOUBLE is used whenever the
1861 constant requires more than one word in order to be adequately
1862 represented. */
1863 if (GET_CODE (x) == CONST_DOUBLE)
1865 long l[2];
1867 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1869 REAL_VALUE_TYPE r;
1871 if (GET_MODE (x) == SFmode)
1873 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1874 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1876 else
1878 rtx first, second;
1880 split_double (x, &first, &second);
1881 return first;
1883 if (mode == SImode)
1884 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1886 return gen_rtx (CONST_INT, VOIDmode,
1887 trunc_int_for_mode ((l[1] >> 16), HImode));
1889 else
1891 l[1] = CONST_DOUBLE_HIGH (x);
1894 if (mode == SImode)
1895 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1896 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1897 return gen_rtx (CONST_INT, VOIDmode,
1898 trunc_int_for_mode ((l[0] >> 16), HImode));
1899 else
1900 abort ();
1902 if (GET_CODE (x) == CONST_INT)
1904 HOST_WIDE_INT val = INTVAL (x);
1906 if (mode == QImode)
1908 return gen_rtx (CONST_INT, VOIDmode,
1909 trunc_int_for_mode (val >> 8, QImode));
1911 else if (mode == HImode)
1913 return gen_rtx (CONST_INT, VOIDmode,
1914 trunc_int_for_mode (val >> 16, HImode));
1917 if (mode == QImode && D_REG_P (x))
1918 return gen_rtx (REG, mode, HARD_A_REGNUM);
1920 /* There is no way in GCC to represent the upper part of a word register.
1921 To obtain the 8-bit upper part of a soft register, we change the
1922 reg into a mem rtx. This is possible because they are physically
1923 located in memory. There is no offset because we are big-endian. */
1924 if (mode == QImode && S_REG_P (x))
1926 int pos;
1928 /* For 68HC12, avoid the '*' for direct addressing mode. */
1929 pos = TARGET_M6812 ? 1 : 0;
1930 return gen_rtx (MEM, QImode,
1931 gen_rtx (SYMBOL_REF, Pmode,
1932 &reg_names[REGNO (x)][pos]));
1935 /* gen_highpart crashes when it is called with a SUBREG. */
1936 if (GET_CODE (x) == SUBREG)
1938 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1940 if (GET_CODE (x) == REG)
1942 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1943 return gen_rtx (REG, mode, REGNO (x));
1944 else
1945 return gen_rtx_SUBREG (mode, x, 0);
1948 if (GET_CODE (x) == MEM)
1950 x = change_address (x, mode, 0);
1952 /* Return a different rtx to avoid to share it in several insns
1953 (when used by a split pattern). Sharing addresses within
1954 a MEM breaks the Z register replacement (and reloading). */
1955 if (GET_CODE (x) == MEM)
1956 x = copy_rtx (x);
1957 return x;
1959 abort ();
1963 /* Obscure register manipulation. */
1965 /* Finds backward in the instructions to see if register 'reg' is
1966 dead. This is used when generating code to see if we can use 'reg'
1967 as a scratch register. This allows us to choose a better generation
1968 of code when we know that some register dies or can be clobbered. */
1971 dead_register_here (x, reg)
1972 rtx x;
1973 rtx reg;
1975 rtx x_reg;
1976 rtx p;
1978 if (D_REG_P (reg))
1979 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
1980 else
1981 x_reg = 0;
1983 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1984 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
1986 rtx body;
1988 body = PATTERN (p);
1990 if (GET_CODE (body) == CALL_INSN)
1991 break;
1992 if (GET_CODE (body) == JUMP_INSN)
1993 break;
1995 if (GET_CODE (body) == SET)
1997 rtx dst = XEXP (body, 0);
1999 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2000 break;
2001 if (x_reg && rtx_equal_p (dst, x_reg))
2002 break;
2004 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2005 return 1;
2007 else if (reg_mentioned_p (reg, p)
2008 || (x_reg && reg_mentioned_p (x_reg, p)))
2009 break;
2012 /* Scan forward to see if the register is set in some insns and never
2013 used since then. */
2014 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2016 rtx body;
2018 if (GET_CODE (p) == CODE_LABEL
2019 || GET_CODE (p) == JUMP_INSN
2020 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2021 break;
2023 if (GET_CODE (p) != INSN)
2024 continue;
2026 body = PATTERN (p);
2027 if (GET_CODE (body) == SET)
2029 rtx src = XEXP (body, 1);
2030 rtx dst = XEXP (body, 0);
2032 if (GET_CODE (dst) == REG
2033 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2034 return 1;
2037 /* Register is used (may be in source or in dest). */
2038 if (reg_mentioned_p (reg, p)
2039 || (x_reg != 0 && GET_MODE (p) == SImode
2040 && reg_mentioned_p (x_reg, p)))
2041 break;
2043 return p == 0 ? 1 : 0;
2047 /* Code generation operations called from machine description file. */
2049 /* Print the name of register 'regno' in the assembly file. */
2050 static void
2051 asm_print_register (file, regno)
2052 FILE *file;
2053 int regno;
2055 const char *name = reg_names[regno];
2057 if (TARGET_M6812 && name[0] == '*')
2058 name++;
2060 asm_fprintf (file, "%s", name);
2063 /* A C compound statement to output to stdio stream STREAM the
2064 assembler syntax for an instruction operand X. X is an RTL
2065 expression.
2067 CODE is a value that can be used to specify one of several ways
2068 of printing the operand. It is used when identical operands
2069 must be printed differently depending on the context. CODE
2070 comes from the `%' specification that was used to request
2071 printing of the operand. If the specification was just `%DIGIT'
2072 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2073 is the ASCII code for LTR.
2075 If X is a register, this macro should print the register's name.
2076 The names can be found in an array `reg_names' whose type is
2077 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2079 When the machine description has a specification `%PUNCT' (a `%'
2080 followed by a punctuation character), this macro is called with
2081 a null pointer for X and the punctuation character for CODE.
2083 The M68HC11 specific codes are:
2085 'b' for the low part of the operand.
2086 'h' for the high part of the operand
2087 The 'b' or 'h' modifiers have no effect if the operand has
2088 the QImode and is not a S_REG_P (soft register). If the
2089 operand is a hard register, these two modifiers have no effect.
2090 't' generate the temporary scratch register. The operand is
2091 ignored.
2092 'T' generate the low-part temporary scratch register. The operand is
2093 ignored. */
2095 void
2096 print_operand (file, op, letter)
2097 FILE *file;
2098 rtx op;
2099 int letter;
2101 if (letter == 't')
2103 asm_print_register (file, SOFT_TMP_REGNUM);
2104 return;
2106 else if (letter == 'T')
2108 asm_print_register (file, SOFT_TMP_REGNUM);
2109 asm_fprintf (file, "+1");
2110 return;
2112 else if (letter == '#')
2114 asm_fprintf (file, "%0I");
2117 if (GET_CODE (op) == REG)
2119 if (letter == 'b' && S_REG_P (op))
2121 asm_print_register (file, REGNO (op));
2122 asm_fprintf (file, "+1");
2124 else
2126 asm_print_register (file, REGNO (op));
2128 return;
2131 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2133 if (letter == 'b')
2134 asm_fprintf (file, "%0I%%lo(");
2135 else
2136 asm_fprintf (file, "%0I%%hi(");
2138 output_addr_const (file, op);
2139 asm_fprintf (file, ")");
2140 return;
2143 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2144 are specified. If we already have a QImode, there is nothing to do. */
2145 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2147 if (letter == 'b')
2149 op = m68hc11_gen_lowpart (QImode, op);
2151 else if (letter == 'h')
2153 op = m68hc11_gen_highpart (QImode, op);
2157 if (GET_CODE (op) == MEM)
2159 rtx base = XEXP (op, 0);
2160 switch (GET_CODE (base))
2162 case PRE_DEC:
2163 if (TARGET_M6812)
2165 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2166 asm_print_register (file, REGNO (XEXP (base, 0)));
2168 else
2169 abort ();
2170 break;
2172 case POST_DEC:
2173 if (TARGET_M6812)
2175 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2176 asm_print_register (file, REGNO (XEXP (base, 0)));
2177 asm_fprintf (file, "-");
2179 else
2180 abort ();
2181 break;
2183 case POST_INC:
2184 if (TARGET_M6812)
2186 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2187 asm_print_register (file, REGNO (XEXP (base, 0)));
2188 asm_fprintf (file, "+");
2190 else
2191 abort ();
2192 break;
2194 case PRE_INC:
2195 if (TARGET_M6812)
2197 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2198 asm_print_register (file, REGNO (XEXP (base, 0)));
2200 else
2201 abort ();
2202 break;
2204 default:
2205 output_address (base);
2206 break;
2209 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2211 REAL_VALUE_TYPE r;
2212 long l;
2214 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2215 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2216 asm_fprintf (file, "%I0x%lx", l);
2218 else if (GET_CODE (op) == CONST_DOUBLE
2219 && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode))
2221 REAL_VALUE_TYPE r;
2222 char dstr[30];
2224 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2225 REAL_VALUE_TO_DECIMAL (r, "%.20g", dstr);
2226 asm_fprintf (file, "%I0r%s", dstr);
2228 else
2230 int need_parenthesize = 0;
2232 if (letter != 'i')
2233 asm_fprintf (file, "%0I");
2234 else
2235 need_parenthesize = must_parenthesize (op);
2237 if (need_parenthesize)
2238 asm_fprintf (file, "(");
2240 output_addr_const (file, op);
2241 if (need_parenthesize)
2242 asm_fprintf (file, ")");
2246 /* Returns true if the operand 'op' must be printed with parenthesis
2247 arround it. This must be done only if there is a symbol whose name
2248 is a processor register. */
2249 static int
2250 must_parenthesize (op)
2251 rtx op;
2253 const char *name;
2255 switch (GET_CODE (op))
2257 case SYMBOL_REF:
2258 name = XSTR (op, 0);
2259 /* Avoid a conflict between symbol name and a possible
2260 register. */
2261 return (strcasecmp (name, "a") == 0
2262 || strcasecmp (name, "b") == 0
2263 || strcasecmp (name, "d") == 0
2264 || strcasecmp (name, "x") == 0
2265 || strcasecmp (name, "y") == 0
2266 || strcasecmp (name, "pc") == 0
2267 || strcasecmp (name, "sp") == 0
2268 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2270 case PLUS:
2271 case MINUS:
2272 return must_parenthesize (XEXP (op, 0))
2273 || must_parenthesize (XEXP (op, 1));
2275 case MEM:
2276 case CONST:
2277 case ZERO_EXTEND:
2278 case SIGN_EXTEND:
2279 return must_parenthesize (XEXP (op, 0));
2281 case CONST_DOUBLE:
2282 case CONST_INT:
2283 case LABEL_REF:
2284 case CODE_LABEL:
2285 default:
2286 return 0;
2290 /* A C compound statement to output to stdio stream STREAM the
2291 assembler syntax for an instruction operand that is a memory
2292 reference whose address is ADDR. ADDR is an RTL expression. */
2294 void
2295 print_operand_address (file, addr)
2296 FILE *file;
2297 rtx addr;
2299 rtx base;
2300 rtx offset;
2301 int need_parenthesis = 0;
2303 switch (GET_CODE (addr))
2305 case REG:
2306 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2307 abort ();
2309 asm_fprintf (file, "0,");
2310 asm_print_register (file, REGNO (addr));
2311 break;
2313 case MEM:
2314 base = XEXP (addr, 0);
2315 switch (GET_CODE (base))
2317 case PRE_DEC:
2318 if (TARGET_M6812)
2320 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2321 asm_print_register (file, REGNO (XEXP (base, 0)));
2323 else
2324 abort ();
2325 break;
2327 case POST_DEC:
2328 if (TARGET_M6812)
2330 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2331 asm_print_register (file, REGNO (XEXP (base, 0)));
2332 asm_fprintf (file, "-");
2334 else
2335 abort ();
2336 break;
2338 case POST_INC:
2339 if (TARGET_M6812)
2341 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2342 asm_print_register (file, REGNO (XEXP (base, 0)));
2343 asm_fprintf (file, "+");
2345 else
2346 abort ();
2347 break;
2349 case PRE_INC:
2350 if (TARGET_M6812)
2352 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2353 asm_print_register (file, REGNO (XEXP (base, 0)));
2355 else
2356 abort ();
2357 break;
2359 default:
2360 need_parenthesis = must_parenthesize (base);
2361 if (need_parenthesis)
2362 asm_fprintf (file, "(");
2364 output_addr_const (file, base);
2365 if (need_parenthesis)
2366 asm_fprintf (file, ")");
2367 break;
2369 break;
2371 case PLUS:
2372 base = XEXP (addr, 0);
2373 offset = XEXP (addr, 1);
2374 if (!G_REG_P (base) && G_REG_P (offset))
2376 base = XEXP (addr, 1);
2377 offset = XEXP (addr, 0);
2379 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2381 need_parenthesis = must_parenthesize (addr);
2383 if (need_parenthesis)
2384 asm_fprintf (file, "(");
2386 output_addr_const (file, base);
2387 asm_fprintf (file, "+");
2388 output_addr_const (file, offset);
2389 if (need_parenthesis)
2390 asm_fprintf (file, ")");
2392 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2394 if (REG_P (offset))
2396 if (TARGET_M6812)
2398 asm_print_register (file, REGNO (offset));
2399 asm_fprintf (file, ",");
2400 asm_print_register (file, REGNO (base));
2402 else
2403 abort ();
2405 else
2407 output_addr_const (file, offset);
2408 asm_fprintf (file, ",");
2409 asm_print_register (file, REGNO (base));
2412 else
2414 abort ();
2416 break;
2418 default:
2419 if (GET_CODE (addr) == CONST_INT
2420 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2422 asm_fprintf (file, "%d", INTVAL (addr));
2424 else
2426 need_parenthesis = must_parenthesize (addr);
2427 if (need_parenthesis)
2428 asm_fprintf (file, "(");
2430 output_addr_const (file, addr);
2431 if (need_parenthesis)
2432 asm_fprintf (file, ")");
2434 break;
2439 /* Splitting of some instructions. */
2441 static rtx
2442 m68hc11_expand_compare (code, op0, op1)
2443 enum rtx_code code;
2444 rtx op0, op1;
2446 rtx ret = 0;
2448 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2449 abort ();
2450 else
2452 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2453 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2454 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2457 return ret;
2461 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2462 enum rtx_code code;
2463 rtx op0, op1, label;
2465 rtx tmp;
2467 switch (GET_MODE (op0))
2469 case QImode:
2470 case HImode:
2471 tmp = m68hc11_expand_compare (code, op0, op1);
2472 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2473 gen_rtx_LABEL_REF (VOIDmode, label),
2474 pc_rtx);
2475 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2476 return 0;
2477 #if 0
2479 /* SCz: from i386.c */
2480 case SFmode:
2481 case DFmode:
2482 /* Don't expand the comparison early, so that we get better code
2483 when jump or whoever decides to reverse the comparison. */
2485 rtvec vec;
2486 int use_fcomi;
2488 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2489 &m68hc11_compare_op1);
2491 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2492 m68hc11_compare_op0, m68hc11_compare_op1);
2493 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2494 gen_rtx_LABEL_REF (VOIDmode, label),
2495 pc_rtx);
2496 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2498 use_fcomi = ix86_use_fcomi_compare (code);
2499 vec = rtvec_alloc (3 + !use_fcomi);
2500 RTVEC_ELT (vec, 0) = tmp;
2501 RTVEC_ELT (vec, 1)
2502 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2503 RTVEC_ELT (vec, 2)
2504 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2505 if (!use_fcomi)
2506 RTVEC_ELT (vec, 3)
2507 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2509 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2510 return;
2512 #endif
2514 case SImode:
2515 /* Expand SImode branch into multiple compare+branch. */
2517 rtx lo[2], hi[2], label2;
2518 enum rtx_code code1, code2, code3;
2520 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2522 tmp = op0;
2523 op0 = op1;
2524 op1 = tmp;
2525 code = swap_condition (code);
2527 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2528 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2529 hi[0] = m68hc11_gen_highpart (HImode, op0);
2530 hi[1] = m68hc11_gen_highpart (HImode, op1);
2532 /* Otherwise, if we are doing less-than, op1 is a constant and the
2533 low word is zero, then we can just examine the high word. */
2535 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2536 && (code == LT || code == LTU))
2538 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2539 label);
2542 /* Otherwise, we need two or three jumps. */
2544 label2 = gen_label_rtx ();
2546 code1 = code;
2547 code2 = swap_condition (code);
2548 code3 = unsigned_condition (code);
2550 switch (code)
2552 case LT:
2553 case GT:
2554 case LTU:
2555 case GTU:
2556 break;
2558 case LE:
2559 code1 = LT;
2560 code2 = GT;
2561 break;
2562 case GE:
2563 code1 = GT;
2564 code2 = LT;
2565 break;
2566 case LEU:
2567 code1 = LTU;
2568 code2 = GTU;
2569 break;
2570 case GEU:
2571 code1 = GTU;
2572 code2 = LTU;
2573 break;
2575 case EQ:
2576 code1 = NIL;
2577 code2 = NE;
2578 break;
2579 case NE:
2580 code2 = NIL;
2581 break;
2583 default:
2584 abort ();
2588 * a < b =>
2589 * if (hi(a) < hi(b)) goto true;
2590 * if (hi(a) > hi(b)) goto false;
2591 * if (lo(a) < lo(b)) goto true;
2592 * false:
2594 if (code1 != NIL)
2595 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2596 if (code2 != NIL)
2597 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2599 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2601 if (code2 != NIL)
2602 emit_label (label2);
2603 return 0;
2606 default:
2607 abort ();
2609 return 0;
2613 /* Split a DI, SI or HI move into several smaller move operations.
2614 The scratch register 'scratch' is used as a temporary to load
2615 store intermediate values. It must be a hard register. */
2616 void
2617 m68hc11_split_move (to, from, scratch)
2618 rtx to, from, scratch;
2620 rtx low_to, low_from;
2621 rtx high_to, high_from;
2622 enum machine_mode mode;
2623 int offset = 0;
2625 mode = GET_MODE (to);
2626 if (GET_MODE_SIZE (mode) == 8)
2627 mode = SImode;
2628 else if (GET_MODE_SIZE (mode) == 4)
2629 mode = HImode;
2630 else
2631 mode = QImode;
2633 if (TARGET_M6812
2634 && IS_STACK_PUSH (to)
2635 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2637 if (mode == SImode)
2639 offset = 4;
2641 else if (mode == HImode)
2643 offset = 2;
2645 else
2646 offset = 0;
2649 low_to = m68hc11_gen_lowpart (mode, to);
2650 high_to = m68hc11_gen_highpart (mode, to);
2652 low_from = m68hc11_gen_lowpart (mode, from);
2653 if (mode == SImode && GET_CODE (from) == CONST_INT)
2655 if (INTVAL (from) >= 0)
2656 high_from = const0_rtx;
2657 else
2658 high_from = constm1_rtx;
2660 else
2661 high_from = m68hc11_gen_highpart (mode, from);
2663 if (offset)
2665 high_from = adjust_address (high_from, mode, offset);
2666 low_from = high_from;
2668 if (mode == SImode)
2670 m68hc11_split_move (low_to, low_from, scratch);
2671 m68hc11_split_move (high_to, high_from, scratch);
2673 else if (H_REG_P (to) || H_REG_P (from)
2674 || (TARGET_M6812
2675 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2676 || m68hc11_small_indexed_indirect_p (from,
2677 GET_MODE (from)))
2678 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2679 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2681 emit_move_insn (low_to, low_from);
2682 emit_move_insn (high_to, high_from);
2684 else
2686 rtx insn;
2688 emit_move_insn (scratch, low_from);
2689 insn = emit_move_insn (low_to, scratch);
2691 emit_move_insn (scratch, high_from);
2692 insn = emit_move_insn (high_to, scratch);
2696 static rtx
2697 simplify_logical (mode, code, operand, result)
2698 enum machine_mode mode;
2699 int code;
2700 rtx operand;
2701 rtx *result;
2703 int val;
2704 int mask;
2706 *result = 0;
2707 if (GET_CODE (operand) != CONST_INT)
2708 return operand;
2710 if (mode == HImode)
2711 mask = 0x0ffff;
2712 else
2713 mask = 0x0ff;
2715 val = INTVAL (operand);
2716 switch (code)
2718 case IOR:
2719 if ((val & mask) == 0)
2720 return 0;
2721 if ((val & mask) == mask)
2722 *result = constm1_rtx;
2723 break;
2725 case AND:
2726 if ((val & mask) == 0)
2727 *result = const0_rtx;
2728 if ((val & mask) == mask)
2729 return 0;
2730 break;
2732 case XOR:
2733 if ((val & mask) == 0)
2734 return 0;
2735 break;
2737 return operand;
2740 static void
2741 m68hc11_emit_logical (mode, code, operands)
2742 enum machine_mode mode;
2743 int code;
2744 rtx *operands;
2746 rtx result;
2747 int need_copy;
2749 need_copy = (rtx_equal_p (operands[0], operands[1])
2750 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2752 operands[1] = simplify_logical (mode, code, operands[1], &result);
2753 operands[2] = simplify_logical (mode, code, operands[2], &result);
2755 if (result && GET_CODE (result) == CONST_INT)
2757 if (!H_REG_P (operands[0]) && operands[3]
2758 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2760 emit_move_insn (operands[3], result);
2761 emit_move_insn (operands[0], operands[3]);
2763 else
2765 emit_move_insn (operands[0], result);
2768 else if (operands[1] != 0 && operands[2] != 0)
2770 rtx insn;
2772 if (!H_REG_P (operands[0]) && operands[3])
2774 emit_move_insn (operands[3], operands[1]);
2775 emit_insn (gen_rtx (SET, mode,
2776 operands[3],
2777 gen_rtx (code, mode,
2778 operands[3], operands[2])));
2779 insn = emit_move_insn (operands[0], operands[3]);
2781 else
2783 insn = emit_insn (gen_rtx (SET, mode,
2784 operands[0],
2785 gen_rtx (code, mode,
2786 operands[0], operands[2])));
2790 /* The logical operation is similar to a copy. */
2791 else if (need_copy)
2793 rtx src;
2795 if (GET_CODE (operands[1]) == CONST_INT)
2796 src = operands[2];
2797 else
2798 src = operands[1];
2800 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2802 emit_move_insn (operands[3], src);
2803 emit_move_insn (operands[0], operands[3]);
2805 else
2807 emit_move_insn (operands[0], src);
2812 void
2813 m68hc11_split_logical (mode, code, operands)
2814 enum machine_mode mode;
2815 int code;
2816 rtx *operands;
2818 rtx low[4];
2819 rtx high[4];
2821 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2822 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2823 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2825 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2827 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
2829 if (INTVAL (operands[1]) >= 0)
2830 high[1] = const0_rtx;
2831 else
2832 high[1] = constm1_rtx;
2834 else
2835 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2837 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
2839 if (INTVAL (operands[2]) >= 0)
2840 high[2] = const0_rtx;
2841 else
2842 high[2] = constm1_rtx;
2844 else
2845 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2847 low[3] = operands[3];
2848 high[3] = operands[3];
2849 if (mode == SImode)
2851 m68hc11_split_logical (HImode, code, low);
2852 m68hc11_split_logical (HImode, code, high);
2853 return;
2856 m68hc11_emit_logical (mode, code, low);
2857 m68hc11_emit_logical (mode, code, high);
2861 /* Code generation. */
2863 void
2864 m68hc11_output_swap (insn, operands)
2865 rtx insn ATTRIBUTE_UNUSED;
2866 rtx operands[];
2868 /* We have to be careful with the cc_status. An address register swap
2869 is generated for some comparison. The comparison is made with D
2870 but the branch really uses the address register. See the split
2871 pattern for compare. The xgdx/xgdy preserve the flags but after
2872 the exchange, the flags will reflect to the value of X and not D.
2873 Tell this by setting the cc_status according to the cc_prev_status. */
2874 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2876 if (cc_prev_status.value1 != 0
2877 && (D_REG_P (cc_prev_status.value1)
2878 || X_REG_P (cc_prev_status.value1)))
2880 cc_status = cc_prev_status;
2881 if (D_REG_P (cc_status.value1))
2882 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2883 HARD_X_REGNUM);
2884 else
2885 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2886 HARD_D_REGNUM);
2888 else
2889 CC_STATUS_INIT;
2891 output_asm_insn ("xgdx", operands);
2893 else
2895 if (cc_prev_status.value1 != 0
2896 && (D_REG_P (cc_prev_status.value1)
2897 || Y_REG_P (cc_prev_status.value1)))
2899 cc_status = cc_prev_status;
2900 if (D_REG_P (cc_status.value1))
2901 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2902 HARD_Y_REGNUM);
2903 else
2904 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2905 HARD_D_REGNUM);
2907 else
2908 CC_STATUS_INIT;
2910 output_asm_insn ("xgdy", operands);
2914 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2915 This is used to decide whether a move that set flags should be used
2916 instead. */
2918 next_insn_test_reg (insn, reg)
2919 rtx insn;
2920 rtx reg;
2922 rtx body;
2924 insn = next_nonnote_insn (insn);
2925 if (GET_CODE (insn) != INSN)
2926 return 0;
2928 body = PATTERN (insn);
2929 if (sets_cc0_p (body) != 1)
2930 return 0;
2932 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
2933 return 0;
2935 return 1;
2938 /* Generate the code to move a 16-bit operand into another one. */
2940 void
2941 m68hc11_gen_movhi (insn, operands)
2942 rtx insn;
2943 rtx *operands;
2945 int reg;
2947 /* Move a register or memory to the same location.
2948 This is possible because such insn can appear
2949 in a non-optimizing mode. */
2950 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
2952 cc_status = cc_prev_status;
2953 return;
2956 if (TARGET_M6812)
2958 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
2960 cc_status = cc_prev_status;
2961 switch (REGNO (operands[1]))
2963 case HARD_X_REGNUM:
2964 case HARD_Y_REGNUM:
2965 case HARD_D_REGNUM:
2966 output_asm_insn ("psh%1", operands);
2967 break;
2968 default:
2969 abort ();
2971 return;
2973 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2975 cc_status = cc_prev_status;
2976 switch (REGNO (operands[0]))
2978 case HARD_X_REGNUM:
2979 case HARD_Y_REGNUM:
2980 case HARD_D_REGNUM:
2981 output_asm_insn ("pul%0", operands);
2982 break;
2983 default:
2984 abort ();
2986 return;
2988 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
2990 m68hc11_notice_keep_cc (operands[0]);
2991 output_asm_insn ("tfr\t%1,%0", operands);
2993 else if (H_REG_P (operands[0]))
2995 if (SP_REG_P (operands[0]))
2996 output_asm_insn ("lds\t%1", operands);
2997 else
2998 output_asm_insn ("ld%0\t%1", operands);
3000 else if (H_REG_P (operands[1]))
3002 if (SP_REG_P (operands[1]))
3003 output_asm_insn ("sts\t%0", operands);
3004 else
3005 output_asm_insn ("st%1\t%0", operands);
3007 else
3009 rtx from = operands[1];
3010 rtx to = operands[0];
3012 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3013 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3014 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3015 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3017 rtx ops[3];
3019 if (operands[2])
3021 ops[0] = operands[2];
3022 ops[1] = from;
3023 ops[2] = 0;
3024 m68hc11_gen_movhi (insn, ops);
3025 ops[0] = to;
3026 ops[1] = operands[2];
3027 m68hc11_gen_movhi (insn, ops);
3029 else
3031 /* !!!! SCz wrong here. */
3032 fatal_insn ("move insn not handled", insn);
3035 else
3037 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3039 output_asm_insn ("clr\t%h0", operands);
3040 output_asm_insn ("clr\t%b0", operands);
3042 else
3044 m68hc11_notice_keep_cc (operands[0]);
3045 output_asm_insn ("movw\t%1,%0", operands);
3049 return;
3052 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3054 cc_status = cc_prev_status;
3055 switch (REGNO (operands[0]))
3057 case HARD_X_REGNUM:
3058 case HARD_Y_REGNUM:
3059 output_asm_insn ("pul%0", operands);
3060 break;
3061 case HARD_D_REGNUM:
3062 output_asm_insn ("pula", operands);
3063 output_asm_insn ("pulb", operands);
3064 break;
3065 default:
3066 abort ();
3068 return;
3070 /* Some moves to a hard register are special. Not all of them
3071 are really supported and we have to use a temporary
3072 location to provide them (either the stack of a temp var). */
3073 if (H_REG_P (operands[0]))
3075 switch (REGNO (operands[0]))
3077 case HARD_D_REGNUM:
3078 if (X_REG_P (operands[1]))
3080 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3082 m68hc11_output_swap (insn, operands);
3084 else if (next_insn_test_reg (insn, operands[0]))
3086 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3088 else
3090 m68hc11_notice_keep_cc (operands[0]);
3091 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3094 else if (Y_REG_P (operands[1]))
3096 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3098 m68hc11_output_swap (insn, operands);
3100 else
3102 /* %t means *ZTMP scratch register. */
3103 output_asm_insn ("sty\t%t1", operands);
3104 output_asm_insn ("ldd\t%t1", operands);
3107 else if (SP_REG_P (operands[1]))
3109 CC_STATUS_INIT;
3110 if (ix_reg == 0)
3111 create_regs_rtx ();
3112 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3113 output_asm_insn ("xgdx", operands);
3114 output_asm_insn ("tsx", operands);
3115 output_asm_insn ("xgdx", operands);
3117 else if (IS_STACK_POP (operands[1]))
3119 output_asm_insn ("pula\n\tpulb", operands);
3121 else if (GET_CODE (operands[1]) == CONST_INT
3122 && INTVAL (operands[1]) == 0)
3124 output_asm_insn ("clra\n\tclrb", operands);
3126 else
3128 output_asm_insn ("ldd\t%1", operands);
3130 break;
3132 case HARD_X_REGNUM:
3133 if (D_REG_P (operands[1]))
3135 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3137 m68hc11_output_swap (insn, operands);
3139 else if (next_insn_test_reg (insn, operands[0]))
3141 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3143 else
3145 m68hc11_notice_keep_cc (operands[0]);
3146 output_asm_insn ("pshb", operands);
3147 output_asm_insn ("psha", operands);
3148 output_asm_insn ("pulx", operands);
3151 else if (Y_REG_P (operands[1]))
3153 /* When both D and Y are dead, use the sequence xgdy, xgdx
3154 to move Y into X. The D and Y registers are modified. */
3155 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3156 && dead_register_here (insn, d_reg))
3158 output_asm_insn ("xgdy", operands);
3159 output_asm_insn ("xgdx", operands);
3160 CC_STATUS_INIT;
3162 else
3164 output_asm_insn ("sty\t%t1", operands);
3165 output_asm_insn ("ldx\t%t1", operands);
3168 else if (SP_REG_P (operands[1]))
3170 /* tsx, tsy preserve the flags */
3171 cc_status = cc_prev_status;
3172 output_asm_insn ("tsx", operands);
3174 else
3176 output_asm_insn ("ldx\t%1", operands);
3178 break;
3180 case HARD_Y_REGNUM:
3181 if (D_REG_P (operands[1]))
3183 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3185 m68hc11_output_swap (insn, operands);
3187 else
3189 output_asm_insn ("std\t%t1", operands);
3190 output_asm_insn ("ldy\t%t1", operands);
3193 else if (X_REG_P (operands[1]))
3195 /* When both D and X are dead, use the sequence xgdx, xgdy
3196 to move X into Y. The D and X registers are modified. */
3197 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3198 && dead_register_here (insn, d_reg))
3200 output_asm_insn ("xgdx", operands);
3201 output_asm_insn ("xgdy", operands);
3202 CC_STATUS_INIT;
3204 else
3206 output_asm_insn ("stx\t%t1", operands);
3207 output_asm_insn ("ldy\t%t1", operands);
3210 else if (SP_REG_P (operands[1]))
3212 /* tsx, tsy preserve the flags */
3213 cc_status = cc_prev_status;
3214 output_asm_insn ("tsy", operands);
3216 else
3218 output_asm_insn ("ldy\t%1", operands);
3220 break;
3222 case HARD_SP_REGNUM:
3223 if (D_REG_P (operands[1]))
3225 m68hc11_notice_keep_cc (operands[0]);
3226 output_asm_insn ("xgdx", operands);
3227 output_asm_insn ("txs", operands);
3228 output_asm_insn ("xgdx", operands);
3230 else if (X_REG_P (operands[1]))
3232 /* tys, txs preserve the flags */
3233 cc_status = cc_prev_status;
3234 output_asm_insn ("txs", operands);
3236 else if (Y_REG_P (operands[1]))
3238 /* tys, txs preserve the flags */
3239 cc_status = cc_prev_status;
3240 output_asm_insn ("tys", operands);
3242 else
3244 /* lds sets the flags but the des does not. */
3245 CC_STATUS_INIT;
3246 output_asm_insn ("lds\t%1", operands);
3247 output_asm_insn ("des", operands);
3249 break;
3251 default:
3252 fatal_insn ("invalid register in the move instruction", insn);
3253 break;
3255 return;
3257 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3258 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3260 output_asm_insn ("sts\t%0", operands);
3261 return;
3264 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3266 cc_status = cc_prev_status;
3267 switch (REGNO (operands[1]))
3269 case HARD_X_REGNUM:
3270 case HARD_Y_REGNUM:
3271 output_asm_insn ("psh%1", operands);
3272 break;
3273 case HARD_D_REGNUM:
3274 output_asm_insn ("pshb", operands);
3275 output_asm_insn ("psha", operands);
3276 break;
3277 default:
3278 abort ();
3280 return;
3283 /* Operand 1 must be a hard register. */
3284 if (!H_REG_P (operands[1]))
3286 fatal_insn ("invalid operand in the instruction", insn);
3289 reg = REGNO (operands[1]);
3290 switch (reg)
3292 case HARD_D_REGNUM:
3293 output_asm_insn ("std\t%0", operands);
3294 break;
3296 case HARD_X_REGNUM:
3297 output_asm_insn ("stx\t%0", operands);
3298 break;
3300 case HARD_Y_REGNUM:
3301 output_asm_insn ("sty\t%0", operands);
3302 break;
3304 case HARD_SP_REGNUM:
3305 if (ix_reg == 0)
3306 create_regs_rtx ();
3308 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3310 output_asm_insn ("pshx", operands);
3311 output_asm_insn ("tsx", operands);
3312 output_asm_insn ("inx", operands);
3313 output_asm_insn ("inx", operands);
3314 output_asm_insn ("stx\t%0", operands);
3315 output_asm_insn ("pulx", operands);
3318 else if (reg_mentioned_p (ix_reg, operands[0]))
3320 output_asm_insn ("sty\t%t0", operands);
3321 output_asm_insn ("tsy", operands);
3322 output_asm_insn ("sty\t%0", operands);
3323 output_asm_insn ("ldy\t%t0", operands);
3325 else
3327 output_asm_insn ("stx\t%t0", operands);
3328 output_asm_insn ("tsx", operands);
3329 output_asm_insn ("stx\t%0", operands);
3330 output_asm_insn ("ldx\t%t0", operands);
3332 CC_STATUS_INIT;
3333 break;
3335 default:
3336 fatal_insn ("invalid register in the move instruction", insn);
3337 break;
3341 void
3342 m68hc11_gen_movqi (insn, operands)
3343 rtx insn;
3344 rtx *operands;
3346 /* Move a register or memory to the same location.
3347 This is possible because such insn can appear
3348 in a non-optimizing mode. */
3349 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3351 cc_status = cc_prev_status;
3352 return;
3355 if (TARGET_M6812)
3358 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3360 m68hc11_notice_keep_cc (operands[0]);
3361 output_asm_insn ("tfr\t%1,%0", operands);
3363 else if (H_REG_P (operands[0]))
3365 if (Q_REG_P (operands[0]))
3366 output_asm_insn ("lda%0\t%b1", operands);
3367 else if (D_REG_P (operands[0]))
3368 output_asm_insn ("ldab\t%b1", operands);
3369 else
3370 goto m6811_move;
3372 else if (H_REG_P (operands[1]))
3374 if (Q_REG_P (operands[1]))
3375 output_asm_insn ("sta%1\t%b0", operands);
3376 else if (D_REG_P (operands[1]))
3377 output_asm_insn ("stab\t%b0", operands);
3378 else
3379 goto m6811_move;
3381 else
3383 rtx from = operands[1];
3384 rtx to = operands[0];
3386 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3387 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3388 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3389 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3391 rtx ops[3];
3393 if (operands[2])
3395 ops[0] = operands[2];
3396 ops[1] = from;
3397 ops[2] = 0;
3398 m68hc11_gen_movqi (insn, ops);
3399 ops[0] = to;
3400 ops[1] = operands[2];
3401 m68hc11_gen_movqi (insn, ops);
3403 else
3405 /* !!!! SCz wrong here. */
3406 fatal_insn ("move insn not handled", insn);
3409 else
3411 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3413 output_asm_insn ("clr\t%b0", operands);
3415 else
3417 m68hc11_notice_keep_cc (operands[0]);
3418 output_asm_insn ("movb\t%b1,%b0", operands);
3422 return;
3425 m6811_move:
3426 if (H_REG_P (operands[0]))
3428 switch (REGNO (operands[0]))
3430 case HARD_B_REGNUM:
3431 case HARD_D_REGNUM:
3432 if (X_REG_P (operands[1]))
3434 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3436 m68hc11_output_swap (insn, operands);
3438 else
3440 output_asm_insn ("stx\t%t1", operands);
3441 output_asm_insn ("ldab\t%T0", operands);
3444 else if (Y_REG_P (operands[1]))
3446 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3448 m68hc11_output_swap (insn, operands);
3450 else
3452 output_asm_insn ("sty\t%t1", operands);
3453 output_asm_insn ("ldab\t%T0", operands);
3456 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3457 && !DA_REG_P (operands[1]))
3459 output_asm_insn ("ldab\t%b1", operands);
3461 else if (DA_REG_P (operands[1]))
3463 output_asm_insn ("tab", operands);
3465 else
3467 cc_status = cc_prev_status;
3468 return;
3470 break;
3472 case HARD_A_REGNUM:
3473 if (X_REG_P (operands[1]))
3475 output_asm_insn ("stx\t%t1", operands);
3476 output_asm_insn ("ldaa\t%T0", operands);
3478 else if (Y_REG_P (operands[1]))
3480 output_asm_insn ("sty\t%t1", operands);
3481 output_asm_insn ("ldaa\t%T0", operands);
3483 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3484 && !DA_REG_P (operands[1]))
3486 output_asm_insn ("ldaa\t%b1", operands);
3488 else if (!DA_REG_P (operands[1]))
3490 output_asm_insn ("tba", operands);
3492 else
3494 cc_status = cc_prev_status;
3496 break;
3498 case HARD_X_REGNUM:
3499 if (D_REG_P (operands[1]))
3501 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3503 m68hc11_output_swap (insn, operands);
3505 else
3507 output_asm_insn ("stab\t%T1", operands);
3508 output_asm_insn ("ldx\t%t1", operands);
3510 CC_STATUS_INIT;
3512 else if (Y_REG_P (operands[1]))
3514 output_asm_insn ("sty\t%t0", operands);
3515 output_asm_insn ("ldx\t%t0", operands);
3517 else if (GET_CODE (operands[1]) == CONST_INT)
3519 output_asm_insn ("ldx\t%1", operands);
3521 else if (dead_register_here (insn, d_reg))
3523 output_asm_insn ("ldab\t%b1", operands);
3524 output_asm_insn ("xgdx", operands);
3526 else if (!reg_mentioned_p (operands[0], operands[1]))
3528 output_asm_insn ("xgdx", operands);
3529 output_asm_insn ("ldab\t%b1", operands);
3530 output_asm_insn ("xgdx", operands);
3532 else
3534 output_asm_insn ("pshb", operands);
3535 output_asm_insn ("ldab\t%b1", operands);
3536 output_asm_insn ("stab\t%T1", operands);
3537 output_asm_insn ("ldx\t%t1", operands);
3538 output_asm_insn ("pulb", operands);
3539 CC_STATUS_INIT;
3541 break;
3543 case HARD_Y_REGNUM:
3544 if (D_REG_P (operands[1]))
3546 output_asm_insn ("stab\t%T1", operands);
3547 output_asm_insn ("ldy\t%t1", operands);
3548 CC_STATUS_INIT;
3550 else if (X_REG_P (operands[1]))
3552 output_asm_insn ("stx\t%t1", operands);
3553 output_asm_insn ("ldy\t%t1", operands);
3554 CC_STATUS_INIT;
3556 else if (GET_CODE (operands[1]) == CONST_INT)
3558 output_asm_insn ("ldy\t%1", operands);
3560 else if (dead_register_here (insn, d_reg))
3562 output_asm_insn ("ldab\t%b1", operands);
3563 output_asm_insn ("xgdy", operands);
3565 else if (!reg_mentioned_p (operands[0], operands[1]))
3567 output_asm_insn ("xgdy", operands);
3568 output_asm_insn ("ldab\t%b1", operands);
3569 output_asm_insn ("xgdy", operands);
3571 else
3573 output_asm_insn ("pshb", operands);
3574 output_asm_insn ("ldab\t%b1", operands);
3575 output_asm_insn ("stab\t%T1", operands);
3576 output_asm_insn ("ldy\t%t1", operands);
3577 output_asm_insn ("pulb", operands);
3578 CC_STATUS_INIT;
3580 break;
3582 default:
3583 fatal_insn ("invalid register in the instruction", insn);
3584 break;
3587 else if (H_REG_P (operands[1]))
3589 switch (REGNO (operands[1]))
3591 case HARD_D_REGNUM:
3592 case HARD_B_REGNUM:
3593 output_asm_insn ("stab\t%b0", operands);
3594 break;
3596 case HARD_A_REGNUM:
3597 output_asm_insn ("staa\t%b0", operands);
3598 break;
3600 case HARD_X_REGNUM:
3601 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3602 break;
3604 case HARD_Y_REGNUM:
3605 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3606 break;
3608 default:
3609 fatal_insn ("invalid register in the move instruction", insn);
3610 break;
3612 return;
3614 else
3616 fatal_insn ("operand 1 must be a hard register", insn);
3620 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3621 The source and destination must be D or A and the shift must
3622 be a constant. */
3623 void
3624 m68hc11_gen_rotate (code, insn, operands)
3625 enum rtx_code code;
3626 rtx insn;
3627 rtx operands[];
3629 int val;
3631 if (GET_CODE (operands[2]) != CONST_INT
3632 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3633 fatal_insn ("invalid rotate insn", insn);
3635 val = INTVAL (operands[2]);
3636 if (code == ROTATERT)
3637 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3639 if (GET_MODE (operands[0]) != QImode)
3640 CC_STATUS_INIT;
3642 /* Rotate by 8-bits if the shift is within [5..11]. */
3643 if (val >= 5 && val <= 11)
3645 output_asm_insn ("psha", operands);
3646 output_asm_insn ("tba", operands);
3647 output_asm_insn ("pulb", operands);
3648 val -= 8;
3651 /* If the shift is big, invert the rotation. */
3652 else if (val >= 12)
3654 val = val - 16;
3657 if (val > 0)
3659 /* Set the carry to bit-15, but don't change D yet. */
3660 if (GET_MODE (operands[0]) != QImode)
3662 output_asm_insn ("asra", operands);
3663 output_asm_insn ("rola", operands);
3666 while (--val >= 0)
3668 /* Rotate B first to move the carry to bit-0. */
3669 if (D_REG_P (operands[0]))
3670 output_asm_insn ("rolb", operands);
3672 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3673 output_asm_insn ("rola", operands);
3676 else
3678 /* Set the carry to bit-8 of D. */
3679 if (val != 0 && GET_MODE (operands[0]) != QImode)
3681 output_asm_insn ("tap", operands);
3684 while (++val <= 0)
3686 /* Rotate B first to move the carry to bit-7. */
3687 if (D_REG_P (operands[0]))
3688 output_asm_insn ("rorb", operands);
3690 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3691 output_asm_insn ("rora", operands);
3698 /* Store in cc_status the expressions that the condition codes will
3699 describe after execution of an instruction whose pattern is EXP.
3700 Do not alter them if the instruction would not alter the cc's. */
3702 void
3703 m68hc11_notice_update_cc (exp, insn)
3704 rtx exp;
3705 rtx insn ATTRIBUTE_UNUSED;
3707 /* recognize SET insn's. */
3708 if (GET_CODE (exp) == SET)
3710 /* Jumps do not alter the cc's. */
3711 if (SET_DEST (exp) == pc_rtx)
3714 /* NOTE: most instructions don't affect the carry bit, but the
3715 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3716 the conditions.h header. */
3718 /* Function calls clobber the cc's. */
3719 else if (GET_CODE (SET_SRC (exp)) == CALL)
3721 CC_STATUS_INIT;
3724 /* Tests and compares set the cc's in predictable ways. */
3725 else if (SET_DEST (exp) == cc0_rtx)
3727 cc_status.flags = 0;
3728 cc_status.value1 = XEXP (exp, 0);
3729 cc_status.value2 = XEXP (exp, 1);
3731 else
3733 /* All other instructions affect the condition codes. */
3734 cc_status.flags = 0;
3735 cc_status.value1 = XEXP (exp, 0);
3736 cc_status.value2 = XEXP (exp, 1);
3739 else
3741 /* Default action if we haven't recognized something
3742 and returned earlier. */
3743 CC_STATUS_INIT;
3746 if (cc_status.value2 != 0)
3747 switch (GET_CODE (cc_status.value2))
3749 /* These logical operations can generate several insns.
3750 The flags are setup according to what is generated. */
3751 case IOR:
3752 case XOR:
3753 case AND:
3754 break;
3756 /* The (not ...) generates several 'com' instructions for
3757 non QImode. We have to invalidate the flags. */
3758 case NOT:
3759 if (GET_MODE (cc_status.value2) != QImode)
3760 CC_STATUS_INIT;
3761 break;
3763 case PLUS:
3764 case MINUS:
3765 case MULT:
3766 case DIV:
3767 case UDIV:
3768 case MOD:
3769 case UMOD:
3770 case NEG:
3771 if (GET_MODE (cc_status.value2) != VOIDmode)
3772 cc_status.flags |= CC_NO_OVERFLOW;
3773 break;
3775 /* The asl sets the overflow bit in such a way that this
3776 makes the flags unusable for a next compare insn. */
3777 case ASHIFT:
3778 case ROTATE:
3779 case ROTATERT:
3780 if (GET_MODE (cc_status.value2) != VOIDmode)
3781 cc_status.flags |= CC_NO_OVERFLOW;
3782 break;
3784 /* A load/store instruction does not affect the carry. */
3785 case MEM:
3786 case SYMBOL_REF:
3787 case REG:
3788 case CONST_INT:
3789 cc_status.flags |= CC_NO_OVERFLOW;
3790 break;
3792 default:
3793 break;
3795 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3796 && cc_status.value2
3797 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3798 cc_status.value2 = 0;
3801 /* The current instruction does not affect the flags but changes
3802 the register 'reg'. See if the previous flags can be kept for the
3803 next instruction to avoid a comparison. */
3804 void
3805 m68hc11_notice_keep_cc (reg)
3806 rtx reg;
3808 if (reg == 0
3809 || cc_prev_status.value1 == 0
3810 || rtx_equal_p (reg, cc_prev_status.value1)
3811 || (cc_prev_status.value2
3812 && reg_mentioned_p (reg, cc_prev_status.value2)))
3813 CC_STATUS_INIT;
3814 else
3815 cc_status = cc_prev_status;
3820 /* Machine Specific Reorg. */
3822 /* Z register replacement:
3824 GCC treats the Z register as an index base address register like
3825 X or Y. In general, it uses it during reload to compute the address
3826 of some operand. This helps the reload pass to avoid to fall into the
3827 register spill failure.
3829 The Z register is in the A_REGS class. In the machine description,
3830 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3832 It can appear everywhere an X or Y register can appear, except for
3833 some templates in the clobber section (when a clobber of X or Y is asked).
3834 For a given instruction, the template must ensure that no more than
3835 2 'A' registers are used. Otherwise, the register replacement is not
3836 possible.
3838 To replace the Z register, the algorithm is not terrific:
3839 1. Insns that do not use the Z register are not changed
3840 2. When a Z register is used, we scan forward the insns to see
3841 a potential register to use: either X or Y and sometimes D.
3842 We stop when a call, a label or a branch is seen, or when we
3843 detect that both X and Y are used (probably at different times, but it does
3844 not matter).
3845 3. The register that will be used for the replacement of Z is saved
3846 in a .page0 register or on the stack. If the first instruction that
3847 used Z, uses Z as an input, the value is loaded from another .page0
3848 register. The replacement register is pushed on the stack in the
3849 rare cases where a compare insn uses Z and we couldn't find if X/Y
3850 are dead.
3851 4. The Z register is replaced in all instructions until we reach
3852 the end of the Z-block, as detected by step 2.
3853 5. If we detect that Z is still alive, its value is saved.
3854 If the replacement register is alive, its old value is loaded.
3856 The Z register can be disabled with -ffixed-z.
3859 struct replace_info
3861 rtx first;
3862 rtx replace_reg;
3863 int need_save_z;
3864 int must_load_z;
3865 int must_save_reg;
3866 int must_restore_reg;
3867 rtx last;
3868 int regno;
3869 int x_used;
3870 int y_used;
3871 int can_use_d;
3872 int found_call;
3873 int z_died;
3874 int z_set_count;
3875 rtx z_value;
3876 int must_push_reg;
3877 int save_before_last;
3878 int z_loaded_with_sp;
3881 static rtx z_reg_qi;
3883 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
3884 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
3885 static void m68hc11_z_replacement PARAMS ((rtx));
3886 static void m68hc11_reassign_regs PARAMS ((rtx));
3888 int z_replacement_completed = 0;
3890 /* Analyze the insn to find out which replacement register to use and
3891 the boundaries of the replacement.
3892 Returns 0 if we reached the last insn to be replaced, 1 if we can
3893 continue replacement in next insns. */
3895 static int
3896 m68hc11_check_z_replacement (insn, info)
3897 rtx insn;
3898 struct replace_info *info;
3900 int this_insn_uses_ix;
3901 int this_insn_uses_iy;
3902 int this_insn_uses_z;
3903 int this_insn_uses_z_in_dst;
3904 int this_insn_uses_d;
3905 rtx body;
3906 int z_dies_here;
3908 /* A call is said to clobber the Z register, we don't need
3909 to save the value of Z. We also don't need to restore
3910 the replacement register (unless it is used by the call). */
3911 if (GET_CODE (insn) == CALL_INSN)
3913 body = PATTERN (insn);
3915 info->can_use_d = 0;
3917 /* If the call is an indirect call with Z, we have to use the
3918 Y register because X can be used as an input (D+X).
3919 We also must not save Z nor restore Y. */
3920 if (reg_mentioned_p (z_reg, body))
3922 insn = NEXT_INSN (insn);
3923 info->x_used = 1;
3924 info->y_used = 0;
3925 info->found_call = 1;
3926 info->must_restore_reg = 0;
3927 info->last = NEXT_INSN (insn);
3929 info->need_save_z = 0;
3930 return 0;
3932 if (GET_CODE (insn) == CODE_LABEL
3933 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
3934 return 0;
3936 if (GET_CODE (insn) == JUMP_INSN)
3938 if (reg_mentioned_p (z_reg, insn) == 0)
3939 return 0;
3941 info->can_use_d = 0;
3942 info->must_save_reg = 0;
3943 info->must_restore_reg = 0;
3944 info->need_save_z = 0;
3945 info->last = NEXT_INSN (insn);
3946 return 0;
3948 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
3950 return 1;
3953 /* Z register dies here. */
3954 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
3956 body = PATTERN (insn);
3957 if (GET_CODE (body) == SET)
3959 rtx src = XEXP (body, 1);
3960 rtx dst = XEXP (body, 0);
3962 /* Condition code is set here. We have to restore the X/Y and
3963 save into Z before any test/compare insn because once we save/restore
3964 we can change the condition codes. When the compare insn uses Z and
3965 we can't use X/Y, the comparison is made with the *ZREG soft register
3966 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3967 if (dst == cc0_rtx)
3969 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
3970 || (GET_CODE (src) == COMPARE &&
3971 (rtx_equal_p (XEXP (src, 0), z_reg)
3972 || rtx_equal_p (XEXP (src, 1), z_reg))))
3974 if (insn == info->first)
3976 info->must_load_z = 0;
3977 info->must_save_reg = 0;
3978 info->must_restore_reg = 0;
3979 info->need_save_z = 0;
3980 info->found_call = 1;
3981 info->regno = SOFT_Z_REGNUM;
3982 info->last = insn;
3984 return 0;
3986 if (reg_mentioned_p (z_reg, src) == 0)
3988 info->can_use_d = 0;
3989 return 0;
3992 if (insn != info->first)
3993 return 0;
3995 /* Compare insn which uses Z. We have to save/restore the X/Y
3996 register without modifying the condition codes. For this
3997 we have to use a push/pop insn. */
3998 info->must_push_reg = 1;
3999 info->last = insn;
4002 /* Z reg is set to something new. We don't need to load it. */
4003 if (Z_REG_P (dst))
4005 if (!reg_mentioned_p (z_reg, src))
4007 /* Z reg is used before being set. Treat this as
4008 a new sequence of Z register replacement. */
4009 if (insn != info->first)
4011 return 0;
4013 info->must_load_z = 0;
4015 info->z_set_count++;
4016 info->z_value = src;
4017 if (SP_REG_P (src))
4018 info->z_loaded_with_sp = 1;
4020 else if (reg_mentioned_p (z_reg, dst))
4021 info->can_use_d = 0;
4023 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4024 | reg_mentioned_p (d_reg, dst);
4025 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4026 | reg_mentioned_p (ix_reg, dst);
4027 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4028 | reg_mentioned_p (iy_reg, dst);
4029 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4031 /* If z is used as an address operand (like (MEM (reg z))),
4032 we can't replace it with d. */
4033 if (this_insn_uses_z && !Z_REG_P (src)
4034 && !(m68hc11_arith_operator (src, GET_MODE (src))
4035 && Z_REG_P (XEXP (src, 0))
4036 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4037 && insn == info->first
4038 && dead_register_here (insn, d_reg)))
4039 info->can_use_d = 0;
4041 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4042 if (TARGET_M6812 && !z_dies_here
4043 && ((this_insn_uses_z && side_effects_p (src))
4044 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4046 info->need_save_z = 1;
4047 info->z_set_count++;
4049 this_insn_uses_z |= this_insn_uses_z_in_dst;
4051 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4053 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4056 if (this_insn_uses_d)
4057 info->can_use_d = 0;
4059 /* IX and IY are used at the same time, we have to restore
4060 the value of the scratch register before this insn. */
4061 if (this_insn_uses_ix && this_insn_uses_iy)
4063 return 0;
4066 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4067 info->can_use_d = 0;
4069 if (info->x_used == 0 && this_insn_uses_ix)
4071 if (info->y_used)
4073 /* We have a (set (REG:HI X) (REG:HI Z)).
4074 Since we use Z as the replacement register, this insn
4075 is no longer necessary. We turn it into a note. We must
4076 not reload the old value of X. */
4077 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4079 if (z_dies_here)
4081 info->need_save_z = 0;
4082 info->z_died = 1;
4084 info->must_save_reg = 0;
4085 info->must_restore_reg = 0;
4086 info->found_call = 1;
4087 info->can_use_d = 0;
4088 PUT_CODE (insn, NOTE);
4089 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4090 NOTE_SOURCE_FILE (insn) = 0;
4091 info->last = NEXT_INSN (insn);
4092 return 0;
4095 if (X_REG_P (dst)
4096 && (rtx_equal_p (src, z_reg)
4097 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4099 if (z_dies_here)
4101 info->need_save_z = 0;
4102 info->z_died = 1;
4104 info->last = NEXT_INSN (insn);
4105 info->must_save_reg = 0;
4106 info->must_restore_reg = 0;
4108 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4109 && !reg_mentioned_p (ix_reg, src))
4111 if (z_dies_here)
4113 info->z_died = 1;
4114 info->need_save_z = 0;
4116 else
4118 info->save_before_last = 1;
4120 info->must_restore_reg = 0;
4121 info->last = NEXT_INSN (insn);
4123 else if (info->can_use_d)
4125 info->last = NEXT_INSN (insn);
4126 info->x_used = 1;
4128 return 0;
4130 info->x_used = 1;
4131 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4132 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4134 info->need_save_z = 0;
4135 info->z_died = 1;
4136 info->last = NEXT_INSN (insn);
4137 info->regno = HARD_X_REGNUM;
4138 info->must_save_reg = 0;
4139 info->must_restore_reg = 0;
4140 return 0;
4142 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4144 info->regno = HARD_X_REGNUM;
4145 info->must_restore_reg = 0;
4146 info->must_save_reg = 0;
4147 return 0;
4150 if (info->y_used == 0 && this_insn_uses_iy)
4152 if (info->x_used)
4154 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4156 if (z_dies_here)
4158 info->need_save_z = 0;
4159 info->z_died = 1;
4161 info->must_save_reg = 0;
4162 info->must_restore_reg = 0;
4163 info->found_call = 1;
4164 info->can_use_d = 0;
4165 PUT_CODE (insn, NOTE);
4166 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4167 NOTE_SOURCE_FILE (insn) = 0;
4168 info->last = NEXT_INSN (insn);
4169 return 0;
4172 if (Y_REG_P (dst)
4173 && (rtx_equal_p (src, z_reg)
4174 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4176 if (z_dies_here)
4178 info->z_died = 1;
4179 info->need_save_z = 0;
4181 info->last = NEXT_INSN (insn);
4182 info->must_save_reg = 0;
4183 info->must_restore_reg = 0;
4185 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4186 && !reg_mentioned_p (iy_reg, src))
4188 if (z_dies_here)
4190 info->z_died = 1;
4191 info->need_save_z = 0;
4193 else
4195 info->save_before_last = 1;
4197 info->must_restore_reg = 0;
4198 info->last = NEXT_INSN (insn);
4200 else if (info->can_use_d)
4202 info->last = NEXT_INSN (insn);
4203 info->y_used = 1;
4206 return 0;
4208 info->y_used = 1;
4209 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4210 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4212 info->need_save_z = 0;
4213 info->z_died = 1;
4214 info->last = NEXT_INSN (insn);
4215 info->regno = HARD_Y_REGNUM;
4216 info->must_save_reg = 0;
4217 info->must_restore_reg = 0;
4218 return 0;
4220 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4222 info->regno = HARD_Y_REGNUM;
4223 info->must_restore_reg = 0;
4224 info->must_save_reg = 0;
4225 return 0;
4228 if (z_dies_here)
4230 info->need_save_z = 0;
4231 info->z_died = 1;
4232 if (info->last == 0)
4233 info->last = NEXT_INSN (insn);
4234 return 0;
4236 return info->last != NULL_RTX ? 0 : 1;
4238 if (GET_CODE (body) == PARALLEL)
4240 int i;
4241 char ix_clobber = 0;
4242 char iy_clobber = 0;
4243 char z_clobber = 0;
4244 this_insn_uses_iy = 0;
4245 this_insn_uses_ix = 0;
4246 this_insn_uses_z = 0;
4248 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4250 rtx x;
4251 int uses_ix, uses_iy, uses_z;
4253 x = XVECEXP (body, 0, i);
4255 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4256 info->can_use_d = 0;
4258 uses_ix = reg_mentioned_p (ix_reg, x);
4259 uses_iy = reg_mentioned_p (iy_reg, x);
4260 uses_z = reg_mentioned_p (z_reg, x);
4261 if (GET_CODE (x) == CLOBBER)
4263 ix_clobber |= uses_ix;
4264 iy_clobber |= uses_iy;
4265 z_clobber |= uses_z;
4267 else
4269 this_insn_uses_ix |= uses_ix;
4270 this_insn_uses_iy |= uses_iy;
4271 this_insn_uses_z |= uses_z;
4273 if (uses_z && GET_CODE (x) == SET)
4275 rtx dst = XEXP (x, 0);
4277 if (Z_REG_P (dst))
4278 info->z_set_count++;
4280 if (TARGET_M6812 && uses_z && side_effects_p (x))
4281 info->need_save_z = 1;
4283 if (z_clobber)
4284 info->need_save_z = 0;
4286 if (debug_m6811)
4288 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4289 this_insn_uses_ix, this_insn_uses_iy,
4290 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4291 debug_rtx (insn);
4293 if (this_insn_uses_z)
4294 info->can_use_d = 0;
4296 if (z_clobber && info->first != insn)
4298 info->need_save_z = 0;
4299 info->last = insn;
4300 return 0;
4302 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4304 if (this_insn_uses_z == 0 && insn == info->first)
4306 info->must_load_z = 0;
4308 if (dead_register_here (insn, d_reg))
4310 info->regno = HARD_D_REGNUM;
4311 info->must_save_reg = 0;
4312 info->must_restore_reg = 0;
4314 else if (dead_register_here (insn, ix_reg))
4316 info->regno = HARD_X_REGNUM;
4317 info->must_save_reg = 0;
4318 info->must_restore_reg = 0;
4320 else if (dead_register_here (insn, iy_reg))
4322 info->regno = HARD_Y_REGNUM;
4323 info->must_save_reg = 0;
4324 info->must_restore_reg = 0;
4326 if (info->regno >= 0)
4328 info->last = NEXT_INSN (insn);
4329 return 0;
4331 if (this_insn_uses_ix == 0)
4333 info->regno = HARD_X_REGNUM;
4334 info->must_save_reg = 1;
4335 info->must_restore_reg = 1;
4337 else if (this_insn_uses_iy == 0)
4339 info->regno = HARD_Y_REGNUM;
4340 info->must_save_reg = 1;
4341 info->must_restore_reg = 1;
4343 else
4345 info->regno = HARD_D_REGNUM;
4346 info->must_save_reg = 1;
4347 info->must_restore_reg = 1;
4349 info->last = NEXT_INSN (insn);
4350 return 0;
4353 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4354 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4356 if (this_insn_uses_z)
4358 if (info->y_used == 0 && iy_clobber)
4360 info->regno = HARD_Y_REGNUM;
4361 info->must_save_reg = 0;
4362 info->must_restore_reg = 0;
4364 info->last = NEXT_INSN (insn);
4365 info->save_before_last = 1;
4367 return 0;
4369 if (this_insn_uses_ix && this_insn_uses_iy)
4371 if (this_insn_uses_z)
4373 fatal_insn ("cannot do z-register replacement", insn);
4375 return 0;
4377 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4379 if (info->y_used)
4381 return 0;
4383 info->x_used = 1;
4384 if (iy_clobber || z_clobber)
4386 info->last = NEXT_INSN (insn);
4387 info->save_before_last = 1;
4388 return 0;
4392 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4394 if (info->x_used)
4396 return 0;
4398 info->y_used = 1;
4399 if (ix_clobber || z_clobber)
4401 info->last = NEXT_INSN (insn);
4402 info->save_before_last = 1;
4403 return 0;
4406 if (z_dies_here)
4408 info->z_died = 1;
4409 info->need_save_z = 0;
4411 return 1;
4413 if (GET_CODE (body) == CLOBBER)
4416 /* IX and IY are used at the same time, we have to restore
4417 the value of the scratch register before this insn. */
4418 if (this_insn_uses_ix && this_insn_uses_iy)
4420 return 0;
4422 if (info->x_used == 0 && this_insn_uses_ix)
4424 if (info->y_used)
4426 return 0;
4428 info->x_used = 1;
4430 if (info->y_used == 0 && this_insn_uses_iy)
4432 if (info->x_used)
4434 return 0;
4436 info->y_used = 1;
4438 return 1;
4440 return 1;
4443 static void
4444 m68hc11_find_z_replacement (insn, info)
4445 rtx insn;
4446 struct replace_info *info;
4448 int reg;
4450 info->replace_reg = NULL_RTX;
4451 info->must_load_z = 1;
4452 info->need_save_z = 1;
4453 info->must_save_reg = 1;
4454 info->must_restore_reg = 1;
4455 info->first = insn;
4456 info->x_used = 0;
4457 info->y_used = 0;
4458 info->can_use_d = TARGET_M6811 ? 1 : 0;
4459 info->found_call = 0;
4460 info->z_died = 0;
4461 info->last = 0;
4462 info->regno = -1;
4463 info->z_set_count = 0;
4464 info->z_value = NULL_RTX;
4465 info->must_push_reg = 0;
4466 info->save_before_last = 0;
4467 info->z_loaded_with_sp = 0;
4469 /* Scan the insn forward to find an address register that is not used.
4470 Stop when:
4471 - the flow of the program changes,
4472 - when we detect that both X and Y are necessary,
4473 - when the Z register dies,
4474 - when the condition codes are set. */
4476 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4478 if (m68hc11_check_z_replacement (insn, info) == 0)
4479 break;
4482 /* May be we can use Y or X if they contain the same value as Z.
4483 This happens very often after the reload. */
4484 if (info->z_set_count == 1)
4486 rtx p = info->first;
4487 rtx v = 0;
4489 if (info->x_used)
4491 v = find_last_value (iy_reg, &p, insn, 1);
4493 else if (info->y_used)
4495 v = find_last_value (ix_reg, &p, insn, 1);
4497 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4499 if (info->x_used)
4500 info->regno = HARD_Y_REGNUM;
4501 else
4502 info->regno = HARD_X_REGNUM;
4503 info->must_load_z = 0;
4504 info->must_save_reg = 0;
4505 info->must_restore_reg = 0;
4506 info->found_call = 1;
4509 if (info->z_set_count == 0)
4510 info->need_save_z = 0;
4512 if (insn == 0)
4513 info->need_save_z = 0;
4515 if (info->last == 0)
4516 info->last = insn;
4518 if (info->regno >= 0)
4520 reg = info->regno;
4521 info->replace_reg = gen_rtx (REG, HImode, reg);
4523 else if (info->can_use_d)
4525 reg = HARD_D_REGNUM;
4526 info->replace_reg = d_reg;
4528 else if (info->x_used)
4530 reg = HARD_Y_REGNUM;
4531 info->replace_reg = iy_reg;
4533 else
4535 reg = HARD_X_REGNUM;
4536 info->replace_reg = ix_reg;
4538 info->regno = reg;
4540 if (info->must_save_reg && info->must_restore_reg)
4542 if (insn && dead_register_here (insn, info->replace_reg))
4544 info->must_save_reg = 0;
4545 info->must_restore_reg = 0;
4550 /* The insn uses the Z register. Find a replacement register for it
4551 (either X or Y) and replace it in the insn and the next ones until
4552 the flow changes or the replacement register is used. Instructions
4553 are emited before and after the Z-block to preserve the value of
4554 Z and of the replacement register. */
4556 static void
4557 m68hc11_z_replacement (insn)
4558 rtx insn;
4560 rtx replace_reg_qi;
4561 rtx replace_reg;
4562 struct replace_info info;
4564 /* Find trivial case where we only need to replace z with the
4565 equivalent soft register. */
4566 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4568 rtx body = PATTERN (insn);
4569 rtx src = XEXP (body, 1);
4570 rtx dst = XEXP (body, 0);
4572 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4574 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4575 return;
4577 else if (Z_REG_P (src)
4578 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4580 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4581 return;
4583 else if (D_REG_P (dst)
4584 && m68hc11_arith_operator (src, GET_MODE (src))
4585 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4587 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4588 return;
4590 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4591 && INTVAL (src) == 0)
4593 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4594 /* Force it to be re-recognized. */
4595 INSN_CODE (insn) = -1;
4596 return;
4600 m68hc11_find_z_replacement (insn, &info);
4602 replace_reg = info.replace_reg;
4603 replace_reg_qi = NULL_RTX;
4605 /* Save the X register in a .page0 location. */
4606 if (info.must_save_reg && !info.must_push_reg)
4608 rtx dst;
4610 if (info.must_push_reg && 0)
4611 dst = gen_rtx (MEM, HImode,
4612 gen_rtx (PRE_DEC, HImode,
4613 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4614 else
4615 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4617 emit_insn_before (gen_movhi (dst,
4618 gen_rtx (REG, HImode, info.regno)), insn);
4620 if (info.must_load_z && !info.must_push_reg)
4622 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4623 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4624 insn);
4628 /* Replace all occurrence of Z by replace_reg.
4629 Stop when the last instruction to replace is reached.
4630 Also stop when we detect a change in the flow (but it's not
4631 necessary; just safeguard). */
4633 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4635 rtx body;
4637 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4638 break;
4640 if (GET_CODE (insn) != INSN
4641 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4642 continue;
4644 body = PATTERN (insn);
4645 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4646 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4648 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4650 printf ("Reg mentioned here...:\n");
4651 fflush (stdout);
4652 debug_rtx (insn);
4655 /* Stack pointer was decremented by 2 due to the push.
4656 Correct that by adding 2 to the destination. */
4657 if (info.must_push_reg
4658 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4660 rtx src, dst;
4662 src = SET_SRC (body);
4663 dst = SET_DEST (body);
4664 if (SP_REG_P (src) && Z_REG_P (dst))
4666 emit_insn_after (gen_addhi3 (dst,
4667 dst,
4668 gen_rtx (CONST_INT,
4669 VOIDmode, 2)), insn);
4673 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4674 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4676 INSN_CODE (insn) = -1;
4677 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4678 fatal_insn ("cannot do z-register replacement", insn);
4681 /* Likewise for (REG:QI Z). */
4682 if (reg_mentioned_p (z_reg, insn))
4684 if (replace_reg_qi == NULL_RTX)
4685 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4686 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4689 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4690 break;
4693 /* Save Z before restoring the old value. */
4694 if (insn && info.need_save_z && !info.must_push_reg)
4696 rtx save_pos_insn = insn;
4698 /* If Z is clobber by the last insn, we have to save its value
4699 before the last instruction. */
4700 if (info.save_before_last)
4701 save_pos_insn = PREV_INSN (save_pos_insn);
4703 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4704 gen_rtx (REG, HImode, info.regno)),
4705 save_pos_insn);
4708 if (info.must_push_reg && info.last)
4710 rtx new_body, body;
4712 body = PATTERN (info.last);
4713 new_body = gen_rtx (PARALLEL, VOIDmode,
4714 gen_rtvec (3, body,
4715 gen_rtx (USE, VOIDmode,
4716 replace_reg),
4717 gen_rtx (USE, VOIDmode,
4718 gen_rtx (REG, HImode,
4719 SOFT_Z_REGNUM))));
4720 PATTERN (info.last) = new_body;
4722 /* Force recognition on insn since we changed it. */
4723 INSN_CODE (insn) = -1;
4725 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4727 fatal_insn ("invalid Z register replacement for insn", insn);
4729 insn = NEXT_INSN (info.last);
4732 /* Restore replacement register unless it was died. */
4733 if (insn && info.must_restore_reg && !info.must_push_reg)
4735 rtx dst;
4737 if (info.must_push_reg && 0)
4738 dst = gen_rtx (MEM, HImode,
4739 gen_rtx (POST_INC, HImode,
4740 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4741 else
4742 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4744 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4745 dst), insn);
4751 /* Scan all the insn and re-affects some registers
4752 - The Z register (if it was used), is affected to X or Y depending
4753 on the instruction. */
4755 static void
4756 m68hc11_reassign_regs (first)
4757 rtx first;
4759 rtx insn;
4761 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
4762 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
4763 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4764 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
4766 /* Scan all insns to replace Z by X or Y preserving the old value
4767 of X/Y and restoring it afterward. */
4769 for (insn = first; insn; insn = NEXT_INSN (insn))
4771 rtx body;
4773 if (GET_CODE (insn) == CODE_LABEL
4774 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4775 continue;
4777 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4778 continue;
4780 body = PATTERN (insn);
4781 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4782 continue;
4784 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4785 || GET_CODE (body) == ASM_OPERANDS
4786 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4787 continue;
4789 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4790 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4793 /* If Z appears in this insn, replace it in the current insn
4794 and the next ones until the flow changes or we have to
4795 restore back the replacement register. */
4797 if (reg_mentioned_p (z_reg, body))
4799 m68hc11_z_replacement (insn);
4802 else
4804 printf ("insn not handled by Z replacement:\n");
4805 fflush (stdout);
4806 debug_rtx (insn);
4812 void
4813 m68hc11_reorg (first)
4814 rtx first;
4816 int split_done = 0;
4817 rtx insn;
4819 z_replacement_completed = 0;
4820 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4822 /* Some RTX are shared at this point. This breaks the Z register
4823 replacement, unshare everything. */
4824 unshare_all_rtl_again (first);
4826 /* Force a split of all splitable insn. This is necessary for the
4827 Z register replacement mechanism because we end up with basic insns. */
4828 split_all_insns_noflow ();
4829 split_done = 1;
4831 z_replacement_completed = 1;
4832 m68hc11_reassign_regs (first);
4834 /* After some splitting, there are some oportunities for CSE pass.
4835 This happens quite often when 32-bit or above patterns are split. */
4836 if (optimize > 0 && split_done)
4837 reload_cse_regs (first);
4839 /* Re-create the REG_DEAD notes. These notes are used in the machine
4840 description to use the best assembly directives. */
4841 if (optimize)
4843 /* Before recomputing the REG_DEAD notes, remove all of them.
4844 This is necessary because the reload_cse_regs() pass can
4845 have replaced some (MEM) with a register. In that case,
4846 the REG_DEAD that could exist for that register may become
4847 wrong. */
4848 for (insn = first; insn; insn = NEXT_INSN (insn))
4850 if (INSN_P (insn))
4852 rtx *pnote;
4854 pnote = &REG_NOTES (insn);
4855 while (*pnote != 0)
4857 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
4858 *pnote = XEXP (*pnote, 1);
4859 else
4860 pnote = &XEXP (*pnote, 1);
4865 find_basic_blocks (first, max_reg_num (), 0);
4866 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
4869 z_replacement_completed = 2;
4871 /* If optimizing, then go ahead and split insns that must be
4872 split after Z register replacement. This gives more opportunities
4873 for peephole (in particular for consecutives xgdx/xgdy). */
4874 if (optimize > 0)
4875 split_all_insns_noflow ();
4877 /* Once insns are split after the z_replacement_completed == 2,
4878 we must not re-run the life_analysis. The xgdx/xgdy patterns
4879 are not recognized and the life_analysis pass removes some
4880 insns because it thinks some (SETs) are noops or made to dead
4881 stores (which is false due to the swap).
4883 Do a simple pass to eliminate the noop set that the final
4884 split could generate (because it was easier for split definition). */
4886 rtx insn;
4888 for (insn = first; insn; insn = NEXT_INSN (insn))
4890 rtx body;
4892 if (INSN_DELETED_P (insn))
4893 continue;
4894 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4895 continue;
4897 /* Remove the (set (R) (R)) insns generated by some splits. */
4898 body = PATTERN (insn);
4899 if (GET_CODE (body) == SET
4900 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
4902 PUT_CODE (insn, NOTE);
4903 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4904 NOTE_SOURCE_FILE (insn) = 0;
4905 continue;
4912 /* Cost functions. */
4914 /* Cost of moving memory. */
4916 m68hc11_memory_move_cost (mode, class, in)
4917 enum machine_mode mode;
4918 enum reg_class class;
4919 int in ATTRIBUTE_UNUSED;
4921 if (class <= H_REGS)
4923 if (GET_MODE_SIZE (mode) <= 2)
4924 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4925 else
4926 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
4928 else
4930 if (GET_MODE_SIZE (mode) <= 2)
4931 return COSTS_N_INSNS (2);
4932 else
4933 return COSTS_N_INSNS (4);
4938 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4939 Reload does not check the constraint of set insns when the two registers
4940 have a move cost of 2. Setting a higher cost will force reload to check
4941 the constraints. */
4943 m68hc11_register_move_cost (from, to)
4944 enum reg_class from;
4945 enum reg_class to;
4947 if (from >= S_REGS && to >= S_REGS)
4949 return COSTS_N_INSNS (3);
4951 if (from <= S_REGS && to <= S_REGS)
4953 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4955 return COSTS_N_INSNS (2);
4959 /* Provide the costs of an addressing mode that contains ADDR.
4960 If ADDR is not a valid address, its cost is irrelevant. */
4963 m68hc11_address_cost (addr)
4964 rtx addr;
4966 int cost = 4;
4968 switch (GET_CODE (addr))
4970 case REG:
4971 /* Make the cost of hard registers and specially SP, FP small. */
4972 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
4973 cost = 0;
4974 else
4975 cost = 1;
4976 break;
4978 case SYMBOL_REF:
4979 cost = 8;
4980 break;
4982 case LABEL_REF:
4983 case CONST:
4984 cost = 0;
4985 break;
4987 case PLUS:
4989 register rtx plus0 = XEXP (addr, 0);
4990 register rtx plus1 = XEXP (addr, 1);
4992 if (GET_CODE (plus0) != REG)
4993 break;
4995 switch (GET_CODE (plus1))
4997 case CONST_INT:
4998 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
4999 || INTVAL (plus1) < m68hc11_min_offset)
5000 cost = 3;
5001 else if (INTVAL (plus1) >= m68hc11_max_offset)
5002 cost = 2;
5003 else
5004 cost = 0;
5005 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5006 cost += 0;
5007 else
5008 cost += 1;
5009 break;
5011 case SYMBOL_REF:
5012 cost = 8;
5013 break;
5015 case CONST:
5016 case LABEL_REF:
5017 cost = 0;
5018 break;
5020 default:
5021 break;
5023 break;
5025 case PRE_DEC:
5026 case PRE_INC:
5027 if (SP_REG_P (XEXP (addr, 0)))
5028 cost = 1;
5029 break;
5031 default:
5032 break;
5034 if (debug_m6811)
5036 printf ("Address cost: %d for :", cost);
5037 fflush (stdout);
5038 debug_rtx (addr);
5041 return cost;
5044 static int
5045 m68hc11_shift_cost (mode, x, shift)
5046 enum machine_mode mode;
5047 rtx x;
5048 int shift;
5050 int total;
5052 total = rtx_cost (x, SET);
5053 if (mode == QImode)
5054 total += m68hc11_cost->shiftQI_const[shift % 8];
5055 else if (mode == HImode)
5056 total += m68hc11_cost->shiftHI_const[shift % 16];
5057 else if (shift == 8 || shift == 16 || shift == 32)
5058 total += m68hc11_cost->shiftHI_const[8];
5059 else if (shift != 0 && shift != 16 && shift != 32)
5061 total += m68hc11_cost->shiftHI_const[1] * shift;
5064 /* For SI and others, the cost is higher. */
5065 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5066 total *= GET_MODE_SIZE (mode) / 2;
5068 /* When optimizing for size, make shift more costly so that
5069 multiplications are preferred. */
5070 if (optimize_size && (shift % 8) != 0)
5071 total *= 2;
5073 return total;
5077 m68hc11_rtx_costs (x, code, outer_code)
5078 rtx x;
5079 enum rtx_code code;
5080 enum rtx_code outer_code ATTRIBUTE_UNUSED;
5082 enum machine_mode mode = GET_MODE (x);
5083 int extra_cost = 0;
5084 int total;
5086 switch (code)
5088 case ROTATE:
5089 case ROTATERT:
5090 case ASHIFT:
5091 case LSHIFTRT:
5092 case ASHIFTRT:
5093 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5095 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5098 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5099 total += m68hc11_cost->shift_var;
5100 return total;
5102 case AND:
5103 case XOR:
5104 case IOR:
5105 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5106 total += m68hc11_cost->logical;
5108 /* Logical instructions are byte instructions only. */
5109 total *= GET_MODE_SIZE (mode);
5110 return total;
5112 case MINUS:
5113 case PLUS:
5114 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5115 total += m68hc11_cost->add;
5116 if (GET_MODE_SIZE (mode) > 2)
5118 total *= GET_MODE_SIZE (mode) / 2;
5120 return total;
5122 case UDIV:
5123 case DIV:
5124 case MOD:
5125 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5126 switch (mode)
5128 case QImode:
5129 total += m68hc11_cost->divQI;
5130 break;
5132 case HImode:
5133 total += m68hc11_cost->divHI;
5134 break;
5136 case SImode:
5137 default:
5138 total += m68hc11_cost->divSI;
5139 break;
5141 return total;
5143 case MULT:
5144 /* mul instruction produces 16-bit result. */
5145 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5146 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5147 return m68hc11_cost->multQI
5148 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5149 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5151 /* emul instruction produces 32-bit result for 68HC12. */
5152 if (TARGET_M6812 && mode == SImode
5153 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5154 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5155 return m68hc11_cost->multHI
5156 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5157 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5159 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5160 switch (mode)
5162 case QImode:
5163 total += m68hc11_cost->multQI;
5164 break;
5166 case HImode:
5167 total += m68hc11_cost->multHI;
5168 break;
5170 case SImode:
5171 default:
5172 total += m68hc11_cost->multSI;
5173 break;
5175 return total;
5177 case NEG:
5178 case SIGN_EXTEND:
5179 extra_cost = COSTS_N_INSNS (2);
5181 /* Fall through */
5182 case NOT:
5183 case COMPARE:
5184 case ABS:
5185 case ZERO_EXTEND:
5186 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5187 if (mode == QImode)
5189 return total + COSTS_N_INSNS (1);
5191 if (mode == HImode)
5193 return total + COSTS_N_INSNS (2);
5195 if (mode == SImode)
5197 return total + COSTS_N_INSNS (4);
5199 return total + COSTS_N_INSNS (8);
5201 case IF_THEN_ELSE:
5202 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5203 return COSTS_N_INSNS (1);
5205 return COSTS_N_INSNS (1);
5207 default:
5208 return COSTS_N_INSNS (4);
5213 /* print_options - called at the start of the code generation for a
5214 module. */
5216 extern char *asm_file_name;
5218 #include <time.h>
5219 #include <sys/types.h>
5221 static void
5222 print_options (out)
5223 FILE *out;
5225 const char *a_time;
5226 long c_time;
5227 int i;
5228 extern int save_argc;
5229 extern char **save_argv;
5231 fprintf (out, ";;; Command:\t");
5232 for (i = 0; i < save_argc; i++)
5234 fprintf (out, "%s", save_argv[i]);
5235 if (i + 1 < save_argc)
5236 fprintf (out, " ");
5238 fprintf (out, "\n");
5239 c_time = time (0);
5240 a_time = ctime (&c_time);
5241 fprintf (out, ";;; Compiled:\t%s", a_time);
5242 #ifdef __GNUC__
5243 #ifndef __VERSION__
5244 #define __VERSION__ "[unknown]"
5245 #endif
5246 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
5247 #else
5248 fprintf (out, ";;; (META)compiled by CC.\n");
5249 #endif
5252 void
5253 m68hc11_asm_file_start (out, main_file)
5254 FILE *out;
5255 const char *main_file;
5257 fprintf (out, ";;;-----------------------------------------\n");
5258 fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
5259 fprintf (out, ";;; gcc compiler %s\n", version_string);
5260 print_options (out);
5261 fprintf (out, ";;;-----------------------------------------\n");
5262 output_file_directive (out, main_file);
5266 static void
5267 m68hc11_add_gc_roots ()
5269 ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
5270 ggc_add_rtx_root (&ix_reg, 1);
5271 ggc_add_rtx_root (&iy_reg, 1);
5272 ggc_add_rtx_root (&d_reg, 1);
5273 ggc_add_rtx_root (&da_reg, 1);
5274 ggc_add_rtx_root (&z_reg, 1);
5275 ggc_add_rtx_root (&z_reg_qi, 1);
5276 ggc_add_rtx_root (&stack_push_word, 1);
5277 ggc_add_rtx_root (&stack_pop_word, 1);
5280 static void
5281 m68hc11_asm_out_constructor (symbol, priority)
5282 rtx symbol;
5283 int priority;
5285 default_ctor_section_asm_out_constructor (symbol, priority);
5286 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5289 static void
5290 m68hc11_asm_out_destructor (symbol, priority)
5291 rtx symbol;
5292 int priority;
5294 default_dtor_section_asm_out_destructor (symbol, priority);
5295 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");