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