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