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