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