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