* target.h (encode_section_info): Add new argument carrying
[official-gcc.git] / gcc / config / m68hc11 / m68hc11.c
blob1a129d1c43dd7329345759393cb9c6477be98b88
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)
5 This file is part of GNU CC.
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.
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.
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.
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.
29 The gcc 2.6.3 port is available at:
31 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
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"
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[];
78 void create_regs_rtx PARAMS ((void));
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, rtx, int));
85 static int autoinc_mode PARAMS((rtx));
86 static int m68hc11_make_autoinc_notes PARAMS((rtx *, void *));
88 /* Must be set to 1 to produce debug messages. */
89 int debug_m6811 = 0;
91 extern FILE *asm_out_file;
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;
103 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
104 int current_function_interrupt;
106 /* Set to 1 by expand_prologue() when the function is a trap handler. */
107 int current_function_trap;
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;
113 /* Min offset that is valid for the indirect addressing mode. */
114 HOST_WIDE_INT m68hc11_min_offset = 0;
116 /* Max offset that is valid for the indirect addressing mode. */
117 HOST_WIDE_INT m68hc11_max_offset = 256;
119 /* The class value for base registers. */
120 enum reg_class m68hc11_base_reg_class = A_REGS;
122 /* The class value for index registers. This is NO_REGS for 68HC11. */
123 enum reg_class m68hc11_index_reg_class = NO_REGS;
125 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
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];
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;
137 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
138 rtx m68hc11_compare_op0;
139 rtx m68hc11_compare_op1;
142 const struct processor_costs *m68hc11_cost;
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) },
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)
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)
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) },
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)
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)
214 /* Machine specific options */
216 const char *m68hc11_regparm_string;
217 const char *m68hc11_reg_alloc_order;
218 const char *m68hc11_soft_reg_count;
220 static int nb_soft_regs;
222 /* Initialize the GCC target structure. */
223 #undef TARGET_ATTRIBUTE_TABLE
224 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
226 #undef TARGET_ASM_ALIGNED_HI_OP
227 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
229 #undef TARGET_ASM_FUNCTION_EPILOGUE
230 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
232 #undef TARGET_ENCODE_SECTION_INFO
233 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
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
240 struct gcc_target targetm = TARGET_INITIALIZER;
243 m68hc11_override_options ()
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));
249 /* Compilation with -fpic generates a wrong code. */
250 if (flag_pic)
252 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
253 (flag_pic > 1) ? "PIC" : "pic");
254 flag_pic = 0;
257 /* Configure for a 68hc11 processor. */
258 if (TARGET_M6811)
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;
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";
281 /* Configure for a 68hc12 processor. */
282 if (TARGET_M6812)
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;
298 if (m68hc11_soft_reg_count == 0)
299 m68hc11_soft_reg_count = "0";
301 if (TARGET_LONG_CALLS)
302 current_function_far = 1;
304 return 0;
308 void
309 m68hc11_conditional_register_usage ()
311 int i;
312 int cnt = atoi (m68hc11_soft_reg_count);
314 if (cnt < 0)
315 cnt = 0;
316 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
317 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
319 nb_soft_regs = cnt;
320 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
322 fixed_regs[i] = 1;
323 call_used_regs[i] = 1;
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)
331 fixed_regs[HARD_Z_REGNUM] = 1;
336 /* Reload and register operations. */
338 static const char *const reg_class_names[] = REG_CLASS_NAMES;
341 void
342 create_regs_rtx ()
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);
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)));
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. */
368 hard_regno_mode_ok (regno, mode)
369 int regno;
370 enum machine_mode mode;
372 switch (GET_MODE_SIZE (mode))
374 case 8:
375 return S_REGNO_P (regno) && nb_soft_regs >= 4;
377 case 4:
378 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
380 case 2:
381 return G_REGNO_P (regno);
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. */
390 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
392 default:
393 return 0;
398 m68hc11_hard_regno_rename_ok (reg1, reg2)
399 int reg1, reg2;
401 /* Don't accept renaming to Z register. We will replace it to
402 X,Y or D during machine reorg pass. */
403 if (reg2 == HARD_Z_REGNUM)
404 return 0;
406 /* Don't accept renaming D,X to Y register as the code will be bigger. */
407 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
408 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
409 return 0;
411 return 1;
414 enum reg_class
415 preferred_reload_class (operand, class)
416 rtx operand;
417 enum reg_class class;
419 enum machine_mode mode;
421 mode = GET_MODE (operand);
423 if (debug_m6811)
425 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
428 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
429 return m68hc11_base_reg_class;
431 if (class >= S_REGS && (GET_CODE (operand) == MEM
432 || GET_CODE (operand) == CONST_INT))
434 /* S_REGS class must not be used. The movhi template does not
435 work to move a memory to a soft register.
436 Restrict to a hard reg. */
437 switch (class)
439 default:
440 case G_REGS:
441 case D_OR_A_OR_S_REGS:
442 class = A_OR_D_REGS;
443 break;
444 case A_OR_S_REGS:
445 class = A_REGS;
446 break;
447 case D_OR_SP_OR_S_REGS:
448 class = D_OR_SP_REGS;
449 break;
450 case D_OR_Y_OR_S_REGS:
451 class = D_OR_Y_REGS;
452 break;
453 case D_OR_X_OR_S_REGS:
454 class = D_OR_X_REGS;
455 break;
456 case SP_OR_S_REGS:
457 class = SP_REGS;
458 break;
459 case Y_OR_S_REGS:
460 class = Y_REGS;
461 break;
462 case X_OR_S_REGS:
463 class = X_REGS;
464 break;
465 case D_OR_S_REGS:
466 class = D_REGS;
469 else if (class == Y_REGS && GET_CODE (operand) == MEM)
471 class = Y_REGS;
473 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
475 class = D_OR_X_REGS;
477 else if (class >= S_REGS && S_REG_P (operand))
479 switch (class)
481 default:
482 case G_REGS:
483 case D_OR_A_OR_S_REGS:
484 class = A_OR_D_REGS;
485 break;
486 case A_OR_S_REGS:
487 class = A_REGS;
488 break;
489 case D_OR_SP_OR_S_REGS:
490 class = D_OR_SP_REGS;
491 break;
492 case D_OR_Y_OR_S_REGS:
493 class = D_OR_Y_REGS;
494 break;
495 case D_OR_X_OR_S_REGS:
496 class = D_OR_X_REGS;
497 break;
498 case SP_OR_S_REGS:
499 class = SP_REGS;
500 break;
501 case Y_OR_S_REGS:
502 class = Y_REGS;
503 break;
504 case X_OR_S_REGS:
505 class = X_REGS;
506 break;
507 case D_OR_S_REGS:
508 class = D_REGS;
511 else if (class >= S_REGS)
513 if (debug_m6811)
515 printf ("Class = %s for: ", reg_class_names[class]);
516 fflush (stdout);
517 debug_rtx (operand);
521 if (debug_m6811)
523 printf (" => class=%s\n", reg_class_names[class]);
524 fflush (stdout);
525 debug_rtx (operand);
528 return class;
531 /* Return 1 if the operand is a valid indexed addressing mode.
532 For 68hc11: n,r with n in [0..255] and r in A_REGS class
533 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
534 static int
535 register_indirect_p (operand, mode, strict)
536 rtx operand;
537 enum machine_mode mode;
538 int strict;
540 rtx base, offset;
542 switch (GET_CODE (operand))
544 case POST_INC:
545 case PRE_INC:
546 case POST_DEC:
547 case PRE_DEC:
548 if (TARGET_M6812 && TARGET_AUTO_INC_DEC)
549 return register_indirect_p (XEXP (operand, 0), mode, strict);
550 return 0;
552 case PLUS:
553 base = XEXP (operand, 0);
554 if (GET_CODE (base) == MEM)
555 return 0;
557 offset = XEXP (operand, 1);
558 if (GET_CODE (offset) == MEM)
559 return 0;
561 if (GET_CODE (base) == REG)
563 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
564 return 0;
566 if (strict == 0)
567 return 1;
569 return REGNO_OK_FOR_BASE_P2 (REGNO (base), strict);
571 if (GET_CODE (offset) == REG)
573 if (!VALID_CONSTANT_OFFSET_P (base, mode))
574 return 0;
576 if (strict == 0)
577 return 1;
579 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), strict);
581 return 0;
583 case REG:
584 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), strict);
586 case CONST_INT:
587 if (TARGET_M6811)
588 return 0;
590 return VALID_CONSTANT_OFFSET_P (operand, mode);
592 default:
593 return 0;
597 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
598 a 68HC12 1-byte index addressing mode. */
600 m68hc11_small_indexed_indirect_p (operand, mode)
601 rtx operand;
602 enum machine_mode mode;
604 rtx base, offset;
606 if (GET_CODE (operand) == REG && reload_in_progress
607 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
608 && reg_equiv_memory_loc[REGNO (operand)])
610 operand = reg_equiv_memory_loc[REGNO (operand)];
611 operand = eliminate_regs (operand, 0, NULL_RTX);
614 if (GET_CODE (operand) != MEM)
615 return 0;
617 operand = XEXP (operand, 0);
618 if (CONSTANT_ADDRESS_P (operand))
619 return 1;
621 if (PUSH_POP_ADDRESS_P (operand))
622 return 1;
624 if (!register_indirect_p (operand, mode, reload_completed))
625 return 0;
627 if (TARGET_M6812 && GET_CODE (operand) == PLUS
628 && (reload_completed | reload_in_progress))
630 base = XEXP (operand, 0);
631 offset = XEXP (operand, 1);
633 /* The offset can be a symbol address and this is too big
634 for the operand constraint. */
635 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
636 return 0;
638 if (GET_CODE (base) == CONST_INT)
639 offset = base;
641 switch (GET_MODE_SIZE (mode))
643 case 8:
644 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
645 return 0;
646 break;
648 case 4:
649 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
650 return 0;
651 break;
653 default:
654 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
655 return 0;
656 break;
659 return 1;
663 m68hc11_register_indirect_p (operand, mode)
664 rtx operand;
665 enum machine_mode mode;
667 if (GET_CODE (operand) != MEM)
668 return 0;
670 operand = XEXP (operand, 0);
671 return register_indirect_p (operand, mode,
672 (reload_completed | reload_in_progress));
675 static int
676 go_if_legitimate_address_internal (operand, mode, strict)
677 rtx operand;
678 enum machine_mode mode;
679 int strict;
681 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
683 /* Reject the global variables if they are too wide. This forces
684 a load of their address in a register and generates smaller code. */
685 if (GET_MODE_SIZE (mode) == 8)
686 return 0;
688 return 1;
690 if (register_indirect_p (operand, mode, strict))
692 return 1;
694 if (PUSH_POP_ADDRESS_P (operand))
696 return 1;
698 if (symbolic_memory_operand (operand, mode))
700 return 1;
702 return 0;
706 m68hc11_go_if_legitimate_address (operand, mode, strict)
707 rtx operand;
708 enum machine_mode mode;
709 int strict;
711 int result;
713 if (debug_m6811)
715 printf ("Checking: ");
716 fflush (stdout);
717 debug_rtx (operand);
720 result = go_if_legitimate_address_internal (operand, mode, strict);
722 if (debug_m6811)
724 printf (" -> %s\n", result == 0 ? "NO" : "YES");
727 if (result == 0)
729 if (debug_m6811)
731 printf ("go_if_legitimate%s, ret 0: %d:",
732 (strict ? "_strict" : ""), mode);
733 fflush (stdout);
734 debug_rtx (operand);
737 return result;
741 m68hc11_legitimize_address (operand, old_operand, mode)
742 rtx *operand ATTRIBUTE_UNUSED;
743 rtx old_operand ATTRIBUTE_UNUSED;
744 enum machine_mode mode ATTRIBUTE_UNUSED;
746 return 0;
751 m68hc11_reload_operands (operands)
752 rtx operands[];
754 enum machine_mode mode;
756 if (regs_inited == 0)
757 create_regs_rtx ();
759 mode = GET_MODE (operands[1]);
761 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
762 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
764 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
765 rtx base = XEXP (XEXP (operands[1], 0), 0);
767 if (GET_CODE (base) != REG)
769 rtx tmp = base;
770 base = big_offset;
771 big_offset = tmp;
774 /* If the offset is out of range, we have to compute the address
775 with a separate add instruction. We try to do with with an 8-bit
776 add on the A register. This is possible only if the lowest part
777 of the offset (ie, big_offset % 256) is a valid constant offset
778 with respect to the mode. If it's not, we have to generate a
779 16-bit add on the D register. From:
781 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
783 we generate:
785 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
786 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
787 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
788 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
790 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
791 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
794 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
796 int vh, vl;
797 rtx reg = operands[0];
798 rtx offset;
799 int val = INTVAL (big_offset);
802 /* We use the 'operands[0]' as a scratch register to compute the
803 address. Make sure 'base' is in that register. */
804 if (!rtx_equal_p (base, operands[0]))
806 emit_move_insn (reg, base);
809 if (val > 0)
811 vh = val >> 8;
812 vl = val & 0x0FF;
814 else
816 vh = (val >> 8) & 0x0FF;
817 vl = val & 0x0FF;
820 /* Create the lowest part offset that still remains to be added.
821 If it's not a valid offset, do a 16-bit add. */
822 offset = GEN_INT (vl);
823 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
825 emit_insn (gen_rtx (SET, VOIDmode, reg,
826 gen_rtx (PLUS, HImode, reg, big_offset)));
827 offset = const0_rtx;
829 else
831 emit_insn (gen_rtx (SET, VOIDmode, reg,
832 gen_rtx (PLUS, HImode, reg,
833 GEN_INT (vh << 8))));
835 emit_move_insn (operands[0],
836 gen_rtx (MEM, GET_MODE (operands[1]),
837 gen_rtx (PLUS, Pmode, reg, offset)));
838 return 1;
842 /* Use the normal gen_movhi pattern. */
843 return 0;
846 void
847 m68hc11_emit_libcall (name, code, dmode, smode, noperands, operands)
848 const char *name;
849 enum rtx_code code;
850 enum machine_mode dmode;
851 enum machine_mode smode;
852 int noperands;
853 rtx *operands;
855 rtx ret;
856 rtx insns;
857 rtx libcall;
858 rtx equiv;
860 start_sequence ();
861 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
862 switch (noperands)
864 case 2:
865 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
866 dmode, 1, operands[1], smode);
867 equiv = gen_rtx (code, dmode, operands[1]);
868 break;
870 case 3:
871 ret = emit_library_call_value (libcall, NULL_RTX,
872 LCT_CONST, dmode, 2,
873 operands[1], smode, operands[2],
874 smode);
875 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
876 break;
878 default:
879 abort ();
882 insns = get_insns ();
883 end_sequence ();
884 emit_libcall_block (insns, operands[0], ret, equiv);
887 /* Returns true if X is a PRE/POST increment decrement
888 (same as auto_inc_p() in rtlanal.c but do not take into
889 account the stack). */
890 static int
891 m68hc11_auto_inc_p (x)
892 rtx x;
894 return GET_CODE (x) == PRE_DEC
895 || GET_CODE (x) == POST_INC
896 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
900 /* Predicates for machine description. */
903 memory_reload_operand (operand, mode)
904 rtx operand;
905 enum machine_mode mode ATTRIBUTE_UNUSED;
907 return GET_CODE (operand) == MEM
908 && GET_CODE (XEXP (operand, 0)) == PLUS
909 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
910 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
911 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
912 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
916 tst_operand (operand, mode)
917 rtx operand;
918 enum machine_mode mode;
920 if (GET_CODE (operand) == MEM && reload_completed == 0)
922 rtx addr = XEXP (operand, 0);
923 if (m68hc11_auto_inc_p (addr))
924 return 0;
926 return nonimmediate_operand (operand, mode);
930 cmp_operand (operand, mode)
931 rtx operand;
932 enum machine_mode mode;
934 if (GET_CODE (operand) == MEM)
936 rtx addr = XEXP (operand, 0);
937 if (m68hc11_auto_inc_p (addr))
938 return 0;
940 return general_operand (operand, mode);
944 non_push_operand (operand, mode)
945 rtx operand;
946 enum machine_mode mode;
948 if (general_operand (operand, mode) == 0)
949 return 0;
951 if (push_operand (operand, mode) == 1)
952 return 0;
953 return 1;
957 reg_or_some_mem_operand (operand, mode)
958 rtx operand;
959 enum machine_mode mode;
961 if (GET_CODE (operand) == MEM)
963 rtx op = XEXP (operand, 0);
965 if (symbolic_memory_operand (op, mode))
966 return 1;
968 if (IS_STACK_PUSH (operand))
969 return 1;
971 if (m68hc11_register_indirect_p (operand, mode))
972 return 1;
974 return 0;
977 return register_operand (operand, mode);
981 m68hc11_symbolic_p (operand, mode)
982 rtx operand;
983 enum machine_mode mode;
985 if (GET_CODE (operand) == MEM)
987 rtx op = XEXP (operand, 0);
989 if (symbolic_memory_operand (op, mode))
990 return 1;
992 return 0;
996 m68hc11_indirect_p (operand, mode)
997 rtx operand;
998 enum machine_mode mode;
1000 if (GET_CODE (operand) == MEM)
1002 rtx op = XEXP (operand, 0);
1004 if (symbolic_memory_operand (op, mode))
1005 return 0;
1007 if (reload_in_progress)
1008 return 1;
1010 operand = XEXP (operand, 0);
1011 return register_indirect_p (operand, mode, reload_completed);
1013 return 0;
1017 stack_register_operand (operand, mode)
1018 rtx operand;
1019 enum machine_mode mode ATTRIBUTE_UNUSED;
1021 return SP_REG_P (operand);
1025 d_register_operand (operand, mode)
1026 rtx operand;
1027 enum machine_mode mode ATTRIBUTE_UNUSED;
1029 if (GET_MODE (operand) != mode && mode != VOIDmode)
1030 return 0;
1032 if (GET_CODE (operand) == SUBREG)
1033 operand = XEXP (operand, 0);
1035 return GET_CODE (operand) == REG
1036 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1037 || REGNO (operand) == HARD_D_REGNUM
1038 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
1042 hard_addr_reg_operand (operand, mode)
1043 rtx operand;
1044 enum machine_mode mode ATTRIBUTE_UNUSED;
1046 if (GET_MODE (operand) != mode && mode != VOIDmode)
1047 return 0;
1049 if (GET_CODE (operand) == SUBREG)
1050 operand = XEXP (operand, 0);
1052 return GET_CODE (operand) == REG
1053 && (REGNO (operand) == HARD_X_REGNUM
1054 || REGNO (operand) == HARD_Y_REGNUM
1055 || REGNO (operand) == HARD_Z_REGNUM);
1059 hard_reg_operand (operand, mode)
1060 rtx operand;
1061 enum machine_mode mode;
1063 if (GET_MODE (operand) != mode && mode != VOIDmode)
1064 return 0;
1066 if (GET_CODE (operand) == SUBREG)
1067 operand = XEXP (operand, 0);
1069 return GET_CODE (operand) == REG
1070 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1071 || H_REGNO_P (REGNO (operand)));
1075 memory_indexed_operand (operand, mode)
1076 rtx operand;
1077 enum machine_mode mode ATTRIBUTE_UNUSED;
1079 if (GET_CODE (operand) != MEM)
1080 return 0;
1082 operand = XEXP (operand, 0);
1083 if (GET_CODE (operand) == PLUS)
1085 if (GET_CODE (XEXP (operand, 0)) == REG)
1086 operand = XEXP (operand, 0);
1087 else if (GET_CODE (XEXP (operand, 1)) == REG)
1088 operand = XEXP (operand, 1);
1090 return GET_CODE (operand) == REG
1091 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1092 || A_REGNO_P (REGNO (operand)));
1096 push_pop_operand_p (operand)
1097 rtx operand;
1099 if (GET_CODE (operand) != MEM)
1101 return 0;
1103 operand = XEXP (operand, 0);
1104 return PUSH_POP_ADDRESS_P (operand);
1107 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1108 reference and a constant. */
1111 symbolic_memory_operand (op, mode)
1112 register rtx op;
1113 enum machine_mode mode;
1115 switch (GET_CODE (op))
1117 case SYMBOL_REF:
1118 case LABEL_REF:
1119 return 1;
1121 case CONST:
1122 op = XEXP (op, 0);
1123 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1124 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1125 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1127 /* ??? This clause seems to be irrelevant. */
1128 case CONST_DOUBLE:
1129 return GET_MODE (op) == mode;
1131 case PLUS:
1132 return symbolic_memory_operand (XEXP (op, 0), mode)
1133 && symbolic_memory_operand (XEXP (op, 1), mode);
1135 default:
1136 return 0;
1141 m68hc11_eq_compare_operator (op, mode)
1142 register rtx op;
1143 enum machine_mode mode ATTRIBUTE_UNUSED;
1145 return GET_CODE (op) == EQ || GET_CODE (op) == NE;
1149 m68hc11_logical_operator (op, mode)
1150 register rtx op;
1151 enum machine_mode mode ATTRIBUTE_UNUSED;
1153 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1157 m68hc11_arith_operator (op, mode)
1158 register rtx op;
1159 enum machine_mode mode ATTRIBUTE_UNUSED;
1161 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1162 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1163 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1164 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1165 || GET_CODE (op) == ROTATERT;
1169 m68hc11_non_shift_operator (op, mode)
1170 register rtx op;
1171 enum machine_mode mode ATTRIBUTE_UNUSED;
1173 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1174 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1177 /* Return true if op is a shift operator. */
1179 m68hc11_shift_operator (op, mode)
1180 register rtx op;
1181 enum machine_mode mode ATTRIBUTE_UNUSED;
1183 return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
1184 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
1185 || GET_CODE (op) == ASHIFTRT;
1189 m68hc11_unary_operator (op, mode)
1190 register rtx op;
1191 enum machine_mode mode ATTRIBUTE_UNUSED;
1193 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1194 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1197 /* Emit the code to build the trampoline used to call a nested function.
1199 68HC11 68HC12
1201 ldy #&CXT movw #&CXT,*_.d1
1202 sty *_.d1 jmp FNADDR
1203 jmp FNADDR
1206 void
1207 m68hc11_initialize_trampoline (tramp, fnaddr, cxt)
1208 rtx tramp;
1209 rtx fnaddr;
1210 rtx cxt;
1212 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1214 /* Skip the '*'. */
1215 if (*static_chain_reg == '*')
1216 static_chain_reg++;
1217 if (TARGET_M6811)
1219 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1220 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1221 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1222 GEN_INT (0x18df));
1223 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1224 gen_rtx_CONST (QImode,
1225 gen_rtx_SYMBOL_REF (Pmode,
1226 static_chain_reg)));
1227 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1228 GEN_INT (0x7e));
1229 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1231 else
1233 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1234 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1235 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1236 gen_rtx_CONST (HImode,
1237 gen_rtx_SYMBOL_REF (Pmode,
1238 static_chain_reg)));
1239 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1240 GEN_INT (0x06));
1241 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1245 /* Declaration of types. */
1247 const struct attribute_spec m68hc11_attribute_table[] =
1249 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1250 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1251 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1252 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1253 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1254 { NULL, 0, 0, false, false, false, NULL }
1257 /* Keep track of the symbol which has a `trap' attribute and which uses
1258 the `swi' calling convention. Since there is only one trap, we only
1259 record one such symbol. If there are several, a warning is reported. */
1260 static rtx trap_handler_symbol = 0;
1262 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1263 arguments as in struct attribute_spec.handler. */
1264 static tree
1265 m68hc11_handle_fntype_attribute (node, name, args, flags, no_add_attrs)
1266 tree *node;
1267 tree name;
1268 tree args ATTRIBUTE_UNUSED;
1269 int flags ATTRIBUTE_UNUSED;
1270 bool *no_add_attrs;
1272 if (TREE_CODE (*node) != FUNCTION_TYPE
1273 && TREE_CODE (*node) != METHOD_TYPE
1274 && TREE_CODE (*node) != FIELD_DECL
1275 && TREE_CODE (*node) != TYPE_DECL)
1277 warning ("`%s' attribute only applies to functions",
1278 IDENTIFIER_POINTER (name));
1279 *no_add_attrs = true;
1282 return NULL_TREE;
1285 /* We want to recognize trap handlers so that we handle calls to traps
1286 in a special manner (by issuing the trap). This information is stored
1287 in SYMBOL_REF_FLAG. */
1289 static void
1290 m68hc11_encode_section_info (decl, rtl, first)
1291 tree decl;
1292 rtx rtl;
1293 int first ATTRIBUTE_UNUSED;
1295 tree func_attr;
1296 int trap_handler;
1297 int is_far = 0;
1299 if (TREE_CODE (decl) != FUNCTION_DECL)
1300 return;
1302 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1305 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1306 is_far = 1;
1307 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1308 is_far = TARGET_LONG_CALLS != 0;
1310 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1311 if (trap_handler && is_far)
1313 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1314 trap_handler = 0;
1316 if (trap_handler)
1318 if (trap_handler_symbol != 0)
1319 warning ("`trap' attribute is already used");
1320 else
1321 trap_handler_symbol = XEXP (rtl, 0);
1323 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1327 m68hc11_is_far_symbol (sym)
1328 rtx sym;
1330 if (GET_CODE (sym) == MEM)
1331 sym = XEXP (sym, 0);
1333 return SYMBOL_REF_FLAG (sym);
1337 m68hc11_is_trap_symbol (sym)
1338 rtx sym;
1340 if (GET_CODE (sym) == MEM)
1341 sym = XEXP (sym, 0);
1343 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1347 /* Argument support functions. */
1349 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1350 Arrays are passed by references and other types by value.
1352 SCz: I tried to pass DImode by reference but it seems that this
1353 does not work very well. */
1355 m68hc11_function_arg_pass_by_reference (cum, mode, type, named)
1356 const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;
1357 enum machine_mode mode ATTRIBUTE_UNUSED;
1358 tree type;
1359 int named ATTRIBUTE_UNUSED;
1361 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1362 /* Consider complex values as aggregates, so care for TCmode. */
1363 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1364 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1368 /* Define the offset between two registers, one to be eliminated, and the
1369 other its replacement, at the start of a routine. */
1371 m68hc11_initial_elimination_offset (from, to)
1372 int from;
1373 int to;
1375 int trap_handler;
1376 tree func_attr;
1377 int size;
1378 int regno;
1380 /* For a trap handler, we must take into account the registers which
1381 are pushed on the stack during the trap (except the PC). */
1382 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1384 if (lookup_attribute ("far", func_attr) != 0)
1385 current_function_far = 1;
1386 else if (lookup_attribute ("near", func_attr) != 0)
1387 current_function_far = 0;
1388 else
1389 current_function_far = TARGET_LONG_CALLS != 0;
1391 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1392 if (trap_handler && from == ARG_POINTER_REGNUM)
1393 size = 7;
1395 /* For a function using 'call/rtc' we must take into account the
1396 page register which is pushed in the call. */
1397 else if (current_function_far && from == ARG_POINTER_REGNUM)
1398 size = 1;
1399 else
1400 size = 0;
1402 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1404 /* 2 is for the saved frame.
1405 1 is for the 'sts' correction when creating the frame. */
1406 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1409 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1411 return m68hc11_sp_correction;
1414 /* Push any 2 byte pseudo hard registers that we need to save. */
1415 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1417 if (regs_ever_live[regno] && !call_used_regs[regno])
1419 size += 2;
1423 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1425 return get_frame_size () + size;
1428 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1430 return size;
1432 return 0;
1435 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1436 for a call to a function whose data type is FNTYPE.
1437 For a library call, FNTYPE is 0. */
1439 void
1440 m68hc11_init_cumulative_args (cum, fntype, libname)
1441 CUMULATIVE_ARGS *cum;
1442 tree fntype;
1443 rtx libname;
1445 tree ret_type;
1447 z_replacement_completed = 0;
1448 cum->words = 0;
1449 cum->nregs = 0;
1451 /* For a library call, we must find out the type of the return value.
1452 When the return value is bigger than 4 bytes, it is returned in
1453 memory. In that case, the first argument of the library call is a
1454 pointer to the memory location. Because the first argument is passed in
1455 register D, we have to identify this, so that the first function
1456 parameter is not passed in D either. */
1457 if (fntype == 0)
1459 const char *name;
1460 size_t len;
1462 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1463 return;
1465 /* If the library ends in 'di' or in 'df', we assume it's
1466 returning some DImode or some DFmode which are 64-bit wide. */
1467 name = XSTR (libname, 0);
1468 len = strlen (name);
1469 if (len > 3
1470 && ((name[len - 2] == 'd'
1471 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1472 || (name[len - 3] == 'd'
1473 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1475 /* We are in. Mark the first parameter register as already used. */
1476 cum->words = 1;
1477 cum->nregs = 1;
1479 return;
1482 ret_type = TREE_TYPE (fntype);
1484 if (ret_type && aggregate_value_p (ret_type))
1486 cum->words = 1;
1487 cum->nregs = 1;
1491 /* Update the data in CUM to advance over an argument
1492 of mode MODE and data type TYPE.
1493 (TYPE is null for libcalls where that information may not be available.) */
1495 void
1496 m68hc11_function_arg_advance (cum, mode, type, named)
1497 CUMULATIVE_ARGS *cum;
1498 enum machine_mode mode;
1499 tree type;
1500 int named ATTRIBUTE_UNUSED;
1502 if (mode != BLKmode)
1504 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1506 cum->nregs = 2;
1507 cum->words = GET_MODE_SIZE (mode);
1509 else
1511 cum->words += GET_MODE_SIZE (mode);
1512 if (cum->words <= HARD_REG_SIZE)
1513 cum->nregs = 1;
1516 else
1518 cum->words += int_size_in_bytes (type);
1520 return;
1523 /* Define where to put the arguments to a function.
1524 Value is zero to push the argument on the stack,
1525 or a hard register in which to store the argument.
1527 MODE is the argument's machine mode.
1528 TYPE is the data type of the argument (as a tree).
1529 This is null for libcalls where that information may
1530 not be available.
1531 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1532 the preceding args and about the function being called.
1533 NAMED is nonzero if this argument is a named parameter
1534 (otherwise it is an extra parameter matching an ellipsis). */
1536 struct rtx_def *
1537 m68hc11_function_arg (cum, mode, type, named)
1538 const CUMULATIVE_ARGS *cum;
1539 enum machine_mode mode;
1540 tree type ATTRIBUTE_UNUSED;
1541 int named ATTRIBUTE_UNUSED;
1543 if (cum->words != 0)
1545 return NULL_RTX;
1548 if (mode != BLKmode)
1550 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1551 return gen_rtx (REG, mode, HARD_X_REGNUM);
1553 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1555 return NULL_RTX;
1557 return gen_rtx (REG, mode, HARD_D_REGNUM);
1559 return NULL_RTX;
1562 /* If defined, a C expression which determines whether, and in which direction,
1563 to pad out an argument with extra space. The value should be of type
1564 `enum direction': either `upward' to pad above the argument,
1565 `downward' to pad below, or `none' to inhibit padding.
1567 Structures are stored left shifted in their argument slot. */
1569 m68hc11_function_arg_padding (mode, type)
1570 enum machine_mode mode;
1571 tree type;
1573 if (type != 0 && AGGREGATE_TYPE_P (type))
1574 return upward;
1576 /* This is the default definition. */
1577 return (!BYTES_BIG_ENDIAN
1578 ? upward
1579 : ((mode == BLKmode
1580 ? (type && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
1581 && int_size_in_bytes (type) <
1582 (PARM_BOUNDARY / BITS_PER_UNIT)) : GET_MODE_BITSIZE (mode) <
1583 PARM_BOUNDARY) ? downward : upward));
1587 /* Function prologue and epilogue. */
1589 /* Emit a move after the reload pass has completed. This is used to
1590 emit the prologue and epilogue. */
1591 static void
1592 emit_move_after_reload (to, from, scratch)
1593 rtx to, from, scratch;
1595 rtx insn;
1597 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1599 insn = emit_move_insn (to, from);
1601 else
1603 emit_move_insn (scratch, from);
1604 insn = emit_move_insn (to, scratch);
1607 /* Put a REG_INC note to tell the flow analysis that the instruction
1608 is necessary. */
1609 if (IS_STACK_PUSH (to))
1611 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1612 XEXP (XEXP (to, 0), 0),
1613 REG_NOTES (insn));
1615 else if (IS_STACK_POP (from))
1617 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1618 XEXP (XEXP (from, 0), 0),
1619 REG_NOTES (insn));
1622 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1623 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1624 The problem is that we are lying to gcc and use `txs' for x = sp
1625 (which is not really true because txs is really x = sp + 1). */
1626 else if (TARGET_M6811 && SP_REG_P (from))
1628 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1629 from,
1630 REG_NOTES (insn));
1635 m68hc11_total_frame_size ()
1637 int size;
1638 int regno;
1640 size = get_frame_size ();
1641 if (current_function_interrupt)
1643 size += 3 * HARD_REG_SIZE;
1645 if (frame_pointer_needed)
1646 size += HARD_REG_SIZE;
1648 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1649 if (regs_ever_live[regno] && !call_used_regs[regno])
1650 size += HARD_REG_SIZE;
1652 return size;
1655 static void
1656 m68hc11_output_function_epilogue (out, size)
1657 FILE *out ATTRIBUTE_UNUSED;
1658 HOST_WIDE_INT size ATTRIBUTE_UNUSED;
1660 /* We catch the function epilogue generation to have a chance
1661 to clear the z_replacement_completed flag. */
1662 z_replacement_completed = 0;
1665 void
1666 expand_prologue ()
1668 tree func_attr;
1669 int size;
1670 int regno;
1671 rtx scratch;
1673 if (reload_completed != 1)
1674 abort ();
1676 size = get_frame_size ();
1678 create_regs_rtx ();
1680 /* Generate specific prologue for interrupt handlers. */
1681 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1682 current_function_interrupt = lookup_attribute ("interrupt",
1683 func_attr) != NULL_TREE;
1684 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1685 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1686 current_function_far = 1;
1687 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1688 current_function_far = 0;
1689 else
1690 current_function_far = TARGET_LONG_CALLS != 0;
1692 /* Get the scratch register to build the frame and push registers.
1693 If the first argument is a 32-bit quantity, the D+X registers
1694 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1695 For 68HC12, this scratch register is not used. */
1696 if (current_function_args_info.nregs == 2)
1697 scratch = iy_reg;
1698 else
1699 scratch = ix_reg;
1701 /* Save current stack frame. */
1702 if (frame_pointer_needed)
1703 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1705 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1706 Other soft registers in page0 need not to be saved because they
1707 will be restored by C functions. For a trap handler, we don't
1708 need to preserve these registers because this is a synchronous call. */
1709 if (current_function_interrupt)
1711 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1712 emit_move_after_reload (stack_push_word,
1713 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1714 emit_move_after_reload (stack_push_word,
1715 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1716 scratch);
1719 /* Allocate local variables. */
1720 if (TARGET_M6812 && (size > 4 || size == 3))
1722 emit_insn (gen_addhi3 (stack_pointer_rtx,
1723 stack_pointer_rtx, GEN_INT (-size)));
1725 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1727 rtx insn;
1729 insn = gen_rtx_PARALLEL
1730 (VOIDmode,
1731 gen_rtvec (2,
1732 gen_rtx_SET (VOIDmode,
1733 stack_pointer_rtx,
1734 gen_rtx_PLUS (HImode,
1735 stack_pointer_rtx,
1736 GEN_INT (-size))),
1737 gen_rtx_CLOBBER (VOIDmode, scratch)));
1738 emit_insn (insn);
1740 else
1742 int i;
1744 /* Allocate by pushing scratch values. */
1745 for (i = 2; i <= size; i += 2)
1746 emit_move_after_reload (stack_push_word, ix_reg, 0);
1748 if (size & 1)
1749 emit_insn (gen_addhi3 (stack_pointer_rtx,
1750 stack_pointer_rtx, GEN_INT (-1)));
1753 /* Create the frame pointer. */
1754 if (frame_pointer_needed)
1755 emit_move_after_reload (hard_frame_pointer_rtx,
1756 stack_pointer_rtx, scratch);
1758 /* Push any 2 byte pseudo hard registers that we need to save. */
1759 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1761 if (regs_ever_live[regno] && !call_used_regs[regno])
1763 emit_move_after_reload (stack_push_word,
1764 gen_rtx (REG, HImode, regno), scratch);
1769 void
1770 expand_epilogue ()
1772 int size;
1773 register int regno;
1774 int return_size;
1775 rtx scratch;
1777 if (reload_completed != 1)
1778 abort ();
1780 size = get_frame_size ();
1782 /* If we are returning a value in two registers, we have to preserve the
1783 X register and use the Y register to restore the stack and the saved
1784 registers. Otherwise, use X because it's faster (and smaller). */
1785 if (current_function_return_rtx == 0)
1786 return_size = 0;
1787 else if (GET_CODE (current_function_return_rtx) == MEM)
1788 return_size = HARD_REG_SIZE;
1789 else
1790 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1792 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1793 scratch = iy_reg;
1794 else
1795 scratch = ix_reg;
1797 /* Pop any 2 byte pseudo hard registers that we saved. */
1798 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1800 if (regs_ever_live[regno] && !call_used_regs[regno])
1802 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1803 stack_pop_word, scratch);
1807 /* de-allocate auto variables */
1808 if (TARGET_M6812 && (size > 4 || size == 3))
1810 emit_insn (gen_addhi3 (stack_pointer_rtx,
1811 stack_pointer_rtx, GEN_INT (size)));
1813 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1815 rtx insn;
1817 insn = gen_rtx_PARALLEL
1818 (VOIDmode,
1819 gen_rtvec (2,
1820 gen_rtx_SET (VOIDmode,
1821 stack_pointer_rtx,
1822 gen_rtx_PLUS (HImode,
1823 stack_pointer_rtx,
1824 GEN_INT (size))),
1825 gen_rtx_CLOBBER (VOIDmode, scratch)));
1826 emit_insn (insn);
1828 else
1830 int i;
1832 for (i = 2; i <= size; i += 2)
1833 emit_move_after_reload (scratch, stack_pop_word, scratch);
1834 if (size & 1)
1835 emit_insn (gen_addhi3 (stack_pointer_rtx,
1836 stack_pointer_rtx, GEN_INT (1)));
1839 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1840 if (current_function_interrupt)
1842 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1843 stack_pop_word, scratch);
1844 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1845 stack_pop_word, scratch);
1846 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1849 /* Restore previous frame pointer. */
1850 if (frame_pointer_needed)
1851 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1853 /* If the trap handler returns some value, copy the value
1854 in D, X onto the stack so that the rti will pop the return value
1855 correctly. */
1856 else if (current_function_trap && return_size != 0)
1858 rtx addr_reg = stack_pointer_rtx;
1860 if (!TARGET_M6812)
1862 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1863 addr_reg = scratch;
1865 emit_move_after_reload (gen_rtx (MEM, HImode,
1866 gen_rtx (PLUS, HImode, addr_reg,
1867 GEN_INT (1))), d_reg, 0);
1868 if (return_size > HARD_REG_SIZE)
1869 emit_move_after_reload (gen_rtx (MEM, HImode,
1870 gen_rtx (PLUS, HImode, addr_reg,
1871 GEN_INT (3))), ix_reg, 0);
1874 emit_jump_insn (gen_return ());
1878 /* Low and High part extraction for 68HC11. These routines are
1879 similar to gen_lowpart and gen_highpart but they have been
1880 fixed to work for constants and 68HC11 specific registers. */
1883 m68hc11_gen_lowpart (mode, x)
1884 enum machine_mode mode;
1885 rtx x;
1887 /* We assume that the low part of an auto-inc mode is the same with
1888 the mode changed and that the caller split the larger mode in the
1889 correct order. */
1890 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1892 return gen_rtx (MEM, mode, XEXP (x, 0));
1895 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1896 floating-point constant. A CONST_DOUBLE is used whenever the
1897 constant requires more than one word in order to be adequately
1898 represented. */
1899 if (GET_CODE (x) == CONST_DOUBLE)
1901 long l[2];
1903 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1905 REAL_VALUE_TYPE r;
1907 if (GET_MODE (x) == SFmode)
1909 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1910 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1912 else
1914 rtx first, second;
1916 split_double (x, &first, &second);
1917 return second;
1919 if (mode == SImode)
1920 return GEN_INT (l[0]);
1922 return gen_int_mode (l[0], HImode);
1924 else
1926 l[0] = CONST_DOUBLE_LOW (x);
1928 if (mode == SImode)
1929 return GEN_INT (l[0]);
1930 else if (mode == HImode && GET_MODE (x) == SFmode)
1931 return gen_int_mode (l[0], HImode);
1932 else
1933 abort ();
1936 if (mode == QImode && D_REG_P (x))
1937 return gen_rtx (REG, mode, HARD_B_REGNUM);
1939 /* gen_lowpart crashes when it is called with a SUBREG. */
1940 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1942 if (mode == SImode)
1943 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1944 else if (mode == HImode)
1945 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1946 else
1947 abort ();
1949 x = gen_lowpart (mode, x);
1951 /* Return a different rtx to avoid to share it in several insns
1952 (when used by a split pattern). Sharing addresses within
1953 a MEM breaks the Z register replacement (and reloading). */
1954 if (GET_CODE (x) == MEM)
1955 x = copy_rtx (x);
1956 return x;
1960 m68hc11_gen_highpart (mode, x)
1961 enum machine_mode mode;
1962 rtx x;
1964 /* We assume that the high part of an auto-inc mode is the same with
1965 the mode changed and that the caller split the larger mode in the
1966 correct order. */
1967 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1969 return gen_rtx (MEM, mode, XEXP (x, 0));
1972 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1973 floating-point constant. A CONST_DOUBLE is used whenever the
1974 constant requires more than one word in order to be adequately
1975 represented. */
1976 if (GET_CODE (x) == CONST_DOUBLE)
1978 long l[2];
1980 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1982 REAL_VALUE_TYPE r;
1984 if (GET_MODE (x) == SFmode)
1986 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1987 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1989 else
1991 rtx first, second;
1993 split_double (x, &first, &second);
1994 return first;
1996 if (mode == SImode)
1997 return GEN_INT (l[1]);
1999 return gen_int_mode ((l[1] >> 16), HImode);
2001 else
2003 l[1] = CONST_DOUBLE_HIGH (x);
2006 if (mode == SImode)
2007 return GEN_INT (l[1]);
2008 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2009 return gen_int_mode ((l[0] >> 16), HImode);
2010 else
2011 abort ();
2013 if (GET_CODE (x) == CONST_INT)
2015 HOST_WIDE_INT val = INTVAL (x);
2017 if (mode == QImode)
2019 return gen_int_mode (val >> 8, QImode);
2021 else if (mode == HImode)
2023 return gen_int_mode (val >> 16, HImode);
2026 if (mode == QImode && D_REG_P (x))
2027 return gen_rtx (REG, mode, HARD_A_REGNUM);
2029 /* There is no way in GCC to represent the upper part of a word register.
2030 To obtain the 8-bit upper part of a soft register, we change the
2031 reg into a mem rtx. This is possible because they are physically
2032 located in memory. There is no offset because we are big-endian. */
2033 if (mode == QImode && S_REG_P (x))
2035 int pos;
2037 /* Avoid the '*' for direct addressing mode when this
2038 addressing mode is disabled. */
2039 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
2040 return gen_rtx (MEM, QImode,
2041 gen_rtx (SYMBOL_REF, Pmode,
2042 &reg_names[REGNO (x)][pos]));
2045 /* gen_highpart crashes when it is called with a SUBREG. */
2046 if (GET_CODE (x) == SUBREG)
2048 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
2050 if (GET_CODE (x) == REG)
2052 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
2053 return gen_rtx (REG, mode, REGNO (x));
2054 else
2055 return gen_rtx_SUBREG (mode, x, 0);
2058 if (GET_CODE (x) == MEM)
2060 x = change_address (x, mode, 0);
2062 /* Return a different rtx to avoid to share it in several insns
2063 (when used by a split pattern). Sharing addresses within
2064 a MEM breaks the Z register replacement (and reloading). */
2065 if (GET_CODE (x) == MEM)
2066 x = copy_rtx (x);
2067 return x;
2069 abort ();
2073 /* Obscure register manipulation. */
2075 /* Finds backward in the instructions to see if register 'reg' is
2076 dead. This is used when generating code to see if we can use 'reg'
2077 as a scratch register. This allows us to choose a better generation
2078 of code when we know that some register dies or can be clobbered. */
2081 dead_register_here (x, reg)
2082 rtx x;
2083 rtx reg;
2085 rtx x_reg;
2086 rtx p;
2088 if (D_REG_P (reg))
2089 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
2090 else
2091 x_reg = 0;
2093 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2094 if (GET_RTX_CLASS (GET_CODE (p)) == 'i')
2096 rtx body;
2098 body = PATTERN (p);
2100 if (GET_CODE (body) == CALL_INSN)
2101 break;
2102 if (GET_CODE (body) == JUMP_INSN)
2103 break;
2105 if (GET_CODE (body) == SET)
2107 rtx dst = XEXP (body, 0);
2109 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2110 break;
2111 if (x_reg && rtx_equal_p (dst, x_reg))
2112 break;
2114 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2115 return 1;
2117 else if (reg_mentioned_p (reg, p)
2118 || (x_reg && reg_mentioned_p (x_reg, p)))
2119 break;
2122 /* Scan forward to see if the register is set in some insns and never
2123 used since then. */
2124 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2126 rtx body;
2128 if (GET_CODE (p) == CODE_LABEL
2129 || GET_CODE (p) == JUMP_INSN
2130 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2131 break;
2133 if (GET_CODE (p) != INSN)
2134 continue;
2136 body = PATTERN (p);
2137 if (GET_CODE (body) == SET)
2139 rtx src = XEXP (body, 1);
2140 rtx dst = XEXP (body, 0);
2142 if (GET_CODE (dst) == REG
2143 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2144 return 1;
2147 /* Register is used (may be in source or in dest). */
2148 if (reg_mentioned_p (reg, p)
2149 || (x_reg != 0 && GET_MODE (p) == SImode
2150 && reg_mentioned_p (x_reg, p)))
2151 break;
2153 return p == 0 ? 1 : 0;
2157 /* Code generation operations called from machine description file. */
2159 /* Print the name of register 'regno' in the assembly file. */
2160 static void
2161 asm_print_register (file, regno)
2162 FILE *file;
2163 int regno;
2165 const char *name = reg_names[regno];
2167 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2168 name++;
2170 fprintf (file, "%s", name);
2173 /* A C compound statement to output to stdio stream STREAM the
2174 assembler syntax for an instruction operand X. X is an RTL
2175 expression.
2177 CODE is a value that can be used to specify one of several ways
2178 of printing the operand. It is used when identical operands
2179 must be printed differently depending on the context. CODE
2180 comes from the `%' specification that was used to request
2181 printing of the operand. If the specification was just `%DIGIT'
2182 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2183 is the ASCII code for LTR.
2185 If X is a register, this macro should print the register's name.
2186 The names can be found in an array `reg_names' whose type is
2187 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2189 When the machine description has a specification `%PUNCT' (a `%'
2190 followed by a punctuation character), this macro is called with
2191 a null pointer for X and the punctuation character for CODE.
2193 The M68HC11 specific codes are:
2195 'b' for the low part of the operand.
2196 'h' for the high part of the operand
2197 The 'b' or 'h' modifiers have no effect if the operand has
2198 the QImode and is not a S_REG_P (soft register). If the
2199 operand is a hard register, these two modifiers have no effect.
2200 't' generate the temporary scratch register. The operand is
2201 ignored.
2202 'T' generate the low-part temporary scratch register. The operand is
2203 ignored. */
2205 void
2206 print_operand (file, op, letter)
2207 FILE *file;
2208 rtx op;
2209 int letter;
2211 if (letter == 't')
2213 asm_print_register (file, SOFT_TMP_REGNUM);
2214 return;
2216 else if (letter == 'T')
2218 asm_print_register (file, SOFT_TMP_REGNUM);
2219 fprintf (file, "+1");
2220 return;
2222 else if (letter == '#')
2224 asm_fprintf (file, "%0I");
2227 if (GET_CODE (op) == REG)
2229 if (letter == 'b' && S_REG_P (op))
2231 asm_print_register (file, REGNO (op));
2232 fprintf (file, "+1");
2234 else if (letter == 'b' && D_REG_P (op))
2236 asm_print_register (file, HARD_B_REGNUM);
2238 else
2240 asm_print_register (file, REGNO (op));
2242 return;
2245 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2247 if (letter == 'b')
2248 asm_fprintf (file, "%0I%%lo(");
2249 else
2250 asm_fprintf (file, "%0I%%hi(");
2252 output_addr_const (file, op);
2253 fprintf (file, ")");
2254 return;
2257 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2258 are specified. If we already have a QImode, there is nothing to do. */
2259 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2261 if (letter == 'b')
2263 op = m68hc11_gen_lowpart (QImode, op);
2265 else if (letter == 'h')
2267 op = m68hc11_gen_highpart (QImode, op);
2271 if (GET_CODE (op) == MEM)
2273 rtx base = XEXP (op, 0);
2274 switch (GET_CODE (base))
2276 case PRE_DEC:
2277 if (TARGET_M6812)
2279 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2280 asm_print_register (file, REGNO (XEXP (base, 0)));
2282 else
2283 abort ();
2284 break;
2286 case POST_DEC:
2287 if (TARGET_M6812)
2289 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2290 asm_print_register (file, REGNO (XEXP (base, 0)));
2291 fprintf (file, "-");
2293 else
2294 abort ();
2295 break;
2297 case POST_INC:
2298 if (TARGET_M6812)
2300 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2301 asm_print_register (file, REGNO (XEXP (base, 0)));
2302 fprintf (file, "+");
2304 else
2305 abort ();
2306 break;
2308 case PRE_INC:
2309 if (TARGET_M6812)
2311 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2312 asm_print_register (file, REGNO (XEXP (base, 0)));
2314 else
2315 abort ();
2316 break;
2318 default:
2319 output_address (base);
2320 break;
2323 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2325 REAL_VALUE_TYPE r;
2326 long l;
2328 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2329 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2330 asm_fprintf (file, "%I0x%lx", l);
2332 else if (GET_CODE (op) == CONST_DOUBLE
2333 && (GET_MODE (op) == DFmode || GET_MODE (op) == XFmode))
2335 char dstr[30];
2337 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2338 sizeof (dstr), 0, 1);
2339 asm_fprintf (file, "%I0r%s", dstr);
2341 else
2343 int need_parenthesize = 0;
2345 if (letter != 'i')
2346 asm_fprintf (file, "%0I");
2347 else
2348 need_parenthesize = must_parenthesize (op);
2350 if (need_parenthesize)
2351 fprintf (file, "(");
2353 output_addr_const (file, op);
2354 if (need_parenthesize)
2355 fprintf (file, ")");
2359 /* Returns true if the operand 'op' must be printed with parenthesis
2360 arround it. This must be done only if there is a symbol whose name
2361 is a processor register. */
2362 static int
2363 must_parenthesize (op)
2364 rtx op;
2366 const char *name;
2368 switch (GET_CODE (op))
2370 case SYMBOL_REF:
2371 name = XSTR (op, 0);
2372 /* Avoid a conflict between symbol name and a possible
2373 register. */
2374 return (strcasecmp (name, "a") == 0
2375 || strcasecmp (name, "b") == 0
2376 || strcasecmp (name, "d") == 0
2377 || strcasecmp (name, "x") == 0
2378 || strcasecmp (name, "y") == 0
2379 || strcasecmp (name, "ix") == 0
2380 || strcasecmp (name, "iy") == 0
2381 || strcasecmp (name, "pc") == 0
2382 || strcasecmp (name, "sp") == 0
2383 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2385 case PLUS:
2386 case MINUS:
2387 return must_parenthesize (XEXP (op, 0))
2388 || must_parenthesize (XEXP (op, 1));
2390 case MEM:
2391 case CONST:
2392 case ZERO_EXTEND:
2393 case SIGN_EXTEND:
2394 return must_parenthesize (XEXP (op, 0));
2396 case CONST_DOUBLE:
2397 case CONST_INT:
2398 case LABEL_REF:
2399 case CODE_LABEL:
2400 default:
2401 return 0;
2405 /* A C compound statement to output to stdio stream STREAM the
2406 assembler syntax for an instruction operand that is a memory
2407 reference whose address is ADDR. ADDR is an RTL expression. */
2409 void
2410 print_operand_address (file, addr)
2411 FILE *file;
2412 rtx addr;
2414 rtx base;
2415 rtx offset;
2416 int need_parenthesis = 0;
2418 switch (GET_CODE (addr))
2420 case REG:
2421 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2422 abort ();
2424 fprintf (file, "0,");
2425 asm_print_register (file, REGNO (addr));
2426 break;
2428 case MEM:
2429 base = XEXP (addr, 0);
2430 switch (GET_CODE (base))
2432 case PRE_DEC:
2433 if (TARGET_M6812)
2435 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2436 asm_print_register (file, REGNO (XEXP (base, 0)));
2438 else
2439 abort ();
2440 break;
2442 case POST_DEC:
2443 if (TARGET_M6812)
2445 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2446 asm_print_register (file, REGNO (XEXP (base, 0)));
2447 fprintf (file, "-");
2449 else
2450 abort ();
2451 break;
2453 case POST_INC:
2454 if (TARGET_M6812)
2456 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2457 asm_print_register (file, REGNO (XEXP (base, 0)));
2458 fprintf (file, "+");
2460 else
2461 abort ();
2462 break;
2464 case PRE_INC:
2465 if (TARGET_M6812)
2467 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2468 asm_print_register (file, REGNO (XEXP (base, 0)));
2470 else
2471 abort ();
2472 break;
2474 default:
2475 need_parenthesis = must_parenthesize (base);
2476 if (need_parenthesis)
2477 fprintf (file, "(");
2479 output_addr_const (file, base);
2480 if (need_parenthesis)
2481 fprintf (file, ")");
2482 break;
2484 break;
2486 case PLUS:
2487 base = XEXP (addr, 0);
2488 offset = XEXP (addr, 1);
2489 if (!G_REG_P (base) && G_REG_P (offset))
2491 base = XEXP (addr, 1);
2492 offset = XEXP (addr, 0);
2494 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2496 need_parenthesis = must_parenthesize (addr);
2498 if (need_parenthesis)
2499 fprintf (file, "(");
2501 output_addr_const (file, base);
2502 fprintf (file, "+");
2503 output_addr_const (file, offset);
2504 if (need_parenthesis)
2505 fprintf (file, ")");
2507 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2509 if (REG_P (offset))
2511 if (TARGET_M6812)
2513 asm_print_register (file, REGNO (offset));
2514 fprintf (file, ",");
2515 asm_print_register (file, REGNO (base));
2517 else
2518 abort ();
2520 else
2522 need_parenthesis = must_parenthesize (offset);
2523 if (need_parenthesis)
2524 fprintf (file, "(");
2526 output_addr_const (file, offset);
2527 if (need_parenthesis)
2528 fprintf (file, ")");
2529 fprintf (file, ",");
2530 asm_print_register (file, REGNO (base));
2533 else
2535 abort ();
2537 break;
2539 default:
2540 if (GET_CODE (addr) == CONST_INT
2541 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2543 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2545 else
2547 need_parenthesis = must_parenthesize (addr);
2548 if (need_parenthesis)
2549 fprintf (file, "(");
2551 output_addr_const (file, addr);
2552 if (need_parenthesis)
2553 fprintf (file, ")");
2555 break;
2560 /* Splitting of some instructions. */
2562 static rtx
2563 m68hc11_expand_compare (code, op0, op1)
2564 enum rtx_code code;
2565 rtx op0, op1;
2567 rtx ret = 0;
2569 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2570 abort ();
2571 else
2573 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2574 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2575 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2578 return ret;
2582 m68hc11_expand_compare_and_branch (code, op0, op1, label)
2583 enum rtx_code code;
2584 rtx op0, op1, label;
2586 rtx tmp;
2588 switch (GET_MODE (op0))
2590 case QImode:
2591 case HImode:
2592 tmp = m68hc11_expand_compare (code, op0, op1);
2593 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2594 gen_rtx_LABEL_REF (VOIDmode, label),
2595 pc_rtx);
2596 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2597 return 0;
2598 #if 0
2600 /* SCz: from i386.c */
2601 case SFmode:
2602 case DFmode:
2603 /* Don't expand the comparison early, so that we get better code
2604 when jump or whoever decides to reverse the comparison. */
2606 rtvec vec;
2607 int use_fcomi;
2609 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2610 &m68hc11_compare_op1);
2612 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2613 m68hc11_compare_op0, m68hc11_compare_op1);
2614 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2615 gen_rtx_LABEL_REF (VOIDmode, label),
2616 pc_rtx);
2617 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2619 use_fcomi = ix86_use_fcomi_compare (code);
2620 vec = rtvec_alloc (3 + !use_fcomi);
2621 RTVEC_ELT (vec, 0) = tmp;
2622 RTVEC_ELT (vec, 1)
2623 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2624 RTVEC_ELT (vec, 2)
2625 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2626 if (!use_fcomi)
2627 RTVEC_ELT (vec, 3)
2628 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2630 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2631 return;
2633 #endif
2635 case SImode:
2636 /* Expand SImode branch into multiple compare+branch. */
2638 rtx lo[2], hi[2], label2;
2639 enum rtx_code code1, code2, code3;
2641 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2643 tmp = op0;
2644 op0 = op1;
2645 op1 = tmp;
2646 code = swap_condition (code);
2648 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2649 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2650 hi[0] = m68hc11_gen_highpart (HImode, op0);
2651 hi[1] = m68hc11_gen_highpart (HImode, op1);
2653 /* Otherwise, if we are doing less-than, op1 is a constant and the
2654 low word is zero, then we can just examine the high word. */
2656 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2657 && (code == LT || code == LTU))
2659 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2660 label);
2663 /* Otherwise, we need two or three jumps. */
2665 label2 = gen_label_rtx ();
2667 code1 = code;
2668 code2 = swap_condition (code);
2669 code3 = unsigned_condition (code);
2671 switch (code)
2673 case LT:
2674 case GT:
2675 case LTU:
2676 case GTU:
2677 break;
2679 case LE:
2680 code1 = LT;
2681 code2 = GT;
2682 break;
2683 case GE:
2684 code1 = GT;
2685 code2 = LT;
2686 break;
2687 case LEU:
2688 code1 = LTU;
2689 code2 = GTU;
2690 break;
2691 case GEU:
2692 code1 = GTU;
2693 code2 = LTU;
2694 break;
2696 case EQ:
2697 code1 = NIL;
2698 code2 = NE;
2699 break;
2700 case NE:
2701 code2 = NIL;
2702 break;
2704 default:
2705 abort ();
2709 * a < b =>
2710 * if (hi(a) < hi(b)) goto true;
2711 * if (hi(a) > hi(b)) goto false;
2712 * if (lo(a) < lo(b)) goto true;
2713 * false:
2715 if (code1 != NIL)
2716 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2717 if (code2 != NIL)
2718 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2720 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2722 if (code2 != NIL)
2723 emit_label (label2);
2724 return 0;
2727 default:
2728 abort ();
2730 return 0;
2733 /* Return the increment/decrement mode of a MEM if it is such.
2734 Return CONST if it is anything else. */
2735 static int
2736 autoinc_mode (x)
2737 rtx x;
2739 if (GET_CODE (x) != MEM)
2740 return CONST;
2742 x = XEXP (x, 0);
2743 if (GET_CODE (x) == PRE_INC
2744 || GET_CODE (x) == PRE_DEC
2745 || GET_CODE (x) == POST_INC
2746 || GET_CODE (x) == POST_DEC)
2747 return GET_CODE (x);
2749 return CONST;
2752 static int
2753 m68hc11_make_autoinc_notes (x, data)
2754 rtx *x;
2755 void *data;
2757 rtx insn;
2759 switch (GET_CODE (*x))
2761 case PRE_DEC:
2762 case PRE_INC:
2763 case POST_DEC:
2764 case POST_INC:
2765 insn = (rtx) data;
2766 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2767 REG_NOTES (insn));
2768 return -1;
2770 default:
2771 return 0;
2775 /* Split a DI, SI or HI move into several smaller move operations.
2776 The scratch register 'scratch' is used as a temporary to load
2777 store intermediate values. It must be a hard register. */
2778 void
2779 m68hc11_split_move (to, from, scratch)
2780 rtx to, from, scratch;
2782 rtx low_to, low_from;
2783 rtx high_to, high_from;
2784 rtx insn;
2785 enum machine_mode mode;
2786 int offset = 0;
2787 int autoinc_from = autoinc_mode (from);
2788 int autoinc_to = autoinc_mode (to);
2790 mode = GET_MODE (to);
2792 /* If the TO and FROM contain autoinc modes that are not compatible
2793 together (one pop and the other a push), we must change one to
2794 an offsetable operand and generate an appropriate add at the end. */
2795 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2797 rtx reg;
2798 int code;
2800 /* The source uses an autoinc mode which is not compatible with
2801 a split (this would result in a word swap). */
2802 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2804 code = GET_CODE (XEXP (from, 0));
2805 reg = XEXP (XEXP (from, 0), 0);
2806 offset = GET_MODE_SIZE (GET_MODE (from));
2807 if (code == POST_DEC)
2808 offset = -offset;
2810 if (code == PRE_INC)
2811 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2813 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2814 if (code == POST_DEC)
2815 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2816 return;
2819 /* Likewise for destination. */
2820 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2822 code = GET_CODE (XEXP (to, 0));
2823 reg = XEXP (XEXP (to, 0), 0);
2824 offset = GET_MODE_SIZE (GET_MODE (to));
2825 if (code == POST_DEC)
2826 offset = -offset;
2828 if (code == PRE_INC)
2829 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2831 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2832 if (code == POST_DEC)
2833 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2834 return;
2837 /* The source and destination auto increment modes must be compatible
2838 with each other: same direction. */
2839 if ((autoinc_to != autoinc_from
2840 && autoinc_to != CONST && autoinc_from != CONST)
2841 /* The destination address register must not be used within
2842 the source operand because the source address would change
2843 while doing the copy. */
2844 || (autoinc_to != CONST
2845 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2846 && !IS_STACK_PUSH (to)))
2848 /* Must change the destination. */
2849 code = GET_CODE (XEXP (to, 0));
2850 reg = XEXP (XEXP (to, 0), 0);
2851 offset = GET_MODE_SIZE (GET_MODE (to));
2852 if (code == PRE_DEC || code == POST_DEC)
2853 offset = -offset;
2855 if (code == PRE_DEC || code == PRE_INC)
2856 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2857 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2858 if (code == POST_DEC || code == POST_INC)
2859 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2861 return;
2864 /* Likewise, the source address register must not be used within
2865 the destination operand. */
2866 if (autoinc_from != CONST
2867 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2868 && !IS_STACK_PUSH (to))
2870 /* Must change the source. */
2871 code = GET_CODE (XEXP (from, 0));
2872 reg = XEXP (XEXP (from, 0), 0);
2873 offset = GET_MODE_SIZE (GET_MODE (from));
2874 if (code == PRE_DEC || code == POST_DEC)
2875 offset = -offset;
2877 if (code == PRE_DEC || code == PRE_INC)
2878 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2879 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2880 if (code == POST_DEC || code == POST_INC)
2881 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2883 return;
2887 if (GET_MODE_SIZE (mode) == 8)
2888 mode = SImode;
2889 else if (GET_MODE_SIZE (mode) == 4)
2890 mode = HImode;
2891 else
2892 mode = QImode;
2894 if (TARGET_M6812
2895 && IS_STACK_PUSH (to)
2896 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2898 if (mode == SImode)
2900 offset = 4;
2902 else if (mode == HImode)
2904 offset = 2;
2906 else
2907 offset = 0;
2910 low_to = m68hc11_gen_lowpart (mode, to);
2911 high_to = m68hc11_gen_highpart (mode, to);
2913 low_from = m68hc11_gen_lowpart (mode, from);
2914 if (mode == SImode && GET_CODE (from) == CONST_INT)
2916 if (INTVAL (from) >= 0)
2917 high_from = const0_rtx;
2918 else
2919 high_from = constm1_rtx;
2921 else
2922 high_from = m68hc11_gen_highpart (mode, from);
2924 if (offset)
2926 high_from = adjust_address (high_from, mode, offset);
2927 low_from = high_from;
2930 /* When copying with a POST_INC mode, we must copy the
2931 high part and then the low part to guarantee a correct
2932 32/64-bit copy. */
2933 if (TARGET_M6812
2934 && GET_MODE_SIZE (mode) >= 2
2935 && autoinc_from != autoinc_to
2936 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2938 rtx swap;
2940 swap = low_to;
2941 low_to = high_to;
2942 high_to = swap;
2944 swap = low_from;
2945 low_from = high_from;
2946 high_from = swap;
2948 if (mode == SImode)
2950 m68hc11_split_move (low_to, low_from, scratch);
2951 m68hc11_split_move (high_to, high_from, scratch);
2953 else if (H_REG_P (to) || H_REG_P (from)
2954 || (low_from == const0_rtx
2955 && high_from == const0_rtx
2956 && ! push_operand (to, GET_MODE (to))
2957 && ! H_REG_P (scratch))
2958 || (TARGET_M6812
2959 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2960 || m68hc11_small_indexed_indirect_p (from,
2961 GET_MODE (from)))
2962 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2963 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2965 insn = emit_move_insn (low_to, low_from);
2966 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2968 insn = emit_move_insn (high_to, high_from);
2969 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2971 else
2973 insn = emit_move_insn (scratch, low_from);
2974 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2975 insn = emit_move_insn (low_to, scratch);
2976 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2978 insn = emit_move_insn (scratch, high_from);
2979 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2980 insn = emit_move_insn (high_to, scratch);
2981 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2985 static rtx
2986 simplify_logical (mode, code, operand, result)
2987 enum machine_mode mode;
2988 int code;
2989 rtx operand;
2990 rtx *result;
2992 int val;
2993 int mask;
2995 *result = 0;
2996 if (GET_CODE (operand) != CONST_INT)
2997 return operand;
2999 if (mode == HImode)
3000 mask = 0x0ffff;
3001 else
3002 mask = 0x0ff;
3004 val = INTVAL (operand);
3005 switch (code)
3007 case IOR:
3008 if ((val & mask) == 0)
3009 return 0;
3010 if ((val & mask) == mask)
3011 *result = constm1_rtx;
3012 break;
3014 case AND:
3015 if ((val & mask) == 0)
3016 *result = const0_rtx;
3017 if ((val & mask) == mask)
3018 return 0;
3019 break;
3021 case XOR:
3022 if ((val & mask) == 0)
3023 return 0;
3024 break;
3026 return operand;
3029 static void
3030 m68hc11_emit_logical (mode, code, operands)
3031 enum machine_mode mode;
3032 int code;
3033 rtx *operands;
3035 rtx result;
3036 int need_copy;
3038 need_copy = (rtx_equal_p (operands[0], operands[1])
3039 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
3041 operands[1] = simplify_logical (mode, code, operands[1], &result);
3042 operands[2] = simplify_logical (mode, code, operands[2], &result);
3044 if (result && GET_CODE (result) == CONST_INT)
3046 if (!H_REG_P (operands[0]) && operands[3]
3047 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
3049 emit_move_insn (operands[3], result);
3050 emit_move_insn (operands[0], operands[3]);
3052 else
3054 emit_move_insn (operands[0], result);
3057 else if (operands[1] != 0 && operands[2] != 0)
3059 rtx insn;
3061 if (!H_REG_P (operands[0]) && operands[3])
3063 emit_move_insn (operands[3], operands[1]);
3064 emit_insn (gen_rtx (SET, mode,
3065 operands[3],
3066 gen_rtx (code, mode,
3067 operands[3], operands[2])));
3068 insn = emit_move_insn (operands[0], operands[3]);
3070 else
3072 insn = emit_insn (gen_rtx (SET, mode,
3073 operands[0],
3074 gen_rtx (code, mode,
3075 operands[0], operands[2])));
3079 /* The logical operation is similar to a copy. */
3080 else if (need_copy)
3082 rtx src;
3084 if (GET_CODE (operands[1]) == CONST_INT)
3085 src = operands[2];
3086 else
3087 src = operands[1];
3089 if (!H_REG_P (operands[0]) && !H_REG_P (src))
3091 emit_move_insn (operands[3], src);
3092 emit_move_insn (operands[0], operands[3]);
3094 else
3096 emit_move_insn (operands[0], src);
3101 void
3102 m68hc11_split_logical (mode, code, operands)
3103 enum machine_mode mode;
3104 int code;
3105 rtx *operands;
3107 rtx low[4];
3108 rtx high[4];
3110 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3111 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3112 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3114 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3116 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3118 if (INTVAL (operands[1]) >= 0)
3119 high[1] = const0_rtx;
3120 else
3121 high[1] = constm1_rtx;
3123 else
3124 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3126 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3128 if (INTVAL (operands[2]) >= 0)
3129 high[2] = const0_rtx;
3130 else
3131 high[2] = constm1_rtx;
3133 else
3134 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3136 low[3] = operands[3];
3137 high[3] = operands[3];
3138 if (mode == SImode)
3140 m68hc11_split_logical (HImode, code, low);
3141 m68hc11_split_logical (HImode, code, high);
3142 return;
3145 m68hc11_emit_logical (mode, code, low);
3146 m68hc11_emit_logical (mode, code, high);
3150 /* Code generation. */
3152 void
3153 m68hc11_output_swap (insn, operands)
3154 rtx insn ATTRIBUTE_UNUSED;
3155 rtx operands[];
3157 /* We have to be careful with the cc_status. An address register swap
3158 is generated for some comparison. The comparison is made with D
3159 but the branch really uses the address register. See the split
3160 pattern for compare. The xgdx/xgdy preserve the flags but after
3161 the exchange, the flags will reflect to the value of X and not D.
3162 Tell this by setting the cc_status according to the cc_prev_status. */
3163 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3165 if (cc_prev_status.value1 != 0
3166 && (D_REG_P (cc_prev_status.value1)
3167 || X_REG_P (cc_prev_status.value1)))
3169 cc_status = cc_prev_status;
3170 if (D_REG_P (cc_status.value1))
3171 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3172 HARD_X_REGNUM);
3173 else
3174 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3175 HARD_D_REGNUM);
3177 else
3178 CC_STATUS_INIT;
3180 output_asm_insn ("xgdx", operands);
3182 else
3184 if (cc_prev_status.value1 != 0
3185 && (D_REG_P (cc_prev_status.value1)
3186 || Y_REG_P (cc_prev_status.value1)))
3188 cc_status = cc_prev_status;
3189 if (D_REG_P (cc_status.value1))
3190 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3191 HARD_Y_REGNUM);
3192 else
3193 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3194 HARD_D_REGNUM);
3196 else
3197 CC_STATUS_INIT;
3199 output_asm_insn ("xgdy", operands);
3203 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3204 This is used to decide whether a move that set flags should be used
3205 instead. */
3207 next_insn_test_reg (insn, reg)
3208 rtx insn;
3209 rtx reg;
3211 rtx body;
3213 insn = next_nonnote_insn (insn);
3214 if (GET_CODE (insn) != INSN)
3215 return 0;
3217 body = PATTERN (insn);
3218 if (sets_cc0_p (body) != 1)
3219 return 0;
3221 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3222 return 0;
3224 return 1;
3227 /* Generate the code to move a 16-bit operand into another one. */
3229 void
3230 m68hc11_gen_movhi (insn, operands)
3231 rtx insn;
3232 rtx *operands;
3234 int reg;
3236 /* Move a register or memory to the same location.
3237 This is possible because such insn can appear
3238 in a non-optimizing mode. */
3239 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3241 cc_status = cc_prev_status;
3242 return;
3245 if (TARGET_M6812)
3247 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3249 cc_status = cc_prev_status;
3250 switch (REGNO (operands[1]))
3252 case HARD_X_REGNUM:
3253 case HARD_Y_REGNUM:
3254 case HARD_D_REGNUM:
3255 output_asm_insn ("psh%1", operands);
3256 break;
3257 case HARD_SP_REGNUM:
3258 output_asm_insn ("sts\t-2,sp", operands);
3259 break;
3260 default:
3261 abort ();
3263 return;
3265 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3267 cc_status = cc_prev_status;
3268 switch (REGNO (operands[0]))
3270 case HARD_X_REGNUM:
3271 case HARD_Y_REGNUM:
3272 case HARD_D_REGNUM:
3273 output_asm_insn ("pul%0", operands);
3274 break;
3275 default:
3276 abort ();
3278 return;
3280 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3282 m68hc11_notice_keep_cc (operands[0]);
3283 output_asm_insn ("tfr\t%1,%0", operands);
3285 else if (H_REG_P (operands[0]))
3287 if (SP_REG_P (operands[0]))
3288 output_asm_insn ("lds\t%1", operands);
3289 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3290 && !D_REG_P (operands[0])
3291 && GET_CODE (operands[1]) == CONST_INT
3292 && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
3293 && find_reg_note (insn, REG_WAS_0, 0))
3295 if (INTVAL (operands[1]) == 1)
3296 output_asm_insn ("in%0", operands);
3297 else
3298 output_asm_insn ("de%0", operands);
3300 else
3301 output_asm_insn ("ld%0\t%1", operands);
3303 else if (H_REG_P (operands[1]))
3305 if (SP_REG_P (operands[1]))
3306 output_asm_insn ("sts\t%0", operands);
3307 else
3308 output_asm_insn ("st%1\t%0", operands);
3310 else
3312 rtx from = operands[1];
3313 rtx to = operands[0];
3315 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3316 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3317 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3318 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3320 rtx ops[3];
3322 if (operands[2])
3324 ops[0] = operands[2];
3325 ops[1] = from;
3326 ops[2] = 0;
3327 m68hc11_gen_movhi (insn, ops);
3328 ops[0] = to;
3329 ops[1] = operands[2];
3330 m68hc11_gen_movhi (insn, ops);
3332 else
3334 /* !!!! SCz wrong here. */
3335 fatal_insn ("move insn not handled", insn);
3338 else
3340 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3342 output_asm_insn ("clr\t%h0", operands);
3343 output_asm_insn ("clr\t%b0", operands);
3345 else
3347 m68hc11_notice_keep_cc (operands[0]);
3348 output_asm_insn ("movw\t%1,%0", operands);
3352 return;
3355 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3357 cc_status = cc_prev_status;
3358 switch (REGNO (operands[0]))
3360 case HARD_X_REGNUM:
3361 case HARD_Y_REGNUM:
3362 output_asm_insn ("pul%0", operands);
3363 break;
3364 case HARD_D_REGNUM:
3365 output_asm_insn ("pula", operands);
3366 output_asm_insn ("pulb", operands);
3367 break;
3368 default:
3369 abort ();
3371 return;
3373 /* Some moves to a hard register are special. Not all of them
3374 are really supported and we have to use a temporary
3375 location to provide them (either the stack of a temp var). */
3376 if (H_REG_P (operands[0]))
3378 switch (REGNO (operands[0]))
3380 case HARD_D_REGNUM:
3381 if (X_REG_P (operands[1]))
3383 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3385 m68hc11_output_swap (insn, operands);
3387 else if (next_insn_test_reg (insn, operands[0]))
3389 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3391 else
3393 m68hc11_notice_keep_cc (operands[0]);
3394 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3397 else if (Y_REG_P (operands[1]))
3399 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3401 m68hc11_output_swap (insn, operands);
3403 else
3405 /* %t means *ZTMP scratch register. */
3406 output_asm_insn ("sty\t%t1", operands);
3407 output_asm_insn ("ldd\t%t1", operands);
3410 else if (SP_REG_P (operands[1]))
3412 CC_STATUS_INIT;
3413 if (ix_reg == 0)
3414 create_regs_rtx ();
3415 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3416 output_asm_insn ("xgdx", operands);
3417 output_asm_insn ("tsx", operands);
3418 output_asm_insn ("xgdx", operands);
3420 else if (IS_STACK_POP (operands[1]))
3422 output_asm_insn ("pula\n\tpulb", operands);
3424 else if (GET_CODE (operands[1]) == CONST_INT
3425 && INTVAL (operands[1]) == 0)
3427 output_asm_insn ("clra\n\tclrb", operands);
3429 else
3431 output_asm_insn ("ldd\t%1", operands);
3433 break;
3435 case HARD_X_REGNUM:
3436 if (D_REG_P (operands[1]))
3438 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3440 m68hc11_output_swap (insn, operands);
3442 else if (next_insn_test_reg (insn, operands[0]))
3444 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3446 else
3448 m68hc11_notice_keep_cc (operands[0]);
3449 output_asm_insn ("pshb", operands);
3450 output_asm_insn ("psha", operands);
3451 output_asm_insn ("pulx", operands);
3454 else if (Y_REG_P (operands[1]))
3456 /* When both D and Y are dead, use the sequence xgdy, xgdx
3457 to move Y into X. The D and Y registers are modified. */
3458 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3459 && dead_register_here (insn, d_reg))
3461 output_asm_insn ("xgdy", operands);
3462 output_asm_insn ("xgdx", operands);
3463 CC_STATUS_INIT;
3465 else if (!optimize_size)
3467 output_asm_insn ("sty\t%t1", operands);
3468 output_asm_insn ("ldx\t%t1", operands);
3470 else
3472 CC_STATUS_INIT;
3473 output_asm_insn ("pshy", operands);
3474 output_asm_insn ("pulx", operands);
3477 else if (SP_REG_P (operands[1]))
3479 /* tsx, tsy preserve the flags */
3480 cc_status = cc_prev_status;
3481 output_asm_insn ("tsx", operands);
3483 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3484 && GET_CODE (operands[1]) == CONST_INT
3485 && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
3486 && find_reg_note (insn, REG_WAS_0, 0))
3488 if (INTVAL (operands[1]) == 1)
3489 output_asm_insn ("in%0", operands);
3490 else
3491 output_asm_insn ("de%0", operands);
3493 else
3495 output_asm_insn ("ldx\t%1", operands);
3497 break;
3499 case HARD_Y_REGNUM:
3500 if (D_REG_P (operands[1]))
3502 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3504 m68hc11_output_swap (insn, operands);
3506 else
3508 output_asm_insn ("std\t%t1", operands);
3509 output_asm_insn ("ldy\t%t1", operands);
3512 else if (X_REG_P (operands[1]))
3514 /* When both D and X are dead, use the sequence xgdx, xgdy
3515 to move X into Y. The D and X registers are modified. */
3516 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3517 && dead_register_here (insn, d_reg))
3519 output_asm_insn ("xgdx", operands);
3520 output_asm_insn ("xgdy", operands);
3521 CC_STATUS_INIT;
3523 else if (!optimize_size)
3525 output_asm_insn ("stx\t%t1", operands);
3526 output_asm_insn ("ldy\t%t1", operands);
3528 else
3530 CC_STATUS_INIT;
3531 output_asm_insn ("pshx", operands);
3532 output_asm_insn ("puly", operands);
3535 else if (SP_REG_P (operands[1]))
3537 /* tsx, tsy preserve the flags */
3538 cc_status = cc_prev_status;
3539 output_asm_insn ("tsy", operands);
3541 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3542 && GET_CODE (operands[1]) == CONST_INT
3543 && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
3544 && find_reg_note (insn, REG_WAS_0, 0))
3546 if (INTVAL (operands[1]) == 1)
3547 output_asm_insn ("in%0", operands);
3548 else
3549 output_asm_insn ("de%0", operands);
3551 else
3553 output_asm_insn ("ldy\t%1", operands);
3555 break;
3557 case HARD_SP_REGNUM:
3558 if (D_REG_P (operands[1]))
3560 m68hc11_notice_keep_cc (operands[0]);
3561 output_asm_insn ("xgdx", operands);
3562 output_asm_insn ("txs", operands);
3563 output_asm_insn ("xgdx", operands);
3565 else if (X_REG_P (operands[1]))
3567 /* tys, txs preserve the flags */
3568 cc_status = cc_prev_status;
3569 output_asm_insn ("txs", operands);
3571 else if (Y_REG_P (operands[1]))
3573 /* tys, txs preserve the flags */
3574 cc_status = cc_prev_status;
3575 output_asm_insn ("tys", operands);
3577 else
3579 /* lds sets the flags but the des does not. */
3580 CC_STATUS_INIT;
3581 output_asm_insn ("lds\t%1", operands);
3582 output_asm_insn ("des", operands);
3584 break;
3586 default:
3587 fatal_insn ("invalid register in the move instruction", insn);
3588 break;
3590 return;
3592 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3593 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3595 output_asm_insn ("sts\t%0", operands);
3596 return;
3599 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3601 cc_status = cc_prev_status;
3602 switch (REGNO (operands[1]))
3604 case HARD_X_REGNUM:
3605 case HARD_Y_REGNUM:
3606 output_asm_insn ("psh%1", operands);
3607 break;
3608 case HARD_D_REGNUM:
3609 output_asm_insn ("pshb", operands);
3610 output_asm_insn ("psha", operands);
3611 break;
3612 default:
3613 abort ();
3615 return;
3618 /* Operand 1 must be a hard register. */
3619 if (!H_REG_P (operands[1]))
3621 fatal_insn ("invalid operand in the instruction", insn);
3624 reg = REGNO (operands[1]);
3625 switch (reg)
3627 case HARD_D_REGNUM:
3628 output_asm_insn ("std\t%0", operands);
3629 break;
3631 case HARD_X_REGNUM:
3632 output_asm_insn ("stx\t%0", operands);
3633 break;
3635 case HARD_Y_REGNUM:
3636 output_asm_insn ("sty\t%0", operands);
3637 break;
3639 case HARD_SP_REGNUM:
3640 if (ix_reg == 0)
3641 create_regs_rtx ();
3643 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3645 output_asm_insn ("pshx", operands);
3646 output_asm_insn ("tsx", operands);
3647 output_asm_insn ("inx", operands);
3648 output_asm_insn ("inx", operands);
3649 output_asm_insn ("stx\t%0", operands);
3650 output_asm_insn ("pulx", operands);
3653 else if (reg_mentioned_p (ix_reg, operands[0]))
3655 output_asm_insn ("sty\t%t0", operands);
3656 output_asm_insn ("tsy", operands);
3657 output_asm_insn ("sty\t%0", operands);
3658 output_asm_insn ("ldy\t%t0", operands);
3660 else
3662 output_asm_insn ("stx\t%t0", operands);
3663 output_asm_insn ("tsx", operands);
3664 output_asm_insn ("stx\t%0", operands);
3665 output_asm_insn ("ldx\t%t0", operands);
3667 CC_STATUS_INIT;
3668 break;
3670 default:
3671 fatal_insn ("invalid register in the move instruction", insn);
3672 break;
3676 void
3677 m68hc11_gen_movqi (insn, operands)
3678 rtx insn;
3679 rtx *operands;
3681 /* Move a register or memory to the same location.
3682 This is possible because such insn can appear
3683 in a non-optimizing mode. */
3684 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3686 cc_status = cc_prev_status;
3687 return;
3690 if (TARGET_M6812)
3693 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3695 m68hc11_notice_keep_cc (operands[0]);
3696 output_asm_insn ("tfr\t%1,%0", operands);
3698 else if (H_REG_P (operands[0]))
3700 if (Q_REG_P (operands[0]))
3701 output_asm_insn ("lda%0\t%b1", operands);
3702 else if (D_REG_P (operands[0]))
3703 output_asm_insn ("ldab\t%b1", operands);
3704 else
3705 goto m6811_move;
3707 else if (H_REG_P (operands[1]))
3709 if (Q_REG_P (operands[1]))
3710 output_asm_insn ("sta%1\t%b0", operands);
3711 else if (D_REG_P (operands[1]))
3712 output_asm_insn ("stab\t%b0", operands);
3713 else
3714 goto m6811_move;
3716 else
3718 rtx from = operands[1];
3719 rtx to = operands[0];
3721 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3722 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3723 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3724 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3726 rtx ops[3];
3728 if (operands[2])
3730 ops[0] = operands[2];
3731 ops[1] = from;
3732 ops[2] = 0;
3733 m68hc11_gen_movqi (insn, ops);
3734 ops[0] = to;
3735 ops[1] = operands[2];
3736 m68hc11_gen_movqi (insn, ops);
3738 else
3740 /* !!!! SCz wrong here. */
3741 fatal_insn ("move insn not handled", insn);
3744 else
3746 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3748 output_asm_insn ("clr\t%b0", operands);
3750 else
3752 m68hc11_notice_keep_cc (operands[0]);
3753 output_asm_insn ("movb\t%b1,%b0", operands);
3757 return;
3760 m6811_move:
3761 if (H_REG_P (operands[0]))
3763 switch (REGNO (operands[0]))
3765 case HARD_B_REGNUM:
3766 case HARD_D_REGNUM:
3767 if (X_REG_P (operands[1]))
3769 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3771 m68hc11_output_swap (insn, operands);
3773 else
3775 output_asm_insn ("stx\t%t1", operands);
3776 output_asm_insn ("ldab\t%T0", operands);
3779 else if (Y_REG_P (operands[1]))
3781 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3783 m68hc11_output_swap (insn, operands);
3785 else
3787 output_asm_insn ("sty\t%t1", operands);
3788 output_asm_insn ("ldab\t%T0", operands);
3791 else if (0 /* REG_WAS_0 note is boggus; don't rely on it. */
3792 && GET_CODE (operands[1]) == CONST_INT
3793 && (INTVAL (operands[1]) == 1 || INTVAL (operands[1]) == -1)
3794 && find_reg_note (insn, REG_WAS_0, 0))
3796 if (INTVAL (operands[1]) == 1)
3797 output_asm_insn ("inc%b0", operands);
3798 else
3799 output_asm_insn ("dec%b0", operands);
3801 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3802 && !DA_REG_P (operands[1]))
3804 output_asm_insn ("ldab\t%b1", operands);
3806 else if (DA_REG_P (operands[1]))
3808 output_asm_insn ("tab", operands);
3810 else
3812 cc_status = cc_prev_status;
3813 return;
3815 break;
3817 case HARD_A_REGNUM:
3818 if (X_REG_P (operands[1]))
3820 output_asm_insn ("stx\t%t1", operands);
3821 output_asm_insn ("ldaa\t%T0", operands);
3823 else if (Y_REG_P (operands[1]))
3825 output_asm_insn ("sty\t%t1", operands);
3826 output_asm_insn ("ldaa\t%T0", operands);
3828 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3829 && !DA_REG_P (operands[1]))
3831 output_asm_insn ("ldaa\t%b1", operands);
3833 else if (!DA_REG_P (operands[1]))
3835 output_asm_insn ("tba", operands);
3837 else
3839 cc_status = cc_prev_status;
3841 break;
3843 case HARD_X_REGNUM:
3844 if (D_REG_P (operands[1]))
3846 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3848 m68hc11_output_swap (insn, operands);
3850 else
3852 output_asm_insn ("stab\t%T1", operands);
3853 output_asm_insn ("ldx\t%t1", operands);
3855 CC_STATUS_INIT;
3857 else if (Y_REG_P (operands[1]))
3859 output_asm_insn ("sty\t%t0", operands);
3860 output_asm_insn ("ldx\t%t0", operands);
3862 else if (GET_CODE (operands[1]) == CONST_INT)
3864 output_asm_insn ("ldx\t%1", operands);
3866 else if (dead_register_here (insn, d_reg))
3868 output_asm_insn ("ldab\t%b1", operands);
3869 output_asm_insn ("xgdx", operands);
3871 else if (!reg_mentioned_p (operands[0], operands[1]))
3873 output_asm_insn ("xgdx", operands);
3874 output_asm_insn ("ldab\t%b1", operands);
3875 output_asm_insn ("xgdx", operands);
3877 else
3879 output_asm_insn ("pshb", operands);
3880 output_asm_insn ("ldab\t%b1", operands);
3881 output_asm_insn ("stab\t%T1", operands);
3882 output_asm_insn ("ldx\t%t1", operands);
3883 output_asm_insn ("pulb", operands);
3884 CC_STATUS_INIT;
3886 break;
3888 case HARD_Y_REGNUM:
3889 if (D_REG_P (operands[1]))
3891 output_asm_insn ("stab\t%T1", operands);
3892 output_asm_insn ("ldy\t%t1", operands);
3893 CC_STATUS_INIT;
3895 else if (X_REG_P (operands[1]))
3897 output_asm_insn ("stx\t%t1", operands);
3898 output_asm_insn ("ldy\t%t1", operands);
3899 CC_STATUS_INIT;
3901 else if (GET_CODE (operands[1]) == CONST_INT)
3903 output_asm_insn ("ldy\t%1", operands);
3905 else if (dead_register_here (insn, d_reg))
3907 output_asm_insn ("ldab\t%b1", operands);
3908 output_asm_insn ("xgdy", operands);
3910 else if (!reg_mentioned_p (operands[0], operands[1]))
3912 output_asm_insn ("xgdy", operands);
3913 output_asm_insn ("ldab\t%b1", operands);
3914 output_asm_insn ("xgdy", operands);
3916 else
3918 output_asm_insn ("pshb", operands);
3919 output_asm_insn ("ldab\t%b1", operands);
3920 output_asm_insn ("stab\t%T1", operands);
3921 output_asm_insn ("ldy\t%t1", operands);
3922 output_asm_insn ("pulb", operands);
3923 CC_STATUS_INIT;
3925 break;
3927 default:
3928 fatal_insn ("invalid register in the instruction", insn);
3929 break;
3932 else if (H_REG_P (operands[1]))
3934 switch (REGNO (operands[1]))
3936 case HARD_D_REGNUM:
3937 case HARD_B_REGNUM:
3938 output_asm_insn ("stab\t%b0", operands);
3939 break;
3941 case HARD_A_REGNUM:
3942 output_asm_insn ("staa\t%b0", operands);
3943 break;
3945 case HARD_X_REGNUM:
3946 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3947 break;
3949 case HARD_Y_REGNUM:
3950 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3951 break;
3953 default:
3954 fatal_insn ("invalid register in the move instruction", insn);
3955 break;
3957 return;
3959 else
3961 fatal_insn ("operand 1 must be a hard register", insn);
3965 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3966 The source and destination must be D or A and the shift must
3967 be a constant. */
3968 void
3969 m68hc11_gen_rotate (code, insn, operands)
3970 enum rtx_code code;
3971 rtx insn;
3972 rtx operands[];
3974 int val;
3976 if (GET_CODE (operands[2]) != CONST_INT
3977 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3978 fatal_insn ("invalid rotate insn", insn);
3980 val = INTVAL (operands[2]);
3981 if (code == ROTATERT)
3982 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3984 if (GET_MODE (operands[0]) != QImode)
3985 CC_STATUS_INIT;
3987 /* Rotate by 8-bits if the shift is within [5..11]. */
3988 if (val >= 5 && val <= 11)
3990 if (TARGET_M6812)
3991 output_asm_insn ("exg\ta,b", operands);
3992 else
3994 output_asm_insn ("psha", operands);
3995 output_asm_insn ("tba", operands);
3996 output_asm_insn ("pulb", operands);
3998 val -= 8;
4001 /* If the shift is big, invert the rotation. */
4002 else if (val >= 12)
4004 val = val - 16;
4007 if (val > 0)
4009 while (--val >= 0)
4011 /* Set the carry to bit-15, but don't change D yet. */
4012 if (GET_MODE (operands[0]) != QImode)
4014 output_asm_insn ("asra", operands);
4015 output_asm_insn ("rola", operands);
4018 /* Rotate B first to move the carry to bit-0. */
4019 if (D_REG_P (operands[0]))
4020 output_asm_insn ("rolb", operands);
4022 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
4023 output_asm_insn ("rola", operands);
4026 else
4028 while (++val <= 0)
4030 /* Set the carry to bit-8 of D. */
4031 if (GET_MODE (operands[0]) != QImode)
4032 output_asm_insn ("tap", operands);
4034 /* Rotate B first to move the carry to bit-7. */
4035 if (D_REG_P (operands[0]))
4036 output_asm_insn ("rorb", operands);
4038 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
4039 output_asm_insn ("rora", operands);
4046 /* Store in cc_status the expressions that the condition codes will
4047 describe after execution of an instruction whose pattern is EXP.
4048 Do not alter them if the instruction would not alter the cc's. */
4050 void
4051 m68hc11_notice_update_cc (exp, insn)
4052 rtx exp;
4053 rtx insn ATTRIBUTE_UNUSED;
4055 /* recognize SET insn's. */
4056 if (GET_CODE (exp) == SET)
4058 /* Jumps do not alter the cc's. */
4059 if (SET_DEST (exp) == pc_rtx)
4062 /* NOTE: most instructions don't affect the carry bit, but the
4063 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
4064 the conditions.h header. */
4066 /* Function calls clobber the cc's. */
4067 else if (GET_CODE (SET_SRC (exp)) == CALL)
4069 CC_STATUS_INIT;
4072 /* Tests and compares set the cc's in predictable ways. */
4073 else if (SET_DEST (exp) == cc0_rtx)
4075 cc_status.flags = 0;
4076 cc_status.value1 = XEXP (exp, 0);
4077 cc_status.value2 = XEXP (exp, 1);
4079 else
4081 /* All other instructions affect the condition codes. */
4082 cc_status.flags = 0;
4083 cc_status.value1 = XEXP (exp, 0);
4084 cc_status.value2 = XEXP (exp, 1);
4087 else
4089 /* Default action if we haven't recognized something
4090 and returned earlier. */
4091 CC_STATUS_INIT;
4094 if (cc_status.value2 != 0)
4095 switch (GET_CODE (cc_status.value2))
4097 /* These logical operations can generate several insns.
4098 The flags are setup according to what is generated. */
4099 case IOR:
4100 case XOR:
4101 case AND:
4102 break;
4104 /* The (not ...) generates several 'com' instructions for
4105 non QImode. We have to invalidate the flags. */
4106 case NOT:
4107 if (GET_MODE (cc_status.value2) != QImode)
4108 CC_STATUS_INIT;
4109 break;
4111 case PLUS:
4112 case MINUS:
4113 case MULT:
4114 case DIV:
4115 case UDIV:
4116 case MOD:
4117 case UMOD:
4118 case NEG:
4119 if (GET_MODE (cc_status.value2) != VOIDmode)
4120 cc_status.flags |= CC_NO_OVERFLOW;
4121 break;
4123 /* The asl sets the overflow bit in such a way that this
4124 makes the flags unusable for a next compare insn. */
4125 case ASHIFT:
4126 case ROTATE:
4127 case ROTATERT:
4128 if (GET_MODE (cc_status.value2) != VOIDmode)
4129 cc_status.flags |= CC_NO_OVERFLOW;
4130 break;
4132 /* A load/store instruction does not affect the carry. */
4133 case MEM:
4134 case SYMBOL_REF:
4135 case REG:
4136 case CONST_INT:
4137 cc_status.flags |= CC_NO_OVERFLOW;
4138 break;
4140 default:
4141 break;
4143 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
4144 && cc_status.value2
4145 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
4146 cc_status.value2 = 0;
4149 /* The current instruction does not affect the flags but changes
4150 the register 'reg'. See if the previous flags can be kept for the
4151 next instruction to avoid a comparison. */
4152 void
4153 m68hc11_notice_keep_cc (reg)
4154 rtx reg;
4156 if (reg == 0
4157 || cc_prev_status.value1 == 0
4158 || rtx_equal_p (reg, cc_prev_status.value1)
4159 || (cc_prev_status.value2
4160 && reg_mentioned_p (reg, cc_prev_status.value2)))
4161 CC_STATUS_INIT;
4162 else
4163 cc_status = cc_prev_status;
4168 /* Machine Specific Reorg. */
4170 /* Z register replacement:
4172 GCC treats the Z register as an index base address register like
4173 X or Y. In general, it uses it during reload to compute the address
4174 of some operand. This helps the reload pass to avoid to fall into the
4175 register spill failure.
4177 The Z register is in the A_REGS class. In the machine description,
4178 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4180 It can appear everywhere an X or Y register can appear, except for
4181 some templates in the clobber section (when a clobber of X or Y is asked).
4182 For a given instruction, the template must ensure that no more than
4183 2 'A' registers are used. Otherwise, the register replacement is not
4184 possible.
4186 To replace the Z register, the algorithm is not terrific:
4187 1. Insns that do not use the Z register are not changed
4188 2. When a Z register is used, we scan forward the insns to see
4189 a potential register to use: either X or Y and sometimes D.
4190 We stop when a call, a label or a branch is seen, or when we
4191 detect that both X and Y are used (probably at different times, but it does
4192 not matter).
4193 3. The register that will be used for the replacement of Z is saved
4194 in a .page0 register or on the stack. If the first instruction that
4195 used Z, uses Z as an input, the value is loaded from another .page0
4196 register. The replacement register is pushed on the stack in the
4197 rare cases where a compare insn uses Z and we couldn't find if X/Y
4198 are dead.
4199 4. The Z register is replaced in all instructions until we reach
4200 the end of the Z-block, as detected by step 2.
4201 5. If we detect that Z is still alive, its value is saved.
4202 If the replacement register is alive, its old value is loaded.
4204 The Z register can be disabled with -ffixed-z.
4207 struct replace_info
4209 rtx first;
4210 rtx replace_reg;
4211 int need_save_z;
4212 int must_load_z;
4213 int must_save_reg;
4214 int must_restore_reg;
4215 rtx last;
4216 int regno;
4217 int x_used;
4218 int y_used;
4219 int can_use_d;
4220 int found_call;
4221 int z_died;
4222 int z_set_count;
4223 rtx z_value;
4224 int must_push_reg;
4225 int save_before_last;
4226 int z_loaded_with_sp;
4229 static int m68hc11_check_z_replacement PARAMS ((rtx, struct replace_info *));
4230 static void m68hc11_find_z_replacement PARAMS ((rtx, struct replace_info *));
4231 static void m68hc11_z_replacement PARAMS ((rtx));
4232 static void m68hc11_reassign_regs PARAMS ((rtx));
4234 int z_replacement_completed = 0;
4236 /* Analyze the insn to find out which replacement register to use and
4237 the boundaries of the replacement.
4238 Returns 0 if we reached the last insn to be replaced, 1 if we can
4239 continue replacement in next insns. */
4241 static int
4242 m68hc11_check_z_replacement (insn, info)
4243 rtx insn;
4244 struct replace_info *info;
4246 int this_insn_uses_ix;
4247 int this_insn_uses_iy;
4248 int this_insn_uses_z;
4249 int this_insn_uses_z_in_dst;
4250 int this_insn_uses_d;
4251 rtx body;
4252 int z_dies_here;
4254 /* A call is said to clobber the Z register, we don't need
4255 to save the value of Z. We also don't need to restore
4256 the replacement register (unless it is used by the call). */
4257 if (GET_CODE (insn) == CALL_INSN)
4259 body = PATTERN (insn);
4261 info->can_use_d = 0;
4263 /* If the call is an indirect call with Z, we have to use the
4264 Y register because X can be used as an input (D+X).
4265 We also must not save Z nor restore Y. */
4266 if (reg_mentioned_p (z_reg, body))
4268 insn = NEXT_INSN (insn);
4269 info->x_used = 1;
4270 info->y_used = 0;
4271 info->found_call = 1;
4272 info->must_restore_reg = 0;
4273 info->last = NEXT_INSN (insn);
4275 info->need_save_z = 0;
4276 return 0;
4278 if (GET_CODE (insn) == CODE_LABEL
4279 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4280 return 0;
4282 if (GET_CODE (insn) == JUMP_INSN)
4284 if (reg_mentioned_p (z_reg, insn) == 0)
4285 return 0;
4287 info->can_use_d = 0;
4288 info->must_save_reg = 0;
4289 info->must_restore_reg = 0;
4290 info->need_save_z = 0;
4291 info->last = NEXT_INSN (insn);
4292 return 0;
4294 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4296 return 1;
4299 /* Z register dies here. */
4300 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4302 body = PATTERN (insn);
4303 if (GET_CODE (body) == SET)
4305 rtx src = XEXP (body, 1);
4306 rtx dst = XEXP (body, 0);
4308 /* Condition code is set here. We have to restore the X/Y and
4309 save into Z before any test/compare insn because once we save/restore
4310 we can change the condition codes. When the compare insn uses Z and
4311 we can't use X/Y, the comparison is made with the *ZREG soft register
4312 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4313 if (dst == cc0_rtx)
4315 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4316 || (GET_CODE (src) == COMPARE &&
4317 (rtx_equal_p (XEXP (src, 0), z_reg)
4318 || rtx_equal_p (XEXP (src, 1), z_reg))))
4320 if (insn == info->first)
4322 info->must_load_z = 0;
4323 info->must_save_reg = 0;
4324 info->must_restore_reg = 0;
4325 info->need_save_z = 0;
4326 info->found_call = 1;
4327 info->regno = SOFT_Z_REGNUM;
4328 info->last = NEXT_INSN (insn);
4330 return 0;
4332 if (reg_mentioned_p (z_reg, src) == 0)
4334 info->can_use_d = 0;
4335 return 0;
4338 if (insn != info->first)
4339 return 0;
4341 /* Compare insn which uses Z. We have to save/restore the X/Y
4342 register without modifying the condition codes. For this
4343 we have to use a push/pop insn. */
4344 info->must_push_reg = 1;
4345 info->last = insn;
4348 /* Z reg is set to something new. We don't need to load it. */
4349 if (Z_REG_P (dst))
4351 if (!reg_mentioned_p (z_reg, src))
4353 /* Z reg is used before being set. Treat this as
4354 a new sequence of Z register replacement. */
4355 if (insn != info->first)
4357 return 0;
4359 info->must_load_z = 0;
4361 info->z_set_count++;
4362 info->z_value = src;
4363 if (SP_REG_P (src))
4364 info->z_loaded_with_sp = 1;
4366 else if (reg_mentioned_p (z_reg, dst))
4367 info->can_use_d = 0;
4369 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4370 | reg_mentioned_p (d_reg, dst);
4371 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4372 | reg_mentioned_p (ix_reg, dst);
4373 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4374 | reg_mentioned_p (iy_reg, dst);
4375 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4377 /* If z is used as an address operand (like (MEM (reg z))),
4378 we can't replace it with d. */
4379 if (this_insn_uses_z && !Z_REG_P (src)
4380 && !(m68hc11_arith_operator (src, GET_MODE (src))
4381 && Z_REG_P (XEXP (src, 0))
4382 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4383 && insn == info->first
4384 && dead_register_here (insn, d_reg)))
4385 info->can_use_d = 0;
4387 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4388 if (TARGET_M6812 && !z_dies_here
4389 && ((this_insn_uses_z && side_effects_p (src))
4390 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4392 info->need_save_z = 1;
4393 info->z_set_count++;
4395 this_insn_uses_z |= this_insn_uses_z_in_dst;
4397 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4399 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4402 if (this_insn_uses_d)
4403 info->can_use_d = 0;
4405 /* IX and IY are used at the same time, we have to restore
4406 the value of the scratch register before this insn. */
4407 if (this_insn_uses_ix && this_insn_uses_iy)
4409 return 0;
4412 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4413 info->can_use_d = 0;
4415 if (info->x_used == 0 && this_insn_uses_ix)
4417 if (info->y_used)
4419 /* We have a (set (REG:HI X) (REG:HI Z)).
4420 Since we use Z as the replacement register, this insn
4421 is no longer necessary. We turn it into a note. We must
4422 not reload the old value of X. */
4423 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4425 if (z_dies_here)
4427 info->need_save_z = 0;
4428 info->z_died = 1;
4430 info->must_save_reg = 0;
4431 info->must_restore_reg = 0;
4432 info->found_call = 1;
4433 info->can_use_d = 0;
4434 PUT_CODE (insn, NOTE);
4435 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4436 NOTE_SOURCE_FILE (insn) = 0;
4437 info->last = NEXT_INSN (insn);
4438 return 0;
4441 if (X_REG_P (dst)
4442 && (rtx_equal_p (src, z_reg)
4443 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4445 if (z_dies_here)
4447 info->need_save_z = 0;
4448 info->z_died = 1;
4450 info->last = NEXT_INSN (insn);
4451 info->must_save_reg = 0;
4452 info->must_restore_reg = 0;
4454 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4455 && !reg_mentioned_p (ix_reg, src))
4457 if (z_dies_here)
4459 info->z_died = 1;
4460 info->need_save_z = 0;
4462 else if (TARGET_M6812 && side_effects_p (src))
4464 info->last = 0;
4465 info->must_restore_reg = 0;
4466 return 0;
4468 else
4470 info->save_before_last = 1;
4472 info->must_restore_reg = 0;
4473 info->last = NEXT_INSN (insn);
4475 else if (info->can_use_d)
4477 info->last = NEXT_INSN (insn);
4478 info->x_used = 1;
4480 return 0;
4482 info->x_used = 1;
4483 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4484 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4486 info->need_save_z = 0;
4487 info->z_died = 1;
4488 info->last = NEXT_INSN (insn);
4489 info->regno = HARD_X_REGNUM;
4490 info->must_save_reg = 0;
4491 info->must_restore_reg = 0;
4492 return 0;
4494 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4496 info->regno = HARD_X_REGNUM;
4497 info->must_restore_reg = 0;
4498 info->must_save_reg = 0;
4499 return 0;
4502 if (info->y_used == 0 && this_insn_uses_iy)
4504 if (info->x_used)
4506 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4508 if (z_dies_here)
4510 info->need_save_z = 0;
4511 info->z_died = 1;
4513 info->must_save_reg = 0;
4514 info->must_restore_reg = 0;
4515 info->found_call = 1;
4516 info->can_use_d = 0;
4517 PUT_CODE (insn, NOTE);
4518 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4519 NOTE_SOURCE_FILE (insn) = 0;
4520 info->last = NEXT_INSN (insn);
4521 return 0;
4524 if (Y_REG_P (dst)
4525 && (rtx_equal_p (src, z_reg)
4526 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4528 if (z_dies_here)
4530 info->z_died = 1;
4531 info->need_save_z = 0;
4533 info->last = NEXT_INSN (insn);
4534 info->must_save_reg = 0;
4535 info->must_restore_reg = 0;
4537 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4538 && !reg_mentioned_p (iy_reg, src))
4540 if (z_dies_here)
4542 info->z_died = 1;
4543 info->need_save_z = 0;
4545 else if (TARGET_M6812 && side_effects_p (src))
4547 info->last = 0;
4548 info->must_restore_reg = 0;
4549 return 0;
4551 else
4553 info->save_before_last = 1;
4555 info->must_restore_reg = 0;
4556 info->last = NEXT_INSN (insn);
4558 else if (info->can_use_d)
4560 info->last = NEXT_INSN (insn);
4561 info->y_used = 1;
4564 return 0;
4566 info->y_used = 1;
4567 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4568 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4570 info->need_save_z = 0;
4571 info->z_died = 1;
4572 info->last = NEXT_INSN (insn);
4573 info->regno = HARD_Y_REGNUM;
4574 info->must_save_reg = 0;
4575 info->must_restore_reg = 0;
4576 return 0;
4578 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4580 info->regno = HARD_Y_REGNUM;
4581 info->must_restore_reg = 0;
4582 info->must_save_reg = 0;
4583 return 0;
4586 if (z_dies_here)
4588 info->need_save_z = 0;
4589 info->z_died = 1;
4590 if (info->last == 0)
4591 info->last = NEXT_INSN (insn);
4592 return 0;
4594 return info->last != NULL_RTX ? 0 : 1;
4596 if (GET_CODE (body) == PARALLEL)
4598 int i;
4599 char ix_clobber = 0;
4600 char iy_clobber = 0;
4601 char z_clobber = 0;
4602 this_insn_uses_iy = 0;
4603 this_insn_uses_ix = 0;
4604 this_insn_uses_z = 0;
4606 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4608 rtx x;
4609 int uses_ix, uses_iy, uses_z;
4611 x = XVECEXP (body, 0, i);
4613 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4614 info->can_use_d = 0;
4616 uses_ix = reg_mentioned_p (ix_reg, x);
4617 uses_iy = reg_mentioned_p (iy_reg, x);
4618 uses_z = reg_mentioned_p (z_reg, x);
4619 if (GET_CODE (x) == CLOBBER)
4621 ix_clobber |= uses_ix;
4622 iy_clobber |= uses_iy;
4623 z_clobber |= uses_z;
4625 else
4627 this_insn_uses_ix |= uses_ix;
4628 this_insn_uses_iy |= uses_iy;
4629 this_insn_uses_z |= uses_z;
4631 if (uses_z && GET_CODE (x) == SET)
4633 rtx dst = XEXP (x, 0);
4635 if (Z_REG_P (dst))
4636 info->z_set_count++;
4638 if (TARGET_M6812 && uses_z && side_effects_p (x))
4639 info->need_save_z = 1;
4641 if (z_clobber)
4642 info->need_save_z = 0;
4644 if (debug_m6811)
4646 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4647 this_insn_uses_ix, this_insn_uses_iy,
4648 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4649 debug_rtx (insn);
4651 if (this_insn_uses_z)
4652 info->can_use_d = 0;
4654 if (z_clobber && info->first != insn)
4656 info->need_save_z = 0;
4657 info->last = insn;
4658 return 0;
4660 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4662 if (this_insn_uses_z == 0 && insn == info->first)
4664 info->must_load_z = 0;
4666 if (dead_register_here (insn, d_reg))
4668 info->regno = HARD_D_REGNUM;
4669 info->must_save_reg = 0;
4670 info->must_restore_reg = 0;
4672 else if (dead_register_here (insn, ix_reg))
4674 info->regno = HARD_X_REGNUM;
4675 info->must_save_reg = 0;
4676 info->must_restore_reg = 0;
4678 else if (dead_register_here (insn, iy_reg))
4680 info->regno = HARD_Y_REGNUM;
4681 info->must_save_reg = 0;
4682 info->must_restore_reg = 0;
4684 if (info->regno >= 0)
4686 info->last = NEXT_INSN (insn);
4687 return 0;
4689 if (this_insn_uses_ix == 0)
4691 info->regno = HARD_X_REGNUM;
4692 info->must_save_reg = 1;
4693 info->must_restore_reg = 1;
4695 else if (this_insn_uses_iy == 0)
4697 info->regno = HARD_Y_REGNUM;
4698 info->must_save_reg = 1;
4699 info->must_restore_reg = 1;
4701 else
4703 info->regno = HARD_D_REGNUM;
4704 info->must_save_reg = 1;
4705 info->must_restore_reg = 1;
4707 info->last = NEXT_INSN (insn);
4708 return 0;
4711 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4712 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4714 if (this_insn_uses_z)
4716 if (info->y_used == 0 && iy_clobber)
4718 info->regno = HARD_Y_REGNUM;
4719 info->must_save_reg = 0;
4720 info->must_restore_reg = 0;
4722 if (info->first != insn
4723 && ((info->y_used && ix_clobber)
4724 || (info->x_used && iy_clobber)))
4725 info->last = insn;
4726 else
4727 info->last = NEXT_INSN (insn);
4728 info->save_before_last = 1;
4730 return 0;
4732 if (this_insn_uses_ix && this_insn_uses_iy)
4734 if (this_insn_uses_z)
4736 fatal_insn ("cannot do z-register replacement", insn);
4738 return 0;
4740 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4742 if (info->y_used)
4744 return 0;
4746 info->x_used = 1;
4747 if (iy_clobber || z_clobber)
4749 info->last = NEXT_INSN (insn);
4750 info->save_before_last = 1;
4751 return 0;
4755 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4757 if (info->x_used)
4759 return 0;
4761 info->y_used = 1;
4762 if (ix_clobber || z_clobber)
4764 info->last = NEXT_INSN (insn);
4765 info->save_before_last = 1;
4766 return 0;
4769 if (z_dies_here)
4771 info->z_died = 1;
4772 info->need_save_z = 0;
4774 return 1;
4776 if (GET_CODE (body) == CLOBBER)
4779 /* IX and IY are used at the same time, we have to restore
4780 the value of the scratch register before this insn. */
4781 if (this_insn_uses_ix && this_insn_uses_iy)
4783 return 0;
4785 if (info->x_used == 0 && this_insn_uses_ix)
4787 if (info->y_used)
4789 return 0;
4791 info->x_used = 1;
4793 if (info->y_used == 0 && this_insn_uses_iy)
4795 if (info->x_used)
4797 return 0;
4799 info->y_used = 1;
4801 return 1;
4803 return 1;
4806 static void
4807 m68hc11_find_z_replacement (insn, info)
4808 rtx insn;
4809 struct replace_info *info;
4811 int reg;
4813 info->replace_reg = NULL_RTX;
4814 info->must_load_z = 1;
4815 info->need_save_z = 1;
4816 info->must_save_reg = 1;
4817 info->must_restore_reg = 1;
4818 info->first = insn;
4819 info->x_used = 0;
4820 info->y_used = 0;
4821 info->can_use_d = TARGET_M6811 ? 1 : 0;
4822 info->found_call = 0;
4823 info->z_died = 0;
4824 info->last = 0;
4825 info->regno = -1;
4826 info->z_set_count = 0;
4827 info->z_value = NULL_RTX;
4828 info->must_push_reg = 0;
4829 info->save_before_last = 0;
4830 info->z_loaded_with_sp = 0;
4832 /* Scan the insn forward to find an address register that is not used.
4833 Stop when:
4834 - the flow of the program changes,
4835 - when we detect that both X and Y are necessary,
4836 - when the Z register dies,
4837 - when the condition codes are set. */
4839 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4841 if (m68hc11_check_z_replacement (insn, info) == 0)
4842 break;
4845 /* May be we can use Y or X if they contain the same value as Z.
4846 This happens very often after the reload. */
4847 if (info->z_set_count == 1)
4849 rtx p = info->first;
4850 rtx v = 0;
4852 if (info->x_used)
4854 v = find_last_value (iy_reg, &p, insn, 1);
4856 else if (info->y_used)
4858 v = find_last_value (ix_reg, &p, insn, 1);
4860 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4862 if (info->x_used)
4863 info->regno = HARD_Y_REGNUM;
4864 else
4865 info->regno = HARD_X_REGNUM;
4866 info->must_load_z = 0;
4867 info->must_save_reg = 0;
4868 info->must_restore_reg = 0;
4869 info->found_call = 1;
4872 if (info->z_set_count == 0)
4873 info->need_save_z = 0;
4875 if (insn == 0)
4876 info->need_save_z = 0;
4878 if (info->last == 0)
4879 info->last = insn;
4881 if (info->regno >= 0)
4883 reg = info->regno;
4884 info->replace_reg = gen_rtx (REG, HImode, reg);
4886 else if (info->can_use_d)
4888 reg = HARD_D_REGNUM;
4889 info->replace_reg = d_reg;
4891 else if (info->x_used)
4893 reg = HARD_Y_REGNUM;
4894 info->replace_reg = iy_reg;
4896 else
4898 reg = HARD_X_REGNUM;
4899 info->replace_reg = ix_reg;
4901 info->regno = reg;
4903 if (info->must_save_reg && info->must_restore_reg)
4905 if (insn && dead_register_here (insn, info->replace_reg))
4907 info->must_save_reg = 0;
4908 info->must_restore_reg = 0;
4913 /* The insn uses the Z register. Find a replacement register for it
4914 (either X or Y) and replace it in the insn and the next ones until
4915 the flow changes or the replacement register is used. Instructions
4916 are emited before and after the Z-block to preserve the value of
4917 Z and of the replacement register. */
4919 static void
4920 m68hc11_z_replacement (insn)
4921 rtx insn;
4923 rtx replace_reg_qi;
4924 rtx replace_reg;
4925 struct replace_info info;
4927 /* Find trivial case where we only need to replace z with the
4928 equivalent soft register. */
4929 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4931 rtx body = PATTERN (insn);
4932 rtx src = XEXP (body, 1);
4933 rtx dst = XEXP (body, 0);
4935 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4937 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4938 return;
4940 else if (Z_REG_P (src)
4941 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4943 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4944 return;
4946 else if (D_REG_P (dst)
4947 && m68hc11_arith_operator (src, GET_MODE (src))
4948 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4950 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4951 return;
4953 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4954 && INTVAL (src) == 0)
4956 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4957 /* Force it to be re-recognized. */
4958 INSN_CODE (insn) = -1;
4959 return;
4963 m68hc11_find_z_replacement (insn, &info);
4965 replace_reg = info.replace_reg;
4966 replace_reg_qi = NULL_RTX;
4968 /* Save the X register in a .page0 location. */
4969 if (info.must_save_reg && !info.must_push_reg)
4971 rtx dst;
4973 if (info.must_push_reg && 0)
4974 dst = gen_rtx (MEM, HImode,
4975 gen_rtx (PRE_DEC, HImode,
4976 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4977 else
4978 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4980 emit_insn_before (gen_movhi (dst,
4981 gen_rtx (REG, HImode, info.regno)), insn);
4983 if (info.must_load_z && !info.must_push_reg)
4985 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4986 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4987 insn);
4991 /* Replace all occurrence of Z by replace_reg.
4992 Stop when the last instruction to replace is reached.
4993 Also stop when we detect a change in the flow (but it's not
4994 necessary; just safeguard). */
4996 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4998 rtx body;
5000 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
5001 break;
5003 if (GET_CODE (insn) != INSN
5004 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
5005 continue;
5007 body = PATTERN (insn);
5008 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5009 || GET_CODE (body) == ASM_OPERANDS
5010 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5012 rtx note;
5014 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
5016 printf ("Reg mentioned here...:\n");
5017 fflush (stdout);
5018 debug_rtx (insn);
5021 /* Stack pointer was decremented by 2 due to the push.
5022 Correct that by adding 2 to the destination. */
5023 if (info.must_push_reg
5024 && info.z_loaded_with_sp && GET_CODE (body) == SET)
5026 rtx src, dst;
5028 src = SET_SRC (body);
5029 dst = SET_DEST (body);
5030 if (SP_REG_P (src) && Z_REG_P (dst))
5031 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
5034 /* Replace any (REG:HI Z) occurrence by either X or Y. */
5035 if (!validate_replace_rtx (z_reg, replace_reg, insn))
5037 INSN_CODE (insn) = -1;
5038 if (!validate_replace_rtx (z_reg, replace_reg, insn))
5039 fatal_insn ("cannot do z-register replacement", insn);
5042 /* Likewise for (REG:QI Z). */
5043 if (reg_mentioned_p (z_reg, insn))
5045 if (replace_reg_qi == NULL_RTX)
5046 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
5047 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
5050 /* If there is a REG_INC note on Z, replace it with a
5051 REG_INC note on the replacement register. This is necessary
5052 to make sure that the flow pass will identify the change
5053 and it will not remove a possible insn that saves Z. */
5054 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
5056 if (REG_NOTE_KIND (note) == REG_INC
5057 && GET_CODE (XEXP (note, 0)) == REG
5058 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
5060 XEXP (note, 0) = replace_reg;
5064 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5065 break;
5068 /* Save Z before restoring the old value. */
5069 if (insn && info.need_save_z && !info.must_push_reg)
5071 rtx save_pos_insn = insn;
5073 /* If Z is clobber by the last insn, we have to save its value
5074 before the last instruction. */
5075 if (info.save_before_last)
5076 save_pos_insn = PREV_INSN (save_pos_insn);
5078 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
5079 gen_rtx (REG, HImode, info.regno)),
5080 save_pos_insn);
5083 if (info.must_push_reg && info.last)
5085 rtx new_body, body;
5087 body = PATTERN (info.last);
5088 new_body = gen_rtx (PARALLEL, VOIDmode,
5089 gen_rtvec (3, body,
5090 gen_rtx (USE, VOIDmode,
5091 replace_reg),
5092 gen_rtx (USE, VOIDmode,
5093 gen_rtx (REG, HImode,
5094 SOFT_Z_REGNUM))));
5095 PATTERN (info.last) = new_body;
5097 /* Force recognition on insn since we changed it. */
5098 INSN_CODE (insn) = -1;
5100 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
5102 fatal_insn ("invalid Z register replacement for insn", insn);
5104 insn = NEXT_INSN (info.last);
5107 /* Restore replacement register unless it was died. */
5108 if (insn && info.must_restore_reg && !info.must_push_reg)
5110 rtx dst;
5112 if (info.must_push_reg && 0)
5113 dst = gen_rtx (MEM, HImode,
5114 gen_rtx (POST_INC, HImode,
5115 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
5116 else
5117 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
5119 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
5120 dst), insn);
5126 /* Scan all the insn and re-affects some registers
5127 - The Z register (if it was used), is affected to X or Y depending
5128 on the instruction. */
5130 static void
5131 m68hc11_reassign_regs (first)
5132 rtx first;
5134 rtx insn;
5136 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
5137 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
5138 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5139 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
5141 /* Scan all insns to replace Z by X or Y preserving the old value
5142 of X/Y and restoring it afterward. */
5144 for (insn = first; insn; insn = NEXT_INSN (insn))
5146 rtx body;
5148 if (GET_CODE (insn) == CODE_LABEL
5149 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
5150 continue;
5152 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
5153 continue;
5155 body = PATTERN (insn);
5156 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5157 continue;
5159 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5160 || GET_CODE (body) == ASM_OPERANDS
5161 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5162 continue;
5164 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5165 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5168 /* If Z appears in this insn, replace it in the current insn
5169 and the next ones until the flow changes or we have to
5170 restore back the replacement register. */
5172 if (reg_mentioned_p (z_reg, body))
5174 m68hc11_z_replacement (insn);
5177 else
5179 printf ("insn not handled by Z replacement:\n");
5180 fflush (stdout);
5181 debug_rtx (insn);
5187 void
5188 m68hc11_reorg (first)
5189 rtx first;
5191 int split_done = 0;
5192 rtx insn;
5194 z_replacement_completed = 0;
5195 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5197 /* Some RTX are shared at this point. This breaks the Z register
5198 replacement, unshare everything. */
5199 unshare_all_rtl_again (first);
5201 /* Force a split of all splitable insn. This is necessary for the
5202 Z register replacement mechanism because we end up with basic insns. */
5203 split_all_insns_noflow ();
5204 split_done = 1;
5206 z_replacement_completed = 1;
5207 m68hc11_reassign_regs (first);
5209 if (optimize)
5210 compute_bb_for_insn ();
5212 /* After some splitting, there are some oportunities for CSE pass.
5213 This happens quite often when 32-bit or above patterns are split. */
5214 if (optimize > 0 && split_done)
5216 reload_cse_regs (first);
5219 /* Re-create the REG_DEAD notes. These notes are used in the machine
5220 description to use the best assembly directives. */
5221 if (optimize)
5223 /* Before recomputing the REG_DEAD notes, remove all of them.
5224 This is necessary because the reload_cse_regs() pass can
5225 have replaced some (MEM) with a register. In that case,
5226 the REG_DEAD that could exist for that register may become
5227 wrong. */
5228 for (insn = first; insn; insn = NEXT_INSN (insn))
5230 if (INSN_P (insn))
5232 rtx *pnote;
5234 pnote = &REG_NOTES (insn);
5235 while (*pnote != 0)
5237 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5238 *pnote = XEXP (*pnote, 1);
5239 else
5240 pnote = &XEXP (*pnote, 1);
5245 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
5248 z_replacement_completed = 2;
5250 /* If optimizing, then go ahead and split insns that must be
5251 split after Z register replacement. This gives more opportunities
5252 for peephole (in particular for consecutives xgdx/xgdy). */
5253 if (optimize > 0)
5254 split_all_insns_noflow ();
5256 /* Once insns are split after the z_replacement_completed == 2,
5257 we must not re-run the life_analysis. The xgdx/xgdy patterns
5258 are not recognized and the life_analysis pass removes some
5259 insns because it thinks some (SETs) are noops or made to dead
5260 stores (which is false due to the swap).
5262 Do a simple pass to eliminate the noop set that the final
5263 split could generate (because it was easier for split definition). */
5265 rtx insn;
5267 for (insn = first; insn; insn = NEXT_INSN (insn))
5269 rtx body;
5271 if (INSN_DELETED_P (insn))
5272 continue;
5273 if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
5274 continue;
5276 /* Remove the (set (R) (R)) insns generated by some splits. */
5277 body = PATTERN (insn);
5278 if (GET_CODE (body) == SET
5279 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5281 PUT_CODE (insn, NOTE);
5282 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5283 NOTE_SOURCE_FILE (insn) = 0;
5284 continue;
5291 /* Cost functions. */
5293 /* Cost of moving memory. */
5295 m68hc11_memory_move_cost (mode, class, in)
5296 enum machine_mode mode;
5297 enum reg_class class;
5298 int in ATTRIBUTE_UNUSED;
5300 if (class <= H_REGS && class > NO_REGS)
5302 if (GET_MODE_SIZE (mode) <= 2)
5303 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5304 else
5305 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5307 else
5309 if (GET_MODE_SIZE (mode) <= 2)
5310 return COSTS_N_INSNS (3);
5311 else
5312 return COSTS_N_INSNS (4);
5317 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5318 Reload does not check the constraint of set insns when the two registers
5319 have a move cost of 2. Setting a higher cost will force reload to check
5320 the constraints. */
5322 m68hc11_register_move_cost (mode, from, to)
5323 enum machine_mode mode;
5324 enum reg_class from;
5325 enum reg_class to;
5327 /* All costs are symmetric, so reduce cases by putting the
5328 lower number class as the destination. */
5329 if (from < to)
5331 enum reg_class tmp = to;
5332 to = from, from = tmp;
5334 if (to >= S_REGS)
5335 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5336 else if (from <= S_REGS)
5337 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5338 else
5339 return COSTS_N_INSNS (2);
5343 /* Provide the costs of an addressing mode that contains ADDR.
5344 If ADDR is not a valid address, its cost is irrelevant. */
5346 static int
5347 m68hc11_address_cost (addr)
5348 rtx addr;
5350 int cost = 4;
5352 switch (GET_CODE (addr))
5354 case REG:
5355 /* Make the cost of hard registers and specially SP, FP small. */
5356 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5357 cost = 0;
5358 else
5359 cost = 1;
5360 break;
5362 case SYMBOL_REF:
5363 cost = 8;
5364 break;
5366 case LABEL_REF:
5367 case CONST:
5368 cost = 0;
5369 break;
5371 case PLUS:
5373 register rtx plus0 = XEXP (addr, 0);
5374 register rtx plus1 = XEXP (addr, 1);
5376 if (GET_CODE (plus0) != REG)
5377 break;
5379 switch (GET_CODE (plus1))
5381 case CONST_INT:
5382 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5383 || INTVAL (plus1) < m68hc11_min_offset)
5384 cost = 3;
5385 else if (INTVAL (plus1) >= m68hc11_max_offset)
5386 cost = 2;
5387 else
5388 cost = 1;
5389 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5390 cost += 0;
5391 else
5392 cost += 1;
5393 break;
5395 case SYMBOL_REF:
5396 cost = 8;
5397 break;
5399 case CONST:
5400 case LABEL_REF:
5401 cost = 0;
5402 break;
5404 default:
5405 break;
5407 break;
5409 case PRE_DEC:
5410 case PRE_INC:
5411 if (SP_REG_P (XEXP (addr, 0)))
5412 cost = 1;
5413 break;
5415 default:
5416 break;
5418 if (debug_m6811)
5420 printf ("Address cost: %d for :", cost);
5421 fflush (stdout);
5422 debug_rtx (addr);
5425 return cost;
5428 static int
5429 m68hc11_shift_cost (mode, x, shift)
5430 enum machine_mode mode;
5431 rtx x;
5432 int shift;
5434 int total;
5436 total = rtx_cost (x, SET);
5437 if (mode == QImode)
5438 total += m68hc11_cost->shiftQI_const[shift % 8];
5439 else if (mode == HImode)
5440 total += m68hc11_cost->shiftHI_const[shift % 16];
5441 else if (shift == 8 || shift == 16 || shift == 32)
5442 total += m68hc11_cost->shiftHI_const[8];
5443 else if (shift != 0 && shift != 16 && shift != 32)
5445 total += m68hc11_cost->shiftHI_const[1] * shift;
5448 /* For SI and others, the cost is higher. */
5449 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5450 total *= GET_MODE_SIZE (mode) / 2;
5452 /* When optimizing for size, make shift more costly so that
5453 multiplications are preferred. */
5454 if (optimize_size && (shift % 8) != 0)
5455 total *= 2;
5457 return total;
5460 static int
5461 m68hc11_rtx_costs_1 (x, code, outer_code)
5462 rtx x;
5463 enum rtx_code code;
5464 enum rtx_code outer_code ATTRIBUTE_UNUSED;
5466 enum machine_mode mode = GET_MODE (x);
5467 int extra_cost = 0;
5468 int total;
5470 switch (code)
5472 case ROTATE:
5473 case ROTATERT:
5474 case ASHIFT:
5475 case LSHIFTRT:
5476 case ASHIFTRT:
5477 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5479 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5482 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5483 total += m68hc11_cost->shift_var;
5484 return total;
5486 case AND:
5487 case XOR:
5488 case IOR:
5489 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5490 total += m68hc11_cost->logical;
5492 /* Logical instructions are byte instructions only. */
5493 total *= GET_MODE_SIZE (mode);
5494 return total;
5496 case MINUS:
5497 case PLUS:
5498 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5499 total += m68hc11_cost->add;
5500 if (GET_MODE_SIZE (mode) > 2)
5502 total *= GET_MODE_SIZE (mode) / 2;
5504 return total;
5506 case UDIV:
5507 case DIV:
5508 case MOD:
5509 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5510 switch (mode)
5512 case QImode:
5513 total += m68hc11_cost->divQI;
5514 break;
5516 case HImode:
5517 total += m68hc11_cost->divHI;
5518 break;
5520 case SImode:
5521 default:
5522 total += m68hc11_cost->divSI;
5523 break;
5525 return total;
5527 case MULT:
5528 /* mul instruction produces 16-bit result. */
5529 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5530 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5531 return m68hc11_cost->multQI
5532 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5533 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5535 /* emul instruction produces 32-bit result for 68HC12. */
5536 if (TARGET_M6812 && mode == SImode
5537 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5538 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5539 return m68hc11_cost->multHI
5540 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5541 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5543 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5544 switch (mode)
5546 case QImode:
5547 total += m68hc11_cost->multQI;
5548 break;
5550 case HImode:
5551 total += m68hc11_cost->multHI;
5552 break;
5554 case SImode:
5555 default:
5556 total += m68hc11_cost->multSI;
5557 break;
5559 return total;
5561 case NEG:
5562 case SIGN_EXTEND:
5563 extra_cost = COSTS_N_INSNS (2);
5565 /* Fall through */
5566 case NOT:
5567 case COMPARE:
5568 case ABS:
5569 case ZERO_EXTEND:
5570 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5571 if (mode == QImode)
5573 return total + COSTS_N_INSNS (1);
5575 if (mode == HImode)
5577 return total + COSTS_N_INSNS (2);
5579 if (mode == SImode)
5581 return total + COSTS_N_INSNS (4);
5583 return total + COSTS_N_INSNS (8);
5585 case IF_THEN_ELSE:
5586 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5587 return COSTS_N_INSNS (1);
5589 return COSTS_N_INSNS (1);
5591 default:
5592 return COSTS_N_INSNS (4);
5596 static bool
5597 m68hc11_rtx_costs (x, code, outer_code, total)
5598 rtx x;
5599 int code, outer_code;
5600 int *total;
5602 switch (code)
5604 /* Constants are cheap. Moving them in registers must be avoided
5605 because most instructions do not handle two register operands. */
5606 case CONST_INT:
5607 case CONST:
5608 case LABEL_REF:
5609 case SYMBOL_REF:
5610 case CONST_DOUBLE:
5611 /* Logical and arithmetic operations with a constant operand are
5612 better because they are not supported with two registers. */
5613 /* 'clr' is slow */
5614 if (outer_code == SET && x == const0_rtx)
5615 /* After reload, the reload_cse pass checks the cost to change
5616 a SET into a PLUS. Make const0 cheap then. */
5617 *total = 1 - reload_completed;
5618 else
5619 *total = 0;
5620 return true;
5622 if (outer_code == SET)
5623 *total = 1 - reload_completed;
5625 case ROTATE:
5626 case ROTATERT:
5627 case ASHIFT:
5628 case LSHIFTRT:
5629 case ASHIFTRT:
5630 case MINUS:
5631 case PLUS:
5632 case AND:
5633 case XOR:
5634 case IOR:
5635 case UDIV:
5636 case DIV:
5637 case MOD:
5638 case MULT:
5639 case NEG:
5640 case SIGN_EXTEND:
5641 case NOT:
5642 case COMPARE:
5643 case ZERO_EXTEND:
5644 case IF_THEN_ELSE:
5645 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5646 return true;
5648 default:
5649 return false;
5654 /* print_options - called at the start of the code generation for a
5655 module. */
5657 extern char *asm_file_name;
5659 #include <time.h>
5660 #include <sys/types.h>
5662 static void
5663 print_options (out)
5664 FILE *out;
5666 const char *a_time;
5667 long c_time;
5668 int i;
5669 extern int save_argc;
5670 extern char **save_argv;
5672 fprintf (out, ";;; Command:\t");
5673 for (i = 0; i < save_argc; i++)
5675 fprintf (out, "%s", save_argv[i]);
5676 if (i + 1 < save_argc)
5677 fprintf (out, " ");
5679 fprintf (out, "\n");
5680 c_time = time (0);
5681 a_time = ctime (&c_time);
5682 fprintf (out, ";;; Compiled:\t%s", a_time);
5683 #ifdef __GNUC__
5684 #ifndef __VERSION__
5685 #define __VERSION__ "[unknown]"
5686 #endif
5687 fprintf (out, ";;; (META)compiled by GNU C version %s.\n", __VERSION__);
5688 #else
5689 fprintf (out, ";;; (META)compiled by CC.\n");
5690 #endif
5693 void
5694 m68hc11_asm_file_start (out, main_file)
5695 FILE *out;
5696 const char *main_file;
5698 fprintf (out, ";;;-----------------------------------------\n");
5699 fprintf (out, ";;; Start %s gcc assembly output\n",
5700 TARGET_M6811
5701 ? "MC68HC11"
5702 : TARGET_M68S12 ? "MC68HCS12" : "MC68HC12");
5703 fprintf (out, ";;; gcc compiler %s\n", version_string);
5704 print_options (out);
5705 fprintf (out, ";;;-----------------------------------------\n");
5706 output_file_directive (out, main_file);
5708 if (TARGET_SHORT)
5709 fprintf (out, "\t.mode mshort\n");
5710 else
5711 fprintf (out, "\t.mode mlong\n");
5715 static void
5716 m68hc11_asm_out_constructor (symbol, priority)
5717 rtx symbol;
5718 int priority;
5720 default_ctor_section_asm_out_constructor (symbol, priority);
5721 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5724 static void
5725 m68hc11_asm_out_destructor (symbol, priority)
5726 rtx symbol;
5727 int priority;
5729 default_dtor_section_asm_out_destructor (symbol, priority);
5730 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5733 #include "gt-m68hc11.h"