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