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