Use byte offsets in SUBREGs instead of words.
[gcc.git] / gcc / config / m68hc11 / m68hc11.c
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)
4
5 This file is part of GNU CC.
6
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.
11
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.
16
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.
21
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.
28
29 The gcc 2.6.3 port is available at:
30
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
32
33 */
34
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
56 static void print_options PARAMS ((FILE *));
57 static void emit_move_after_reload PARAMS ((rtx, rtx, rtx));
58 static rtx simplify_logical PARAMS ((enum machine_mode, int, rtx, rtx *));
59 static void m68hc11_emit_logical PARAMS ((enum machine_mode, int, rtx *));
60 static int go_if_legitimate_address_internal PARAMS((rtx, enum machine_mode,
61 int));
62 static int register_indirect_p PARAMS((rtx, enum machine_mode, int));
63 static rtx m68hc11_expand_compare PARAMS((enum rtx_code, rtx, rtx));
64 static int must_parenthesize PARAMS ((rtx));
65
66 static int m68hc11_auto_inc_p PARAMS ((rtx));
67
68 void create_regs_rtx PARAMS ((void));
69
70 static void asm_print_register PARAMS ((FILE *, int));
71
72 rtx m68hc11_soft_tmp_reg;
73
74 /* Must be set to 1 to produce debug messages. */
75 int debug_m6811 = 0;
76
77 extern FILE *asm_out_file;
78
79 rtx ix_reg;
80 rtx iy_reg;
81 rtx d_reg;
82 rtx da_reg;
83 rtx stack_push_word;
84 rtx stack_pop_word;
85 static int regs_inited = 0;
86 static rtx z_reg;
87
88 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
89 int current_function_interrupt;
90
91 /* Set to 1 by expand_prologue() when the function is a trap handler. */
92 int current_function_trap;
93
94 /* Min offset that is valid for the indirect addressing mode. */
95 HOST_WIDE_INT m68hc11_min_offset = 0;
96
97 /* Max offset that is valid for the indirect addressing mode. */
98 HOST_WIDE_INT m68hc11_max_offset = 256;
99
100 /* The class value for base registers. */
101 enum reg_class m68hc11_base_reg_class = A_REGS;
102
103 /* The class value for index registers. This is NO_REGS for 68HC11. */
104 enum reg_class m68hc11_index_reg_class = NO_REGS;
105
106 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
107
108 /* Tables that tell whether a given hard register is valid for
109 a base or an index register. It is filled at init time depending
110 on the target processor. */
111 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
112 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
113
114 /* A correction offset which is applied to the stack pointer.
115 This is 1 for 68HC11 and 0 for 68HC12. */
116 int m68hc11_sp_correction;
117
118 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
119 rtx m68hc11_compare_op0;
120 rtx m68hc11_compare_op1;
121 \f
122
123 /* Machine specific options */
124
125 const char *m68hc11_regparm_string;
126 const char *m68hc11_reg_alloc_order;
127 const char *m68hc11_soft_reg_count;
128
129 static void m68hc11_add_gc_roots PARAMS ((void));
130
131 static int nb_soft_regs;
132
133 /* Flag defined in c-decl.c
134
135 Nonzero means don't recognize the non-ANSI builtin functions.
136 -ansi sets this.
137
138 It is set by 'm68hc11_override_options' to ensure that bcmp() and
139 bzero() are not defined. Their prototype are wrong and they
140 conflict with newlib definition. Don't define as external to
141 avoid a link problem for f77. */
142 int flag_no_nonansi_builtin;
143
144 int
145 m68hc11_override_options ()
146 {
147 m68hc11_add_gc_roots ();
148
149 flag_no_nonansi_builtin = 1;
150
151 memset (m68hc11_reg_valid_for_index, 0,
152 sizeof (m68hc11_reg_valid_for_index));
153 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
154
155 /* Configure for a 68hc11 processor. */
156 if (TARGET_M6811)
157 {
158 /* If gcc was built for a 68hc12, invalidate that because
159 a -m68hc11 option was specified on the command line. */
160 if (TARGET_DEFAULT != MASK_M6811)
161 target_flags &= ~TARGET_DEFAULT;
162
163 m68hc11_min_offset = 0;
164 m68hc11_max_offset = 256;
165 m68hc11_index_reg_class = NO_REGS;
166 m68hc11_base_reg_class = A_REGS;
167 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
168 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
169 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
170 m68hc11_sp_correction = 1;
171 m68hc11_tmp_regs_class = D_REGS;
172 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
173 m68hc11_soft_reg_count = "4";
174 }
175
176 /* Configure for a 68hc12 processor. */
177 if (TARGET_M6812)
178 {
179 m68hc11_min_offset = 0;
180 m68hc11_max_offset = 65536;
181 m68hc11_index_reg_class = D_REGS;
182 m68hc11_base_reg_class = A_OR_SP_REGS;
183 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
184 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
185 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
186 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
187 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
188 m68hc11_sp_correction = 0;
189 m68hc11_tmp_regs_class = TMP_REGS;
190 target_flags &= ~MASK_M6811;
191 if (m68hc11_soft_reg_count == 0)
192 m68hc11_soft_reg_count = "2";
193 }
194 return 0;
195 }
196
197
198 void
199 m68hc11_conditional_register_usage ()
200 {
201 int i;
202 int cnt = atoi (m68hc11_soft_reg_count);
203
204 if (cnt < 0)
205 cnt = 0;
206 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
207 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
208
209 nb_soft_regs = cnt;
210 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
211 {
212 fixed_regs[i] = 1;
213 call_used_regs[i] = 1;
214 }
215 }
216 \f
217
218 /* Reload and register operations. */
219
220 static const char *reg_class_names[] = REG_CLASS_NAMES;
221
222
223 void
224 create_regs_rtx ()
225 {
226 /* regs_inited = 1; */
227 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
228 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
229 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
230 da_reg = gen_rtx (REG, QImode, HARD_A_REGNUM);
231 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
232
233 stack_push_word = gen_rtx (MEM, HImode,
234 gen_rtx (PRE_DEC, HImode,
235 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
236 stack_pop_word = gen_rtx (MEM, HImode,
237 gen_rtx (POST_INC, HImode,
238 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
239
240 }
241
242 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
243 - 8 bit values are stored anywhere (except the SP register).
244 - 16 bit values can be stored in any register whose mode is 16
245 - 32 bit values can be stored in D, X registers or in a soft register
246 (except the last one because we need 2 soft registers)
247 - Values whose size is > 32 bit are not stored in real hard
248 registers. They may be stored in soft registers if there are
249 enough of them. */
250 int
251 hard_regno_mode_ok (regno, mode)
252 int regno;
253 enum machine_mode mode;
254 {
255 switch (GET_MODE_SIZE (mode))
256 {
257 case 8:
258 return S_REGNO_P (regno) && nb_soft_regs >= 4;
259
260 case 4:
261 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
262
263 case 2:
264 return G_REGNO_P (regno);
265
266 case 1:
267 /* We have to accept a QImode in X or Y registers. Otherwise, the
268 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
269 in the insns. Reload fails if the insn rejects the register class 'a'
270 as well as if it accepts it. Patterns that failed were
271 zero_extend_qihi2 and iorqi3. */
272
273 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
274
275 default:
276 return 0;
277 }
278 }
279
280 enum reg_class
281 limit_reload_class (mode, class)
282 enum machine_mode mode;
283 enum reg_class class;
284 {
285 if (mode == Pmode)
286 {
287 if (class == m68hc11_base_reg_class || class == SP_REGS
288 || class == Y_REGS || class == X_REGS
289 || class == X_OR_SP_REGS || class == Y_OR_S_REGS
290 || class == A_OR_SP_REGS)
291 return class;
292
293 if (debug_m6811)
294 {
295 printf ("Forcing to A_REGS\n");
296 fflush (stdout);
297 }
298 return m68hc11_base_reg_class;
299 }
300 return class;
301 }
302
303 enum reg_class
304 preferred_reload_class (operand, class)
305 rtx operand;
306 enum reg_class class;
307 {
308 enum machine_mode mode;
309
310 mode = GET_MODE (operand);
311
312 if (debug_m6811)
313 {
314 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
315 }
316
317 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
318 return m68hc11_base_reg_class;
319
320 if (class >= S_REGS && (GET_CODE (operand) == MEM
321 || GET_CODE (operand) == CONST_INT))
322 {
323 /* S_REGS class must not be used. The movhi template does not
324 work to move a memory to a soft register.
325 Restrict to a hard reg. */
326 switch (class)
327 {
328 default:
329 case G_REGS:
330 case D_OR_A_OR_S_REGS:
331 class = A_OR_D_REGS;
332 break;
333 case A_OR_S_REGS:
334 class = A_REGS;
335 break;
336 case D_OR_SP_OR_S_REGS:
337 class = D_OR_SP_REGS;
338 break;
339 case D_OR_Y_OR_S_REGS:
340 class = D_OR_Y_REGS;
341 break;
342 case D_OR_X_OR_S_REGS:
343 class = D_OR_X_REGS;
344 break;
345 case SP_OR_S_REGS:
346 class = SP_REGS;
347 break;
348 case Y_OR_S_REGS:
349 class = Y_REGS;
350 break;
351 case X_OR_S_REGS:
352 class = X_REGS;
353 break;
354 case D_OR_S_REGS:
355 class = D_REGS;
356 }
357 }
358 else if (class == Y_REGS && GET_CODE (operand) == MEM)
359 {
360 class = Y_REGS;
361 }
362 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
363 {
364 class = D_OR_X_REGS;
365 }
366 else if (class >= S_REGS && S_REG_P (operand))
367 {
368 switch (class)
369 {
370 default:
371 case G_REGS:
372 case D_OR_A_OR_S_REGS:
373 class = A_OR_D_REGS;
374 break;
375 case A_OR_S_REGS:
376 class = A_REGS;
377 break;
378 case D_OR_SP_OR_S_REGS:
379 class = D_OR_SP_REGS;
380 break;
381 case D_OR_Y_OR_S_REGS:
382 class = D_OR_Y_REGS;
383 break;
384 case D_OR_X_OR_S_REGS:
385 class = D_OR_X_REGS;
386 break;
387 case SP_OR_S_REGS:
388 class = SP_REGS;
389 break;
390 case Y_OR_S_REGS:
391 class = Y_REGS;
392 break;
393 case X_OR_S_REGS:
394 class = X_REGS;
395 break;
396 case D_OR_S_REGS:
397 class = D_REGS;
398 }
399 }
400 else if (class >= S_REGS)
401 {
402 if (debug_m6811)
403 {
404 printf ("Class = %s for: ", reg_class_names[class]);
405 fflush (stdout);
406 debug_rtx (operand);
407 }
408 }
409
410 if (debug_m6811)
411 {
412 printf (" => class=%s\n", reg_class_names[class]);
413 fflush (stdout);
414 debug_rtx (operand);
415 }
416
417 return class;
418 }
419
420 /* Return 1 if the operand is a valid indexed addressing mode.
421 For 68hc11: n,r with n in [0..255] and r in A_REGS class
422 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
423 static int
424 register_indirect_p (operand, mode, strict)
425 rtx operand;
426 enum machine_mode mode;
427 int strict;
428 {
429 rtx base, offset;
430
431 switch (GET_CODE (operand))
432 {
433 case POST_INC:
434 case PRE_INC:
435 case POST_DEC:
436 case PRE_DEC:
437 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
438 return register_indirect_p (XEXP (operand, 0), mode, strict);
439 return 0;
440
441 case PLUS:
442 base = XEXP (operand, 0);
443 if (GET_CODE (base) == MEM)
444 return 0;
445
446 offset = XEXP (operand, 1);
447 if (GET_CODE (offset) == MEM)
448 return 0;
449
450 if (GET_CODE (base) == REG)
451 {
452 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
453 return 0;
454
455 if (strict == 0)
456 return 1;
457
458 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
459 }
460 if (GET_CODE (offset) == REG)
461 {
462 if (!VALID_CONSTANT_OFFSET_P (base, mode))
463 return 0;
464
465 if (strict == 0)
466 return 1;
467
468 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
469 }
470 return 0;
471
472 case REG:
473 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
474
475 default:
476 return 0;
477 }
478 }
479
480 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
481 a 68HC12 1-byte index addressing mode. */
482 int
483 m68hc11_small_indexed_indirect_p (operand, mode)
484 rtx operand;
485 enum machine_mode mode;
486 {
487 rtx base, offset;
488
489 if (GET_CODE (operand) != MEM)
490 return 0;
491
492 operand = XEXP (operand, 0);
493 if (CONSTANT_ADDRESS_P (operand))
494 return 1;
495
496 if (PUSH_POP_ADDRESS_P (operand))
497 return 1;
498
499 if (!register_indirect_p (operand, mode,
500 (reload_completed | reload_in_progress)))
501 return 0;
502
503 if (TARGET_M6812 && GET_CODE (operand) == PLUS
504 && (reload_completed | reload_in_progress))
505 {
506 base = XEXP (operand, 0);
507 offset = XEXP (operand, 1);
508 if (GET_CODE (base) == CONST_INT)
509 offset = base;
510
511 switch (GET_MODE_SIZE (mode))
512 {
513 case 8:
514 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
515 return 0;
516 break;
517
518 case 4:
519 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
520 return 0;
521 break;
522
523 default:
524 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
525 return 0;
526 break;
527 }
528 }
529 return 1;
530 }
531
532 int
533 m68hc11_register_indirect_p (operand, mode)
534 rtx operand;
535 enum machine_mode mode;
536 {
537 if (GET_CODE (operand) != MEM)
538 return 0;
539
540 operand = XEXP (operand, 0);
541 return register_indirect_p (operand, mode,
542 (reload_completed | reload_in_progress));
543 }
544
545 static int
546 go_if_legitimate_address_internal (operand, mode, strict)
547 rtx operand;
548 enum machine_mode mode;
549 int strict;
550 {
551 if (CONSTANT_ADDRESS_P (operand))
552 {
553 /* Reject the global variables if they are too wide. This forces
554 a load of their address in a register and generates smaller code. */
555 if (GET_MODE_SIZE (mode) == 8)
556 return 0;
557
558 return 1;
559 }
560 if (register_indirect_p (operand, mode, strict))
561 {
562 return 1;
563 }
564 if (PUSH_POP_ADDRESS_P (operand))
565 {
566 return 1;
567 }
568 if (symbolic_memory_operand (operand, mode))
569 {
570 return 1;
571 }
572 return 0;
573 }
574
575 int
576 m68hc11_go_if_legitimate_address (operand, mode, strict)
577 rtx operand;
578 enum machine_mode mode;
579 int strict;
580 {
581 int result;
582
583 if (debug_m6811)
584 {
585 printf ("Checking: ");
586 fflush (stdout);
587 debug_rtx (operand);
588 }
589
590 result = go_if_legitimate_address_internal (operand, mode, strict);
591
592 if (debug_m6811)
593 {
594 printf (" -> %s\n", result == 0 ? "NO" : "YES");
595 }
596
597 if (result == 0)
598 {
599 if (debug_m6811)
600 {
601 printf ("go_if_legitimate%s, ret 0: %d:",
602 (strict ? "_strict" : ""), mode);
603 fflush (stdout);
604 debug_rtx (operand);
605 }
606 }
607 return result;
608 }
609
610 int
611 m68hc11_legitimize_address (operand, old_operand, mode)
612 rtx *operand ATTRIBUTE_UNUSED;
613 rtx old_operand ATTRIBUTE_UNUSED;
614 enum machine_mode mode ATTRIBUTE_UNUSED;
615 {
616 return 0;
617 }
618
619
620 int
621 m68hc11_reload_operands (operands)
622 rtx operands[];
623 {
624 enum machine_mode mode;
625
626 if (regs_inited == 0)
627 create_regs_rtx ();
628
629 mode = GET_MODE (operands[1]);
630
631 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
632 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
633 {
634 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
635 rtx base = XEXP (XEXP (operands[1], 0), 0);
636
637 if (GET_CODE (base) != REG)
638 {
639 rtx tmp = base;
640 base = big_offset;
641 big_offset = tmp;
642 }
643
644 /* If the offset is out of range, we have to compute the address
645 with a separate add instruction. We try to do with with an 8-bit
646 add on the A register. This is possible only if the lowest part
647 of the offset (ie, big_offset % 256) is a valid constant offset
648 with respect to the mode. If it's not, we have to generate a
649 16-bit add on the D register. From:
650
651 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
652
653 we generate:
654
655 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
656 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
657 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
658 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
659
660 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
661 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
662
663 */
664 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
665 {
666 int vh, vl;
667 rtx reg = operands[0];
668 rtx offset;
669 int val = INTVAL (big_offset);
670
671
672 /* We use the 'operands[0]' as a scratch register to compute the
673 address. Make sure 'base' is in that register. */
674 if (!rtx_equal_p (base, operands[0]))
675 {
676 emit_move_insn (reg, base);
677 }
678
679 if (val > 0)
680 {
681 vh = val >> 8;
682 vl = val & 0x0FF;
683 }
684 else
685 {
686 vh = (val >> 8) & 0x0FF;
687 vl = val & 0x0FF;
688 }
689
690 /* Create the lowest part offset that still remains to be added.
691 If it's not a valid offset, do a 16-bit add. */
692 offset = gen_rtx (CONST_INT, VOIDmode, vl);
693 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
694 {
695 emit_insn (gen_rtx (SET, VOIDmode, reg,
696 gen_rtx (PLUS, HImode, reg, big_offset)));
697 offset = const0_rtx;
698 }
699 else
700 {
701 emit_insn (gen_rtx (SET, VOIDmode, reg,
702 gen_rtx (PLUS, HImode, reg,
703 gen_rtx (CONST_INT,
704 VOIDmode, vh << 8))));
705 }
706 emit_move_insn (operands[0],
707 gen_rtx (MEM, GET_MODE (operands[1]),
708 gen_rtx (PLUS, Pmode, reg, offset)));
709 return 1;
710 }
711 }
712
713 /* Use the normal gen_movhi pattern. */
714 return 0;
715 }
716
717 void
718 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
719 const char *name;
720 enum rtx_code code;
721 enum machine_mode dmode;
722 enum machine_mode smode;
723 int noperands;
724 rtx *operands;
725 {
726 rtx ret;
727 rtx insns;
728 rtx libcall;
729 rtx equiv;
730
731 start_sequence ();
732 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
733 switch (noperands)
734 {
735 case 2:
736 ret = emit_library_call_value (libcall, NULL_RTX, 1, dmode, 1,
737 operands[1], smode);
738 equiv = gen_rtx (code, dmode, operands[1]);
739 break;
740
741 case 3:
742 ret = emit_library_call_value (libcall, operands[0], 1, dmode, 2,
743 operands[1], smode, operands[2],
744 smode);
745 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
746 break;
747
748 default:
749 abort ();
750 }
751
752 insns = get_insns ();
753 end_sequence ();
754 emit_libcall_block (insns, operands[0], ret, equiv);
755 }
756
757 /* Returns true if X is a PRE/POST increment decrement
758 (same as auto_inc_p() in rtlanal.c but do not take into
759 account the stack). */
760 static int
761 m68hc11_auto_inc_p (x)
762 rtx x;
763 {
764 return GET_CODE (x) == PRE_DEC
765 || GET_CODE (x) == POST_INC
766 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
767 }
768 \f
769
770 /* Predicates for machine description. */
771
772 int
773 memory_reload_operand (operand, mode)
774 rtx operand;
775 enum machine_mode mode ATTRIBUTE_UNUSED;
776 {
777 return GET_CODE (operand) == MEM
778 && GET_CODE (XEXP (operand, 0)) == PLUS
779 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
780 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
781 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
782 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
783 }
784
785 int
786 tst_operand (operand, mode)
787 rtx operand;
788 enum machine_mode mode;
789 {
790 if (GET_CODE (operand) == MEM)
791 {
792 rtx addr = XEXP (operand, 0);
793 if (m68hc11_auto_inc_p (addr))
794 return 0;
795 }
796 return nonimmediate_operand (operand, mode);
797 }
798
799 int
800 cmp_operand (operand, mode)
801 rtx operand;
802 enum machine_mode mode;
803 {
804 if (GET_CODE (operand) == MEM)
805 {
806 rtx addr = XEXP (operand, 0);
807 if (m68hc11_auto_inc_p (addr))
808 return 0;
809 }
810 return general_operand (operand, mode);
811 }
812
813 int
814 non_push_operand (operand, mode)
815 rtx operand;
816 enum machine_mode mode;
817 {
818 if (general_operand (operand, mode) == 0)
819 return 0;
820
821 if (push_operand (operand, mode) == 1)
822 return 0;
823 return 1;
824 }
825
826 int
827 reg_or_some_mem_operand (operand, mode)
828 rtx operand;
829 enum machine_mode mode;
830 {
831 if (GET_CODE (operand) == MEM)
832 {
833 rtx op = XEXP (operand, 0);
834
835 if (symbolic_memory_operand (op, mode))
836 return 1;
837
838 if (IS_STACK_PUSH (operand))
839 return 1;
840
841 if (m68hc11_register_indirect_p (operand, mode))
842 return 1;
843
844 return 0;
845 }
846
847 return register_operand (operand, mode);
848 }
849
850 int
851 stack_register_operand (operand, mode)
852 rtx operand;
853 enum machine_mode mode ATTRIBUTE_UNUSED;
854 {
855 return SP_REG_P (operand);
856 }
857
858 int
859 d_register_operand (operand, mode)
860 rtx operand;
861 enum machine_mode mode ATTRIBUTE_UNUSED;
862 {
863 if (GET_CODE (operand) == SUBREG)
864 operand = XEXP (operand, 0);
865
866 return GET_CODE (operand) == REG
867 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
868 || REGNO (operand) == HARD_D_REGNUM);
869 }
870
871 int
872 hard_addr_reg_operand (operand, mode)
873 rtx operand;
874 enum machine_mode mode ATTRIBUTE_UNUSED;
875 {
876 if (GET_CODE (operand) == SUBREG)
877 operand = XEXP (operand, 0);
878
879 return GET_CODE (operand) == REG
880 && (REGNO (operand) == HARD_X_REGNUM
881 || REGNO (operand) == HARD_Y_REGNUM
882 || REGNO (operand) == HARD_Z_REGNUM);
883 }
884
885 int
886 hard_reg_operand (operand, mode)
887 rtx operand;
888 enum machine_mode mode ATTRIBUTE_UNUSED;
889 {
890 if (GET_CODE (operand) == SUBREG)
891 operand = XEXP (operand, 0);
892
893 return GET_CODE (operand) == REG
894 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
895 || H_REGNO_P (REGNO (operand)));
896 }
897
898 int
899 memory_indexed_operand (operand, mode)
900 rtx operand;
901 enum machine_mode mode ATTRIBUTE_UNUSED;
902 {
903 if (GET_CODE (operand) != MEM)
904 return 0;
905
906 operand = XEXP (operand, 0);
907 if (GET_CODE (operand) == PLUS)
908 {
909 if (GET_CODE (XEXP (operand, 0)) == REG)
910 operand = XEXP (operand, 0);
911 else if (GET_CODE (XEXP (operand, 1)) == REG)
912 operand = XEXP (operand, 1);
913 }
914 return GET_CODE (operand) == REG
915 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
916 || A_REGNO_P (REGNO (operand)));
917 }
918
919 int
920 push_pop_operand_p (operand)
921 rtx operand;
922 {
923 if (GET_CODE (operand) != MEM)
924 {
925 return 0;
926 }
927 operand = XEXP (operand, 0);
928 return PUSH_POP_ADDRESS_P (operand);
929 }
930
931 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
932 reference and a constant. */
933
934 int
935 symbolic_memory_operand (op, mode)
936 register rtx op;
937 enum machine_mode mode;
938 {
939 switch (GET_CODE (op))
940 {
941 case SYMBOL_REF:
942 case LABEL_REF:
943 return 1;
944
945 case CONST:
946 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
947 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
948 && GET_CODE (XEXP (op, 1)) == CONST_INT);
949
950 /* ??? This clause seems to be irrelevant. */
951 case CONST_DOUBLE:
952 return GET_MODE (op) == mode;
953
954 case PLUS:
955 return symbolic_memory_operand (XEXP (op, 0), mode)
956 && symbolic_memory_operand (XEXP (op, 1), mode);
957
958 default:
959 return 0;
960 }
961 }
962
963 int
964 m68hc11_logical_operator (op, mode)
965 register rtx op;
966 enum machine_mode mode ATTRIBUTE_UNUSED;
967 {
968 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
969 }
970
971 int
972 m68hc11_arith_operator (op, mode)
973 register rtx op;
974 enum machine_mode mode ATTRIBUTE_UNUSED;
975 {
976 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
977 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
978 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
979 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
980 || GET_CODE (op) == ROTATERT;
981 }
982
983 int
984 m68hc11_non_shift_operator (op, mode)
985 register rtx op;
986 enum machine_mode mode ATTRIBUTE_UNUSED;
987 {
988 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
989 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
990 }
991
992
993 int
994 m68hc11_unary_operator (op, mode)
995 register rtx op;
996 enum machine_mode mode ATTRIBUTE_UNUSED;
997 {
998 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
999 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1000 }
1001 \f
1002
1003 /* Profiling. */
1004
1005 int
1006 m68hc11_block_profiler (out, blockno)
1007 FILE *out ATTRIBUTE_UNUSED;
1008 int blockno ATTRIBUTE_UNUSED;
1009 {
1010 return 0;
1011 }
1012
1013 int
1014 m68hc11_function_block_profiler (out, block_or_label)
1015 FILE *out ATTRIBUTE_UNUSED;
1016 int block_or_label ATTRIBUTE_UNUSED;
1017 {
1018 return 0;
1019 }
1020 \f
1021 /* Declaration of types. */
1022
1023 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1024 with arguments ARGS is a valid machine specific attribute for DECL.
1025 The attributes in ATTRIBUTES have previously been assigned to DECL. */
1026
1027 int
1028 m68hc11_valid_decl_attribute_p (decl, attributes, identifier, args)
1029 tree decl ATTRIBUTE_UNUSED;
1030 tree attributes ATTRIBUTE_UNUSED;
1031 tree identifier ATTRIBUTE_UNUSED;
1032 tree args ATTRIBUTE_UNUSED;
1033 {
1034 return 0;
1035 }
1036
1037 /* If defined, a C expression whose value is nonzero if IDENTIFIER
1038 with arguments ARGS is a valid machine specific attribute for TYPE.
1039 The attributes in ATTRIBUTES have previously been assigned to TYPE. */
1040
1041 int
1042 m68hc11_valid_type_attribute_p (type, attributes, identifier, args)
1043 tree type;
1044 tree attributes ATTRIBUTE_UNUSED;
1045 tree identifier;
1046 tree args;
1047 {
1048 if (TREE_CODE (type) != FUNCTION_TYPE
1049 && TREE_CODE (type) != FIELD_DECL && TREE_CODE (type) != TYPE_DECL)
1050 return 0;
1051
1052 if (TREE_CODE (type) == FUNCTION_TYPE)
1053 {
1054 if (is_attribute_p ("interrupt", identifier))
1055 return (args == NULL_TREE);
1056 if (is_attribute_p ("trap", identifier))
1057 return (args == NULL_TREE);
1058 }
1059
1060 return 0;
1061 }
1062
1063 /* If defined, a C expression whose value is zero if the attributes on
1064 TYPE1 and TYPE2 are incompatible, one if they are compatible, and
1065 two if they are nearly compatible (which causes a warning to be
1066 generated). */
1067
1068 int
1069 m68hc11_comp_type_attributes (type1, type2)
1070 tree type1 ATTRIBUTE_UNUSED;
1071 tree type2 ATTRIBUTE_UNUSED;
1072 {
1073 return 1;
1074 }
1075
1076 /* If defined, a C statement that assigns default attributes to newly
1077 defined TYPE. */
1078
1079 void
1080 m68hc11_set_default_type_attributes (type)
1081 tree type ATTRIBUTE_UNUSED;
1082 {
1083 }
1084
1085 /* Define this macro if references to a symbol must be treated
1086 differently depending on something about the variable or function
1087 named by the symbol (such as what section it is in).
1088
1089 For the 68HC11, we want to recognize trap handlers so that we
1090 handle calls to traps in a special manner (by issuing the trap).
1091 This information is stored in SYMBOL_REF_FLAG. */
1092 void
1093 m68hc11_encode_section_info (decl)
1094 tree decl;
1095 {
1096 tree func_attr;
1097 int trap_handler;
1098 rtx rtl;
1099
1100 if (TREE_CODE (decl) != FUNCTION_DECL)
1101 return;
1102
1103 rtl = DECL_RTL (decl);
1104
1105 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1106 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1107 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = trap_handler;
1108 }
1109 \f
1110
1111 /* Argument support functions. */
1112
1113 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1114 Arrays are passed by references and other types by value.
1115
1116 SCz: I tried to pass DImode by reference but it seems that this
1117 does not work very well. */
1118 int
1119 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1120 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1121 enum machine_mode mode ATTRIBUTE_UNUSED;
1122 tree type;
1123 int named ATTRIBUTE_UNUSED;
1124 {
1125 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1126 /* Consider complex values as aggregates, so care for TCmode. */
1127 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1128 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1129 }
1130
1131
1132 /* Define the offset between two registers, one to be eliminated, and the
1133 other its replacement, at the start of a routine. */
1134 int
1135 m68hc11_initial_elimination_offset (from, to)
1136 int from;
1137 int to;
1138 {
1139 int trap_handler;
1140 tree func_attr;
1141 int size;
1142 int regno;
1143
1144 /* For a trap handler, we must take into account the registers which
1145 are pushed on the stack during the trap (except the PC). */
1146 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1147 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1148 if (trap_handler && from == ARG_POINTER_REGNUM)
1149 size = 7;
1150 else
1151 size = 0;
1152
1153 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1154 {
1155 /* 2 is for the saved frame.
1156 1 is for the 'sts' correction when creating the frame. */
1157 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1158 }
1159
1160 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1161 {
1162 return 0;
1163 }
1164
1165 /* Push any 2 byte pseudo hard registers that we need to save. */
1166 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1167 {
1168 if (regs_ever_live[regno] && !call_used_regs[regno])
1169 {
1170 size += 2;
1171 }
1172 }
1173
1174 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1175 {
1176 return get_frame_size () + size;
1177 }
1178
1179 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1180 {
1181 return size - m68hc11_sp_correction;
1182 }
1183 return 0;
1184 }
1185
1186 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1187 for a call to a function whose data type is FNTYPE.
1188 For a library call, FNTYPE is 0. */
1189
1190 void
1191 m68hc11_init_cumulative_args (cum, fntype, libname)
1192 CUMULATIVE_ARGS *cum;
1193 tree fntype;
1194 rtx libname;
1195 {
1196 tree ret_type;
1197
1198 z_replacement_completed = 0;
1199 cum->words = 0;
1200 cum->nregs = 0;
1201
1202 /* For a library call, we must find out the type of the return value.
1203 When the return value is bigger than 4 bytes, it is returned in
1204 memory. In that case, the first argument of the library call is a
1205 pointer to the memory location. Because the first argument is passed in
1206 register D, we have to identify this, so that the first function
1207 parameter is not passed in D either. */
1208 if (fntype == 0)
1209 {
1210 const char *name;
1211 size_t len;
1212
1213 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1214 return;
1215
1216 /* If the library ends in 'di' or in 'df', we assume it's
1217 returning some DImode or some DFmode which are 64-bit wide. */
1218 name = XSTR (libname, 0);
1219 len = strlen (name);
1220 if (len > 3
1221 && ((name[len - 2] == 'd'
1222 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1223 || (name[len - 3] == 'd'
1224 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1225 {
1226 /* We are in. Mark the first parameter register as already used. */
1227 cum->words = 1;
1228 cum->nregs = 1;
1229 }
1230 return;
1231 }
1232
1233 ret_type = TREE_TYPE (fntype);
1234
1235 if (ret_type && aggregate_value_p (ret_type))
1236 {
1237 cum->words = 1;
1238 cum->nregs = 1;
1239 }
1240 }
1241
1242 /* Update the data in CUM to advance over an argument
1243 of mode MODE and data type TYPE.
1244 (TYPE is null for libcalls where that information may not be available.) */
1245
1246 void
1247 m68hc11_function_arg_advance (cum, mode, type, named)
1248 CUMULATIVE_ARGS *cum;
1249 enum machine_mode mode;
1250 tree type;
1251 int named ATTRIBUTE_UNUSED;
1252 {
1253 if (mode != BLKmode)
1254 {
1255 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1256 {
1257 cum->nregs = 2;
1258 cum->words = GET_MODE_SIZE (mode);
1259 }
1260 else
1261 {
1262 cum->words += GET_MODE_SIZE (mode);
1263 if (cum->words <= HARD_REG_SIZE)
1264 cum->nregs = 1;
1265 }
1266 }
1267 else
1268 {
1269 cum->words += int_size_in_bytes (type);
1270 }
1271 return;
1272 }
1273
1274 /* Define where to put the arguments to a function.
1275 Value is zero to push the argument on the stack,
1276 or a hard register in which to store the argument.
1277
1278 MODE is the argument's machine mode.
1279 TYPE is the data type of the argument (as a tree).
1280 This is null for libcalls where that information may
1281 not be available.
1282 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1283 the preceding args and about the function being called.
1284 NAMED is nonzero if this argument is a named parameter
1285 (otherwise it is an extra parameter matching an ellipsis). */
1286
1287 struct rtx_def *
1288 m68hc11_function_arg (cum, mode, type, named)
1289 const CUMULATIVE_ARGS *cum;
1290 enum machine_mode mode;
1291 tree type ATTRIBUTE_UNUSED;
1292 int named ATTRIBUTE_UNUSED;
1293 {
1294 if (cum->words != 0)
1295 {
1296 return NULL_RTX;
1297 }
1298
1299 if (mode != BLKmode)
1300 {
1301 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1302 return gen_rtx (REG, mode, HARD_X_REGNUM);
1303
1304 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1305 {
1306 return NULL_RTX;
1307 }
1308 return gen_rtx (REG, mode, HARD_D_REGNUM);
1309 }
1310 return NULL_RTX;
1311 }
1312
1313 /* The "standard" implementation of va_start: just assign `nextarg' to
1314 the variable. */
1315 void
1316 m68hc11_expand_builtin_va_start (stdarg_p, valist, nextarg)
1317 int stdarg_p ATTRIBUTE_UNUSED;
1318 tree valist;
1319 rtx nextarg;
1320 {
1321 tree t;
1322
1323 /* SCz: the default implementation in builtins.c adjust the
1324 nextarg using UNITS_PER_WORD. This works only with -mshort
1325 and fails when integers are 32-bit. Here is the correct way. */
1326 if (!stdarg_p)
1327 nextarg = plus_constant (nextarg, -INT_TYPE_SIZE / 8);
1328
1329 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1330 make_tree (ptr_type_node, nextarg));
1331 TREE_SIDE_EFFECTS (t) = 1;
1332
1333 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1334 }
1335
1336 rtx
1337 m68hc11_va_arg (valist, type)
1338 tree valist;
1339 tree type;
1340 {
1341 tree addr_tree, t;
1342 HOST_WIDE_INT align;
1343 HOST_WIDE_INT rounded_size;
1344 rtx addr;
1345 int pad_direction;
1346
1347 /* Compute the rounded size of the type. */
1348 align = PARM_BOUNDARY / BITS_PER_UNIT;
1349 rounded_size = (((int_size_in_bytes (type) + align - 1) / align) * align);
1350
1351 /* Get AP. */
1352 addr_tree = valist;
1353 pad_direction = m68hc11_function_arg_padding (TYPE_MODE (type), type);
1354
1355 if (pad_direction == downward)
1356 {
1357 /* Small args are padded downward. */
1358
1359 HOST_WIDE_INT adj;
1360 adj = TREE_INT_CST_LOW (TYPE_SIZE (type)) / BITS_PER_UNIT;
1361 if (rounded_size > align)
1362 adj = rounded_size;
1363
1364 addr_tree = build (PLUS_EXPR, TREE_TYPE (addr_tree), addr_tree,
1365 build_int_2 (rounded_size - adj, 0));
1366 }
1367
1368 addr = expand_expr (addr_tree, NULL_RTX, Pmode, EXPAND_NORMAL);
1369 addr = copy_to_reg (addr);
1370
1371 /* Compute new value for AP. */
1372 t = build (MODIFY_EXPR, TREE_TYPE (valist), valist,
1373 build (PLUS_EXPR, TREE_TYPE (valist), valist,
1374 build_int_2 (rounded_size, 0)));
1375 TREE_SIDE_EFFECTS (t) = 1;
1376 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
1377
1378 return addr;
1379 }
1380
1381 /* If defined, a C expression which determines whether, and in which direction,
1382 to pad out an argument with extra space. The value should be of type
1383 `enum direction': either `upward' to pad above the argument,
1384 `downward' to pad below, or `none' to inhibit padding.
1385
1386 Structures are stored left shifted in their argument slot. */
1387 int
1388 m68hc11_function_arg_padding (mode, type)
1389 enum machine_mode mode;
1390 tree type;
1391 {
1392 if (type != 0 && AGGREGATE_TYPE_P (type))
1393 return upward;
1394
1395 /* This is the default definition. */
1396 return (!BYTES_BIG_ENDIAN
1397 ? upward
1398 : ((mode == BLKmode
1399 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1400 && int_size_in_bytes (type) <
1401 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1402 PARM_BOUNDARY) ? downward : upward));
1403 }
1404 \f
1405
1406 /* Function prologue and epilogue. */
1407
1408 /* Emit a move after the reload pass has completed. This is used to
1409 emit the prologue and epilogue. */
1410 static void
1411 emit_move_after_reload (to, from, scratch)
1412 rtx to, from, scratch;
1413 {
1414 rtx insn;
1415
1416 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1417 {
1418 insn = emit_move_insn (to, from);
1419 }
1420 else
1421 {
1422 emit_move_insn (scratch, from);
1423 insn = emit_move_insn (to, scratch);
1424 }
1425
1426 /* Put a REG_INC note to tell the flow analysis that the instruction
1427 is necessary. */
1428 if (IS_STACK_PUSH (to))
1429 {
1430 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1431 XEXP (XEXP (to, 0), 0),
1432 REG_NOTES (insn));
1433 }
1434 else if (IS_STACK_POP (from))
1435 {
1436 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1437 XEXP (XEXP (from, 0), 0),
1438 REG_NOTES (insn));
1439 }
1440 }
1441
1442 int
1443 m68hc11_total_frame_size ()
1444 {
1445 int size;
1446 int regno;
1447
1448 size = get_frame_size ();
1449 if (current_function_interrupt)
1450 {
1451 size += 3 * HARD_REG_SIZE;
1452 }
1453 if (frame_pointer_needed)
1454 size += HARD_REG_SIZE;
1455
1456 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1457 if (regs_ever_live[regno] && !call_used_regs[regno])
1458 size += HARD_REG_SIZE;
1459
1460 return size;
1461 }
1462
1463 void
1464 m68hc11_function_epilogue (out, size)
1465 FILE *out ATTRIBUTE_UNUSED;
1466 int size ATTRIBUTE_UNUSED;
1467 {
1468 /* We catch the function epilogue generation to have a chance
1469 to clear the z_replacement_completed flag. */
1470 z_replacement_completed = 0;
1471 }
1472
1473 void
1474 expand_prologue ()
1475 {
1476 tree func_attr;
1477 int size;
1478 int regno;
1479 rtx scratch;
1480
1481 if (reload_completed != 1)
1482 abort ();
1483
1484 size = get_frame_size ();
1485
1486 create_regs_rtx ();
1487
1488 /* Generate specific prologue for interrupt handlers. */
1489 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1490 current_function_interrupt = lookup_attribute ("interrupt",
1491 func_attr) != NULL_TREE;
1492 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1493
1494 /* Get the scratch register to build the frame and push registers.
1495 If the first argument is a 32-bit quantity, the D+X registers
1496 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1497 For 68HC12, this scratch register is not used. */
1498 if (current_function_args_info.nregs == 2)
1499 scratch = iy_reg;
1500 else
1501 scratch = ix_reg;
1502
1503 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1504 Other soft registers in page0 need not to be saved because they
1505 will be restored by C functions. For a trap handler, we don't
1506 need to preserve these registers because this is a synchronous call. */
1507 if (current_function_interrupt)
1508 {
1509 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1510 emit_move_after_reload (stack_push_word,
1511 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1512 emit_move_after_reload (stack_push_word,
1513 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1514 scratch);
1515 }
1516
1517 /* Save current stack frame. */
1518 if (frame_pointer_needed)
1519 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1520
1521 /* Allocate local variables. */
1522 if (TARGET_M6812 && size >= 2)
1523 {
1524 emit_insn (gen_addhi3 (stack_pointer_rtx,
1525 stack_pointer_rtx, GEN_INT (-size)));
1526 }
1527 else if (size > 8)
1528 {
1529 rtx insn;
1530
1531 insn = gen_rtx_PARALLEL
1532 (VOIDmode,
1533 gen_rtvec (2,
1534 gen_rtx_SET (VOIDmode,
1535 stack_pointer_rtx,
1536 gen_rtx_PLUS (HImode,
1537 stack_pointer_rtx,
1538 GEN_INT (-size))),
1539 gen_rtx_CLOBBER (VOIDmode, scratch)));
1540 emit_insn (insn);
1541 }
1542 else
1543 {
1544 int i;
1545
1546 /* Allocate by pushing scratch values. */
1547 for (i = 2; i <= size; i += 2)
1548 emit_move_after_reload (stack_push_word, ix_reg, 0);
1549
1550 if (size & 1)
1551 emit_insn (gen_addhi3 (stack_pointer_rtx,
1552 stack_pointer_rtx, GEN_INT (-1)));
1553 }
1554
1555 /* Create the frame pointer. */
1556 if (frame_pointer_needed)
1557 emit_move_after_reload (hard_frame_pointer_rtx,
1558 stack_pointer_rtx, scratch);
1559
1560 /* Push any 2 byte pseudo hard registers that we need to save. */
1561 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1562 {
1563 if (regs_ever_live[regno] && !call_used_regs[regno])
1564 {
1565 emit_move_after_reload (stack_push_word,
1566 gen_rtx (REG, HImode, regno), scratch);
1567 }
1568 }
1569 }
1570
1571 void
1572 expand_epilogue ()
1573 {
1574 int size;
1575 register int regno;
1576 int return_size;
1577 rtx scratch;
1578
1579 if (reload_completed != 1)
1580 abort ();
1581
1582 size = get_frame_size ();
1583
1584 /* If we are returning a value in two registers, we have to preserve the
1585 X register and use the Y register to restore the stack and the saved
1586 registers. Otherwise, use X because it's faster (and smaller). */
1587 if (current_function_return_rtx == 0)
1588 return_size = 0;
1589 else if (GET_CODE (current_function_return_rtx) == MEM)
1590 return_size = HARD_REG_SIZE;
1591 else
1592 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1593
1594 if (return_size > HARD_REG_SIZE)
1595 scratch = iy_reg;
1596 else
1597 scratch = ix_reg;
1598
1599 /* Pop any 2 byte pseudo hard registers that we saved. */
1600 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1601 {
1602 if (regs_ever_live[regno] && !call_used_regs[regno])
1603 {
1604 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1605 stack_pop_word, scratch);
1606 }
1607 }
1608
1609 /* de-allocate auto variables */
1610 if (TARGET_M6812 && size >= 2)
1611 {
1612 emit_insn (gen_addhi3 (stack_pointer_rtx,
1613 stack_pointer_rtx, GEN_INT (size)));
1614 }
1615 else if (size > 8)
1616 {
1617 rtx insn;
1618
1619 insn = gen_rtx_PARALLEL
1620 (VOIDmode,
1621 gen_rtvec (2,
1622 gen_rtx_SET (VOIDmode,
1623 stack_pointer_rtx,
1624 gen_rtx_PLUS (HImode,
1625 stack_pointer_rtx,
1626 GEN_INT (size))),
1627 gen_rtx_CLOBBER (VOIDmode, scratch)));
1628 emit_insn (insn);
1629 }
1630 else
1631 {
1632 int i;
1633
1634 for (i = 2; i <= size; i += 2)
1635 emit_move_after_reload (scratch, stack_pop_word, scratch);
1636 if (size & 1)
1637 emit_insn (gen_addhi3 (stack_pointer_rtx,
1638 stack_pointer_rtx, GEN_INT (1)));
1639 }
1640
1641 /* Restore previous frame pointer. */
1642 if (frame_pointer_needed)
1643 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1644
1645 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1646 if (current_function_interrupt)
1647 {
1648 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1649 stack_pop_word, scratch);
1650 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1651 stack_pop_word, scratch);
1652 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1653 }
1654
1655 /* If the trap handler returns some value, copy the value
1656 in D, X onto the stack so that the rti will pop the return value
1657 correctly. */
1658 else if (current_function_trap && return_size != 0)
1659 {
1660 rtx addr_reg = stack_pointer_rtx;
1661
1662 if (!TARGET_M6812)
1663 {
1664 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1665 addr_reg = scratch;
1666 }
1667 emit_move_after_reload (gen_rtx (MEM, HImode,
1668 gen_rtx (PLUS, HImode, addr_reg,
1669 GEN_INT (1))), d_reg, 0);
1670 if (return_size > HARD_REG_SIZE)
1671 emit_move_after_reload (gen_rtx (MEM, HImode,
1672 gen_rtx (PLUS, HImode, addr_reg,
1673 GEN_INT (3))), ix_reg, 0);
1674 }
1675
1676 emit_jump_insn (gen_return ());
1677 }
1678 \f
1679
1680 /* Low and High part extraction for 68HC11. These routines are
1681 similar to gen_lowpart and gen_highpart but they have been
1682 fixed to work for constants and 68HC11 specific registers. */
1683
1684 rtx
1685 m68hc11_gen_lowpart (mode, x)
1686 enum machine_mode mode;
1687 rtx x;
1688 {
1689 /* We assume that the low part of an auto-inc mode is the same with
1690 the mode changed and that the caller split the larger mode in the
1691 correct order. */
1692 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1693 {
1694 return gen_rtx (MEM, mode, XEXP (x, 0));
1695 }
1696
1697 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1698 floating-point constant. A CONST_DOUBLE is used whenever the
1699 constant requires more than one word in order to be adequately
1700 represented. */
1701 if (GET_CODE (x) == CONST_DOUBLE)
1702 {
1703 long l[2];
1704
1705 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1706 {
1707 REAL_VALUE_TYPE r;
1708
1709 if (GET_MODE (x) == SFmode)
1710 {
1711 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1712 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1713 }
1714 else
1715 {
1716 rtx first, second;
1717
1718 split_double (x, &first, &second);
1719 return second;
1720 }
1721 if (mode == SImode)
1722 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1723
1724 return gen_rtx (CONST_INT, VOIDmode, l[0] & 0x0ffff);
1725 }
1726 else
1727 {
1728 l[0] = CONST_DOUBLE_LOW (x);
1729 }
1730 if (mode == SImode)
1731 return gen_rtx (CONST_INT, VOIDmode, l[0]);
1732 else if (mode == HImode && GET_MODE (x) == SFmode)
1733 return gen_rtx (CONST_INT, VOIDmode, l[0] & 0x0FFFF);
1734 else
1735 abort ();
1736 }
1737
1738 if (mode == QImode && D_REG_P (x))
1739 return gen_rtx (REG, mode, HARD_B_REGNUM);
1740
1741 /* gen_lowpart crashes when it is called with a SUBREG. */
1742 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1743 {
1744 if (mode == SImode)
1745 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1746 else if (mode == HImode)
1747 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 1);
1748 else
1749 abort ();
1750 }
1751 x = gen_lowpart (mode, x);
1752
1753 /* Return a different rtx to avoid to share it in several insns
1754 (when used by a split pattern). Sharing addresses within
1755 a MEM breaks the Z register replacement (and reloading). */
1756 if (GET_CODE (x) == MEM)
1757 x = copy_rtx (x);
1758 return x;
1759 }
1760
1761 rtx
1762 m68hc11_gen_highpart (mode, x)
1763 enum machine_mode mode;
1764 rtx x;
1765 {
1766 /* We assume that the high part of an auto-inc mode is the same with
1767 the mode changed and that the caller split the larger mode in the
1768 correct order. */
1769 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1770 {
1771 return gen_rtx (MEM, mode, XEXP (x, 0));
1772 }
1773
1774 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1775 floating-point constant. A CONST_DOUBLE is used whenever the
1776 constant requires more than one word in order to be adequately
1777 represented. */
1778 if (GET_CODE (x) == CONST_DOUBLE)
1779 {
1780 long l[2];
1781
1782 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1783 {
1784 REAL_VALUE_TYPE r;
1785
1786 if (GET_MODE (x) == SFmode)
1787 {
1788 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1789 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1790 }
1791 else
1792 {
1793 rtx first, second;
1794
1795 split_double (x, &first, &second);
1796 return first;
1797 }
1798 if (mode == SImode)
1799 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1800
1801 return gen_rtx (CONST_INT, VOIDmode, (l[1] >> 16) & 0x0ffff);
1802 }
1803 else
1804 {
1805 l[1] = CONST_DOUBLE_HIGH (x);
1806 }
1807
1808 if (mode == SImode)
1809 return gen_rtx (CONST_INT, VOIDmode, l[1]);
1810 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1811 return gen_rtx (CONST_INT, VOIDmode, (l[0] >> 16) & 0x0FFFF);
1812 else
1813 abort ();
1814 }
1815 if (GET_CODE (x) == CONST_INT)
1816 {
1817 HOST_WIDE_INT val = INTVAL (x);
1818
1819 if (mode == QImode)
1820 {
1821 return gen_rtx (CONST_INT, VOIDmode, val >> 8);
1822 }
1823 else if (mode == HImode)
1824 {
1825 return gen_rtx (CONST_INT, VOIDmode, val >> 16);
1826 }
1827 }
1828 if (mode == QImode && D_REG_P (x))
1829 return gen_rtx (REG, mode, HARD_A_REGNUM);
1830
1831 /* There is no way in GCC to represent the upper part of a word register.
1832 To obtain the 8-bit upper part of a soft register, we change the
1833 reg into a mem rtx. This is possible because they are physically
1834 located in memory. There is no offset because we are big-endian. */
1835 if (mode == QImode && S_REG_P (x))
1836 {
1837 int pos;
1838
1839 /* For 68HC12, avoid the '*' for direct addressing mode. */
1840 pos = TARGET_M6812 ? 1 : 0;
1841 return gen_rtx (MEM, QImode,
1842 gen_rtx (SYMBOL_REF, Pmode,
1843 &reg_names[REGNO (x)][pos]));
1844 }
1845
1846 /* gen_highpart crashes when it is called with a SUBREG. */
1847 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1848 {
1849 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
1850 }
1851 x = gen_highpart (mode, x);
1852
1853 /* Return a different rtx to avoid to share it in several insns
1854 (when used by a split pattern). Sharing addresses within
1855 a MEM breaks the Z register replacement (and reloading). */
1856 if (GET_CODE (x) == MEM)
1857 x = copy_rtx (x);
1858 return x;
1859 }
1860 \f
1861
1862 /* Obscure register manipulation. */
1863
1864 /* Finds backward in the instructions to see if register 'reg' is
1865 dead. This is used when generating code to see if we can use 'reg'
1866 as a scratch register. This allows us to choose a better generation
1867 of code when we know that some register dies or can be clobbered. */
1868
1869 int
1870 dead_register_here (x, reg)
1871 rtx x;
1872 rtx reg;
1873 {
1874 rtx x_reg;
1875 rtx p;
1876
1877 if (D_REG_P (reg))
1878 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
1879 else
1880 x_reg = 0;
1881
1882 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1883 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
1884 {
1885 rtx body;
1886
1887 body = PATTERN (p);
1888
1889 if (GET_CODE (body) == CALL_INSN)
1890 break;
1891 if (GET_CODE (body) == JUMP_INSN)
1892 break;
1893
1894 if (GET_CODE (body) == SET)
1895 {
1896 rtx dst = XEXP (body, 0);
1897
1898 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
1899 break;
1900 if (x_reg && rtx_equal_p (dst, x_reg))
1901 break;
1902
1903 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
1904 return 1;
1905 }
1906 else if (reg_mentioned_p (reg, p)
1907 || (x_reg && reg_mentioned_p (x_reg, p)))
1908 break;
1909 }
1910
1911 /* Scan forward to see if the register is set in some insns and never
1912 used since then. */
1913 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
1914 {
1915 rtx body;
1916
1917 if (GET_CODE (p) == CODE_LABEL
1918 || GET_CODE (p) == JUMP_INSN
1919 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
1920 break;
1921
1922 if (GET_CODE (p) != INSN)
1923 continue;
1924
1925 body = PATTERN (p);
1926 if (GET_CODE (body) == SET)
1927 {
1928 rtx src = XEXP (body, 1);
1929 rtx dst = XEXP (body, 0);
1930
1931 if (GET_CODE (dst) == REG
1932 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
1933 return 1;
1934 }
1935
1936 /* Register is used (may be in source or in dest). */
1937 if (reg_mentioned_p (reg, p)
1938 || (x_reg != 0 && GET_MODE (p) == SImode
1939 && reg_mentioned_p (x_reg, p)))
1940 break;
1941 }
1942 return p == 0 ? 1 : 0;
1943 }
1944 \f
1945
1946 /* Code generation operations called from machine description file. */
1947
1948 /* Print the name of register 'regno' in the assembly file. */
1949 static void
1950 asm_print_register (file, regno)
1951 FILE *file;
1952 int regno;
1953 {
1954 const char *name = reg_names[regno];
1955
1956 if (TARGET_M6812 && name[0] == '*')
1957 name++;
1958
1959 asm_fprintf (file, "%s", name);
1960 }
1961
1962 /* A C compound statement to output to stdio stream STREAM the
1963 assembler syntax for an instruction operand X. X is an RTL
1964 expression.
1965
1966 CODE is a value that can be used to specify one of several ways
1967 of printing the operand. It is used when identical operands
1968 must be printed differently depending on the context. CODE
1969 comes from the `%' specification that was used to request
1970 printing of the operand. If the specification was just `%DIGIT'
1971 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
1972 is the ASCII code for LTR.
1973
1974 If X is a register, this macro should print the register's name.
1975 The names can be found in an array `reg_names' whose type is
1976 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
1977
1978 When the machine description has a specification `%PUNCT' (a `%'
1979 followed by a punctuation character), this macro is called with
1980 a null pointer for X and the punctuation character for CODE.
1981
1982 The M68HC11 specific codes are:
1983
1984 'b' for the low part of the operand.
1985 'h' for the high part of the operand
1986 The 'b' or 'h' modifiers have no effect if the operand has
1987 the QImode and is not a S_REG_P (soft register). If the
1988 operand is a hard register, these two modifiers have no effect.
1989 't' generate the temporary scratch register. The operand is
1990 ignored.
1991 'T' generate the low-part temporary scratch register. The operand is
1992 ignored. */
1993
1994 void
1995 print_operand (file, op, letter)
1996 FILE *file;
1997 rtx op;
1998 int letter;
1999 {
2000 if (letter == 't')
2001 {
2002 asm_print_register (file, SOFT_TMP_REGNUM);
2003 return;
2004 }
2005 else if (letter == 'T')
2006 {
2007 asm_print_register (file, SOFT_TMP_REGNUM);
2008 asm_fprintf (file, "+1");
2009 return;
2010 }
2011 else if (letter == '#')
2012 {
2013 asm_fprintf (file, "%0I");
2014 }
2015
2016 if (GET_CODE (op) == REG)
2017 {
2018 if (letter == 'b' && S_REG_P (op))
2019 {
2020 asm_print_register (file, REGNO (op));
2021 asm_fprintf (file, "+1");
2022 }
2023 else
2024 {
2025 asm_print_register (file, REGNO (op));
2026 }
2027 return;
2028 }
2029
2030 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2031 {
2032 if (letter == 'b')
2033 asm_fprintf (file, "%0I%%lo(");
2034 else
2035 asm_fprintf (file, "%0I%%hi(");
2036
2037 output_addr_const (file, op);
2038 asm_fprintf (file, ")");
2039 return;
2040 }
2041
2042 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2043 are specified. If we already have a QImode, there is nothing to do. */
2044 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2045 {
2046 if (letter == 'b')
2047 {
2048 op = m68hc11_gen_lowpart (QImode, op);
2049 }
2050 else if (letter == 'h')
2051 {
2052 op = m68hc11_gen_highpart (QImode, op);
2053 }
2054 }
2055
2056 if (GET_CODE (op) == MEM)
2057 {
2058 rtx base = XEXP (op, 0);
2059 switch (GET_CODE (base))
2060 {
2061 case PRE_DEC:
2062 if (TARGET_M6812)
2063 {
2064 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2065 asm_print_register (file, REGNO (XEXP (base, 0)));
2066 }
2067 else
2068 abort ();
2069 break;
2070
2071 case POST_DEC:
2072 if (TARGET_M6812)
2073 {
2074 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2075 asm_print_register (file, REGNO (XEXP (base, 0)));
2076 asm_fprintf (file, "-");
2077 }
2078 else
2079 abort ();
2080 break;
2081
2082 case POST_INC:
2083 if (TARGET_M6812)
2084 {
2085 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2086 asm_print_register (file, REGNO (XEXP (base, 0)));
2087 asm_fprintf (file, "+");
2088 }
2089 else
2090 abort ();
2091 break;
2092
2093 case PRE_INC:
2094 if (TARGET_M6812)
2095 {
2096 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2097 asm_print_register (file, REGNO (XEXP (base, 0)));
2098 }
2099 else
2100 abort ();
2101 break;
2102
2103 default:
2104 output_address (base);
2105 break;
2106 }
2107 }
2108 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2109 {
2110 REAL_VALUE_TYPE r;
2111 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2112 ASM_OUTPUT_FLOAT_OPERAND (letter, file, r);
2113 }
2114 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == XFmode)
2115 {
2116 REAL_VALUE_TYPE r;
2117 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2118 ASM_OUTPUT_LONG_DOUBLE_OPERAND (file, r);
2119 }
2120 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2121 {
2122 REAL_VALUE_TYPE r;
2123 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2124 ASM_OUTPUT_DOUBLE_OPERAND (file, r);
2125 }
2126 else
2127 {
2128 if (letter != 'i')
2129 asm_fprintf (file, "%0I");
2130 output_addr_const (file, op);
2131 }
2132 }
2133
2134 /* Returns true if the operand 'op' must be printed with parenthesis
2135 arround it. This must be done only if there is a symbol whose name
2136 is a processor register. */
2137 static int
2138 must_parenthesize (op)
2139 rtx op;
2140 {
2141 const char *name;
2142
2143 switch (GET_CODE (op))
2144 {
2145 case SYMBOL_REF:
2146 name = XSTR (op, 0);
2147 /* Avoid a conflict between symbol name and a possible
2148 register. */
2149 return (strcasecmp (name, "a") == 0
2150 || strcasecmp (name, "b") == 0
2151 || strcasecmp (name, "d") == 0
2152 || strcasecmp (name, "x") == 0
2153 || strcasecmp (name, "y") == 0
2154 || strcasecmp (name, "pc") == 0
2155 || strcasecmp (name, "sp") == 0
2156 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2157
2158 case PLUS:
2159 case MINUS:
2160 return must_parenthesize (XEXP (op, 0))
2161 || must_parenthesize (XEXP (op, 1));
2162
2163 case MEM:
2164 case CONST:
2165 case ZERO_EXTEND:
2166 case SIGN_EXTEND:
2167 return must_parenthesize (XEXP (op, 0));
2168
2169 case CONST_DOUBLE:
2170 case CONST_INT:
2171 case LABEL_REF:
2172 case CODE_LABEL:
2173 default:
2174 return 0;
2175 }
2176 }
2177
2178 /* A C compound statement to output to stdio stream STREAM the
2179 assembler syntax for an instruction operand that is a memory
2180 reference whose address is ADDR. ADDR is an RTL expression. */
2181
2182 void
2183 print_operand_address (file, addr)
2184 FILE *file;
2185 rtx addr;
2186 {
2187 rtx base;
2188 rtx offset;
2189 int need_parenthesis = 0;
2190
2191 switch (GET_CODE (addr))
2192 {
2193 case REG:
2194 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2195 abort ();
2196
2197 asm_fprintf (file, "0,");
2198 asm_print_register (file, REGNO (addr));
2199 break;
2200
2201 case MEM:
2202 base = XEXP (addr, 0);
2203 switch (GET_CODE (base))
2204 {
2205 case PRE_DEC:
2206 if (TARGET_M6812)
2207 {
2208 asm_fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2209 asm_print_register (file, REGNO (XEXP (base, 0)));
2210 }
2211 else
2212 abort ();
2213 break;
2214
2215 case POST_DEC:
2216 if (TARGET_M6812)
2217 {
2218 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2219 asm_print_register (file, REGNO (XEXP (base, 0)));
2220 asm_fprintf (file, "-");
2221 }
2222 else
2223 abort ();
2224 break;
2225
2226 case POST_INC:
2227 if (TARGET_M6812)
2228 {
2229 asm_fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2230 asm_print_register (file, REGNO (XEXP (base, 0)));
2231 asm_fprintf (file, "+");
2232 }
2233 else
2234 abort ();
2235 break;
2236
2237 case PRE_INC:
2238 if (TARGET_M6812)
2239 {
2240 asm_fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2241 asm_print_register (file, REGNO (XEXP (base, 0)));
2242 }
2243 else
2244 abort ();
2245 break;
2246
2247 default:
2248 need_parenthesis = must_parenthesize (base);
2249 if (need_parenthesis)
2250 asm_fprintf (file, "(");
2251
2252 output_addr_const (file, base);
2253 if (need_parenthesis)
2254 asm_fprintf (file, ")");
2255 break;
2256 }
2257 break;
2258
2259 case PLUS:
2260 base = XEXP (addr, 0);
2261 offset = XEXP (addr, 1);
2262 if (!G_REG_P (base) && G_REG_P (offset))
2263 {
2264 base = XEXP (addr, 1);
2265 offset = XEXP (addr, 0);
2266 }
2267 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2268 {
2269 need_parenthesis = must_parenthesize (addr);
2270
2271 if (need_parenthesis)
2272 asm_fprintf (file, "(");
2273
2274 output_addr_const (file, base);
2275 asm_fprintf (file, "+");
2276 output_addr_const (file, offset);
2277 if (need_parenthesis)
2278 asm_fprintf (file, ")");
2279 }
2280 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2281 {
2282 if (REG_P (offset))
2283 {
2284 if (TARGET_M6812)
2285 {
2286 asm_print_register (file, REGNO (offset));
2287 asm_fprintf (file, ",");
2288 asm_print_register (file, REGNO (base));
2289 }
2290 else
2291 abort ();
2292 }
2293 else
2294 {
2295 output_addr_const (file, offset);
2296 asm_fprintf (file, ",");
2297 asm_print_register (file, REGNO (base));
2298 }
2299 }
2300 else
2301 {
2302 abort ();
2303 }
2304 break;
2305
2306 default:
2307 if (GET_CODE (addr) == CONST_INT
2308 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2309 {
2310 asm_fprintf (file, "%d", INTVAL (addr));
2311 }
2312 else
2313 {
2314 need_parenthesis = must_parenthesize (addr);
2315 if (need_parenthesis)
2316 asm_fprintf (file, "(");
2317
2318 output_addr_const (file, addr);
2319 if (need_parenthesis)
2320 asm_fprintf (file, ")");
2321 }
2322 break;
2323 }
2324 }
2325 \f
2326
2327 /* Splitting of some instructions. */
2328
2329 static rtx
2330 m68hc11_expand_compare (code, op0, op1)
2331 enum rtx_code code;
2332 rtx op0, op1;
2333 {
2334 rtx ret = 0;
2335
2336 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2337 abort ();
2338 else
2339 {
2340 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2341 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2342 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2343 }
2344
2345 return ret;
2346 }
2347
2348 rtx
2349 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2350 enum rtx_code code;
2351 rtx op0, op1, label;
2352 {
2353 rtx tmp;
2354
2355 switch (GET_MODE (op0))
2356 {
2357 case QImode:
2358 case HImode:
2359 tmp = m68hc11_expand_compare (code, op0, op1);
2360 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2361 gen_rtx_LABEL_REF (VOIDmode, label),
2362 pc_rtx);
2363 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2364 return 0;
2365 #if 0
2366
2367 /* SCz: from i386.c */
2368 case SFmode:
2369 case DFmode:
2370 /* Don't expand the comparison early, so that we get better code
2371 when jump or whoever decides to reverse the comparison. */
2372 {
2373 rtvec vec;
2374 int use_fcomi;
2375
2376 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2377 &m68hc11_compare_op1);
2378
2379 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2380 m68hc11_compare_op0, m68hc11_compare_op1);
2381 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2382 gen_rtx_LABEL_REF (VOIDmode, label),
2383 pc_rtx);
2384 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2385
2386 use_fcomi = ix86_use_fcomi_compare (code);
2387 vec = rtvec_alloc (3 + !use_fcomi);
2388 RTVEC_ELT (vec, 0) = tmp;
2389 RTVEC_ELT (vec, 1)
2390 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2391 RTVEC_ELT (vec, 2)
2392 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2393 if (!use_fcomi)
2394 RTVEC_ELT (vec, 3)
2395 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2396
2397 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2398 return;
2399 }
2400 #endif
2401
2402 case SImode:
2403 /* Expand SImode branch into multiple compare+branch. */
2404 {
2405 rtx lo[2], hi[2], label2;
2406 enum rtx_code code1, code2, code3;
2407
2408 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2409 {
2410 tmp = op0;
2411 op0 = op1;
2412 op1 = tmp;
2413 code = swap_condition (code);
2414 }
2415 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2416 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2417 hi[0] = m68hc11_gen_highpart (HImode, op0);
2418 hi[1] = m68hc11_gen_highpart (HImode, op1);
2419
2420 /* Otherwise, if we are doing less-than, op1 is a constant and the
2421 low word is zero, then we can just examine the high word. */
2422
2423 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2424 && (code == LT || code == LTU))
2425 {
2426 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2427 label);
2428 }
2429
2430 /* Otherwise, we need two or three jumps. */
2431
2432 label2 = gen_label_rtx ();
2433
2434 code1 = code;
2435 code2 = swap_condition (code);
2436 code3 = unsigned_condition (code);
2437
2438 switch (code)
2439 {
2440 case LT:
2441 case GT:
2442 case LTU:
2443 case GTU:
2444 break;
2445
2446 case LE:
2447 code1 = LT;
2448 code2 = GT;
2449 break;
2450 case GE:
2451 code1 = GT;
2452 code2 = LT;
2453 break;
2454 case LEU:
2455 code1 = LTU;
2456 code2 = GTU;
2457 break;
2458 case GEU:
2459 code1 = GTU;
2460 code2 = LTU;
2461 break;
2462
2463 case EQ:
2464 code1 = NIL;
2465 code2 = NE;
2466 break;
2467 case NE:
2468 code2 = NIL;
2469 break;
2470
2471 default:
2472 abort ();
2473 }
2474
2475 /*
2476 * a < b =>
2477 * if (hi(a) < hi(b)) goto true;
2478 * if (hi(a) > hi(b)) goto false;
2479 * if (lo(a) < lo(b)) goto true;
2480 * false:
2481 */
2482 if (code1 != NIL)
2483 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2484 if (code2 != NIL)
2485 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2486
2487 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2488
2489 if (code2 != NIL)
2490 emit_label (label2);
2491 return 0;
2492 }
2493
2494 default:
2495 abort ();
2496 }
2497 return 0;
2498 }
2499
2500
2501 /* Split a DI, SI or HI move into several smaller move operations.
2502 The scratch register 'scratch' is used as a temporary to load
2503 store intermediate values. It must be a hard register. */
2504 void
2505 m68hc11_split_move (to, from, scratch)
2506 rtx to, from, scratch;
2507 {
2508 rtx low_to, low_from;
2509 rtx high_to, high_from;
2510 enum machine_mode mode;
2511
2512 mode = GET_MODE (to);
2513 if (GET_MODE_SIZE (mode) == 8)
2514 mode = SImode;
2515 else if (GET_MODE_SIZE (mode) == 4)
2516 mode = HImode;
2517 else
2518 mode = QImode;
2519
2520 low_to = m68hc11_gen_lowpart (mode, to);
2521 high_to = m68hc11_gen_highpart (mode, to);
2522
2523 low_from = m68hc11_gen_lowpart (mode, from);
2524 if (mode == SImode && GET_CODE (from) == CONST_INT)
2525 {
2526 if (INTVAL (from) >= 0)
2527 high_from = const0_rtx;
2528 else
2529 high_from = constm1_rtx;
2530 }
2531 else
2532 high_from = m68hc11_gen_highpart (mode, from);
2533
2534 if (mode == SImode)
2535 {
2536 m68hc11_split_move (low_to, low_from, scratch);
2537 m68hc11_split_move (high_to, high_from, scratch);
2538 }
2539 else if (H_REG_P (to) || H_REG_P (from)
2540 || (TARGET_M6812
2541 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2542 || m68hc11_small_indexed_indirect_p (from,
2543 GET_MODE (from)))
2544 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2545 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2546 {
2547 emit_move_insn (low_to, low_from);
2548 emit_move_insn (high_to, high_from);
2549 }
2550 else
2551 {
2552 rtx insn;
2553
2554 emit_move_insn (scratch, low_from);
2555 insn = emit_move_insn (low_to, scratch);
2556
2557 emit_move_insn (scratch, high_from);
2558 insn = emit_move_insn (high_to, scratch);
2559 }
2560 }
2561
2562 static rtx
2563 simplify_logical (mode, code, operand, result)
2564 enum machine_mode mode;
2565 int code;
2566 rtx operand;
2567 rtx *result;
2568 {
2569 int val;
2570 int mask;
2571
2572 *result = 0;
2573 if (GET_CODE (operand) != CONST_INT)
2574 return operand;
2575
2576 if (mode == HImode)
2577 mask = 0x0ffff;
2578 else
2579 mask = 0x0ff;
2580
2581 val = INTVAL (operand);
2582 switch (code)
2583 {
2584 case IOR:
2585 if ((val & mask) == 0)
2586 return 0;
2587 if ((val & mask) == mask)
2588 *result = constm1_rtx;
2589 break;
2590
2591 case AND:
2592 if ((val & mask) == 0)
2593 *result = const0_rtx;
2594 if ((val & mask) == mask)
2595 return 0;
2596 break;
2597
2598 case XOR:
2599 if ((val & mask) == 0)
2600 return 0;
2601 break;
2602 }
2603 return operand;
2604 }
2605
2606 static void
2607 m68hc11_emit_logical (mode, code, operands)
2608 enum machine_mode mode;
2609 int code;
2610 rtx *operands;
2611 {
2612 rtx result;
2613 int need_copy;
2614
2615 need_copy = (rtx_equal_p (operands[0], operands[1])
2616 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2617
2618 operands[1] = simplify_logical (mode, code, operands[1], &result);
2619 operands[2] = simplify_logical (mode, code, operands[2], &result);
2620
2621 if (result && GET_CODE (result) == CONST_INT)
2622 {
2623 if (!H_REG_P (operands[0]) && operands[3]
2624 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2625 {
2626 emit_move_insn (operands[3], result);
2627 emit_move_insn (operands[0], operands[3]);
2628 }
2629 else
2630 {
2631 emit_move_insn (operands[0], result);
2632 }
2633 }
2634 else if (operands[1] != 0 && operands[2] != 0)
2635 {
2636 rtx insn;
2637
2638 if (!H_REG_P (operands[0]) && operands[3])
2639 {
2640 emit_move_insn (operands[3], operands[1]);
2641 emit_insn (gen_rtx (SET, mode,
2642 operands[3],
2643 gen_rtx (code, mode,
2644 operands[3], operands[2])));
2645 insn = emit_move_insn (operands[0], operands[3]);
2646 }
2647 else
2648 {
2649 insn = emit_insn (gen_rtx (SET, mode,
2650 operands[0],
2651 gen_rtx (code, mode,
2652 operands[0], operands[2])));
2653 }
2654 }
2655
2656 /* The logical operation is similar to a copy. */
2657 else if (need_copy)
2658 {
2659 rtx src;
2660
2661 if (GET_CODE (operands[1]) == CONST_INT)
2662 src = operands[2];
2663 else
2664 src = operands[1];
2665
2666 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2667 {
2668 emit_move_insn (operands[3], src);
2669 emit_move_insn (operands[0], operands[3]);
2670 }
2671 else
2672 {
2673 emit_move_insn (operands[0], src);
2674 }
2675 }
2676 }
2677
2678 void
2679 m68hc11_split_logical (mode, code, operands)
2680 enum machine_mode mode;
2681 int code;
2682 rtx *operands;
2683 {
2684 rtx low[4];
2685 rtx high[4];
2686
2687 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
2688 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
2689 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
2690
2691 high[0] = m68hc11_gen_highpart (mode, operands[0]);
2692
2693 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
2694 {
2695 if (INTVAL (operands[1]) >= 0)
2696 high[1] = const0_rtx;
2697 else
2698 high[1] = constm1_rtx;
2699 }
2700 else
2701 high[1] = m68hc11_gen_highpart (mode, operands[1]);
2702
2703 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
2704 {
2705 if (INTVAL (operands[2]) >= 0)
2706 high[2] = const0_rtx;
2707 else
2708 high[2] = constm1_rtx;
2709 }
2710 else
2711 high[2] = m68hc11_gen_highpart (mode, operands[2]);
2712
2713 low[3] = operands[3];
2714 high[3] = operands[3];
2715 if (mode == SImode)
2716 {
2717 m68hc11_split_logical (HImode, code, low);
2718 m68hc11_split_logical (HImode, code, high);
2719 return;
2720 }
2721
2722 m68hc11_emit_logical (mode, code, low);
2723 m68hc11_emit_logical (mode, code, high);
2724 }
2725 \f
2726
2727 /* Code generation. */
2728
2729 void
2730 m68hc11_output_swap (insn, operands)
2731 rtx insn ATTRIBUTE_UNUSED;
2732 rtx operands[];
2733 {
2734 /* We have to be careful with the cc_status. An address register swap
2735 is generated for some comparison. The comparison is made with D
2736 but the branch really uses the address register. See the split
2737 pattern for compare. The xgdx/xgdy preserve the flags but after
2738 the exchange, the flags will reflect to the value of X and not D.
2739 Tell this by setting the cc_status according to the cc_prev_status. */
2740 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
2741 {
2742 if (cc_prev_status.value1 != 0
2743 && (D_REG_P (cc_prev_status.value1)
2744 || X_REG_P (cc_prev_status.value1)))
2745 {
2746 cc_status = cc_prev_status;
2747 if (D_REG_P (cc_status.value1))
2748 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2749 HARD_X_REGNUM);
2750 else
2751 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2752 HARD_D_REGNUM);
2753 }
2754 else
2755 CC_STATUS_INIT;
2756
2757 output_asm_insn ("xgdx", operands);
2758 }
2759 else
2760 {
2761 if (cc_prev_status.value1 != 0
2762 && (D_REG_P (cc_prev_status.value1)
2763 || Y_REG_P (cc_prev_status.value1)))
2764 {
2765 cc_status = cc_prev_status;
2766 if (D_REG_P (cc_status.value1))
2767 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2768 HARD_Y_REGNUM);
2769 else
2770 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
2771 HARD_D_REGNUM);
2772 }
2773 else
2774 CC_STATUS_INIT;
2775
2776 output_asm_insn ("xgdy", operands);
2777 }
2778 }
2779
2780 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
2781 This is used to decide whether a move that set flags should be used
2782 instead. */
2783 int
2784 next_insn_test_reg (insn, reg)
2785 rtx insn;
2786 rtx reg;
2787 {
2788 rtx body;
2789
2790 insn = next_nonnote_insn (insn);
2791 if (GET_CODE (insn) != INSN)
2792 return 0;
2793
2794 body = PATTERN (insn);
2795 if (sets_cc0_p (body) != 1)
2796 return 0;
2797
2798 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
2799 return 0;
2800
2801 return 1;
2802 }
2803
2804 /* Generate the code to move a 16-bit operand into another one. */
2805
2806 void
2807 m68hc11_gen_movhi (insn, operands)
2808 rtx insn;
2809 rtx *operands;
2810 {
2811 int reg;
2812
2813 /* Move a register or memory to the same location.
2814 This is possible because such insn can appear
2815 in a non-optimizing mode. */
2816 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
2817 {
2818 cc_status = cc_prev_status;
2819 return;
2820 }
2821
2822 if (TARGET_M6812)
2823 {
2824 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
2825 {
2826 switch (REGNO (operands[1]))
2827 {
2828 case HARD_X_REGNUM:
2829 case HARD_Y_REGNUM:
2830 case HARD_D_REGNUM:
2831 output_asm_insn ("psh%1", operands);
2832 break;
2833 default:
2834 abort ();
2835 }
2836 return;
2837 }
2838 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2839 {
2840 switch (REGNO (operands[0]))
2841 {
2842 case HARD_X_REGNUM:
2843 case HARD_Y_REGNUM:
2844 case HARD_D_REGNUM:
2845 output_asm_insn ("pul%0", operands);
2846 break;
2847 default:
2848 abort ();
2849 }
2850 return;
2851 }
2852 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
2853 {
2854 output_asm_insn ("tfr\t%1,%0", operands);
2855 }
2856 else if (H_REG_P (operands[0]))
2857 {
2858 if (SP_REG_P (operands[0]))
2859 output_asm_insn ("lds\t%1", operands);
2860 else
2861 output_asm_insn ("ld%0\t%1", operands);
2862 }
2863 else if (H_REG_P (operands[1]))
2864 {
2865 if (SP_REG_P (operands[1]))
2866 output_asm_insn ("sts\t%0", operands);
2867 else
2868 output_asm_insn ("st%1\t%0", operands);
2869 }
2870 else
2871 {
2872 rtx from = operands[1];
2873 rtx to = operands[0];
2874
2875 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
2876 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
2877 || (m68hc11_register_indirect_p (to, GET_MODE (to))
2878 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
2879 {
2880 rtx ops[3];
2881
2882 if (operands[2])
2883 {
2884 ops[0] = operands[2];
2885 ops[1] = from;
2886 ops[2] = 0;
2887 m68hc11_gen_movhi (insn, ops);
2888 ops[0] = to;
2889 ops[1] = operands[2];
2890 m68hc11_gen_movhi (insn, ops);
2891 }
2892 else
2893 {
2894 /* !!!! SCz wrong here. */
2895 }
2896 }
2897 else
2898 {
2899 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
2900 {
2901 output_asm_insn ("clr\t%h0", operands);
2902 output_asm_insn ("clr\t%b0", operands);
2903 }
2904 else
2905 {
2906 output_asm_insn ("movw\t%1,%0", operands);
2907 }
2908 }
2909 }
2910 return;
2911 }
2912
2913 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
2914 {
2915 switch (REGNO (operands[0]))
2916 {
2917 case HARD_X_REGNUM:
2918 case HARD_Y_REGNUM:
2919 output_asm_insn ("pul%0", operands);
2920 break;
2921 case HARD_D_REGNUM:
2922 output_asm_insn ("pula", operands);
2923 output_asm_insn ("pulb", operands);
2924 break;
2925 default:
2926 abort ();
2927 }
2928 return;
2929 }
2930 /* Some moves to a hard register are special. Not all of them
2931 are really supported and we have to use a temporary
2932 location to provide them (either the stack of a temp var). */
2933 if (H_REG_P (operands[0]))
2934 {
2935 switch (REGNO (operands[0]))
2936 {
2937 case HARD_D_REGNUM:
2938 if (X_REG_P (operands[1]))
2939 {
2940 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
2941 {
2942 m68hc11_output_swap (insn, operands);
2943 }
2944 else if (next_insn_test_reg (insn, operands[0]))
2945 {
2946 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
2947 }
2948 else
2949 {
2950 cc_status = cc_prev_status;
2951 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
2952 }
2953 }
2954 else if (Y_REG_P (operands[1]))
2955 {
2956 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
2957 {
2958 m68hc11_output_swap (insn, operands);
2959 }
2960 else
2961 {
2962 /* %t means *ZTMP scratch register. */
2963 output_asm_insn ("sty\t%t1", operands);
2964 output_asm_insn ("ldd\t%t1", operands);
2965 }
2966 }
2967 else if (SP_REG_P (operands[1]))
2968 {
2969 CC_STATUS_INIT;
2970 if (ix_reg == 0)
2971 create_regs_rtx ();
2972 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
2973 output_asm_insn ("xgdx", operands);
2974 output_asm_insn ("tsx", operands);
2975 output_asm_insn ("xgdx", operands);
2976 }
2977 else if (IS_STACK_POP (operands[1]))
2978 {
2979 output_asm_insn ("pula\n\tpulb", operands);
2980 }
2981 else if (GET_CODE (operands[1]) == CONST_INT
2982 && INTVAL (operands[1]) == 0)
2983 {
2984 output_asm_insn ("clra\n\tclrb", operands);
2985 }
2986 else
2987 {
2988 output_asm_insn ("ldd\t%1", operands);
2989 }
2990 break;
2991
2992 case HARD_X_REGNUM:
2993 if (D_REG_P (operands[1]))
2994 {
2995 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
2996 {
2997 m68hc11_output_swap (insn, operands);
2998 }
2999 else if (next_insn_test_reg (insn, operands[0]))
3000 {
3001 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3002 }
3003 else
3004 {
3005 cc_status = cc_prev_status;
3006 output_asm_insn ("pshb", operands);
3007 output_asm_insn ("psha", operands);
3008 output_asm_insn ("pulx", operands);
3009 }
3010 }
3011 else if (Y_REG_P (operands[1]))
3012 {
3013 output_asm_insn ("sty\t%t1", operands);
3014 output_asm_insn ("ldx\t%t1", operands);
3015 }
3016 else if (SP_REG_P (operands[1]))
3017 {
3018 /* tsx, tsy preserve the flags */
3019 cc_status = cc_prev_status;
3020 output_asm_insn ("tsx", operands);
3021 }
3022 else
3023 {
3024 output_asm_insn ("ldx\t%1", operands);
3025 }
3026 break;
3027
3028 case HARD_Y_REGNUM:
3029 if (D_REG_P (operands[1]))
3030 {
3031 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3032 {
3033 m68hc11_output_swap (insn, operands);
3034 }
3035 else
3036 {
3037 output_asm_insn ("std\t%t1", operands);
3038 output_asm_insn ("ldy\t%t1", operands);
3039 }
3040 }
3041 else if (X_REG_P (operands[1]))
3042 {
3043 output_asm_insn ("stx\t%t1", operands);
3044 output_asm_insn ("ldy\t%t1", operands);
3045 }
3046 else if (SP_REG_P (operands[1]))
3047 {
3048 /* tsx, tsy preserve the flags */
3049 cc_status = cc_prev_status;
3050 output_asm_insn ("tsy", operands);
3051 }
3052 else
3053 {
3054 output_asm_insn ("ldy\t%1", operands);
3055 }
3056 break;
3057
3058 case HARD_SP_REGNUM:
3059 if (D_REG_P (operands[1]))
3060 {
3061 cc_status = cc_prev_status;
3062 output_asm_insn ("xgdx", operands);
3063 output_asm_insn ("txs", operands);
3064 output_asm_insn ("xgdx", operands);
3065 }
3066 else if (X_REG_P (operands[1]))
3067 {
3068 /* tys, txs preserve the flags */
3069 cc_status = cc_prev_status;
3070 output_asm_insn ("txs", operands);
3071 }
3072 else if (Y_REG_P (operands[1]))
3073 {
3074 /* tys, txs preserve the flags */
3075 cc_status = cc_prev_status;
3076 output_asm_insn ("tys", operands);
3077 }
3078 else
3079 {
3080 /* lds sets the flags but the des does not. */
3081 CC_STATUS_INIT;
3082 output_asm_insn ("lds\t%1", operands);
3083 output_asm_insn ("des", operands);
3084 }
3085 break;
3086
3087 default:
3088 fatal_insn ("Invalid register in the move instruction", insn);
3089 break;
3090 }
3091 return;
3092 }
3093 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3094 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3095 {
3096 output_asm_insn ("sts\t%0", operands);
3097 return;
3098 }
3099
3100 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3101 {
3102 switch (REGNO (operands[1]))
3103 {
3104 case HARD_X_REGNUM:
3105 case HARD_Y_REGNUM:
3106 output_asm_insn ("psh%1", operands);
3107 break;
3108 case HARD_D_REGNUM:
3109 output_asm_insn ("pshb", operands);
3110 output_asm_insn ("psha", operands);
3111 break;
3112 default:
3113 abort ();
3114 }
3115 return;
3116 }
3117
3118 /* Operand 1 must be a hard register. */
3119 if (!H_REG_P (operands[1]))
3120 {
3121 fatal_insn ("Invalid operand in the instruction", insn);
3122 }
3123
3124 reg = REGNO (operands[1]);
3125 switch (reg)
3126 {
3127 case HARD_D_REGNUM:
3128 output_asm_insn ("std\t%0", operands);
3129 break;
3130
3131 case HARD_X_REGNUM:
3132 output_asm_insn ("stx\t%0", operands);
3133 break;
3134
3135 case HARD_Y_REGNUM:
3136 output_asm_insn ("sty\t%0", operands);
3137 break;
3138
3139 case HARD_SP_REGNUM:
3140 if (ix_reg == 0)
3141 create_regs_rtx ();
3142
3143 if (reg_mentioned_p (ix_reg, operands[0]))
3144 {
3145 output_asm_insn ("sty\t%t0", operands);
3146 output_asm_insn ("tsy", operands);
3147 output_asm_insn ("sty\t%0", operands);
3148 output_asm_insn ("ldy\t%t0", operands);
3149 }
3150 else
3151 {
3152 output_asm_insn ("stx\t%t0", operands);
3153 output_asm_insn ("tsx", operands);
3154 output_asm_insn ("stx\t%0", operands);
3155 output_asm_insn ("ldx\t%t0", operands);
3156 }
3157 CC_STATUS_INIT;
3158 break;
3159
3160 default:
3161 fatal_insn ("Invalid register in the move instruction", insn);
3162 break;
3163 }
3164 }
3165
3166 void
3167 m68hc11_gen_movqi (insn, operands)
3168 rtx insn;
3169 rtx *operands;
3170 {
3171 /* Move a register or memory to the same location.
3172 This is possible because such insn can appear
3173 in a non-optimizing mode. */
3174 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3175 {
3176 cc_status = cc_prev_status;
3177 return;
3178 }
3179
3180 if (TARGET_M6812)
3181 {
3182
3183 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3184 {
3185 output_asm_insn ("tfr\t%1,%0", operands);
3186 }
3187 else if (H_REG_P (operands[0]))
3188 {
3189 if (Q_REG_P (operands[0]))
3190 output_asm_insn ("lda%0\t%1", operands);
3191 else if (D_REG_P (operands[0]))
3192 output_asm_insn ("ldab\t%1", operands);
3193 else
3194 output_asm_insn ("ld%0\t%1", operands);
3195 }
3196 else if (H_REG_P (operands[1]))
3197 {
3198 if (Q_REG_P (operands[1]))
3199 output_asm_insn ("sta%1\t%0", operands);
3200 else if (D_REG_P (operands[1]))
3201 output_asm_insn ("staa\t%0", operands);
3202 else
3203 output_asm_insn ("st%1\t%0", operands);
3204 }
3205 else
3206 {
3207 rtx from = operands[1];
3208 rtx to = operands[0];
3209
3210 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3211 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3212 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3213 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3214 {
3215 rtx ops[3];
3216
3217 if (operands[2])
3218 {
3219 ops[0] = operands[2];
3220 ops[1] = from;
3221 ops[2] = 0;
3222 m68hc11_gen_movqi (insn, ops);
3223 ops[0] = to;
3224 ops[1] = operands[2];
3225 m68hc11_gen_movqi (insn, ops);
3226 }
3227 else
3228 {
3229 /* !!!! SCz wrong here. */
3230 }
3231 }
3232 else
3233 {
3234 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3235 {
3236 output_asm_insn ("clr\t%b0", operands);
3237 }
3238 else
3239 {
3240 output_asm_insn ("movb\t%1,%0", operands);
3241 }
3242 }
3243 }
3244 return;
3245 }
3246
3247 if (H_REG_P (operands[0]))
3248 {
3249 switch (REGNO (operands[0]))
3250 {
3251 case HARD_B_REGNUM:
3252 case HARD_D_REGNUM:
3253 if (X_REG_P (operands[1]))
3254 {
3255 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3256 {
3257 m68hc11_output_swap (insn, operands);
3258 }
3259 else
3260 {
3261 output_asm_insn ("stx\t%t1", operands);
3262 output_asm_insn ("ldab\t%T0", operands);
3263 }
3264 }
3265 else if (Y_REG_P (operands[1]))
3266 {
3267 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3268 {
3269 m68hc11_output_swap (insn, operands);
3270 }
3271 else
3272 {
3273 output_asm_insn ("sty\t%t1", operands);
3274 output_asm_insn ("ldab\t%T0", operands);
3275 }
3276 }
3277 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3278 && !DA_REG_P (operands[1]))
3279 {
3280 output_asm_insn ("ldab\t%b1", operands);
3281 }
3282 else if (DA_REG_P (operands[1]))
3283 {
3284 output_asm_insn ("tab", operands);
3285 }
3286 else
3287 {
3288 cc_status = cc_prev_status;
3289 return;
3290 }
3291 break;
3292
3293 case HARD_A_REGNUM:
3294 if (X_REG_P (operands[1]))
3295 {
3296 output_asm_insn ("stx\t%t1", operands);
3297 output_asm_insn ("ldaa\t%T0", operands);
3298 }
3299 else if (Y_REG_P (operands[1]))
3300 {
3301 output_asm_insn ("sty\t%t1", operands);
3302 output_asm_insn ("ldaa\t%T0", operands);
3303 }
3304 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3305 && !DA_REG_P (operands[1]))
3306 {
3307 output_asm_insn ("ldaa\t%b1", operands);
3308 }
3309 else if (!DA_REG_P (operands[1]))
3310 {
3311 output_asm_insn ("tba", operands);
3312 }
3313 else
3314 {
3315 cc_status = cc_prev_status;
3316 }
3317 break;
3318
3319 case HARD_X_REGNUM:
3320 if (D_REG_P (operands[1]))
3321 {
3322 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3323 {
3324 m68hc11_output_swap (insn, operands);
3325 }
3326 else
3327 {
3328 output_asm_insn ("stab\t%T1", operands);
3329 output_asm_insn ("ldx\t%t1", operands);
3330 }
3331 CC_STATUS_INIT;
3332 }
3333 else if (Y_REG_P (operands[1]))
3334 {
3335 output_asm_insn ("sty\t%t0", operands);
3336 output_asm_insn ("ldx\t%t0", operands);
3337 }
3338 else if (GET_CODE (operands[1]) == CONST_INT)
3339 {
3340 output_asm_insn ("ldx\t%1", operands);
3341 }
3342 else if (dead_register_here (insn, d_reg))
3343 {
3344 output_asm_insn ("ldab\t%b1", operands);
3345 output_asm_insn ("xgdx", operands);
3346 }
3347 else if (!reg_mentioned_p (operands[0], operands[1]))
3348 {
3349 output_asm_insn ("xgdx", operands);
3350 output_asm_insn ("ldab\t%b1", operands);
3351 output_asm_insn ("xgdx", operands);
3352 }
3353 else
3354 {
3355 output_asm_insn ("pshb", operands);
3356 output_asm_insn ("ldab\t%b1", operands);
3357 output_asm_insn ("stab\t%T1", operands);
3358 output_asm_insn ("ldx\t%t1", operands);
3359 output_asm_insn ("pulb", operands);
3360 CC_STATUS_INIT;
3361 }
3362 break;
3363
3364 case HARD_Y_REGNUM:
3365 if (D_REG_P (operands[1]))
3366 {
3367 output_asm_insn ("stab\t%T1", operands);
3368 output_asm_insn ("ldy\t%t1", operands);
3369 CC_STATUS_INIT;
3370 }
3371 else if (X_REG_P (operands[1]))
3372 {
3373 output_asm_insn ("stx\t%t1", operands);
3374 output_asm_insn ("ldy\t%t1", operands);
3375 CC_STATUS_INIT;
3376 }
3377 else if (GET_CODE (operands[1]) == CONST_INT)
3378 {
3379 output_asm_insn ("ldy\t%1", operands);
3380 }
3381 else if (dead_register_here (insn, d_reg))
3382 {
3383 output_asm_insn ("ldab\t%b1", operands);
3384 output_asm_insn ("xgdy", operands);
3385 }
3386 else if (!reg_mentioned_p (operands[0], operands[1]))
3387 {
3388 output_asm_insn ("xgdy", operands);
3389 output_asm_insn ("ldab\t%b1", operands);
3390 output_asm_insn ("xgdy", operands);
3391 }
3392 else
3393 {
3394 output_asm_insn ("pshb", operands);
3395 output_asm_insn ("ldab\t%b1", operands);
3396 output_asm_insn ("stab\t%T1", operands);
3397 output_asm_insn ("ldy\t%t1", operands);
3398 output_asm_insn ("pulb", operands);
3399 CC_STATUS_INIT;
3400 }
3401 break;
3402
3403 default:
3404 fatal_insn ("Invalid register in the instruction", insn);
3405 break;
3406 }
3407 }
3408 else if (H_REG_P (operands[1]))
3409 {
3410 switch (REGNO (operands[1]))
3411 {
3412 case HARD_D_REGNUM:
3413 case HARD_B_REGNUM:
3414 output_asm_insn ("stab\t%b0", operands);
3415 break;
3416
3417 case HARD_A_REGNUM:
3418 output_asm_insn ("staa\t%b0", operands);
3419 break;
3420
3421 case HARD_X_REGNUM:
3422 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3423 break;
3424
3425 case HARD_Y_REGNUM:
3426 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3427 break;
3428
3429 default:
3430 fatal_insn ("Invalid register in the move instruction", insn);
3431 break;
3432 }
3433 return;
3434 }
3435 else
3436 {
3437 fatal_insn ("Operand 1 must be a hard register", insn);
3438 }
3439 }
3440
3441 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3442 The source and destination must be D or A and the shift must
3443 be a constant. */
3444 void
3445 m68hc11_gen_rotate (code, insn, operands)
3446 enum rtx_code code;
3447 rtx insn;
3448 rtx operands[];
3449 {
3450 int val;
3451
3452 if (GET_CODE (operands[2]) != CONST_INT
3453 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3454 fatal_insn ("Invalid rotate insn", insn);
3455
3456 val = INTVAL (operands[2]);
3457 if (code == ROTATERT)
3458 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3459
3460 if (GET_MODE (operands[0]) != QImode)
3461 CC_STATUS_INIT;
3462
3463 /* Rotate by 8-bits if the shift is within [5..11]. */
3464 if (val >= 5 && val <= 11)
3465 {
3466 output_asm_insn ("psha", operands);
3467 output_asm_insn ("tba", operands);
3468 output_asm_insn ("pulb", operands);
3469 val -= 8;
3470 }
3471
3472 /* If the shift is big, invert the rotation. */
3473 else if (val >= 12)
3474 {
3475 val = val - 16;
3476 }
3477
3478 if (val > 0)
3479 {
3480 /* Set the carry to bit-15, but don't change D yet. */
3481 if (GET_MODE (operands[0]) != QImode)
3482 {
3483 output_asm_insn ("asra", operands);
3484 output_asm_insn ("rola", operands);
3485 }
3486
3487 while (--val >= 0)
3488 {
3489 /* Rotate B first to move the carry to bit-0. */
3490 if (D_REG_P (operands[0]))
3491 output_asm_insn ("rolb", operands);
3492
3493 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3494 output_asm_insn ("rola", operands);
3495 }
3496 }
3497 else
3498 {
3499 /* Set the carry to bit-8 of D. */
3500 if (val != 0 && GET_MODE (operands[0]) != QImode)
3501 {
3502 output_asm_insn ("tap", operands);
3503 }
3504
3505 while (++val <= 0)
3506 {
3507 /* Rotate B first to move the carry to bit-7. */
3508 if (D_REG_P (operands[0]))
3509 output_asm_insn ("rorb", operands);
3510
3511 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3512 output_asm_insn ("rora", operands);
3513 }
3514 }
3515 }
3516
3517 \f
3518
3519 /* Store in cc_status the expressions that the condition codes will
3520 describe after execution of an instruction whose pattern is EXP.
3521 Do not alter them if the instruction would not alter the cc's. */
3522
3523 void
3524 m68hc11_notice_update_cc (exp, insn)
3525 rtx exp;
3526 rtx insn ATTRIBUTE_UNUSED;
3527 {
3528 /* recognize SET insn's. */
3529 if (GET_CODE (exp) == SET)
3530 {
3531 /* Jumps do not alter the cc's. */
3532 if (SET_DEST (exp) == pc_rtx)
3533 ;
3534
3535 /* NOTE: most instructions don't affect the carry bit, but the
3536 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3537 the conditions.h header. */
3538
3539 /* Function calls clobber the cc's. */
3540 else if (GET_CODE (SET_SRC (exp)) == CALL)
3541 {
3542 CC_STATUS_INIT;
3543 }
3544
3545 /* Tests and compares set the cc's in predictable ways. */
3546 else if (SET_DEST (exp) == cc0_rtx)
3547 {
3548 cc_status.flags = 0;
3549 cc_status.value1 = XEXP (exp, 0);
3550 cc_status.value2 = XEXP (exp, 1);
3551 }
3552 else
3553 {
3554 /* All other instructions affect the condition codes. */
3555 cc_status.flags = 0;
3556 cc_status.value1 = XEXP (exp, 0);
3557 cc_status.value2 = XEXP (exp, 1);
3558 }
3559 }
3560 else
3561 {
3562 /* Default action if we haven't recognized something
3563 and returned earlier. */
3564 CC_STATUS_INIT;
3565 }
3566
3567 if (cc_status.value2 != 0)
3568 switch (GET_CODE (cc_status.value2))
3569 {
3570 /* These logical operations can generate several insns.
3571 The flags are setup according to what is generated. */
3572 case IOR:
3573 case XOR:
3574 case AND:
3575 break;
3576
3577 /* The (not ...) generates several 'com' instructions for
3578 non QImode. We have to invalidate the flags. */
3579 case NOT:
3580 if (GET_MODE (cc_status.value2) != QImode)
3581 CC_STATUS_INIT;
3582 break;
3583
3584 case PLUS:
3585 case MINUS:
3586 case MULT:
3587 case DIV:
3588 case UDIV:
3589 case MOD:
3590 case UMOD:
3591 case NEG:
3592 if (GET_MODE (cc_status.value2) != VOIDmode)
3593 cc_status.flags |= CC_NO_OVERFLOW;
3594 break;
3595
3596 /* The asl sets the overflow bit in such a way that this
3597 makes the flags unusable for a next compare insn. */
3598 case ASHIFT:
3599 case ROTATE:
3600 case ROTATERT:
3601 if (GET_MODE (cc_status.value2) != VOIDmode)
3602 cc_status.flags |= CC_NO_OVERFLOW;
3603 break;
3604
3605 /* A load/store instruction does not affect the carry. */
3606 case MEM:
3607 case SYMBOL_REF:
3608 case REG:
3609 case CONST_INT:
3610 cc_status.flags |= CC_NO_OVERFLOW;
3611 break;
3612
3613 default:
3614 break;
3615 }
3616 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3617 && cc_status.value2
3618 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3619 cc_status.value2 = 0;
3620 }
3621 \f
3622
3623 /* Machine Specific Reorg. */
3624
3625 /* Z register replacement:
3626
3627 GCC treats the Z register as an index base address register like
3628 X or Y. In general, it uses it during reload to compute the address
3629 of some operand. This helps the reload pass to avoid to fall into the
3630 register spill failure.
3631
3632 The Z register is in the A_REGS class. In the machine description,
3633 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
3634
3635 It can appear everywhere an X or Y register can appear, except for
3636 some templates in the clobber section (when a clobber of X or Y is asked).
3637 For a given instruction, the template must ensure that no more than
3638 2 'A' registers are used. Otherwise, the register replacement is not
3639 possible.
3640
3641 To replace the Z register, the algorithm is not terrific:
3642 1. Insns that do not use the Z register are not changed
3643 2. When a Z register is used, we scan forward the insns to see
3644 a potential register to use: either X or Y and sometimes D.
3645 We stop when a call, a label or a branch is seen, or when we
3646 detect that both X and Y are used (probably at different times, but it does
3647 not matter).
3648 3. The register that will be used for the replacement of Z is saved
3649 in a .page0 register or on the stack. If the first instruction that
3650 used Z, uses Z as an input, the value is loaded from another .page0
3651 register. The replacement register is pushed on the stack in the
3652 rare cases where a compare insn uses Z and we couldn't find if X/Y
3653 are dead.
3654 4. The Z register is replaced in all instructions until we reach
3655 the end of the Z-block, as detected by step 2.
3656 5. If we detect that Z is still alive, its value is saved.
3657 If the replacement register is alive, its old value is loaded.
3658
3659 The Z register can be disabled with -ffixed-z.
3660 */
3661
3662 struct replace_info
3663 {
3664 rtx first;
3665 rtx replace_reg;
3666 int need_save_z;
3667 int must_load_z;
3668 int must_save_reg;
3669 int must_restore_reg;
3670 rtx last;
3671 int regno;
3672 int x_used;
3673 int y_used;
3674 int can_use_d;
3675 int found_call;
3676 int z_died;
3677 int z_set_count;
3678 rtx z_value;
3679 int must_push_reg;
3680 int save_before_last;
3681 int z_loaded_with_sp;
3682 };
3683
3684 static rtx z_reg_qi;
3685
3686 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
3687 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
3688 static void m68hc11_z_replacement PARAMS ((rtx));
3689 static void m68hc11_reassign_regs PARAMS ((rtx));
3690
3691 int z_replacement_completed = 0;
3692
3693 /* Analyze the insn to find out which replacement register to use and
3694 the boundaries of the replacement.
3695 Returns 0 if we reached the last insn to be replaced, 1 if we can
3696 continue replacement in next insns. */
3697
3698 static int
3699 m68hc11_check_z_replacement (insn, info)
3700 rtx insn;
3701 struct replace_info *info;
3702 {
3703 int this_insn_uses_ix;
3704 int this_insn_uses_iy;
3705 int this_insn_uses_z;
3706 int this_insn_uses_d;
3707 rtx body;
3708 int z_dies_here;
3709
3710 /* A call is said to clobber the Z register, we don't need
3711 to save the value of Z. We also don't need to restore
3712 the replacement register (unless it is used by the call). */
3713 if (GET_CODE (insn) == CALL_INSN)
3714 {
3715 body = PATTERN (insn);
3716
3717 info->can_use_d = 0;
3718
3719 /* If the call is an indirect call with Z, we have to use the
3720 Y register because X can be used as an input (D+X).
3721 We also must not save Z nor restore Y. */
3722 if (reg_mentioned_p (z_reg, body))
3723 {
3724 insn = NEXT_INSN (insn);
3725 info->x_used = 1;
3726 info->y_used = 0;
3727 info->found_call = 1;
3728 info->must_restore_reg = 0;
3729 info->last = NEXT_INSN (insn);
3730 }
3731 info->need_save_z = 0;
3732 return 0;
3733 }
3734 if (GET_CODE (insn) == CODE_LABEL
3735 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
3736 return 0;
3737
3738 if (GET_CODE (insn) == JUMP_INSN)
3739 {
3740 if (reg_mentioned_p (z_reg, insn) == 0)
3741 return 0;
3742
3743 info->can_use_d = 0;
3744 info->must_save_reg = 0;
3745 info->must_restore_reg = 0;
3746 info->need_save_z = 0;
3747 info->last = NEXT_INSN (insn);
3748 return 0;
3749 }
3750 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
3751 {
3752 return 1;
3753 }
3754
3755 /* Z register dies here. */
3756 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
3757
3758 body = PATTERN (insn);
3759 if (GET_CODE (body) == SET)
3760 {
3761 rtx src = XEXP (body, 1);
3762 rtx dst = XEXP (body, 0);
3763
3764 /* Condition code is set here. We have to restore the X/Y and
3765 save into Z before any test/compare insn because once we save/restore
3766 we can change the condition codes. When the compare insn uses Z and
3767 we can't use X/Y, the comparison is made with the *ZREG soft register
3768 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
3769 if (dst == cc0_rtx)
3770 {
3771 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
3772 || (GET_CODE (src) == COMPARE &&
3773 (rtx_equal_p (XEXP (src, 0), z_reg)
3774 || rtx_equal_p (XEXP (src, 1), z_reg))))
3775 {
3776 if (insn == info->first)
3777 {
3778 info->must_load_z = 0;
3779 info->must_save_reg = 0;
3780 info->must_restore_reg = 0;
3781 info->need_save_z = 0;
3782 info->found_call = 1;
3783 info->regno = SOFT_Z_REGNUM;
3784 info->last = insn;
3785 }
3786 return 0;
3787 }
3788 if (reg_mentioned_p (z_reg, src) == 0)
3789 {
3790 info->can_use_d = 0;
3791 return 0;
3792 }
3793
3794 if (insn != info->first)
3795 return 0;
3796
3797 /* Compare insn which uses Z. We have to save/restore the X/Y
3798 register without modifying the condition codes. For this
3799 we have to use a push/pop insn. */
3800 info->must_push_reg = 1;
3801 info->last = insn;
3802 }
3803
3804 /* Z reg is set to something new. We don't need to load it. */
3805 if (Z_REG_P (dst))
3806 {
3807 if (!reg_mentioned_p (z_reg, src))
3808 {
3809 if (insn == info->first)
3810 {
3811 info->must_load_z = 0;
3812 }
3813 }
3814 info->z_set_count++;
3815 info->z_value = src;
3816 if (SP_REG_P (src))
3817 info->z_loaded_with_sp = 1;
3818 }
3819 else if (reg_mentioned_p (z_reg, dst))
3820 info->can_use_d = 0;
3821
3822 this_insn_uses_d = reg_mentioned_p (d_reg, src)
3823 | reg_mentioned_p (d_reg, dst);
3824 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
3825 | reg_mentioned_p (ix_reg, dst);
3826 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
3827 | reg_mentioned_p (iy_reg, dst);
3828 this_insn_uses_z = reg_mentioned_p (z_reg, src);
3829
3830 /* If z is used as an address operand (like (MEM (reg z))),
3831 we can't replace it with d. */
3832 if (this_insn_uses_z && !Z_REG_P (src))
3833 info->can_use_d = 0;
3834 this_insn_uses_z |= reg_mentioned_p (z_reg, dst);
3835
3836 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
3837 {
3838 fatal_insn ("Registers IX, IY and Z used in the same INSN", insn);
3839 }
3840
3841 if (this_insn_uses_d)
3842 info->can_use_d = 0;
3843
3844 /* IX and IY are used at the same time, we have to restore
3845 the value of the scratch register before this insn. */
3846 if (this_insn_uses_ix && this_insn_uses_iy)
3847 {
3848 return 0;
3849 }
3850
3851 if (info->x_used == 0 && this_insn_uses_ix)
3852 {
3853 if (info->y_used)
3854 {
3855 /* We have a (set (REG:HI X) (REG:HI Z)).
3856 Since we use Z as the replacement register, this insn
3857 is no longer necessary. We turn it into a note. We must
3858 not reload the old value of X. */
3859 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
3860 {
3861 if (z_dies_here)
3862 {
3863 info->need_save_z = 0;
3864 info->z_died = 1;
3865 }
3866 info->must_save_reg = 0;
3867 info->must_restore_reg = 0;
3868 info->found_call = 1;
3869 info->can_use_d = 0;
3870 PUT_CODE (insn, NOTE);
3871 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
3872 NOTE_SOURCE_FILE (insn) = 0;
3873 info->last = NEXT_INSN (insn);
3874 return 0;
3875 }
3876
3877 if (X_REG_P (dst)
3878 && (rtx_equal_p (src, z_reg)
3879 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
3880 {
3881 if (z_dies_here)
3882 {
3883 info->need_save_z = 0;
3884 info->z_died = 1;
3885 }
3886 info->last = NEXT_INSN (insn);
3887 info->must_save_reg = 0;
3888 info->must_restore_reg = 0;
3889 }
3890 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
3891 && !reg_mentioned_p (ix_reg, src))
3892 {
3893 if (z_dies_here)
3894 {
3895 info->z_died = 1;
3896 info->need_save_z = 0;
3897 }
3898 else
3899 {
3900 info->save_before_last = 1;
3901 }
3902 info->must_restore_reg = 0;
3903 info->last = NEXT_INSN (insn);
3904 }
3905 else if (info->can_use_d)
3906 {
3907 info->last = NEXT_INSN (insn);
3908 info->x_used = 1;
3909 }
3910 return 0;
3911 }
3912 info->x_used = 1;
3913 if (z_dies_here && !reg_mentioned_p (src, ix_reg)
3914 && GET_CODE (src) == REG && REGNO (src) == HARD_X_REGNUM)
3915 {
3916 info->need_save_z = 0;
3917 info->z_died = 1;
3918 info->last = NEXT_INSN (insn);
3919 info->regno = HARD_X_REGNUM;
3920 info->must_save_reg = 0;
3921 info->must_restore_reg = 0;
3922 return 0;
3923 }
3924 }
3925 if (info->y_used == 0 && this_insn_uses_iy)
3926 {
3927 if (info->x_used)
3928 {
3929 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
3930 {
3931 if (z_dies_here)
3932 {
3933 info->need_save_z = 0;
3934 info->z_died = 1;
3935 }
3936 info->must_save_reg = 0;
3937 info->must_restore_reg = 0;
3938 info->found_call = 1;
3939 info->can_use_d = 0;
3940 PUT_CODE (insn, NOTE);
3941 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
3942 NOTE_SOURCE_FILE (insn) = 0;
3943 info->last = NEXT_INSN (insn);
3944 return 0;
3945 }
3946
3947 if (Y_REG_P (dst)
3948 && (rtx_equal_p (src, z_reg)
3949 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
3950 {
3951 if (z_dies_here)
3952 {
3953 info->z_died = 1;
3954 info->need_save_z = 0;
3955 }
3956 info->last = NEXT_INSN (insn);
3957 info->must_save_reg = 0;
3958 info->must_restore_reg = 0;
3959 }
3960 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
3961 && !reg_mentioned_p (iy_reg, src))
3962 {
3963 if (z_dies_here)
3964 {
3965 info->z_died = 1;
3966 info->need_save_z = 0;
3967 }
3968 else
3969 {
3970 info->save_before_last = 1;
3971 }
3972 info->must_restore_reg = 0;
3973 info->last = NEXT_INSN (insn);
3974 }
3975 else if (info->can_use_d)
3976 {
3977 info->last = NEXT_INSN (insn);
3978 info->y_used = 1;
3979 }
3980
3981 return 0;
3982 }
3983 info->y_used = 1;
3984 if (z_dies_here && !reg_mentioned_p (src, iy_reg)
3985 && GET_CODE (src) == REG && REGNO (src) == HARD_Y_REGNUM)
3986 {
3987 info->need_save_z = 0;
3988 info->z_died = 1;
3989 info->last = NEXT_INSN (insn);
3990 info->regno = HARD_Y_REGNUM;
3991 info->must_save_reg = 0;
3992 info->must_restore_reg = 0;
3993 return 0;
3994 }
3995 }
3996 if (z_dies_here)
3997 {
3998 info->need_save_z = 0;
3999 info->z_died = 1;
4000 if (info->last == 0)
4001 info->last = NEXT_INSN (insn);
4002 return 0;
4003 }
4004 return info->last != NULL_RTX ? 0 : 1;
4005 }
4006 if (GET_CODE (body) == PARALLEL)
4007 {
4008 int i;
4009 char ix_clobber = 0;
4010 char iy_clobber = 0;
4011 char z_clobber = 0;
4012 this_insn_uses_iy = 0;
4013 this_insn_uses_ix = 0;
4014 this_insn_uses_z = 0;
4015
4016 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4017 {
4018 rtx x;
4019 int uses_ix, uses_iy, uses_z;
4020
4021 x = XVECEXP (body, 0, i);
4022
4023 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4024 info->can_use_d = 0;
4025
4026 uses_ix = reg_mentioned_p (ix_reg, x);
4027 uses_iy = reg_mentioned_p (iy_reg, x);
4028 uses_z = reg_mentioned_p (z_reg, x);
4029 if (GET_CODE (x) == CLOBBER)
4030 {
4031 ix_clobber |= uses_ix;
4032 iy_clobber |= uses_iy;
4033 z_clobber |= uses_z;
4034 }
4035 else
4036 {
4037 this_insn_uses_ix |= uses_ix;
4038 this_insn_uses_iy |= uses_iy;
4039 this_insn_uses_z |= uses_z;
4040 }
4041 if (uses_z && GET_CODE (x) == SET)
4042 {
4043 rtx dst = XEXP (x, 0);
4044
4045 if (Z_REG_P (dst))
4046 info->z_set_count++;
4047 }
4048 if (z_clobber)
4049 info->need_save_z = 0;
4050 }
4051 if (debug_m6811)
4052 {
4053 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4054 this_insn_uses_ix, this_insn_uses_iy,
4055 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4056 debug_rtx (insn);
4057 }
4058 if (this_insn_uses_z)
4059 info->can_use_d = 0;
4060
4061 if (z_clobber && info->first != insn)
4062 {
4063 info->need_save_z = 0;
4064 info->last = insn;
4065 return 0;
4066 }
4067 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4068 {
4069 if (this_insn_uses_z == 0 && insn == info->first)
4070 {
4071 info->must_load_z = 0;
4072 }
4073 if (dead_register_here (insn, d_reg))
4074 {
4075 info->regno = HARD_D_REGNUM;
4076 info->must_save_reg = 0;
4077 info->must_restore_reg = 0;
4078 }
4079 else if (dead_register_here (insn, ix_reg))
4080 {
4081 info->regno = HARD_X_REGNUM;
4082 info->must_save_reg = 0;
4083 info->must_restore_reg = 0;
4084 }
4085 else if (dead_register_here (insn, iy_reg))
4086 {
4087 info->regno = HARD_Y_REGNUM;
4088 info->must_save_reg = 0;
4089 info->must_restore_reg = 0;
4090 }
4091 if (info->regno >= 0)
4092 {
4093 info->last = NEXT_INSN (insn);
4094 return 0;
4095 }
4096 if (this_insn_uses_ix == 0)
4097 {
4098 info->regno = HARD_X_REGNUM;
4099 info->must_save_reg = 1;
4100 info->must_restore_reg = 1;
4101 }
4102 else if (this_insn_uses_iy == 0)
4103 {
4104 info->regno = HARD_Y_REGNUM;
4105 info->must_save_reg = 1;
4106 info->must_restore_reg = 1;
4107 }
4108 else
4109 {
4110 info->regno = HARD_D_REGNUM;
4111 info->must_save_reg = 1;
4112 info->must_restore_reg = 1;
4113 }
4114 info->last = NEXT_INSN (insn);
4115 return 0;
4116 }
4117
4118 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4119 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4120 {
4121 if (this_insn_uses_z)
4122 {
4123 if (info->y_used == 0 && iy_clobber)
4124 {
4125 info->regno = HARD_Y_REGNUM;
4126 info->must_save_reg = 0;
4127 info->must_restore_reg = 0;
4128 }
4129 info->last = NEXT_INSN (insn);
4130 info->save_before_last = 1;
4131 }
4132 return 0;
4133 }
4134 if (this_insn_uses_ix && this_insn_uses_iy)
4135 {
4136 if (this_insn_uses_z)
4137 {
4138 fatal_insn ("Cannot do z-register replacement", insn);
4139 }
4140 return 0;
4141 }
4142 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4143 {
4144 if (info->y_used)
4145 {
4146 return 0;
4147 }
4148 info->x_used = 1;
4149 if (iy_clobber || z_clobber)
4150 {
4151 info->last = NEXT_INSN (insn);
4152 info->save_before_last = 1;
4153 return 0;
4154 }
4155 }
4156
4157 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4158 {
4159 if (info->x_used)
4160 {
4161 return 0;
4162 }
4163 info->y_used = 1;
4164 if (ix_clobber || z_clobber)
4165 {
4166 info->last = NEXT_INSN (insn);
4167 info->save_before_last = 1;
4168 return 0;
4169 }
4170 }
4171 if (z_dies_here)
4172 {
4173 info->z_died = 1;
4174 info->need_save_z = 0;
4175 }
4176 return 1;
4177 }
4178 if (GET_CODE (body) == CLOBBER)
4179 {
4180
4181 /* IX and IY are used at the same time, we have to restore
4182 the value of the scratch register before this insn. */
4183 if (this_insn_uses_ix && this_insn_uses_iy)
4184 {
4185 return 0;
4186 }
4187 if (info->x_used == 0 && this_insn_uses_ix)
4188 {
4189 if (info->y_used)
4190 {
4191 return 0;
4192 }
4193 info->x_used = 1;
4194 }
4195 if (info->y_used == 0 && this_insn_uses_iy)
4196 {
4197 if (info->x_used)
4198 {
4199 return 0;
4200 }
4201 info->y_used = 1;
4202 }
4203 return 1;
4204 }
4205 return 1;
4206 }
4207
4208 static void
4209 m68hc11_find_z_replacement (insn, info)
4210 rtx insn;
4211 struct replace_info *info;
4212 {
4213 int reg;
4214
4215 info->replace_reg = NULL_RTX;
4216 info->must_load_z = 1;
4217 info->need_save_z = 1;
4218 info->must_save_reg = 1;
4219 info->must_restore_reg = 1;
4220 info->first = insn;
4221 info->x_used = 0;
4222 info->y_used = 0;
4223 info->can_use_d = TARGET_M6811 ? 1 : 0;
4224 info->found_call = 0;
4225 info->z_died = 0;
4226 info->last = 0;
4227 info->regno = -1;
4228 info->z_set_count = 0;
4229 info->z_value = NULL_RTX;
4230 info->must_push_reg = 0;
4231 info->save_before_last = 0;
4232 info->z_loaded_with_sp = 0;
4233
4234 /* Scan the insn forward to find an address register that is not used.
4235 Stop when:
4236 - the flow of the program changes,
4237 - when we detect that both X and Y are necessary,
4238 - when the Z register dies,
4239 - when the condition codes are set. */
4240
4241 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4242 {
4243 if (m68hc11_check_z_replacement (insn, info) == 0)
4244 break;
4245 }
4246
4247 /* May be we can use Y or X if they contain the same value as Z.
4248 This happens very often after the reload. */
4249 if (info->z_set_count == 1)
4250 {
4251 rtx p = info->first;
4252 rtx v = 0;
4253
4254 if (info->x_used)
4255 {
4256 v = find_last_value (iy_reg, &p, insn, 1);
4257 }
4258 else if (info->y_used)
4259 {
4260 v = find_last_value (ix_reg, &p, insn, 1);
4261 }
4262 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4263 {
4264 if (info->x_used)
4265 info->regno = HARD_Y_REGNUM;
4266 else
4267 info->regno = HARD_X_REGNUM;
4268 info->must_load_z = 0;
4269 info->must_save_reg = 0;
4270 info->must_restore_reg = 0;
4271 info->found_call = 1;
4272 }
4273 }
4274 if (info->z_set_count == 0)
4275 info->need_save_z = 0;
4276
4277 if (insn == 0)
4278 info->need_save_z = 0;
4279
4280 if (info->last == 0)
4281 info->last = insn;
4282
4283 if (info->regno >= 0)
4284 {
4285 reg = info->regno;
4286 info->replace_reg = gen_rtx (REG, HImode, reg);
4287 }
4288 else if (info->can_use_d)
4289 {
4290 reg = HARD_D_REGNUM;
4291 info->replace_reg = d_reg;
4292 }
4293 else if (info->x_used)
4294 {
4295 reg = HARD_Y_REGNUM;
4296 info->replace_reg = iy_reg;
4297 }
4298 else
4299 {
4300 reg = HARD_X_REGNUM;
4301 info->replace_reg = ix_reg;
4302 }
4303 info->regno = reg;
4304
4305 if (info->must_save_reg && info->must_restore_reg)
4306 {
4307 if (insn && dead_register_here (insn, info->replace_reg))
4308 {
4309 info->must_save_reg = 0;
4310 info->must_restore_reg = 0;
4311 }
4312 }
4313 }
4314
4315 /* The insn uses the Z register. Find a replacement register for it
4316 (either X or Y) and replace it in the insn and the next ones until
4317 the flow changes or the replacement register is used. Instructions
4318 are emited before and after the Z-block to preserve the value of
4319 Z and of the replacement register. */
4320
4321 static void
4322 m68hc11_z_replacement (insn)
4323 rtx insn;
4324 {
4325 rtx replace_reg_qi;
4326 rtx replace_reg;
4327 struct replace_info info;
4328
4329 /* Find trivial case where we only need to replace z with the
4330 equivalent soft register. */
4331 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4332 {
4333 rtx body = PATTERN (insn);
4334 rtx src = XEXP (body, 1);
4335 rtx dst = XEXP (body, 0);
4336
4337 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4338 {
4339 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4340 return;
4341 }
4342 else if (Z_REG_P (src)
4343 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4344 {
4345 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4346 return;
4347 }
4348 else if (D_REG_P (dst)
4349 && m68hc11_arith_operator (src, GET_MODE (src))
4350 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4351 {
4352 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4353 return;
4354 }
4355 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4356 && INTVAL (src) == 0)
4357 {
4358 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4359 return;
4360 }
4361 }
4362
4363 m68hc11_find_z_replacement (insn, &info);
4364
4365 replace_reg = info.replace_reg;
4366 replace_reg_qi = NULL_RTX;
4367
4368 /* Save the X register in a .page0 location. */
4369 if (info.must_save_reg && !info.must_push_reg)
4370 {
4371 rtx dst;
4372
4373 if (info.must_push_reg && 0)
4374 dst = gen_rtx (MEM, HImode,
4375 gen_rtx (PRE_DEC, HImode,
4376 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4377 else
4378 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4379
4380 emit_insn_before (gen_movhi (dst,
4381 gen_rtx (REG, HImode, info.regno)), insn);
4382 }
4383 if (info.must_load_z && !info.must_push_reg)
4384 {
4385 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4386 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4387 insn);
4388 }
4389
4390
4391 /* Replace all occurence of Z by replace_reg.
4392 Stop when the last instruction to replace is reached.
4393 Also stop when we detect a change in the flow (but it's not
4394 necessary; just safeguard). */
4395
4396 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4397 {
4398 rtx body;
4399
4400 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4401 break;
4402
4403 if (GET_CODE (insn) != INSN
4404 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4405 continue;
4406
4407 body = PATTERN (insn);
4408 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4409 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4410 {
4411 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4412 {
4413 printf ("Reg mentioned here...:\n");
4414 fflush (stdout);
4415 debug_rtx (insn);
4416 }
4417
4418 /* Stack pointer was decremented by 2 due to the push.
4419 Correct that by adding 2 to the destination. */
4420 if (info.must_push_reg
4421 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4422 {
4423 rtx src, dst;
4424
4425 src = SET_SRC (body);
4426 dst = SET_DEST (body);
4427 if (SP_REG_P (src) && Z_REG_P (dst))
4428 {
4429 emit_insn_after (gen_addhi3 (dst,
4430 dst,
4431 gen_rtx (CONST_INT,
4432 VOIDmode, 2)), insn);
4433 }
4434 }
4435
4436 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4437 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4438 {
4439 INSN_CODE (insn) = -1;
4440 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4441 fatal_insn ("Cannot do z-register replacement", insn);
4442 }
4443
4444 /* Likewise for (REG:QI Z). */
4445 if (reg_mentioned_p (z_reg, insn))
4446 {
4447 if (replace_reg_qi == NULL_RTX)
4448 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4449 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4450 }
4451 }
4452 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4453 break;
4454 }
4455
4456 /* Save Z before restoring the old value. */
4457 if (insn && info.need_save_z && !info.must_push_reg)
4458 {
4459 rtx save_pos_insn = insn;
4460
4461 /* If Z is clobber by the last insn, we have to save its value
4462 before the last instruction. */
4463 if (info.save_before_last)
4464 save_pos_insn = PREV_INSN (save_pos_insn);
4465
4466 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
4467 gen_rtx (REG, HImode, info.regno)),
4468 save_pos_insn);
4469 }
4470
4471 if (info.must_push_reg && info.last)
4472 {
4473 rtx new_body, body;
4474
4475 body = PATTERN (info.last);
4476 new_body = gen_rtx (PARALLEL, VOIDmode,
4477 gen_rtvec (3, body,
4478 gen_rtx (USE, VOIDmode,
4479 replace_reg),
4480 gen_rtx (USE, VOIDmode,
4481 gen_rtx (REG, HImode,
4482 SOFT_Z_REGNUM))));
4483 PATTERN (info.last) = new_body;
4484
4485 /* Force recognition on insn since we changed it. */
4486 INSN_CODE (insn) = -1;
4487
4488 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4489 {
4490 fatal_insn ("Invalid Z register replacement for insn", insn);
4491 }
4492 insn = NEXT_INSN (info.last);
4493 }
4494
4495 /* Restore replacement register unless it was died. */
4496 if (insn && info.must_restore_reg && !info.must_push_reg)
4497 {
4498 rtx dst;
4499
4500 if (info.must_push_reg && 0)
4501 dst = gen_rtx (MEM, HImode,
4502 gen_rtx (POST_INC, HImode,
4503 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4504 else
4505 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4506
4507 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4508 dst), insn);
4509 }
4510
4511 }
4512
4513
4514 /* Scan all the insn and re-affects some registers
4515 - The Z register (if it was used), is affected to X or Y depending
4516 on the instruction. */
4517
4518 static void
4519 m68hc11_reassign_regs (first)
4520 rtx first;
4521 {
4522 rtx insn;
4523
4524 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
4525 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
4526 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4527 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
4528
4529 /* Scan all insns to replace Z by X or Y preserving the old value
4530 of X/Y and restoring it afterward. */
4531
4532 for (insn = first; insn; insn = NEXT_INSN (insn))
4533 {
4534 rtx body;
4535
4536 if (GET_CODE (insn) == CODE_LABEL
4537 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4538 continue;
4539
4540 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4541 continue;
4542
4543 body = PATTERN (insn);
4544 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4545 continue;
4546
4547 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
4548 || GET_CODE (body) == ASM_OPERANDS
4549 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
4550 continue;
4551
4552 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4553 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4554 {
4555
4556 /* If Z appears in this insn, replace it in the current insn
4557 and the next ones until the flow changes or we have to
4558 restore back the replacement register. */
4559
4560 if (reg_mentioned_p (z_reg, body))
4561 {
4562 m68hc11_z_replacement (insn);
4563 }
4564 }
4565 else
4566 {
4567 printf ("Insn not handled by Z replacement:\n");
4568 fflush (stdout);
4569 debug_rtx (insn);
4570 }
4571 }
4572 }
4573
4574
4575 void
4576 m68hc11_reorg (first)
4577 rtx first;
4578 {
4579 int split_done = 0;
4580
4581 z_replacement_completed = 0;
4582 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
4583
4584 /* Some RTX are shared at this point. This breaks the Z register
4585 replacement, unshare everything. */
4586 unshare_all_rtl_again (first);
4587
4588 /* Force a split of all splitable insn. This is necessary for the
4589 Z register replacement mechanism because we end up with basic insns. */
4590 split_all_insns (0);
4591 split_done = 1;
4592
4593 z_replacement_completed = 1;
4594 m68hc11_reassign_regs (first);
4595
4596 /* After some splitting, there are some oportunities for CSE pass.
4597 This happens quite often when 32-bit or above patterns are split. */
4598 if (optimize > 0 && split_done)
4599 reload_cse_regs (first);
4600
4601 /* Re-create the REG_DEAD notes. These notes are used in the machine
4602 description to use the best assembly directives. */
4603 if (optimize)
4604 {
4605 find_basic_blocks (first, max_reg_num (), 0);
4606 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
4607 }
4608
4609 z_replacement_completed = 2;
4610
4611 /* If optimizing, then go ahead and split insns that must be
4612 split after Z register replacement. This gives more opportunities
4613 for peephole (in particular for consecutives xgdx/xgdy). */
4614 if (optimize > 0)
4615 split_all_insns (0);
4616
4617 /* Once insns are split after the z_replacement_completed == 2,
4618 we must not re-run the life_analysis. The xgdx/xgdy patterns
4619 are not recognized and the life_analysis pass removes some
4620 insns because it thinks some (SETs) are noops or made to dead
4621 stores (which is false due to the swap).
4622
4623 Do a simple pass to eliminate the noop set that the final
4624 split could generate (because it was easier for split definition). */
4625 {
4626 rtx insn;
4627
4628 for (insn = first; insn; insn = NEXT_INSN (insn))
4629 {
4630 rtx body;
4631
4632 if (INSN_DELETED_P (insn))
4633 continue;
4634 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
4635 continue;
4636
4637 /* Remove the (set (R) (R)) insns generated by some splits. */
4638 body = PATTERN (insn);
4639 if (GET_CODE (body) == SET
4640 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
4641 {
4642 PUT_CODE (insn, NOTE);
4643 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4644 NOTE_SOURCE_FILE (insn) = 0;
4645 continue;
4646 }
4647 }
4648 }
4649 }
4650 \f
4651
4652 /* Cost functions. */
4653
4654 #define COSTS_N_INSNS(N) ((N) * 4 - 2)
4655
4656 /* Cost of moving memory. */
4657 int
4658 m68hc11_memory_move_cost (mode, class, in)
4659 enum machine_mode mode;
4660 enum reg_class class;
4661 int in ATTRIBUTE_UNUSED;
4662 {
4663 if (class <= H_REGS)
4664 {
4665 if (GET_MODE_SIZE (mode) <= 2)
4666 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4667 else
4668 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
4669 }
4670 else
4671 {
4672 if (GET_MODE_SIZE (mode) <= 2)
4673 return COSTS_N_INSNS (2);
4674 else
4675 return COSTS_N_INSNS (4);
4676 }
4677 }
4678
4679
4680 /* Cost of moving data from a register of class 'from' to on in class 'to'.
4681 Reload does not check the constraint of set insns when the two registers
4682 have a move cost of 2. Setting a higher cost will force reload to check
4683 the constraints. */
4684 int
4685 m68hc11_register_move_cost (from, to)
4686 enum reg_class from;
4687 enum reg_class to;
4688 {
4689 if (from >= S_REGS && to >= S_REGS)
4690 {
4691 return COSTS_N_INSNS (3);
4692 }
4693 if (from <= S_REGS && to <= S_REGS)
4694 {
4695 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
4696 }
4697 return COSTS_N_INSNS (2);
4698 }
4699
4700
4701 /* Provide the costs of an addressing mode that contains ADDR.
4702 If ADDR is not a valid address, its cost is irrelevant. */
4703
4704 int
4705 m68hc11_address_cost (addr)
4706 rtx addr;
4707 {
4708 int cost = 4;
4709
4710 switch (GET_CODE (addr))
4711 {
4712 case REG:
4713 /* Make the cost of hard registers and specially SP, FP small. */
4714 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
4715 cost = 0;
4716 else
4717 cost = 1;
4718 break;
4719
4720 case SYMBOL_REF:
4721 cost = 8;
4722 break;
4723
4724 case LABEL_REF:
4725 case CONST:
4726 cost = 0;
4727 break;
4728
4729 case PLUS:
4730 {
4731 register rtx plus0 = XEXP (addr, 0);
4732 register rtx plus1 = XEXP (addr, 1);
4733
4734 if (GET_CODE (plus0) != REG)
4735 break;
4736
4737 switch (GET_CODE (plus1))
4738 {
4739 case CONST_INT:
4740 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
4741 || INTVAL (plus1) < m68hc11_min_offset)
4742 cost = 3;
4743 else if (INTVAL (plus1) >= m68hc11_max_offset)
4744 cost = 2;
4745 else
4746 cost = 0;
4747 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
4748 cost += 0;
4749 else
4750 cost += 1;
4751 break;
4752
4753 case SYMBOL_REF:
4754 cost = 8;
4755 break;
4756
4757 case CONST:
4758 case LABEL_REF:
4759 cost = 0;
4760 break;
4761
4762 default:
4763 break;
4764 }
4765 break;
4766 }
4767 case PRE_DEC:
4768 case PRE_INC:
4769 if (SP_REG_P (XEXP (addr, 0)))
4770 cost = 1;
4771 break;
4772
4773 default:
4774 break;
4775 }
4776 if (debug_m6811)
4777 {
4778 printf ("Address cost: %d for :", cost);
4779 fflush (stdout);
4780 debug_rtx (addr);
4781 }
4782
4783 return cost;
4784 }
4785
4786 int
4787 m68hc11_rtx_costs (x, code, outer_code)
4788 rtx x;
4789 enum rtx_code code, outer_code;
4790 {
4791 enum machine_mode mode = GET_MODE (x);
4792 int extra_cost = 0;
4793 int total;
4794
4795 switch (code)
4796 {
4797 case MEM:
4798 return m68hc11_address_cost (XEXP (x, 0)) + 4;
4799
4800 case ROTATE:
4801 case ROTATERT:
4802 case ASHIFT:
4803 case LSHIFTRT:
4804 case ASHIFTRT:
4805 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
4806 {
4807 int val = INTVAL (XEXP (x, 1));
4808 int cost;
4809
4810 /* 8 or 16 shift instructions are fast.
4811 Others are proportional to the shift counter. */
4812 if (val == 8 || val == 16 || val == -8 || val == -16)
4813 {
4814 val = 0;
4815 }
4816 cost = COSTS_N_INSNS (val + 1);
4817 cost += rtx_cost (XEXP (x, 0), outer_code);
4818 if (GET_MODE_SIZE (mode) >= 4 && val)
4819 {
4820 cost *= 4;
4821 }
4822 return cost;
4823 }
4824 total = rtx_cost (XEXP (x, 0), outer_code);
4825 if (GET_MODE_SIZE (mode) >= 4)
4826 {
4827 total += COSTS_N_INSNS (16);
4828 }
4829 else
4830 {
4831 total += COSTS_N_INSNS (8);
4832 }
4833 return total;
4834
4835 case MINUS:
4836 case PLUS:
4837 case AND:
4838 case XOR:
4839 case IOR:
4840 extra_cost = 0;
4841
4842 total = rtx_cost (XEXP (x, 0), outer_code)
4843 + rtx_cost (XEXP (x, 1), outer_code);
4844 if (GET_MODE_SIZE (mode) <= 2)
4845 {
4846 total += COSTS_N_INSNS (2);
4847 }
4848 else
4849 {
4850 total += COSTS_N_INSNS (4);
4851 }
4852 return total;
4853
4854 case DIV:
4855 case MOD:
4856 if (mode == QImode || mode == HImode)
4857 {
4858 return 30;
4859 }
4860 else if (mode == SImode)
4861 {
4862 return 100;
4863 }
4864 else
4865 {
4866 return 150;
4867 }
4868
4869 case MULT:
4870 if (mode == QImode)
4871 {
4872 return TARGET_OP_TIME ? 10 : 2;
4873 }
4874 if (mode == HImode)
4875 {
4876 return TARGET_OP_TIME ? 30 : 4;
4877 }
4878 if (mode == SImode)
4879 {
4880 return TARGET_OP_TIME ? 100 : 20;
4881 }
4882 return 150;
4883
4884 case NEG:
4885 case SIGN_EXTEND:
4886 extra_cost = COSTS_N_INSNS (2);
4887
4888 /* Fall through */
4889 case NOT:
4890 case COMPARE:
4891 case ABS:
4892 case ZERO_EXTEND:
4893 total = rtx_cost (XEXP (x, 0), outer_code);
4894 if (mode == QImode)
4895 {
4896 return total + extra_cost + COSTS_N_INSNS (1);
4897 }
4898 if (mode == HImode)
4899 {
4900 return total + extra_cost + COSTS_N_INSNS (2);
4901 }
4902 if (mode == SImode)
4903 {
4904 return total + extra_cost + COSTS_N_INSNS (4);
4905 }
4906 return total + extra_cost + COSTS_N_INSNS (8);
4907
4908 case IF_THEN_ELSE:
4909 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
4910 return COSTS_N_INSNS (1);
4911
4912 return COSTS_N_INSNS (1);
4913
4914 default:
4915 return COSTS_N_INSNS (4);
4916 }
4917 }
4918 \f
4919
4920 /* print_options - called at the start of the code generation for a
4921 module. */
4922
4923 extern char *asm_file_name;
4924
4925 #include <time.h>
4926 #include <sys/types.h>
4927
4928 static void
4929 print_options (out)
4930 FILE *out;
4931 {
4932 char *a_time;
4933 long c_time;
4934 int i;
4935 extern int save_argc;
4936 extern char **save_argv;
4937
4938 fprintf (out, ";;; Command:\t");
4939 for (i = 0; i < save_argc; i++)
4940 {
4941 fprintf (out, "%s", save_argv[i]);
4942 if (i + 1 < save_argc)
4943 fprintf (out, " ");
4944 }
4945 fprintf (out, "\n");
4946 c_time = time (0);
4947 a_time = ctime (&c_time);
4948 fprintf (out, ";;; Compiled:\t%s", a_time);
4949 #ifdef __GNUC__
4950 #ifndef __VERSION__
4951 #define __VERSION__ "[unknown]"
4952 #endif
4953 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
4954 #else
4955 fprintf (out, ";;; (META)compiled by CC.\n");
4956 #endif
4957 }
4958
4959 void
4960 m68hc11_asm_file_start (out, main_file)
4961 FILE *out;
4962 char *main_file;
4963 {
4964 fprintf (out, ";;;-----------------------------------------\n");
4965 fprintf (out, ";;; Start MC68HC11 gcc assembly output\n");
4966 fprintf (out, ";;; gcc compiler %s\n", version_string);
4967 print_options (out);
4968 fprintf (out, ";;;-----------------------------------------\n");
4969 output_file_directive (out, main_file);
4970 }
4971
4972
4973 static void
4974 m68hc11_add_gc_roots ()
4975 {
4976 ggc_add_rtx_root (&m68hc11_soft_tmp_reg, 1);
4977 ggc_add_rtx_root (&ix_reg, 1);
4978 ggc_add_rtx_root (&iy_reg, 1);
4979 ggc_add_rtx_root (&d_reg, 1);
4980 ggc_add_rtx_root (&da_reg, 1);
4981 ggc_add_rtx_root (&z_reg, 1);
4982 ggc_add_rtx_root (&z_reg_qi, 1);
4983 ggc_add_rtx_root (&stack_push_word, 1);
4984 ggc_add_rtx_root (&stack_pop_word, 1);
4985 }