This commit was manufactured by cvs2svn to create branch
[official-gcc.git] / gcc / config / m68hc11 / m68hc11.c
blobf24bc78f038bce3140008a9170e5e3fc3e7e2c7b
1 /* Subroutines for code generation on Motorola 68HC11 and 68HC12.
2 Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004
3 Free Software Foundation, Inc.
4 Contributed by Stephane Carrez (stcarrez@nerim.fr)
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
13 GCC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING. If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.
23 Note:
24 A first 68HC11 port was made by Otto Lind (otto@coactive.com)
25 on gcc 2.6.3. I have used it as a starting point for this port.
26 However, this new port is a complete re-write. Its internal
27 design is completely different. The generated code is not
28 compatible with the gcc 2.6.3 port.
30 The gcc 2.6.3 port is available at:
32 ftp.unina.it/pub/electronics/motorola/68hc11/gcc/gcc-6811-fsf.tar.gz
36 #include <stdio.h>
37 #include "config.h"
38 #include "system.h"
39 #include "coretypes.h"
40 #include "tm.h"
41 #include "rtl.h"
42 #include "tree.h"
43 #include "tm_p.h"
44 #include "regs.h"
45 #include "hard-reg-set.h"
46 #include "real.h"
47 #include "insn-config.h"
48 #include "conditions.h"
49 #include "output.h"
50 #include "insn-attr.h"
51 #include "flags.h"
52 #include "recog.h"
53 #include "expr.h"
54 #include "libfuncs.h"
55 #include "toplev.h"
56 #include "basic-block.h"
57 #include "function.h"
58 #include "ggc.h"
59 #include "reload.h"
60 #include "target.h"
61 #include "target-def.h"
63 static void emit_move_after_reload (rtx, rtx, rtx);
64 static rtx simplify_logical (enum machine_mode, int, rtx, rtx *);
65 static void m68hc11_emit_logical (enum machine_mode, int, rtx *);
66 static void m68hc11_reorg (void);
67 static int go_if_legitimate_address_internal (rtx, enum machine_mode, int);
68 static int register_indirect_p (rtx, enum machine_mode, int);
69 static rtx m68hc11_expand_compare (enum rtx_code, rtx, rtx);
70 static int must_parenthesize (rtx);
71 static int m68hc11_address_cost (rtx);
72 static int m68hc11_shift_cost (enum machine_mode, rtx, int);
73 static int m68hc11_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
74 static bool m68hc11_rtx_costs (rtx, int, int, int *);
75 static int m68hc11_auto_inc_p (rtx);
76 static tree m68hc11_handle_fntype_attribute (tree *, tree, tree, int, bool *);
77 const struct attribute_spec m68hc11_attribute_table[];
79 void create_regs_rtx (void);
81 static void asm_print_register (FILE *, int);
82 static void m68hc11_output_function_epilogue (FILE *, HOST_WIDE_INT);
83 static void m68hc11_asm_out_constructor (rtx, int);
84 static void m68hc11_asm_out_destructor (rtx, int);
85 static void m68hc11_file_start (void);
86 static void m68hc11_encode_section_info (tree, rtx, int);
87 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
88 static int autoinc_mode (rtx);
89 static int m68hc11_make_autoinc_notes (rtx *, void *);
90 static void m68hc11_init_libfuncs (void);
92 /* Must be set to 1 to produce debug messages. */
93 int debug_m6811 = 0;
95 extern FILE *asm_out_file;
97 rtx ix_reg;
98 rtx iy_reg;
99 rtx d_reg;
100 rtx m68hc11_soft_tmp_reg;
101 static GTY(()) rtx stack_push_word;
102 static GTY(()) rtx stack_pop_word;
103 static GTY(()) rtx z_reg;
104 static GTY(()) rtx z_reg_qi;
105 static int regs_inited = 0;
107 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
108 int current_function_interrupt;
110 /* Set to 1 by expand_prologue() when the function is a trap handler. */
111 int current_function_trap;
113 /* Set to 1 when the current function is placed in 68HC12 banked
114 memory and must return with rtc. */
115 int current_function_far;
117 /* Min offset that is valid for the indirect addressing mode. */
118 HOST_WIDE_INT m68hc11_min_offset = 0;
120 /* Max offset that is valid for the indirect addressing mode. */
121 HOST_WIDE_INT m68hc11_max_offset = 256;
123 /* The class value for base registers. */
124 enum reg_class m68hc11_base_reg_class = A_REGS;
126 /* The class value for index registers. This is NO_REGS for 68HC11. */
127 enum reg_class m68hc11_index_reg_class = NO_REGS;
129 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
131 /* Tables that tell whether a given hard register is valid for
132 a base or an index register. It is filled at init time depending
133 on the target processor. */
134 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
135 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
137 /* A correction offset which is applied to the stack pointer.
138 This is 1 for 68HC11 and 0 for 68HC12. */
139 int m68hc11_sp_correction;
141 #define ADDR_STRICT 0x01 /* Accept only registers in class A_REGS */
142 #define ADDR_INCDEC 0x02 /* Post/Pre inc/dec */
143 #define ADDR_INDEXED 0x04 /* D-reg index */
144 #define ADDR_OFFSET 0x08
145 #define ADDR_INDIRECT 0x10 /* Accept (mem (mem ...)) for [n,X] */
146 #define ADDR_CONST 0x20 /* Accept const and symbol_ref */
148 int m68hc11_addr_mode;
149 int m68hc11_mov_addr_mode;
151 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
152 rtx m68hc11_compare_op0;
153 rtx m68hc11_compare_op1;
156 const struct processor_costs *m68hc11_cost;
158 /* Costs for a 68HC11. */
159 static const struct processor_costs m6811_cost = {
160 /* add */
161 COSTS_N_INSNS (2),
162 /* logical */
163 COSTS_N_INSNS (2),
164 /* non-constant shift */
165 COSTS_N_INSNS (20),
166 /* shiftQI const */
167 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
168 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
169 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
171 /* shiftHI const */
172 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
173 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
174 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
175 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
176 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
177 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
179 /* mulQI */
180 COSTS_N_INSNS (20),
181 /* mulHI */
182 COSTS_N_INSNS (20 * 4),
183 /* mulSI */
184 COSTS_N_INSNS (20 * 16),
185 /* divQI */
186 COSTS_N_INSNS (20),
187 /* divHI */
188 COSTS_N_INSNS (80),
189 /* divSI */
190 COSTS_N_INSNS (100)
193 /* Costs for a 68HC12. */
194 static const struct processor_costs m6812_cost = {
195 /* add */
196 COSTS_N_INSNS (2),
197 /* logical */
198 COSTS_N_INSNS (2),
199 /* non-constant shift */
200 COSTS_N_INSNS (20),
201 /* shiftQI const */
202 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
203 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
204 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
206 /* shiftHI const */
207 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
208 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
209 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
210 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
211 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
212 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
214 /* mulQI */
215 COSTS_N_INSNS (3),
216 /* mulHI */
217 COSTS_N_INSNS (3),
218 /* mulSI */
219 COSTS_N_INSNS (3 * 4),
220 /* divQI */
221 COSTS_N_INSNS (12),
222 /* divHI */
223 COSTS_N_INSNS (12),
224 /* divSI */
225 COSTS_N_INSNS (100)
228 /* Machine specific options */
230 const char *m68hc11_regparm_string;
231 const char *m68hc11_reg_alloc_order;
232 const char *m68hc11_soft_reg_count;
234 static int nb_soft_regs;
236 /* Initialize the GCC target structure. */
237 #undef TARGET_ATTRIBUTE_TABLE
238 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
240 #undef TARGET_ASM_ALIGNED_HI_OP
241 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
243 #undef TARGET_ASM_FUNCTION_EPILOGUE
244 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
246 #undef TARGET_ASM_FILE_START
247 #define TARGET_ASM_FILE_START m68hc11_file_start
248 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
249 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
251 #undef TARGET_ENCODE_SECTION_INFO
252 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
254 #undef TARGET_SECTION_TYPE_FLAGS
255 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
257 #undef TARGET_RTX_COSTS
258 #define TARGET_RTX_COSTS m68hc11_rtx_costs
259 #undef TARGET_ADDRESS_COST
260 #define TARGET_ADDRESS_COST m68hc11_address_cost
262 #undef TARGET_MACHINE_DEPENDENT_REORG
263 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
265 #undef TARGET_INIT_LIBFUNCS
266 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
268 struct gcc_target targetm = TARGET_INITIALIZER;
271 m68hc11_override_options (void)
273 memset (m68hc11_reg_valid_for_index, 0,
274 sizeof (m68hc11_reg_valid_for_index));
275 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
277 /* Compilation with -fpic generates a wrong code. */
278 if (flag_pic)
280 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
281 (flag_pic > 1) ? "PIC" : "pic");
282 flag_pic = 0;
285 /* Do not enable -fweb because it breaks the 32-bit shift patterns
286 by breaking the match_dup of those patterns. The shift patterns
287 will no longer be recognized after that. */
288 flag_web = 0;
290 /* Configure for a 68hc11 processor. */
291 if (TARGET_M6811)
293 /* If gcc was built for a 68hc12, invalidate that because
294 a -m68hc11 option was specified on the command line. */
295 if (TARGET_DEFAULT != MASK_M6811)
296 target_flags &= ~TARGET_DEFAULT;
298 if (!TARGET_M6812)
299 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
300 m68hc11_cost = &m6811_cost;
301 m68hc11_min_offset = 0;
302 m68hc11_max_offset = 256;
303 m68hc11_index_reg_class = NO_REGS;
304 m68hc11_base_reg_class = A_REGS;
305 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
306 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
307 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
308 m68hc11_sp_correction = 1;
309 m68hc11_tmp_regs_class = D_REGS;
310 m68hc11_addr_mode = ADDR_OFFSET;
311 m68hc11_mov_addr_mode = 0;
312 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
313 m68hc11_soft_reg_count = "4";
316 /* Configure for a 68hc12 processor. */
317 if (TARGET_M6812)
319 m68hc11_cost = &m6812_cost;
320 m68hc11_min_offset = -65536;
321 m68hc11_max_offset = 65536;
322 m68hc11_index_reg_class = D_REGS;
323 m68hc11_base_reg_class = A_OR_SP_REGS;
324 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
325 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
326 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
327 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
328 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
329 m68hc11_sp_correction = 0;
330 m68hc11_tmp_regs_class = TMP_REGS;
331 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
332 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
333 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
334 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
335 target_flags &= ~MASK_M6811;
336 target_flags |= MASK_NO_DIRECT_MODE;
337 if (m68hc11_soft_reg_count == 0)
338 m68hc11_soft_reg_count = "0";
340 if (TARGET_LONG_CALLS)
341 current_function_far = 1;
343 return 0;
347 void
348 m68hc11_conditional_register_usage (void)
350 int i;
351 int cnt = atoi (m68hc11_soft_reg_count);
353 if (cnt < 0)
354 cnt = 0;
355 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
356 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
358 nb_soft_regs = cnt;
359 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
361 fixed_regs[i] = 1;
362 call_used_regs[i] = 1;
365 /* For 68HC12, the Z register emulation is not necessary when the
366 frame pointer is not used. The frame pointer is eliminated and
367 replaced by the stack register (which is a BASE_REG_CLASS). */
368 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
370 fixed_regs[HARD_Z_REGNUM] = 1;
375 /* Reload and register operations. */
377 static const char *const reg_class_names[] = REG_CLASS_NAMES;
380 void
381 create_regs_rtx (void)
383 /* regs_inited = 1; */
384 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
385 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
386 d_reg = gen_rtx (REG, HImode, HARD_D_REGNUM);
387 m68hc11_soft_tmp_reg = gen_rtx (REG, HImode, SOFT_TMP_REGNUM);
389 stack_push_word = gen_rtx (MEM, HImode,
390 gen_rtx (PRE_DEC, HImode,
391 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
392 stack_pop_word = gen_rtx (MEM, HImode,
393 gen_rtx (POST_INC, HImode,
394 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
398 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
399 - 8 bit values are stored anywhere (except the SP register).
400 - 16 bit values can be stored in any register whose mode is 16
401 - 32 bit values can be stored in D, X registers or in a soft register
402 (except the last one because we need 2 soft registers)
403 - Values whose size is > 32 bit are not stored in real hard
404 registers. They may be stored in soft registers if there are
405 enough of them. */
407 hard_regno_mode_ok (int regno, enum machine_mode mode)
409 switch (GET_MODE_SIZE (mode))
411 case 8:
412 return S_REGNO_P (regno) && nb_soft_regs >= 4;
414 case 4:
415 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
417 case 2:
418 return G_REGNO_P (regno);
420 case 1:
421 /* We have to accept a QImode in X or Y registers. Otherwise, the
422 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
423 in the insns. Reload fails if the insn rejects the register class 'a'
424 as well as if it accepts it. Patterns that failed were
425 zero_extend_qihi2 and iorqi3. */
427 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
429 default:
430 return 0;
435 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
437 /* Don't accept renaming to Z register. We will replace it to
438 X,Y or D during machine reorg pass. */
439 if (reg2 == HARD_Z_REGNUM)
440 return 0;
442 /* Don't accept renaming D,X to Y register as the code will be bigger. */
443 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
444 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
445 return 0;
447 return 1;
450 enum reg_class
451 preferred_reload_class (rtx operand, enum reg_class class)
453 enum machine_mode mode;
455 mode = GET_MODE (operand);
457 if (debug_m6811)
459 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
462 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
463 return m68hc11_base_reg_class;
465 if (class >= S_REGS && (GET_CODE (operand) == MEM
466 || GET_CODE (operand) == CONST_INT))
468 /* S_REGS class must not be used. The movhi template does not
469 work to move a memory to a soft register.
470 Restrict to a hard reg. */
471 switch (class)
473 default:
474 case G_REGS:
475 case D_OR_A_OR_S_REGS:
476 class = A_OR_D_REGS;
477 break;
478 case A_OR_S_REGS:
479 class = A_REGS;
480 break;
481 case D_OR_SP_OR_S_REGS:
482 class = D_OR_SP_REGS;
483 break;
484 case D_OR_Y_OR_S_REGS:
485 class = D_OR_Y_REGS;
486 break;
487 case D_OR_X_OR_S_REGS:
488 class = D_OR_X_REGS;
489 break;
490 case SP_OR_S_REGS:
491 class = SP_REGS;
492 break;
493 case Y_OR_S_REGS:
494 class = Y_REGS;
495 break;
496 case X_OR_S_REGS:
497 class = X_REGS;
498 break;
499 case D_OR_S_REGS:
500 class = D_REGS;
503 else if (class == Y_REGS && GET_CODE (operand) == MEM)
505 class = Y_REGS;
507 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
509 class = D_OR_X_REGS;
511 else if (class >= S_REGS && S_REG_P (operand))
513 switch (class)
515 default:
516 case G_REGS:
517 case D_OR_A_OR_S_REGS:
518 class = A_OR_D_REGS;
519 break;
520 case A_OR_S_REGS:
521 class = A_REGS;
522 break;
523 case D_OR_SP_OR_S_REGS:
524 class = D_OR_SP_REGS;
525 break;
526 case D_OR_Y_OR_S_REGS:
527 class = D_OR_Y_REGS;
528 break;
529 case D_OR_X_OR_S_REGS:
530 class = D_OR_X_REGS;
531 break;
532 case SP_OR_S_REGS:
533 class = SP_REGS;
534 break;
535 case Y_OR_S_REGS:
536 class = Y_REGS;
537 break;
538 case X_OR_S_REGS:
539 class = X_REGS;
540 break;
541 case D_OR_S_REGS:
542 class = D_REGS;
545 else if (class >= S_REGS)
547 if (debug_m6811)
549 printf ("Class = %s for: ", reg_class_names[class]);
550 fflush (stdout);
551 debug_rtx (operand);
555 if (debug_m6811)
557 printf (" => class=%s\n", reg_class_names[class]);
558 fflush (stdout);
559 debug_rtx (operand);
562 return class;
565 /* Return 1 if the operand is a valid indexed addressing mode.
566 For 68hc11: n,r with n in [0..255] and r in A_REGS class
567 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
568 static int
569 register_indirect_p (rtx operand, enum machine_mode mode, int addr_mode)
571 rtx base, offset;
573 switch (GET_CODE (operand))
575 case MEM:
576 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
577 return register_indirect_p (XEXP (operand, 0), mode,
578 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
579 return 0;
581 case POST_INC:
582 case PRE_INC:
583 case POST_DEC:
584 case PRE_DEC:
585 if (addr_mode & ADDR_INCDEC)
586 return register_indirect_p (XEXP (operand, 0), mode,
587 addr_mode & ADDR_STRICT);
588 return 0;
590 case PLUS:
591 base = XEXP (operand, 0);
592 if (GET_CODE (base) == MEM)
593 return 0;
595 offset = XEXP (operand, 1);
596 if (GET_CODE (offset) == MEM)
597 return 0;
599 /* Indexed addressing mode with 2 registers. */
600 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
602 if (!(addr_mode & ADDR_INDEXED))
603 return 0;
605 addr_mode &= ADDR_STRICT;
606 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
607 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
608 return 1;
610 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
611 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
612 return 1;
614 return 0;
617 if (!(addr_mode & ADDR_OFFSET))
618 return 0;
620 if (GET_CODE (base) == REG)
622 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
623 return 0;
625 if (!(addr_mode & ADDR_STRICT))
626 return 1;
628 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
631 if (GET_CODE (offset) == REG)
633 if (!VALID_CONSTANT_OFFSET_P (base, mode))
634 return 0;
636 if (!(addr_mode & ADDR_STRICT))
637 return 1;
639 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
641 return 0;
643 case REG:
644 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
646 case CONST_INT:
647 if (addr_mode & ADDR_CONST)
648 return VALID_CONSTANT_OFFSET_P (operand, mode);
649 return 0;
651 default:
652 return 0;
656 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
657 a 68HC12 1-byte index addressing mode. */
659 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
661 rtx base, offset;
662 int addr_mode;
664 if (GET_CODE (operand) == REG && reload_in_progress
665 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
666 && reg_equiv_memory_loc[REGNO (operand)])
668 operand = reg_equiv_memory_loc[REGNO (operand)];
669 operand = eliminate_regs (operand, 0, NULL_RTX);
672 if (GET_CODE (operand) != MEM)
673 return 0;
675 operand = XEXP (operand, 0);
676 if (CONSTANT_ADDRESS_P (operand))
677 return 1;
679 if (PUSH_POP_ADDRESS_P (operand))
680 return 1;
682 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
683 if (!register_indirect_p (operand, mode, addr_mode))
684 return 0;
686 if (TARGET_M6812 && GET_CODE (operand) == PLUS
687 && (reload_completed | reload_in_progress))
689 base = XEXP (operand, 0);
690 offset = XEXP (operand, 1);
692 /* The offset can be a symbol address and this is too big
693 for the operand constraint. */
694 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
695 return 0;
697 if (GET_CODE (base) == CONST_INT)
698 offset = base;
700 switch (GET_MODE_SIZE (mode))
702 case 8:
703 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
704 return 0;
705 break;
707 case 4:
708 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
709 return 0;
710 break;
712 default:
713 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
714 return 0;
715 break;
718 return 1;
722 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
724 int addr_mode;
726 if (GET_CODE (operand) == REG && reload_in_progress
727 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
728 && reg_equiv_memory_loc[REGNO (operand)])
730 operand = reg_equiv_memory_loc[REGNO (operand)];
731 operand = eliminate_regs (operand, 0, NULL_RTX);
733 if (GET_CODE (operand) != MEM)
734 return 0;
736 operand = XEXP (operand, 0);
737 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
738 return register_indirect_p (operand, mode, addr_mode);
741 static int
742 go_if_legitimate_address_internal (rtx operand, enum machine_mode mode,
743 int strict)
745 int addr_mode;
747 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
749 /* Reject the global variables if they are too wide. This forces
750 a load of their address in a register and generates smaller code. */
751 if (GET_MODE_SIZE (mode) == 8)
752 return 0;
754 return 1;
756 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
757 if (register_indirect_p (operand, mode, addr_mode))
759 return 1;
761 if (PUSH_POP_ADDRESS_P (operand))
763 return 1;
765 if (symbolic_memory_operand (operand, mode))
767 return 1;
769 return 0;
773 m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode,
774 int strict)
776 int result;
778 if (debug_m6811)
780 printf ("Checking: ");
781 fflush (stdout);
782 debug_rtx (operand);
785 result = go_if_legitimate_address_internal (operand, mode, strict);
787 if (debug_m6811)
789 printf (" -> %s\n", result == 0 ? "NO" : "YES");
792 if (result == 0)
794 if (debug_m6811)
796 printf ("go_if_legitimate%s, ret 0: %d:",
797 (strict ? "_strict" : ""), mode);
798 fflush (stdout);
799 debug_rtx (operand);
802 return result;
806 m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED,
807 rtx old_operand ATTRIBUTE_UNUSED,
808 enum machine_mode mode ATTRIBUTE_UNUSED)
810 return 0;
815 m68hc11_reload_operands (rtx operands[])
817 enum machine_mode mode;
819 if (regs_inited == 0)
820 create_regs_rtx ();
822 mode = GET_MODE (operands[1]);
824 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
825 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
827 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
828 rtx base = XEXP (XEXP (operands[1], 0), 0);
830 if (GET_CODE (base) != REG)
832 rtx tmp = base;
833 base = big_offset;
834 big_offset = tmp;
837 /* If the offset is out of range, we have to compute the address
838 with a separate add instruction. We try to do with with an 8-bit
839 add on the A register. This is possible only if the lowest part
840 of the offset (ie, big_offset % 256) is a valid constant offset
841 with respect to the mode. If it's not, we have to generate a
842 16-bit add on the D register. From:
844 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
846 we generate:
848 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
849 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
850 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
851 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
853 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
854 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
857 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
859 int vh, vl;
860 rtx reg = operands[0];
861 rtx offset;
862 int val = INTVAL (big_offset);
865 /* We use the 'operands[0]' as a scratch register to compute the
866 address. Make sure 'base' is in that register. */
867 if (!rtx_equal_p (base, operands[0]))
869 emit_move_insn (reg, base);
872 if (val > 0)
874 vh = val >> 8;
875 vl = val & 0x0FF;
877 else
879 vh = (val >> 8) & 0x0FF;
880 vl = val & 0x0FF;
883 /* Create the lowest part offset that still remains to be added.
884 If it's not a valid offset, do a 16-bit add. */
885 offset = GEN_INT (vl);
886 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
888 emit_insn (gen_rtx (SET, VOIDmode, reg,
889 gen_rtx (PLUS, HImode, reg, big_offset)));
890 offset = const0_rtx;
892 else
894 emit_insn (gen_rtx (SET, VOIDmode, reg,
895 gen_rtx (PLUS, HImode, reg,
896 GEN_INT (vh << 8))));
898 emit_move_insn (operands[0],
899 gen_rtx (MEM, GET_MODE (operands[1]),
900 gen_rtx (PLUS, Pmode, reg, offset)));
901 return 1;
905 /* Use the normal gen_movhi pattern. */
906 return 0;
909 void
910 m68hc11_emit_libcall (const char *name, enum rtx_code code,
911 enum machine_mode dmode, enum machine_mode smode,
912 int noperands, rtx *operands)
914 rtx ret;
915 rtx insns;
916 rtx libcall;
917 rtx equiv;
919 start_sequence ();
920 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
921 switch (noperands)
923 case 2:
924 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
925 dmode, 1, operands[1], smode);
926 equiv = gen_rtx (code, dmode, operands[1]);
927 break;
929 case 3:
930 ret = emit_library_call_value (libcall, NULL_RTX,
931 LCT_CONST, dmode, 2,
932 operands[1], smode, operands[2],
933 smode);
934 equiv = gen_rtx (code, dmode, operands[1], operands[2]);
935 break;
937 default:
938 abort ();
941 insns = get_insns ();
942 end_sequence ();
943 emit_libcall_block (insns, operands[0], ret, equiv);
946 /* Returns true if X is a PRE/POST increment decrement
947 (same as auto_inc_p() in rtlanal.c but do not take into
948 account the stack). */
949 static int
950 m68hc11_auto_inc_p (rtx x)
952 return GET_CODE (x) == PRE_DEC
953 || GET_CODE (x) == POST_INC
954 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
958 /* Predicates for machine description. */
961 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
963 return GET_CODE (operand) == MEM
964 && GET_CODE (XEXP (operand, 0)) == PLUS
965 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
966 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
967 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
968 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
972 tst_operand (rtx operand, enum machine_mode mode)
974 if (GET_CODE (operand) == MEM && reload_completed == 0)
976 rtx addr = XEXP (operand, 0);
977 if (m68hc11_auto_inc_p (addr))
978 return 0;
980 return nonimmediate_operand (operand, mode);
984 cmp_operand (rtx operand, enum machine_mode mode)
986 if (GET_CODE (operand) == MEM)
988 rtx addr = XEXP (operand, 0);
989 if (m68hc11_auto_inc_p (addr))
990 return 0;
992 return general_operand (operand, mode);
996 non_push_operand (rtx operand, enum machine_mode mode)
998 if (general_operand (operand, mode) == 0)
999 return 0;
1001 if (push_operand (operand, mode) == 1)
1002 return 0;
1003 return 1;
1007 reg_or_some_mem_operand (rtx operand, enum machine_mode mode)
1009 if (GET_CODE (operand) == MEM)
1011 rtx op = XEXP (operand, 0);
1013 if (symbolic_memory_operand (op, mode))
1014 return 1;
1016 if (IS_STACK_PUSH (operand))
1017 return 1;
1019 if (m68hc11_register_indirect_p (operand, mode))
1020 return 1;
1022 return 0;
1025 return register_operand (operand, mode);
1029 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
1031 if (GET_CODE (operand) == MEM)
1033 rtx op = XEXP (operand, 0);
1035 if (symbolic_memory_operand (op, mode))
1036 return 1;
1038 return 0;
1042 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
1044 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
1046 rtx op = XEXP (operand, 0);
1047 int addr_mode;
1049 if (symbolic_memory_operand (op, mode))
1050 return TARGET_M6812;
1052 if (reload_in_progress)
1053 return 1;
1055 operand = XEXP (operand, 0);
1056 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1057 return register_indirect_p (operand, mode, addr_mode);
1059 return 0;
1063 stack_register_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1065 return SP_REG_P (operand);
1069 d_register_operand (rtx operand, enum machine_mode mode)
1071 if (GET_MODE (operand) != mode && mode != VOIDmode)
1072 return 0;
1074 if (GET_CODE (operand) == SUBREG)
1075 operand = XEXP (operand, 0);
1077 return GET_CODE (operand) == REG
1078 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1079 || REGNO (operand) == HARD_D_REGNUM
1080 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
1084 hard_addr_reg_operand (rtx operand, enum machine_mode mode)
1086 if (GET_MODE (operand) != mode && mode != VOIDmode)
1087 return 0;
1089 if (GET_CODE (operand) == SUBREG)
1090 operand = XEXP (operand, 0);
1092 return GET_CODE (operand) == REG
1093 && (REGNO (operand) == HARD_X_REGNUM
1094 || REGNO (operand) == HARD_Y_REGNUM
1095 || REGNO (operand) == HARD_Z_REGNUM);
1099 hard_reg_operand (rtx operand, enum machine_mode mode)
1101 if (GET_MODE (operand) != mode && mode != VOIDmode)
1102 return 0;
1104 if (GET_CODE (operand) == SUBREG)
1105 operand = XEXP (operand, 0);
1107 return GET_CODE (operand) == REG
1108 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1109 || H_REGNO_P (REGNO (operand)));
1113 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1115 if (GET_CODE (operand) != MEM)
1116 return 0;
1118 operand = XEXP (operand, 0);
1119 if (GET_CODE (operand) == PLUS)
1121 if (GET_CODE (XEXP (operand, 0)) == REG)
1122 operand = XEXP (operand, 0);
1123 else if (GET_CODE (XEXP (operand, 1)) == REG)
1124 operand = XEXP (operand, 1);
1126 return GET_CODE (operand) == REG
1127 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1128 || A_REGNO_P (REGNO (operand)));
1132 push_pop_operand_p (rtx operand)
1134 if (GET_CODE (operand) != MEM)
1136 return 0;
1138 operand = XEXP (operand, 0);
1139 return PUSH_POP_ADDRESS_P (operand);
1142 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1143 reference and a constant. */
1146 symbolic_memory_operand (rtx op, enum machine_mode mode)
1148 switch (GET_CODE (op))
1150 case SYMBOL_REF:
1151 case LABEL_REF:
1152 return 1;
1154 case CONST:
1155 op = XEXP (op, 0);
1156 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1157 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1158 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1160 /* ??? This clause seems to be irrelevant. */
1161 case CONST_DOUBLE:
1162 return GET_MODE (op) == mode;
1164 case PLUS:
1165 return symbolic_memory_operand (XEXP (op, 0), mode)
1166 && symbolic_memory_operand (XEXP (op, 1), mode);
1168 default:
1169 return 0;
1174 m68hc11_eq_compare_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1176 return GET_CODE (op) == EQ || GET_CODE (op) == NE;
1180 m68hc11_logical_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1182 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1186 m68hc11_arith_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1188 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1189 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1190 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1191 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1192 || GET_CODE (op) == ROTATERT;
1196 m68hc11_non_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1198 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1199 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1202 /* Return true if op is a shift operator. */
1204 m68hc11_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1206 return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
1207 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
1208 || GET_CODE (op) == ASHIFTRT;
1212 m68hc11_unary_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1214 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1215 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1218 /* Emit the code to build the trampoline used to call a nested function.
1220 68HC11 68HC12
1222 ldy #&CXT movw #&CXT,*_.d1
1223 sty *_.d1 jmp FNADDR
1224 jmp FNADDR
1227 void
1228 m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1230 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1232 /* Skip the '*'. */
1233 if (*static_chain_reg == '*')
1234 static_chain_reg++;
1235 if (TARGET_M6811)
1237 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1238 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1239 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1240 GEN_INT (0x18df));
1241 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1242 gen_rtx_CONST (QImode,
1243 gen_rtx_SYMBOL_REF (Pmode,
1244 static_chain_reg)));
1245 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1246 GEN_INT (0x7e));
1247 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1249 else
1251 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1252 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1253 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1254 gen_rtx_CONST (HImode,
1255 gen_rtx_SYMBOL_REF (Pmode,
1256 static_chain_reg)));
1257 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1258 GEN_INT (0x06));
1259 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1263 /* Declaration of types. */
1265 const struct attribute_spec m68hc11_attribute_table[] =
1267 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1268 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1269 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1270 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1271 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1272 { NULL, 0, 0, false, false, false, NULL }
1275 /* Keep track of the symbol which has a `trap' attribute and which uses
1276 the `swi' calling convention. Since there is only one trap, we only
1277 record one such symbol. If there are several, a warning is reported. */
1278 static rtx trap_handler_symbol = 0;
1280 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1281 arguments as in struct attribute_spec.handler. */
1282 static tree
1283 m68hc11_handle_fntype_attribute (tree *node, tree name,
1284 tree args ATTRIBUTE_UNUSED,
1285 int flags ATTRIBUTE_UNUSED,
1286 bool *no_add_attrs)
1288 if (TREE_CODE (*node) != FUNCTION_TYPE
1289 && TREE_CODE (*node) != METHOD_TYPE
1290 && TREE_CODE (*node) != FIELD_DECL
1291 && TREE_CODE (*node) != TYPE_DECL)
1293 warning ("`%s' attribute only applies to functions",
1294 IDENTIFIER_POINTER (name));
1295 *no_add_attrs = true;
1298 return NULL_TREE;
1301 /* We want to recognize trap handlers so that we handle calls to traps
1302 in a special manner (by issuing the trap). This information is stored
1303 in SYMBOL_REF_FLAG. */
1305 static void
1306 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1308 tree func_attr;
1309 int trap_handler;
1310 int is_far = 0;
1312 if (TREE_CODE (decl) != FUNCTION_DECL)
1313 return;
1315 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1318 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1319 is_far = 1;
1320 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1321 is_far = TARGET_LONG_CALLS != 0;
1323 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1324 if (trap_handler && is_far)
1326 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1327 trap_handler = 0;
1329 if (trap_handler)
1331 if (trap_handler_symbol != 0)
1332 warning ("`trap' attribute is already used");
1333 else
1334 trap_handler_symbol = XEXP (rtl, 0);
1336 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1339 static unsigned int
1340 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1342 unsigned int flags = default_section_type_flags (decl, name, reloc);
1344 if (strncmp (name, ".eeprom", 7) == 0)
1346 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1349 return flags;
1353 m68hc11_is_far_symbol (rtx sym)
1355 if (GET_CODE (sym) == MEM)
1356 sym = XEXP (sym, 0);
1358 return SYMBOL_REF_FLAG (sym);
1362 m68hc11_is_trap_symbol (rtx sym)
1364 if (GET_CODE (sym) == MEM)
1365 sym = XEXP (sym, 0);
1367 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1371 /* Argument support functions. */
1373 /* Handle the FUNCTION_ARG_PASS_BY_REFERENCE macro.
1374 Arrays are passed by references and other types by value.
1376 SCz: I tried to pass DImode by reference but it seems that this
1377 does not work very well. */
1379 m68hc11_function_arg_pass_by_reference (const CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
1380 enum machine_mode mode ATTRIBUTE_UNUSED,
1381 tree type,
1382 int named ATTRIBUTE_UNUSED)
1384 return ((type && TREE_CODE (type) == ARRAY_TYPE)
1385 /* Consider complex values as aggregates, so care for TCmode. */
1386 /*|| GET_MODE_SIZE (mode) > 4 SCz, temporary */
1387 /*|| (type && AGGREGATE_TYPE_P (type))) */ );
1391 /* Define the offset between two registers, one to be eliminated, and the
1392 other its replacement, at the start of a routine. */
1394 m68hc11_initial_elimination_offset (int from, int to)
1396 int trap_handler;
1397 tree func_attr;
1398 int size;
1399 int regno;
1401 /* For a trap handler, we must take into account the registers which
1402 are pushed on the stack during the trap (except the PC). */
1403 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1404 current_function_interrupt = lookup_attribute ("interrupt",
1405 func_attr) != NULL_TREE;
1406 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1408 if (lookup_attribute ("far", func_attr) != 0)
1409 current_function_far = 1;
1410 else if (lookup_attribute ("near", func_attr) != 0)
1411 current_function_far = 0;
1412 else
1413 current_function_far = (TARGET_LONG_CALLS != 0
1414 && !current_function_interrupt
1415 && !trap_handler);
1417 if (trap_handler && from == ARG_POINTER_REGNUM)
1418 size = 7;
1420 /* For a function using 'call/rtc' we must take into account the
1421 page register which is pushed in the call. */
1422 else if (current_function_far && from == ARG_POINTER_REGNUM)
1423 size = 1;
1424 else
1425 size = 0;
1427 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1429 /* 2 is for the saved frame.
1430 1 is for the 'sts' correction when creating the frame. */
1431 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1434 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1436 return m68hc11_sp_correction;
1439 /* Push any 2 byte pseudo hard registers that we need to save. */
1440 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1442 if (regs_ever_live[regno] && !call_used_regs[regno])
1444 size += 2;
1448 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1450 return get_frame_size () + size;
1453 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1455 return size;
1457 return 0;
1460 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1461 for a call to a function whose data type is FNTYPE.
1462 For a library call, FNTYPE is 0. */
1464 void
1465 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1467 tree ret_type;
1469 z_replacement_completed = 0;
1470 cum->words = 0;
1471 cum->nregs = 0;
1473 /* For a library call, we must find out the type of the return value.
1474 When the return value is bigger than 4 bytes, it is returned in
1475 memory. In that case, the first argument of the library call is a
1476 pointer to the memory location. Because the first argument is passed in
1477 register D, we have to identify this, so that the first function
1478 parameter is not passed in D either. */
1479 if (fntype == 0)
1481 const char *name;
1482 size_t len;
1484 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1485 return;
1487 /* If the library ends in 'di' or in 'df', we assume it's
1488 returning some DImode or some DFmode which are 64-bit wide. */
1489 name = XSTR (libname, 0);
1490 len = strlen (name);
1491 if (len > 3
1492 && ((name[len - 2] == 'd'
1493 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1494 || (name[len - 3] == 'd'
1495 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1497 /* We are in. Mark the first parameter register as already used. */
1498 cum->words = 1;
1499 cum->nregs = 1;
1501 return;
1504 ret_type = TREE_TYPE (fntype);
1506 if (ret_type && aggregate_value_p (ret_type, fntype))
1508 cum->words = 1;
1509 cum->nregs = 1;
1513 /* Update the data in CUM to advance over an argument
1514 of mode MODE and data type TYPE.
1515 (TYPE is null for libcalls where that information may not be available.) */
1517 void
1518 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1519 tree type, int named ATTRIBUTE_UNUSED)
1521 if (mode != BLKmode)
1523 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1525 cum->nregs = 2;
1526 cum->words = GET_MODE_SIZE (mode);
1528 else
1530 cum->words += GET_MODE_SIZE (mode);
1531 if (cum->words <= HARD_REG_SIZE)
1532 cum->nregs = 1;
1535 else
1537 cum->words += int_size_in_bytes (type);
1539 return;
1542 /* Define where to put the arguments to a function.
1543 Value is zero to push the argument on the stack,
1544 or a hard register in which to store the argument.
1546 MODE is the argument's machine mode.
1547 TYPE is the data type of the argument (as a tree).
1548 This is null for libcalls where that information may
1549 not be available.
1550 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1551 the preceding args and about the function being called.
1552 NAMED is nonzero if this argument is a named parameter
1553 (otherwise it is an extra parameter matching an ellipsis). */
1555 struct rtx_def *
1556 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1557 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1559 if (cum->words != 0)
1561 return NULL_RTX;
1564 if (mode != BLKmode)
1566 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1567 return gen_rtx (REG, mode, HARD_X_REGNUM);
1569 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1571 return NULL_RTX;
1573 return gen_rtx (REG, mode, HARD_D_REGNUM);
1575 return NULL_RTX;
1578 /* If defined, a C expression which determines whether, and in which direction,
1579 to pad out an argument with extra space. The value should be of type
1580 `enum direction': either `upward' to pad above the argument,
1581 `downward' to pad below, or `none' to inhibit padding.
1583 Structures are stored left shifted in their argument slot. */
1585 m68hc11_function_arg_padding (enum machine_mode mode, tree type)
1587 if (type != 0 && AGGREGATE_TYPE_P (type))
1588 return upward;
1590 /* Fall back to the default. */
1591 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1595 /* Function prologue and epilogue. */
1597 /* Emit a move after the reload pass has completed. This is used to
1598 emit the prologue and epilogue. */
1599 static void
1600 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1602 rtx insn;
1604 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1606 insn = emit_move_insn (to, from);
1608 else
1610 emit_move_insn (scratch, from);
1611 insn = emit_move_insn (to, scratch);
1614 /* Put a REG_INC note to tell the flow analysis that the instruction
1615 is necessary. */
1616 if (IS_STACK_PUSH (to))
1618 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1619 XEXP (XEXP (to, 0), 0),
1620 REG_NOTES (insn));
1622 else if (IS_STACK_POP (from))
1624 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1625 XEXP (XEXP (from, 0), 0),
1626 REG_NOTES (insn));
1629 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1630 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1631 The problem is that we are lying to gcc and use `txs' for x = sp
1632 (which is not really true because txs is really x = sp + 1). */
1633 else if (TARGET_M6811 && SP_REG_P (from))
1635 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1636 from,
1637 REG_NOTES (insn));
1642 m68hc11_total_frame_size (void)
1644 int size;
1645 int regno;
1647 size = get_frame_size ();
1648 if (current_function_interrupt)
1650 size += 3 * HARD_REG_SIZE;
1652 if (frame_pointer_needed)
1653 size += HARD_REG_SIZE;
1655 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1656 if (regs_ever_live[regno] && !call_used_regs[regno])
1657 size += HARD_REG_SIZE;
1659 return size;
1662 static void
1663 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1664 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1666 /* We catch the function epilogue generation to have a chance
1667 to clear the z_replacement_completed flag. */
1668 z_replacement_completed = 0;
1671 void
1672 expand_prologue (void)
1674 tree func_attr;
1675 int size;
1676 int regno;
1677 rtx scratch;
1679 if (reload_completed != 1)
1680 abort ();
1682 size = get_frame_size ();
1684 create_regs_rtx ();
1686 /* Generate specific prologue for interrupt handlers. */
1687 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1688 current_function_interrupt = lookup_attribute ("interrupt",
1689 func_attr) != NULL_TREE;
1690 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1691 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1692 current_function_far = 1;
1693 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1694 current_function_far = 0;
1695 else
1696 current_function_far = (TARGET_LONG_CALLS != 0
1697 && !current_function_interrupt
1698 && !current_function_trap);
1700 /* Get the scratch register to build the frame and push registers.
1701 If the first argument is a 32-bit quantity, the D+X registers
1702 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1703 For 68HC12, this scratch register is not used. */
1704 if (current_function_args_info.nregs == 2)
1705 scratch = iy_reg;
1706 else
1707 scratch = ix_reg;
1709 /* Save current stack frame. */
1710 if (frame_pointer_needed)
1711 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1713 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1714 Other soft registers in page0 need not to be saved because they
1715 will be restored by C functions. For a trap handler, we don't
1716 need to preserve these registers because this is a synchronous call. */
1717 if (current_function_interrupt)
1719 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1720 emit_move_after_reload (stack_push_word,
1721 gen_rtx (REG, HImode, SOFT_Z_REGNUM), scratch);
1722 emit_move_after_reload (stack_push_word,
1723 gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1724 scratch);
1727 /* Allocate local variables. */
1728 if (TARGET_M6812 && (size > 4 || size == 3))
1730 emit_insn (gen_addhi3 (stack_pointer_rtx,
1731 stack_pointer_rtx, GEN_INT (-size)));
1733 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1735 rtx insn;
1737 insn = gen_rtx_PARALLEL
1738 (VOIDmode,
1739 gen_rtvec (2,
1740 gen_rtx_SET (VOIDmode,
1741 stack_pointer_rtx,
1742 gen_rtx_PLUS (HImode,
1743 stack_pointer_rtx,
1744 GEN_INT (-size))),
1745 gen_rtx_CLOBBER (VOIDmode, scratch)));
1746 emit_insn (insn);
1748 else
1750 int i;
1752 /* Allocate by pushing scratch values. */
1753 for (i = 2; i <= size; i += 2)
1754 emit_move_after_reload (stack_push_word, ix_reg, 0);
1756 if (size & 1)
1757 emit_insn (gen_addhi3 (stack_pointer_rtx,
1758 stack_pointer_rtx, GEN_INT (-1)));
1761 /* Create the frame pointer. */
1762 if (frame_pointer_needed)
1763 emit_move_after_reload (hard_frame_pointer_rtx,
1764 stack_pointer_rtx, scratch);
1766 /* Push any 2 byte pseudo hard registers that we need to save. */
1767 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1769 if (regs_ever_live[regno] && !call_used_regs[regno])
1771 emit_move_after_reload (stack_push_word,
1772 gen_rtx (REG, HImode, regno), scratch);
1777 void
1778 expand_epilogue (void)
1780 int size;
1781 register int regno;
1782 int return_size;
1783 rtx scratch;
1785 if (reload_completed != 1)
1786 abort ();
1788 size = get_frame_size ();
1790 /* If we are returning a value in two registers, we have to preserve the
1791 X register and use the Y register to restore the stack and the saved
1792 registers. Otherwise, use X because it's faster (and smaller). */
1793 if (current_function_return_rtx == 0)
1794 return_size = 0;
1795 else if (GET_CODE (current_function_return_rtx) == MEM)
1796 return_size = HARD_REG_SIZE;
1797 else
1798 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1800 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1801 scratch = iy_reg;
1802 else
1803 scratch = ix_reg;
1805 /* Pop any 2 byte pseudo hard registers that we saved. */
1806 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1808 if (regs_ever_live[regno] && !call_used_regs[regno])
1810 emit_move_after_reload (gen_rtx (REG, HImode, regno),
1811 stack_pop_word, scratch);
1815 /* de-allocate auto variables */
1816 if (TARGET_M6812 && (size > 4 || size == 3))
1818 emit_insn (gen_addhi3 (stack_pointer_rtx,
1819 stack_pointer_rtx, GEN_INT (size)));
1821 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1823 rtx insn;
1825 insn = gen_rtx_PARALLEL
1826 (VOIDmode,
1827 gen_rtvec (2,
1828 gen_rtx_SET (VOIDmode,
1829 stack_pointer_rtx,
1830 gen_rtx_PLUS (HImode,
1831 stack_pointer_rtx,
1832 GEN_INT (size))),
1833 gen_rtx_CLOBBER (VOIDmode, scratch)));
1834 emit_insn (insn);
1836 else
1838 int i;
1840 for (i = 2; i <= size; i += 2)
1841 emit_move_after_reload (scratch, stack_pop_word, scratch);
1842 if (size & 1)
1843 emit_insn (gen_addhi3 (stack_pointer_rtx,
1844 stack_pointer_rtx, GEN_INT (1)));
1847 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1848 if (current_function_interrupt)
1850 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM),
1851 stack_pop_word, scratch);
1852 emit_move_after_reload (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
1853 stack_pop_word, scratch);
1854 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1857 /* Restore previous frame pointer. */
1858 if (frame_pointer_needed)
1859 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1861 /* If the trap handler returns some value, copy the value
1862 in D, X onto the stack so that the rti will pop the return value
1863 correctly. */
1864 else if (current_function_trap && return_size != 0)
1866 rtx addr_reg = stack_pointer_rtx;
1868 if (!TARGET_M6812)
1870 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1871 addr_reg = scratch;
1873 emit_move_after_reload (gen_rtx (MEM, HImode,
1874 gen_rtx (PLUS, HImode, addr_reg,
1875 GEN_INT (1))), d_reg, 0);
1876 if (return_size > HARD_REG_SIZE)
1877 emit_move_after_reload (gen_rtx (MEM, HImode,
1878 gen_rtx (PLUS, HImode, addr_reg,
1879 GEN_INT (3))), ix_reg, 0);
1882 emit_jump_insn (gen_return ());
1886 /* Low and High part extraction for 68HC11. These routines are
1887 similar to gen_lowpart and gen_highpart but they have been
1888 fixed to work for constants and 68HC11 specific registers. */
1891 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1893 /* We assume that the low part of an auto-inc mode is the same with
1894 the mode changed and that the caller split the larger mode in the
1895 correct order. */
1896 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1898 return gen_rtx (MEM, mode, XEXP (x, 0));
1901 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1902 floating-point constant. A CONST_DOUBLE is used whenever the
1903 constant requires more than one word in order to be adequately
1904 represented. */
1905 if (GET_CODE (x) == CONST_DOUBLE)
1907 long l[2];
1909 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1911 REAL_VALUE_TYPE r;
1913 if (GET_MODE (x) == SFmode)
1915 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1916 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
1918 else
1920 rtx first, second;
1922 split_double (x, &first, &second);
1923 return second;
1925 if (mode == SImode)
1926 return GEN_INT (l[0]);
1928 return gen_int_mode (l[0], HImode);
1930 else
1932 l[0] = CONST_DOUBLE_LOW (x);
1934 if (mode == SImode)
1935 return GEN_INT (l[0]);
1936 else if (mode == HImode && GET_MODE (x) == SFmode)
1937 return gen_int_mode (l[0], HImode);
1938 else
1939 abort ();
1942 if (mode == QImode && D_REG_P (x))
1943 return gen_rtx (REG, mode, HARD_B_REGNUM);
1945 /* gen_lowpart crashes when it is called with a SUBREG. */
1946 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
1948 if (mode == SImode)
1949 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
1950 else if (mode == HImode)
1951 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
1952 else
1953 abort ();
1955 x = gen_lowpart (mode, x);
1957 /* Return a different rtx to avoid to share it in several insns
1958 (when used by a split pattern). Sharing addresses within
1959 a MEM breaks the Z register replacement (and reloading). */
1960 if (GET_CODE (x) == MEM)
1961 x = copy_rtx (x);
1962 return x;
1966 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
1968 /* We assume that the high part of an auto-inc mode is the same with
1969 the mode changed and that the caller split the larger mode in the
1970 correct order. */
1971 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1973 return gen_rtx (MEM, mode, XEXP (x, 0));
1976 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1977 floating-point constant. A CONST_DOUBLE is used whenever the
1978 constant requires more than one word in order to be adequately
1979 represented. */
1980 if (GET_CODE (x) == CONST_DOUBLE)
1982 long l[2];
1984 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
1986 REAL_VALUE_TYPE r;
1988 if (GET_MODE (x) == SFmode)
1990 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
1991 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
1993 else
1995 rtx first, second;
1997 split_double (x, &first, &second);
1998 return first;
2000 if (mode == SImode)
2001 return GEN_INT (l[1]);
2003 return gen_int_mode ((l[1] >> 16), HImode);
2005 else
2007 l[1] = CONST_DOUBLE_HIGH (x);
2010 if (mode == SImode)
2011 return GEN_INT (l[1]);
2012 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2013 return gen_int_mode ((l[0] >> 16), HImode);
2014 else
2015 abort ();
2017 if (GET_CODE (x) == CONST_INT)
2019 HOST_WIDE_INT val = INTVAL (x);
2021 if (mode == QImode)
2023 return gen_int_mode (val >> 8, QImode);
2025 else if (mode == HImode)
2027 return gen_int_mode (val >> 16, HImode);
2030 if (mode == QImode && D_REG_P (x))
2031 return gen_rtx (REG, mode, HARD_A_REGNUM);
2033 /* There is no way in GCC to represent the upper part of a word register.
2034 To obtain the 8-bit upper part of a soft register, we change the
2035 reg into a mem rtx. This is possible because they are physically
2036 located in memory. There is no offset because we are big-endian. */
2037 if (mode == QImode && S_REG_P (x))
2039 int pos;
2041 /* Avoid the '*' for direct addressing mode when this
2042 addressing mode is disabled. */
2043 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
2044 return gen_rtx (MEM, QImode,
2045 gen_rtx (SYMBOL_REF, Pmode,
2046 &reg_names[REGNO (x)][pos]));
2049 /* gen_highpart crashes when it is called with a SUBREG. */
2050 if (GET_CODE (x) == SUBREG)
2052 return gen_rtx (SUBREG, mode, XEXP (x, 0), XEXP (x, 1));
2054 if (GET_CODE (x) == REG)
2056 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
2057 return gen_rtx (REG, mode, REGNO (x));
2058 else
2059 return gen_rtx_SUBREG (mode, x, 0);
2062 if (GET_CODE (x) == MEM)
2064 x = change_address (x, mode, 0);
2066 /* Return a different rtx to avoid to share it in several insns
2067 (when used by a split pattern). Sharing addresses within
2068 a MEM breaks the Z register replacement (and reloading). */
2069 if (GET_CODE (x) == MEM)
2070 x = copy_rtx (x);
2071 return x;
2073 abort ();
2077 /* Obscure register manipulation. */
2079 /* Finds backward in the instructions to see if register 'reg' is
2080 dead. This is used when generating code to see if we can use 'reg'
2081 as a scratch register. This allows us to choose a better generation
2082 of code when we know that some register dies or can be clobbered. */
2085 dead_register_here (rtx x, rtx reg)
2087 rtx x_reg;
2088 rtx p;
2090 if (D_REG_P (reg))
2091 x_reg = gen_rtx (REG, SImode, HARD_X_REGNUM);
2092 else
2093 x_reg = 0;
2095 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2096 if (INSN_P (p))
2098 rtx body;
2100 body = PATTERN (p);
2102 if (GET_CODE (body) == CALL_INSN)
2103 break;
2104 if (GET_CODE (body) == JUMP_INSN)
2105 break;
2107 if (GET_CODE (body) == SET)
2109 rtx dst = XEXP (body, 0);
2111 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2112 break;
2113 if (x_reg && rtx_equal_p (dst, x_reg))
2114 break;
2116 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2117 return 1;
2119 else if (reg_mentioned_p (reg, p)
2120 || (x_reg && reg_mentioned_p (x_reg, p)))
2121 break;
2124 /* Scan forward to see if the register is set in some insns and never
2125 used since then. */
2126 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2128 rtx body;
2130 if (GET_CODE (p) == CODE_LABEL
2131 || GET_CODE (p) == JUMP_INSN
2132 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2133 break;
2135 if (GET_CODE (p) != INSN)
2136 continue;
2138 body = PATTERN (p);
2139 if (GET_CODE (body) == SET)
2141 rtx src = XEXP (body, 1);
2142 rtx dst = XEXP (body, 0);
2144 if (GET_CODE (dst) == REG
2145 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2146 return 1;
2149 /* Register is used (may be in source or in dest). */
2150 if (reg_mentioned_p (reg, p)
2151 || (x_reg != 0 && GET_MODE (p) == SImode
2152 && reg_mentioned_p (x_reg, p)))
2153 break;
2155 return p == 0 ? 1 : 0;
2159 /* Code generation operations called from machine description file. */
2161 /* Print the name of register 'regno' in the assembly file. */
2162 static void
2163 asm_print_register (FILE *file, 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 *file, rtx op, int letter)
2208 if (letter == 't')
2210 asm_print_register (file, SOFT_TMP_REGNUM);
2211 return;
2213 else if (letter == 'T')
2215 asm_print_register (file, SOFT_TMP_REGNUM);
2216 fprintf (file, "+1");
2217 return;
2219 else if (letter == '#')
2221 asm_fprintf (file, "%I");
2224 if (GET_CODE (op) == REG)
2226 if (letter == 'b' && S_REG_P (op))
2228 asm_print_register (file, REGNO (op));
2229 fprintf (file, "+1");
2231 else if (letter == 'b' && D_REG_P (op))
2233 asm_print_register (file, HARD_B_REGNUM);
2235 else
2237 asm_print_register (file, REGNO (op));
2239 return;
2242 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2244 if (letter == 'b')
2245 asm_fprintf (file, "%I%%lo(");
2246 else
2247 asm_fprintf (file, "%I%%hi(");
2249 output_addr_const (file, op);
2250 fprintf (file, ")");
2251 return;
2254 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2255 are specified. If we already have a QImode, there is nothing to do. */
2256 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2258 if (letter == 'b')
2260 op = m68hc11_gen_lowpart (QImode, op);
2262 else if (letter == 'h')
2264 op = m68hc11_gen_highpart (QImode, op);
2268 if (GET_CODE (op) == MEM)
2270 rtx base = XEXP (op, 0);
2271 switch (GET_CODE (base))
2273 case PRE_DEC:
2274 if (TARGET_M6812)
2276 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2277 asm_print_register (file, REGNO (XEXP (base, 0)));
2279 else
2280 abort ();
2281 break;
2283 case POST_DEC:
2284 if (TARGET_M6812)
2286 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2287 asm_print_register (file, REGNO (XEXP (base, 0)));
2288 fprintf (file, "-");
2290 else
2291 abort ();
2292 break;
2294 case POST_INC:
2295 if (TARGET_M6812)
2297 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2298 asm_print_register (file, REGNO (XEXP (base, 0)));
2299 fprintf (file, "+");
2301 else
2302 abort ();
2303 break;
2305 case PRE_INC:
2306 if (TARGET_M6812)
2308 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2309 asm_print_register (file, REGNO (XEXP (base, 0)));
2311 else
2312 abort ();
2313 break;
2315 case MEM:
2316 if (TARGET_M6812)
2318 fprintf (file, "[");
2319 print_operand_address (file, XEXP (base, 0));
2320 fprintf (file, "]");
2322 else
2323 abort ();
2324 break;
2326 default:
2327 output_address (base);
2328 break;
2331 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2333 REAL_VALUE_TYPE r;
2334 long l;
2336 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2337 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2338 asm_fprintf (file, "%I0x%lx", l);
2340 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2342 char dstr[30];
2344 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2345 sizeof (dstr), 0, 1);
2346 asm_fprintf (file, "%I0r%s", dstr);
2348 else
2350 int need_parenthesize = 0;
2352 if (letter != 'i')
2353 asm_fprintf (file, "%I");
2354 else
2355 need_parenthesize = must_parenthesize (op);
2357 if (need_parenthesize)
2358 fprintf (file, "(");
2360 output_addr_const (file, op);
2361 if (need_parenthesize)
2362 fprintf (file, ")");
2366 /* Returns true if the operand 'op' must be printed with parenthesis
2367 around it. This must be done only if there is a symbol whose name
2368 is a processor register. */
2369 static int
2370 must_parenthesize (rtx op)
2372 const char *name;
2374 switch (GET_CODE (op))
2376 case SYMBOL_REF:
2377 name = XSTR (op, 0);
2378 /* Avoid a conflict between symbol name and a possible
2379 register. */
2380 return (strcasecmp (name, "a") == 0
2381 || strcasecmp (name, "b") == 0
2382 || strcasecmp (name, "d") == 0
2383 || strcasecmp (name, "x") == 0
2384 || strcasecmp (name, "y") == 0
2385 || strcasecmp (name, "ix") == 0
2386 || strcasecmp (name, "iy") == 0
2387 || strcasecmp (name, "pc") == 0
2388 || strcasecmp (name, "sp") == 0
2389 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2391 case PLUS:
2392 case MINUS:
2393 return must_parenthesize (XEXP (op, 0))
2394 || must_parenthesize (XEXP (op, 1));
2396 case MEM:
2397 case CONST:
2398 case ZERO_EXTEND:
2399 case SIGN_EXTEND:
2400 return must_parenthesize (XEXP (op, 0));
2402 case CONST_DOUBLE:
2403 case CONST_INT:
2404 case LABEL_REF:
2405 case CODE_LABEL:
2406 default:
2407 return 0;
2411 /* A C compound statement to output to stdio stream STREAM the
2412 assembler syntax for an instruction operand that is a memory
2413 reference whose address is ADDR. ADDR is an RTL expression. */
2415 void
2416 print_operand_address (FILE *file, rtx addr)
2418 rtx base;
2419 rtx offset;
2420 int need_parenthesis = 0;
2422 switch (GET_CODE (addr))
2424 case REG:
2425 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2426 abort ();
2428 fprintf (file, "0,");
2429 asm_print_register (file, REGNO (addr));
2430 break;
2432 case MEM:
2433 base = XEXP (addr, 0);
2434 switch (GET_CODE (base))
2436 case PRE_DEC:
2437 if (TARGET_M6812)
2439 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2440 asm_print_register (file, REGNO (XEXP (base, 0)));
2442 else
2443 abort ();
2444 break;
2446 case POST_DEC:
2447 if (TARGET_M6812)
2449 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2450 asm_print_register (file, REGNO (XEXP (base, 0)));
2451 fprintf (file, "-");
2453 else
2454 abort ();
2455 break;
2457 case POST_INC:
2458 if (TARGET_M6812)
2460 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2461 asm_print_register (file, REGNO (XEXP (base, 0)));
2462 fprintf (file, "+");
2464 else
2465 abort ();
2466 break;
2468 case PRE_INC:
2469 if (TARGET_M6812)
2471 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2472 asm_print_register (file, REGNO (XEXP (base, 0)));
2474 else
2475 abort ();
2476 break;
2478 default:
2479 need_parenthesis = must_parenthesize (base);
2480 if (need_parenthesis)
2481 fprintf (file, "(");
2483 output_addr_const (file, base);
2484 if (need_parenthesis)
2485 fprintf (file, ")");
2486 break;
2488 break;
2490 case PLUS:
2491 base = XEXP (addr, 0);
2492 offset = XEXP (addr, 1);
2493 if (!G_REG_P (base) && G_REG_P (offset))
2495 base = XEXP (addr, 1);
2496 offset = XEXP (addr, 0);
2498 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2500 need_parenthesis = must_parenthesize (addr);
2502 if (need_parenthesis)
2503 fprintf (file, "(");
2505 output_addr_const (file, base);
2506 fprintf (file, "+");
2507 output_addr_const (file, offset);
2508 if (need_parenthesis)
2509 fprintf (file, ")");
2511 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2513 if (REG_P (offset))
2515 if (TARGET_M6812)
2517 asm_print_register (file, REGNO (offset));
2518 fprintf (file, ",");
2519 asm_print_register (file, REGNO (base));
2521 else
2522 abort ();
2524 else
2526 need_parenthesis = must_parenthesize (offset);
2527 if (need_parenthesis)
2528 fprintf (file, "(");
2530 output_addr_const (file, offset);
2531 if (need_parenthesis)
2532 fprintf (file, ")");
2533 fprintf (file, ",");
2534 asm_print_register (file, REGNO (base));
2537 else
2539 abort ();
2541 break;
2543 default:
2544 if (GET_CODE (addr) == CONST_INT
2545 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2547 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2549 else
2551 need_parenthesis = must_parenthesize (addr);
2552 if (need_parenthesis)
2553 fprintf (file, "(");
2555 output_addr_const (file, addr);
2556 if (need_parenthesis)
2557 fprintf (file, ")");
2559 break;
2564 /* Splitting of some instructions. */
2566 static rtx
2567 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2569 rtx ret = 0;
2571 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2572 abort ();
2573 else
2575 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2576 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2577 ret = gen_rtx (code, VOIDmode, cc0_rtx, const0_rtx);
2580 return ret;
2584 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2585 rtx label)
2587 rtx tmp;
2589 switch (GET_MODE (op0))
2591 case QImode:
2592 case HImode:
2593 tmp = m68hc11_expand_compare (code, op0, op1);
2594 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2595 gen_rtx_LABEL_REF (VOIDmode, label),
2596 pc_rtx);
2597 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2598 return 0;
2599 #if 0
2601 /* SCz: from i386.c */
2602 case SFmode:
2603 case DFmode:
2604 /* Don't expand the comparison early, so that we get better code
2605 when jump or whoever decides to reverse the comparison. */
2607 rtvec vec;
2608 int use_fcomi;
2610 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2611 &m68hc11_compare_op1);
2613 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2614 m68hc11_compare_op0, m68hc11_compare_op1);
2615 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2616 gen_rtx_LABEL_REF (VOIDmode, label),
2617 pc_rtx);
2618 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2620 use_fcomi = ix86_use_fcomi_compare (code);
2621 vec = rtvec_alloc (3 + !use_fcomi);
2622 RTVEC_ELT (vec, 0) = tmp;
2623 RTVEC_ELT (vec, 1)
2624 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2625 RTVEC_ELT (vec, 2)
2626 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2627 if (!use_fcomi)
2628 RTVEC_ELT (vec, 3)
2629 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2631 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2632 return;
2634 #endif
2636 case SImode:
2637 /* Expand SImode branch into multiple compare+branch. */
2639 rtx lo[2], hi[2], label2;
2640 enum rtx_code code1, code2, code3;
2642 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2644 tmp = op0;
2645 op0 = op1;
2646 op1 = tmp;
2647 code = swap_condition (code);
2649 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2650 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2651 hi[0] = m68hc11_gen_highpart (HImode, op0);
2652 hi[1] = m68hc11_gen_highpart (HImode, op1);
2654 /* Otherwise, if we are doing less-than, op1 is a constant and the
2655 low word is zero, then we can just examine the high word. */
2657 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2658 && (code == LT || code == LTU))
2660 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2661 label);
2664 /* Otherwise, we need two or three jumps. */
2666 label2 = gen_label_rtx ();
2668 code1 = code;
2669 code2 = swap_condition (code);
2670 code3 = unsigned_condition (code);
2672 switch (code)
2674 case LT:
2675 case GT:
2676 case LTU:
2677 case GTU:
2678 break;
2680 case LE:
2681 code1 = LT;
2682 code2 = GT;
2683 break;
2684 case GE:
2685 code1 = GT;
2686 code2 = LT;
2687 break;
2688 case LEU:
2689 code1 = LTU;
2690 code2 = GTU;
2691 break;
2692 case GEU:
2693 code1 = GTU;
2694 code2 = LTU;
2695 break;
2697 case EQ:
2698 code1 = NIL;
2699 code2 = NE;
2700 break;
2701 case NE:
2702 code2 = NIL;
2703 break;
2705 default:
2706 abort ();
2710 * a < b =>
2711 * if (hi(a) < hi(b)) goto true;
2712 * if (hi(a) > hi(b)) goto false;
2713 * if (lo(a) < lo(b)) goto true;
2714 * false:
2716 if (code1 != NIL)
2717 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2718 if (code2 != NIL)
2719 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2721 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2723 if (code2 != NIL)
2724 emit_label (label2);
2725 return 0;
2728 default:
2729 abort ();
2731 return 0;
2734 /* Return the increment/decrement mode of a MEM if it is such.
2735 Return CONST if it is anything else. */
2736 static int
2737 autoinc_mode (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 (rtx *x, void *data)
2755 rtx insn;
2757 switch (GET_CODE (*x))
2759 case PRE_DEC:
2760 case PRE_INC:
2761 case POST_DEC:
2762 case POST_INC:
2763 insn = (rtx) data;
2764 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2765 REG_NOTES (insn));
2766 return -1;
2768 default:
2769 return 0;
2773 /* Split a DI, SI or HI move into several smaller move operations.
2774 The scratch register 'scratch' is used as a temporary to load
2775 store intermediate values. It must be a hard register. */
2776 void
2777 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2779 rtx low_to, low_from;
2780 rtx high_to, high_from;
2781 rtx insn;
2782 enum machine_mode mode;
2783 int offset = 0;
2784 int autoinc_from = autoinc_mode (from);
2785 int autoinc_to = autoinc_mode (to);
2787 mode = GET_MODE (to);
2789 /* If the TO and FROM contain autoinc modes that are not compatible
2790 together (one pop and the other a push), we must change one to
2791 an offsetable operand and generate an appropriate add at the end. */
2792 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2794 rtx reg;
2795 int code;
2797 /* The source uses an autoinc mode which is not compatible with
2798 a split (this would result in a word swap). */
2799 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2801 code = GET_CODE (XEXP (from, 0));
2802 reg = XEXP (XEXP (from, 0), 0);
2803 offset = GET_MODE_SIZE (GET_MODE (from));
2804 if (code == POST_DEC)
2805 offset = -offset;
2807 if (code == PRE_INC)
2808 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2810 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2811 if (code == POST_DEC)
2812 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2813 return;
2816 /* Likewise for destination. */
2817 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2819 code = GET_CODE (XEXP (to, 0));
2820 reg = XEXP (XEXP (to, 0), 0);
2821 offset = GET_MODE_SIZE (GET_MODE (to));
2822 if (code == POST_DEC)
2823 offset = -offset;
2825 if (code == PRE_INC)
2826 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2828 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2829 if (code == POST_DEC)
2830 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2831 return;
2834 /* The source and destination auto increment modes must be compatible
2835 with each other: same direction. */
2836 if ((autoinc_to != autoinc_from
2837 && autoinc_to != CONST && autoinc_from != CONST)
2838 /* The destination address register must not be used within
2839 the source operand because the source address would change
2840 while doing the copy. */
2841 || (autoinc_to != CONST
2842 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2843 && !IS_STACK_PUSH (to)))
2845 /* Must change the destination. */
2846 code = GET_CODE (XEXP (to, 0));
2847 reg = XEXP (XEXP (to, 0), 0);
2848 offset = GET_MODE_SIZE (GET_MODE (to));
2849 if (code == PRE_DEC || code == POST_DEC)
2850 offset = -offset;
2852 if (code == PRE_DEC || code == PRE_INC)
2853 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2854 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2855 if (code == POST_DEC || code == POST_INC)
2856 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2858 return;
2861 /* Likewise, the source address register must not be used within
2862 the destination operand. */
2863 if (autoinc_from != CONST
2864 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2865 && !IS_STACK_PUSH (to))
2867 /* Must change the source. */
2868 code = GET_CODE (XEXP (from, 0));
2869 reg = XEXP (XEXP (from, 0), 0);
2870 offset = GET_MODE_SIZE (GET_MODE (from));
2871 if (code == PRE_DEC || code == POST_DEC)
2872 offset = -offset;
2874 if (code == PRE_DEC || code == PRE_INC)
2875 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2876 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2877 if (code == POST_DEC || code == POST_INC)
2878 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2880 return;
2884 if (GET_MODE_SIZE (mode) == 8)
2885 mode = SImode;
2886 else if (GET_MODE_SIZE (mode) == 4)
2887 mode = HImode;
2888 else
2889 mode = QImode;
2891 if (TARGET_M6812
2892 && IS_STACK_PUSH (to)
2893 && reg_mentioned_p (gen_rtx (REG, HImode, HARD_SP_REGNUM), from))
2895 if (mode == SImode)
2897 offset = 4;
2899 else if (mode == HImode)
2901 offset = 2;
2903 else
2904 offset = 0;
2907 low_to = m68hc11_gen_lowpart (mode, to);
2908 high_to = m68hc11_gen_highpart (mode, to);
2910 low_from = m68hc11_gen_lowpart (mode, from);
2911 if (mode == SImode && GET_CODE (from) == CONST_INT)
2913 if (INTVAL (from) >= 0)
2914 high_from = const0_rtx;
2915 else
2916 high_from = constm1_rtx;
2918 else
2919 high_from = m68hc11_gen_highpart (mode, from);
2921 if (offset)
2923 high_from = adjust_address (high_from, mode, offset);
2924 low_from = high_from;
2927 /* When copying with a POST_INC mode, we must copy the
2928 high part and then the low part to guarantee a correct
2929 32/64-bit copy. */
2930 if (TARGET_M6812
2931 && GET_MODE_SIZE (mode) >= 2
2932 && autoinc_from != autoinc_to
2933 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2935 rtx swap;
2937 swap = low_to;
2938 low_to = high_to;
2939 high_to = swap;
2941 swap = low_from;
2942 low_from = high_from;
2943 high_from = swap;
2945 if (mode == SImode)
2947 m68hc11_split_move (low_to, low_from, scratch);
2948 m68hc11_split_move (high_to, high_from, scratch);
2950 else if (H_REG_P (to) || H_REG_P (from)
2951 || (low_from == const0_rtx
2952 && high_from == const0_rtx
2953 && ! push_operand (to, GET_MODE (to))
2954 && ! H_REG_P (scratch))
2955 || (TARGET_M6812
2956 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2957 || m68hc11_small_indexed_indirect_p (from,
2958 GET_MODE (from)))
2959 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2960 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2962 insn = emit_move_insn (low_to, low_from);
2963 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2965 insn = emit_move_insn (high_to, high_from);
2966 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2968 else
2970 insn = emit_move_insn (scratch, low_from);
2971 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2972 insn = emit_move_insn (low_to, scratch);
2973 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2975 insn = emit_move_insn (scratch, high_from);
2976 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2977 insn = emit_move_insn (high_to, scratch);
2978 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2982 static rtx
2983 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2985 int val;
2986 int mask;
2988 *result = 0;
2989 if (GET_CODE (operand) != CONST_INT)
2990 return operand;
2992 if (mode == HImode)
2993 mask = 0x0ffff;
2994 else
2995 mask = 0x0ff;
2997 val = INTVAL (operand);
2998 switch (code)
3000 case IOR:
3001 if ((val & mask) == 0)
3002 return 0;
3003 if ((val & mask) == mask)
3004 *result = constm1_rtx;
3005 break;
3007 case AND:
3008 if ((val & mask) == 0)
3009 *result = const0_rtx;
3010 if ((val & mask) == mask)
3011 return 0;
3012 break;
3014 case XOR:
3015 if ((val & mask) == 0)
3016 return 0;
3017 break;
3019 return operand;
3022 static void
3023 m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
3025 rtx result;
3026 int need_copy;
3028 need_copy = (rtx_equal_p (operands[0], operands[1])
3029 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
3031 operands[1] = simplify_logical (mode, code, operands[1], &result);
3032 operands[2] = simplify_logical (mode, code, operands[2], &result);
3034 if (result && GET_CODE (result) == CONST_INT)
3036 if (!H_REG_P (operands[0]) && operands[3]
3037 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
3039 emit_move_insn (operands[3], result);
3040 emit_move_insn (operands[0], operands[3]);
3042 else
3044 emit_move_insn (operands[0], result);
3047 else if (operands[1] != 0 && operands[2] != 0)
3049 rtx insn;
3051 if (!H_REG_P (operands[0]) && operands[3])
3053 emit_move_insn (operands[3], operands[1]);
3054 emit_insn (gen_rtx (SET, mode,
3055 operands[3],
3056 gen_rtx (code, mode,
3057 operands[3], operands[2])));
3058 insn = emit_move_insn (operands[0], operands[3]);
3060 else
3062 insn = emit_insn (gen_rtx (SET, mode,
3063 operands[0],
3064 gen_rtx (code, mode,
3065 operands[0], operands[2])));
3069 /* The logical operation is similar to a copy. */
3070 else if (need_copy)
3072 rtx src;
3074 if (GET_CODE (operands[1]) == CONST_INT)
3075 src = operands[2];
3076 else
3077 src = operands[1];
3079 if (!H_REG_P (operands[0]) && !H_REG_P (src))
3081 emit_move_insn (operands[3], src);
3082 emit_move_insn (operands[0], operands[3]);
3084 else
3086 emit_move_insn (operands[0], src);
3091 void
3092 m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
3094 rtx low[4];
3095 rtx high[4];
3097 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3098 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3099 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3101 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3103 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3105 if (INTVAL (operands[1]) >= 0)
3106 high[1] = const0_rtx;
3107 else
3108 high[1] = constm1_rtx;
3110 else
3111 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3113 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3115 if (INTVAL (operands[2]) >= 0)
3116 high[2] = const0_rtx;
3117 else
3118 high[2] = constm1_rtx;
3120 else
3121 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3123 low[3] = operands[3];
3124 high[3] = operands[3];
3125 if (mode == SImode)
3127 m68hc11_split_logical (HImode, code, low);
3128 m68hc11_split_logical (HImode, code, high);
3129 return;
3132 m68hc11_emit_logical (mode, code, low);
3133 m68hc11_emit_logical (mode, code, high);
3137 /* Code generation. */
3139 void
3140 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3142 /* We have to be careful with the cc_status. An address register swap
3143 is generated for some comparison. The comparison is made with D
3144 but the branch really uses the address register. See the split
3145 pattern for compare. The xgdx/xgdy preserve the flags but after
3146 the exchange, the flags will reflect to the value of X and not D.
3147 Tell this by setting the cc_status according to the cc_prev_status. */
3148 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3150 if (cc_prev_status.value1 != 0
3151 && (D_REG_P (cc_prev_status.value1)
3152 || X_REG_P (cc_prev_status.value1)))
3154 cc_status = cc_prev_status;
3155 if (D_REG_P (cc_status.value1))
3156 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3157 HARD_X_REGNUM);
3158 else
3159 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3160 HARD_D_REGNUM);
3162 else
3163 CC_STATUS_INIT;
3165 output_asm_insn ("xgdx", operands);
3167 else
3169 if (cc_prev_status.value1 != 0
3170 && (D_REG_P (cc_prev_status.value1)
3171 || Y_REG_P (cc_prev_status.value1)))
3173 cc_status = cc_prev_status;
3174 if (D_REG_P (cc_status.value1))
3175 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3176 HARD_Y_REGNUM);
3177 else
3178 cc_status.value1 = gen_rtx (REG, GET_MODE (cc_status.value1),
3179 HARD_D_REGNUM);
3181 else
3182 CC_STATUS_INIT;
3184 output_asm_insn ("xgdy", operands);
3188 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3189 This is used to decide whether a move that set flags should be used
3190 instead. */
3192 next_insn_test_reg (rtx insn, rtx reg)
3194 rtx body;
3196 insn = next_nonnote_insn (insn);
3197 if (GET_CODE (insn) != INSN)
3198 return 0;
3200 body = PATTERN (insn);
3201 if (sets_cc0_p (body) != 1)
3202 return 0;
3204 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3205 return 0;
3207 return 1;
3210 /* Generate the code to move a 16-bit operand into another one. */
3212 void
3213 m68hc11_gen_movhi (rtx insn, rtx *operands)
3215 int reg;
3217 /* Move a register or memory to the same location.
3218 This is possible because such insn can appear
3219 in a non-optimizing mode. */
3220 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3222 cc_status = cc_prev_status;
3223 return;
3226 if (TARGET_M6812)
3228 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3230 cc_status = cc_prev_status;
3231 switch (REGNO (operands[1]))
3233 case HARD_X_REGNUM:
3234 case HARD_Y_REGNUM:
3235 case HARD_D_REGNUM:
3236 output_asm_insn ("psh%1", operands);
3237 break;
3238 case HARD_SP_REGNUM:
3239 output_asm_insn ("sts\t2,-sp", operands);
3240 break;
3241 default:
3242 abort ();
3244 return;
3246 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3248 cc_status = cc_prev_status;
3249 switch (REGNO (operands[0]))
3251 case HARD_X_REGNUM:
3252 case HARD_Y_REGNUM:
3253 case HARD_D_REGNUM:
3254 output_asm_insn ("pul%0", operands);
3255 break;
3256 default:
3257 abort ();
3259 return;
3261 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3263 m68hc11_notice_keep_cc (operands[0]);
3264 output_asm_insn ("tfr\t%1,%0", operands);
3266 else if (H_REG_P (operands[0]))
3268 if (SP_REG_P (operands[0]))
3269 output_asm_insn ("lds\t%1", operands);
3270 else
3271 output_asm_insn ("ld%0\t%1", operands);
3273 else if (H_REG_P (operands[1]))
3275 if (SP_REG_P (operands[1]))
3276 output_asm_insn ("sts\t%0", operands);
3277 else
3278 output_asm_insn ("st%1\t%0", operands);
3280 else
3282 rtx from = operands[1];
3283 rtx to = operands[0];
3285 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3286 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3287 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3288 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3290 rtx ops[3];
3292 if (operands[2])
3294 ops[0] = operands[2];
3295 ops[1] = from;
3296 ops[2] = 0;
3297 m68hc11_gen_movhi (insn, ops);
3298 ops[0] = to;
3299 ops[1] = operands[2];
3300 m68hc11_gen_movhi (insn, ops);
3302 else
3304 /* !!!! SCz wrong here. */
3305 fatal_insn ("move insn not handled", insn);
3308 else
3310 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3312 output_asm_insn ("clr\t%h0", operands);
3313 output_asm_insn ("clr\t%b0", operands);
3315 else
3317 m68hc11_notice_keep_cc (operands[0]);
3318 output_asm_insn ("movw\t%1,%0", operands);
3322 return;
3325 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3327 cc_status = cc_prev_status;
3328 switch (REGNO (operands[0]))
3330 case HARD_X_REGNUM:
3331 case HARD_Y_REGNUM:
3332 output_asm_insn ("pul%0", operands);
3333 break;
3334 case HARD_D_REGNUM:
3335 output_asm_insn ("pula", operands);
3336 output_asm_insn ("pulb", operands);
3337 break;
3338 default:
3339 abort ();
3341 return;
3343 /* Some moves to a hard register are special. Not all of them
3344 are really supported and we have to use a temporary
3345 location to provide them (either the stack of a temp var). */
3346 if (H_REG_P (operands[0]))
3348 switch (REGNO (operands[0]))
3350 case HARD_D_REGNUM:
3351 if (X_REG_P (operands[1]))
3353 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3355 m68hc11_output_swap (insn, operands);
3357 else if (next_insn_test_reg (insn, operands[0]))
3359 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3361 else
3363 m68hc11_notice_keep_cc (operands[0]);
3364 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3367 else if (Y_REG_P (operands[1]))
3369 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3371 m68hc11_output_swap (insn, operands);
3373 else
3375 /* %t means *ZTMP scratch register. */
3376 output_asm_insn ("sty\t%t1", operands);
3377 output_asm_insn ("ldd\t%t1", operands);
3380 else if (SP_REG_P (operands[1]))
3382 CC_STATUS_INIT;
3383 if (ix_reg == 0)
3384 create_regs_rtx ();
3385 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3386 output_asm_insn ("xgdx", operands);
3387 output_asm_insn ("tsx", operands);
3388 output_asm_insn ("xgdx", operands);
3390 else if (IS_STACK_POP (operands[1]))
3392 output_asm_insn ("pula\n\tpulb", operands);
3394 else if (GET_CODE (operands[1]) == CONST_INT
3395 && INTVAL (operands[1]) == 0)
3397 output_asm_insn ("clra\n\tclrb", operands);
3399 else
3401 output_asm_insn ("ldd\t%1", operands);
3403 break;
3405 case HARD_X_REGNUM:
3406 if (D_REG_P (operands[1]))
3408 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3410 m68hc11_output_swap (insn, operands);
3412 else if (next_insn_test_reg (insn, operands[0]))
3414 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3416 else
3418 m68hc11_notice_keep_cc (operands[0]);
3419 output_asm_insn ("pshb", operands);
3420 output_asm_insn ("psha", operands);
3421 output_asm_insn ("pulx", operands);
3424 else if (Y_REG_P (operands[1]))
3426 /* When both D and Y are dead, use the sequence xgdy, xgdx
3427 to move Y into X. The D and Y registers are modified. */
3428 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3429 && dead_register_here (insn, d_reg))
3431 output_asm_insn ("xgdy", operands);
3432 output_asm_insn ("xgdx", operands);
3433 CC_STATUS_INIT;
3435 else if (!optimize_size)
3437 output_asm_insn ("sty\t%t1", operands);
3438 output_asm_insn ("ldx\t%t1", operands);
3440 else
3442 CC_STATUS_INIT;
3443 output_asm_insn ("pshy", operands);
3444 output_asm_insn ("pulx", operands);
3447 else if (SP_REG_P (operands[1]))
3449 /* tsx, tsy preserve the flags */
3450 cc_status = cc_prev_status;
3451 output_asm_insn ("tsx", operands);
3453 else
3455 output_asm_insn ("ldx\t%1", operands);
3457 break;
3459 case HARD_Y_REGNUM:
3460 if (D_REG_P (operands[1]))
3462 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3464 m68hc11_output_swap (insn, operands);
3466 else
3468 output_asm_insn ("std\t%t1", operands);
3469 output_asm_insn ("ldy\t%t1", operands);
3472 else if (X_REG_P (operands[1]))
3474 /* When both D and X are dead, use the sequence xgdx, xgdy
3475 to move X into Y. The D and X registers are modified. */
3476 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3477 && dead_register_here (insn, d_reg))
3479 output_asm_insn ("xgdx", operands);
3480 output_asm_insn ("xgdy", operands);
3481 CC_STATUS_INIT;
3483 else if (!optimize_size)
3485 output_asm_insn ("stx\t%t1", operands);
3486 output_asm_insn ("ldy\t%t1", operands);
3488 else
3490 CC_STATUS_INIT;
3491 output_asm_insn ("pshx", operands);
3492 output_asm_insn ("puly", operands);
3495 else if (SP_REG_P (operands[1]))
3497 /* tsx, tsy preserve the flags */
3498 cc_status = cc_prev_status;
3499 output_asm_insn ("tsy", operands);
3501 else
3503 output_asm_insn ("ldy\t%1", operands);
3505 break;
3507 case HARD_SP_REGNUM:
3508 if (D_REG_P (operands[1]))
3510 m68hc11_notice_keep_cc (operands[0]);
3511 output_asm_insn ("xgdx", operands);
3512 output_asm_insn ("txs", operands);
3513 output_asm_insn ("xgdx", operands);
3515 else if (X_REG_P (operands[1]))
3517 /* tys, txs preserve the flags */
3518 cc_status = cc_prev_status;
3519 output_asm_insn ("txs", operands);
3521 else if (Y_REG_P (operands[1]))
3523 /* tys, txs preserve the flags */
3524 cc_status = cc_prev_status;
3525 output_asm_insn ("tys", operands);
3527 else
3529 /* lds sets the flags but the des does not. */
3530 CC_STATUS_INIT;
3531 output_asm_insn ("lds\t%1", operands);
3532 output_asm_insn ("des", operands);
3534 break;
3536 default:
3537 fatal_insn ("invalid register in the move instruction", insn);
3538 break;
3540 return;
3542 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3543 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3545 output_asm_insn ("sts\t%0", operands);
3546 return;
3549 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3551 cc_status = cc_prev_status;
3552 switch (REGNO (operands[1]))
3554 case HARD_X_REGNUM:
3555 case HARD_Y_REGNUM:
3556 output_asm_insn ("psh%1", operands);
3557 break;
3558 case HARD_D_REGNUM:
3559 output_asm_insn ("pshb", operands);
3560 output_asm_insn ("psha", operands);
3561 break;
3562 default:
3563 abort ();
3565 return;
3568 /* Operand 1 must be a hard register. */
3569 if (!H_REG_P (operands[1]))
3571 fatal_insn ("invalid operand in the instruction", insn);
3574 reg = REGNO (operands[1]);
3575 switch (reg)
3577 case HARD_D_REGNUM:
3578 output_asm_insn ("std\t%0", operands);
3579 break;
3581 case HARD_X_REGNUM:
3582 output_asm_insn ("stx\t%0", operands);
3583 break;
3585 case HARD_Y_REGNUM:
3586 output_asm_insn ("sty\t%0", operands);
3587 break;
3589 case HARD_SP_REGNUM:
3590 if (ix_reg == 0)
3591 create_regs_rtx ();
3593 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3595 output_asm_insn ("pshx", operands);
3596 output_asm_insn ("tsx", operands);
3597 output_asm_insn ("inx", operands);
3598 output_asm_insn ("inx", operands);
3599 output_asm_insn ("stx\t%0", operands);
3600 output_asm_insn ("pulx", operands);
3603 else if (reg_mentioned_p (ix_reg, operands[0]))
3605 output_asm_insn ("sty\t%t0", operands);
3606 output_asm_insn ("tsy", operands);
3607 output_asm_insn ("sty\t%0", operands);
3608 output_asm_insn ("ldy\t%t0", operands);
3610 else
3612 output_asm_insn ("stx\t%t0", operands);
3613 output_asm_insn ("tsx", operands);
3614 output_asm_insn ("stx\t%0", operands);
3615 output_asm_insn ("ldx\t%t0", operands);
3617 CC_STATUS_INIT;
3618 break;
3620 default:
3621 fatal_insn ("invalid register in the move instruction", insn);
3622 break;
3626 void
3627 m68hc11_gen_movqi (rtx insn, rtx *operands)
3629 /* Move a register or memory to the same location.
3630 This is possible because such insn can appear
3631 in a non-optimizing mode. */
3632 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3634 cc_status = cc_prev_status;
3635 return;
3638 if (TARGET_M6812)
3641 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3643 m68hc11_notice_keep_cc (operands[0]);
3644 output_asm_insn ("tfr\t%1,%0", operands);
3646 else if (H_REG_P (operands[0]))
3648 if (Q_REG_P (operands[0]))
3649 output_asm_insn ("lda%0\t%b1", operands);
3650 else if (D_REG_P (operands[0]))
3651 output_asm_insn ("ldab\t%b1", operands);
3652 else
3653 goto m6811_move;
3655 else if (H_REG_P (operands[1]))
3657 if (Q_REG_P (operands[1]))
3658 output_asm_insn ("sta%1\t%b0", operands);
3659 else if (D_REG_P (operands[1]))
3660 output_asm_insn ("stab\t%b0", operands);
3661 else
3662 goto m6811_move;
3664 else
3666 rtx from = operands[1];
3667 rtx to = operands[0];
3669 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3670 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3671 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3672 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3674 rtx ops[3];
3676 if (operands[2])
3678 ops[0] = operands[2];
3679 ops[1] = from;
3680 ops[2] = 0;
3681 m68hc11_gen_movqi (insn, ops);
3682 ops[0] = to;
3683 ops[1] = operands[2];
3684 m68hc11_gen_movqi (insn, ops);
3686 else
3688 /* !!!! SCz wrong here. */
3689 fatal_insn ("move insn not handled", insn);
3692 else
3694 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3696 output_asm_insn ("clr\t%b0", operands);
3698 else
3700 m68hc11_notice_keep_cc (operands[0]);
3701 output_asm_insn ("movb\t%b1,%b0", operands);
3705 return;
3708 m6811_move:
3709 if (H_REG_P (operands[0]))
3711 switch (REGNO (operands[0]))
3713 case HARD_B_REGNUM:
3714 case HARD_D_REGNUM:
3715 if (X_REG_P (operands[1]))
3717 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3719 m68hc11_output_swap (insn, operands);
3721 else
3723 output_asm_insn ("stx\t%t1", operands);
3724 output_asm_insn ("ldab\t%T0", operands);
3727 else if (Y_REG_P (operands[1]))
3729 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3731 m68hc11_output_swap (insn, operands);
3733 else
3735 output_asm_insn ("sty\t%t1", operands);
3736 output_asm_insn ("ldab\t%T0", operands);
3739 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3740 && !DA_REG_P (operands[1]))
3742 output_asm_insn ("ldab\t%b1", operands);
3744 else if (DA_REG_P (operands[1]))
3746 output_asm_insn ("tab", operands);
3748 else
3750 cc_status = cc_prev_status;
3751 return;
3753 break;
3755 case HARD_A_REGNUM:
3756 if (X_REG_P (operands[1]))
3758 output_asm_insn ("stx\t%t1", operands);
3759 output_asm_insn ("ldaa\t%T0", operands);
3761 else if (Y_REG_P (operands[1]))
3763 output_asm_insn ("sty\t%t1", operands);
3764 output_asm_insn ("ldaa\t%T0", operands);
3766 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3767 && !DA_REG_P (operands[1]))
3769 output_asm_insn ("ldaa\t%b1", operands);
3771 else if (!DA_REG_P (operands[1]))
3773 output_asm_insn ("tba", operands);
3775 else
3777 cc_status = cc_prev_status;
3779 break;
3781 case HARD_X_REGNUM:
3782 if (D_REG_P (operands[1]))
3784 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3786 m68hc11_output_swap (insn, operands);
3788 else
3790 output_asm_insn ("stab\t%T1", operands);
3791 output_asm_insn ("ldx\t%t1", operands);
3793 CC_STATUS_INIT;
3795 else if (Y_REG_P (operands[1]))
3797 output_asm_insn ("sty\t%t0", operands);
3798 output_asm_insn ("ldx\t%t0", operands);
3800 else if (GET_CODE (operands[1]) == CONST_INT)
3802 output_asm_insn ("ldx\t%1", operands);
3804 else if (dead_register_here (insn, d_reg))
3806 output_asm_insn ("ldab\t%b1", operands);
3807 output_asm_insn ("xgdx", operands);
3809 else if (!reg_mentioned_p (operands[0], operands[1]))
3811 output_asm_insn ("xgdx", operands);
3812 output_asm_insn ("ldab\t%b1", operands);
3813 output_asm_insn ("xgdx", operands);
3815 else
3817 output_asm_insn ("pshb", operands);
3818 output_asm_insn ("ldab\t%b1", operands);
3819 output_asm_insn ("stab\t%T1", operands);
3820 output_asm_insn ("ldx\t%t1", operands);
3821 output_asm_insn ("pulb", operands);
3822 CC_STATUS_INIT;
3824 break;
3826 case HARD_Y_REGNUM:
3827 if (D_REG_P (operands[1]))
3829 output_asm_insn ("stab\t%T1", operands);
3830 output_asm_insn ("ldy\t%t1", operands);
3831 CC_STATUS_INIT;
3833 else if (X_REG_P (operands[1]))
3835 output_asm_insn ("stx\t%t1", operands);
3836 output_asm_insn ("ldy\t%t1", operands);
3837 CC_STATUS_INIT;
3839 else if (GET_CODE (operands[1]) == CONST_INT)
3841 output_asm_insn ("ldy\t%1", operands);
3843 else if (dead_register_here (insn, d_reg))
3845 output_asm_insn ("ldab\t%b1", operands);
3846 output_asm_insn ("xgdy", operands);
3848 else if (!reg_mentioned_p (operands[0], operands[1]))
3850 output_asm_insn ("xgdy", operands);
3851 output_asm_insn ("ldab\t%b1", operands);
3852 output_asm_insn ("xgdy", operands);
3854 else
3856 output_asm_insn ("pshb", operands);
3857 output_asm_insn ("ldab\t%b1", operands);
3858 output_asm_insn ("stab\t%T1", operands);
3859 output_asm_insn ("ldy\t%t1", operands);
3860 output_asm_insn ("pulb", operands);
3861 CC_STATUS_INIT;
3863 break;
3865 default:
3866 fatal_insn ("invalid register in the instruction", insn);
3867 break;
3870 else if (H_REG_P (operands[1]))
3872 switch (REGNO (operands[1]))
3874 case HARD_D_REGNUM:
3875 case HARD_B_REGNUM:
3876 output_asm_insn ("stab\t%b0", operands);
3877 break;
3879 case HARD_A_REGNUM:
3880 output_asm_insn ("staa\t%b0", operands);
3881 break;
3883 case HARD_X_REGNUM:
3884 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3885 break;
3887 case HARD_Y_REGNUM:
3888 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3889 break;
3891 default:
3892 fatal_insn ("invalid register in the move instruction", insn);
3893 break;
3895 return;
3897 else
3899 fatal_insn ("operand 1 must be a hard register", insn);
3903 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3904 The source and destination must be D or A and the shift must
3905 be a constant. */
3906 void
3907 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3909 int val;
3911 if (GET_CODE (operands[2]) != CONST_INT
3912 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3913 fatal_insn ("invalid rotate insn", insn);
3915 val = INTVAL (operands[2]);
3916 if (code == ROTATERT)
3917 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3919 if (GET_MODE (operands[0]) != QImode)
3920 CC_STATUS_INIT;
3922 /* Rotate by 8-bits if the shift is within [5..11]. */
3923 if (val >= 5 && val <= 11)
3925 if (TARGET_M6812)
3926 output_asm_insn ("exg\ta,b", operands);
3927 else
3929 output_asm_insn ("psha", operands);
3930 output_asm_insn ("tba", operands);
3931 output_asm_insn ("pulb", operands);
3933 val -= 8;
3936 /* If the shift is big, invert the rotation. */
3937 else if (val >= 12)
3939 val = val - 16;
3942 if (val > 0)
3944 while (--val >= 0)
3946 /* Set the carry to bit-15, but don't change D yet. */
3947 if (GET_MODE (operands[0]) != QImode)
3949 output_asm_insn ("asra", operands);
3950 output_asm_insn ("rola", operands);
3953 /* Rotate B first to move the carry to bit-0. */
3954 if (D_REG_P (operands[0]))
3955 output_asm_insn ("rolb", operands);
3957 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3958 output_asm_insn ("rola", operands);
3961 else
3963 while (++val <= 0)
3965 /* Set the carry to bit-8 of D. */
3966 if (GET_MODE (operands[0]) != QImode)
3967 output_asm_insn ("tap", operands);
3969 /* Rotate B first to move the carry to bit-7. */
3970 if (D_REG_P (operands[0]))
3971 output_asm_insn ("rorb", operands);
3973 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3974 output_asm_insn ("rora", operands);
3981 /* Store in cc_status the expressions that the condition codes will
3982 describe after execution of an instruction whose pattern is EXP.
3983 Do not alter them if the instruction would not alter the cc's. */
3985 void
3986 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3988 /* recognize SET insn's. */
3989 if (GET_CODE (exp) == SET)
3991 /* Jumps do not alter the cc's. */
3992 if (SET_DEST (exp) == pc_rtx)
3995 /* NOTE: most instructions don't affect the carry bit, but the
3996 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3997 the conditions.h header. */
3999 /* Function calls clobber the cc's. */
4000 else if (GET_CODE (SET_SRC (exp)) == CALL)
4002 CC_STATUS_INIT;
4005 /* Tests and compares set the cc's in predictable ways. */
4006 else if (SET_DEST (exp) == cc0_rtx)
4008 cc_status.flags = 0;
4009 cc_status.value1 = XEXP (exp, 0);
4010 cc_status.value2 = XEXP (exp, 1);
4012 else
4014 /* All other instructions affect the condition codes. */
4015 cc_status.flags = 0;
4016 cc_status.value1 = XEXP (exp, 0);
4017 cc_status.value2 = XEXP (exp, 1);
4020 else
4022 /* Default action if we haven't recognized something
4023 and returned earlier. */
4024 CC_STATUS_INIT;
4027 if (cc_status.value2 != 0)
4028 switch (GET_CODE (cc_status.value2))
4030 /* These logical operations can generate several insns.
4031 The flags are setup according to what is generated. */
4032 case IOR:
4033 case XOR:
4034 case AND:
4035 break;
4037 /* The (not ...) generates several 'com' instructions for
4038 non QImode. We have to invalidate the flags. */
4039 case NOT:
4040 if (GET_MODE (cc_status.value2) != QImode)
4041 CC_STATUS_INIT;
4042 break;
4044 case PLUS:
4045 case MINUS:
4046 case MULT:
4047 case DIV:
4048 case UDIV:
4049 case MOD:
4050 case UMOD:
4051 case NEG:
4052 if (GET_MODE (cc_status.value2) != VOIDmode)
4053 cc_status.flags |= CC_NO_OVERFLOW;
4054 break;
4056 /* The asl sets the overflow bit in such a way that this
4057 makes the flags unusable for a next compare insn. */
4058 case ASHIFT:
4059 case ROTATE:
4060 case ROTATERT:
4061 if (GET_MODE (cc_status.value2) != VOIDmode)
4062 cc_status.flags |= CC_NO_OVERFLOW;
4063 break;
4065 /* A load/store instruction does not affect the carry. */
4066 case MEM:
4067 case SYMBOL_REF:
4068 case REG:
4069 case CONST_INT:
4070 cc_status.flags |= CC_NO_OVERFLOW;
4071 break;
4073 default:
4074 break;
4076 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
4077 && cc_status.value2
4078 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
4079 cc_status.value2 = 0;
4081 else if (cc_status.value1 && side_effects_p (cc_status.value1))
4082 cc_status.value1 = 0;
4084 else if (cc_status.value2 && side_effects_p (cc_status.value2))
4085 cc_status.value2 = 0;
4088 /* The current instruction does not affect the flags but changes
4089 the register 'reg'. See if the previous flags can be kept for the
4090 next instruction to avoid a comparison. */
4091 void
4092 m68hc11_notice_keep_cc (rtx reg)
4094 if (reg == 0
4095 || cc_prev_status.value1 == 0
4096 || rtx_equal_p (reg, cc_prev_status.value1)
4097 || (cc_prev_status.value2
4098 && reg_mentioned_p (reg, cc_prev_status.value2)))
4099 CC_STATUS_INIT;
4100 else
4101 cc_status = cc_prev_status;
4106 /* Machine Specific Reorg. */
4108 /* Z register replacement:
4110 GCC treats the Z register as an index base address register like
4111 X or Y. In general, it uses it during reload to compute the address
4112 of some operand. This helps the reload pass to avoid to fall into the
4113 register spill failure.
4115 The Z register is in the A_REGS class. In the machine description,
4116 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4118 It can appear everywhere an X or Y register can appear, except for
4119 some templates in the clobber section (when a clobber of X or Y is asked).
4120 For a given instruction, the template must ensure that no more than
4121 2 'A' registers are used. Otherwise, the register replacement is not
4122 possible.
4124 To replace the Z register, the algorithm is not terrific:
4125 1. Insns that do not use the Z register are not changed
4126 2. When a Z register is used, we scan forward the insns to see
4127 a potential register to use: either X or Y and sometimes D.
4128 We stop when a call, a label or a branch is seen, or when we
4129 detect that both X and Y are used (probably at different times, but it does
4130 not matter).
4131 3. The register that will be used for the replacement of Z is saved
4132 in a .page0 register or on the stack. If the first instruction that
4133 used Z, uses Z as an input, the value is loaded from another .page0
4134 register. The replacement register is pushed on the stack in the
4135 rare cases where a compare insn uses Z and we couldn't find if X/Y
4136 are dead.
4137 4. The Z register is replaced in all instructions until we reach
4138 the end of the Z-block, as detected by step 2.
4139 5. If we detect that Z is still alive, its value is saved.
4140 If the replacement register is alive, its old value is loaded.
4142 The Z register can be disabled with -ffixed-z.
4145 struct replace_info
4147 rtx first;
4148 rtx replace_reg;
4149 int need_save_z;
4150 int must_load_z;
4151 int must_save_reg;
4152 int must_restore_reg;
4153 rtx last;
4154 int regno;
4155 int x_used;
4156 int y_used;
4157 int can_use_d;
4158 int found_call;
4159 int z_died;
4160 int z_set_count;
4161 rtx z_value;
4162 int must_push_reg;
4163 int save_before_last;
4164 int z_loaded_with_sp;
4167 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4168 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4169 static void m68hc11_z_replacement (rtx);
4170 static void m68hc11_reassign_regs (rtx);
4172 int z_replacement_completed = 0;
4174 /* Analyze the insn to find out which replacement register to use and
4175 the boundaries of the replacement.
4176 Returns 0 if we reached the last insn to be replaced, 1 if we can
4177 continue replacement in next insns. */
4179 static int
4180 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4182 int this_insn_uses_ix;
4183 int this_insn_uses_iy;
4184 int this_insn_uses_z;
4185 int this_insn_uses_z_in_dst;
4186 int this_insn_uses_d;
4187 rtx body;
4188 int z_dies_here;
4190 /* A call is said to clobber the Z register, we don't need
4191 to save the value of Z. We also don't need to restore
4192 the replacement register (unless it is used by the call). */
4193 if (GET_CODE (insn) == CALL_INSN)
4195 body = PATTERN (insn);
4197 info->can_use_d = 0;
4199 /* If the call is an indirect call with Z, we have to use the
4200 Y register because X can be used as an input (D+X).
4201 We also must not save Z nor restore Y. */
4202 if (reg_mentioned_p (z_reg, body))
4204 insn = NEXT_INSN (insn);
4205 info->x_used = 1;
4206 info->y_used = 0;
4207 info->found_call = 1;
4208 info->must_restore_reg = 0;
4209 info->last = NEXT_INSN (insn);
4211 info->need_save_z = 0;
4212 return 0;
4214 if (GET_CODE (insn) == CODE_LABEL
4215 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4216 return 0;
4218 if (GET_CODE (insn) == JUMP_INSN)
4220 if (reg_mentioned_p (z_reg, insn) == 0)
4221 return 0;
4223 info->can_use_d = 0;
4224 info->must_save_reg = 0;
4225 info->must_restore_reg = 0;
4226 info->need_save_z = 0;
4227 info->last = NEXT_INSN (insn);
4228 return 0;
4230 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4232 return 1;
4235 /* Z register dies here. */
4236 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4238 body = PATTERN (insn);
4239 if (GET_CODE (body) == SET)
4241 rtx src = XEXP (body, 1);
4242 rtx dst = XEXP (body, 0);
4244 /* Condition code is set here. We have to restore the X/Y and
4245 save into Z before any test/compare insn because once we save/restore
4246 we can change the condition codes. When the compare insn uses Z and
4247 we can't use X/Y, the comparison is made with the *ZREG soft register
4248 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4249 if (dst == cc0_rtx)
4251 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4252 || (GET_CODE (src) == COMPARE &&
4253 ((rtx_equal_p (XEXP (src, 0), z_reg)
4254 && H_REG_P (XEXP (src, 1)))
4255 || (rtx_equal_p (XEXP (src, 1), z_reg)
4256 && H_REG_P (XEXP (src, 0))))))
4258 if (insn == info->first)
4260 info->must_load_z = 0;
4261 info->must_save_reg = 0;
4262 info->must_restore_reg = 0;
4263 info->need_save_z = 0;
4264 info->found_call = 1;
4265 info->regno = SOFT_Z_REGNUM;
4266 info->last = NEXT_INSN (insn);
4268 return 0;
4270 if (reg_mentioned_p (z_reg, src) == 0)
4272 info->can_use_d = 0;
4273 return 0;
4276 if (insn != info->first)
4277 return 0;
4279 /* Compare insn which uses Z. We have to save/restore the X/Y
4280 register without modifying the condition codes. For this
4281 we have to use a push/pop insn. */
4282 info->must_push_reg = 1;
4283 info->last = insn;
4286 /* Z reg is set to something new. We don't need to load it. */
4287 if (Z_REG_P (dst))
4289 if (!reg_mentioned_p (z_reg, src))
4291 /* Z reg is used before being set. Treat this as
4292 a new sequence of Z register replacement. */
4293 if (insn != info->first)
4295 return 0;
4297 info->must_load_z = 0;
4299 info->z_set_count++;
4300 info->z_value = src;
4301 if (SP_REG_P (src))
4302 info->z_loaded_with_sp = 1;
4304 else if (reg_mentioned_p (z_reg, dst))
4305 info->can_use_d = 0;
4307 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4308 | reg_mentioned_p (d_reg, dst);
4309 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4310 | reg_mentioned_p (ix_reg, dst);
4311 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4312 | reg_mentioned_p (iy_reg, dst);
4313 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4315 /* If z is used as an address operand (like (MEM (reg z))),
4316 we can't replace it with d. */
4317 if (this_insn_uses_z && !Z_REG_P (src)
4318 && !(m68hc11_arith_operator (src, GET_MODE (src))
4319 && Z_REG_P (XEXP (src, 0))
4320 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4321 && insn == info->first
4322 && dead_register_here (insn, d_reg)))
4323 info->can_use_d = 0;
4325 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4326 if (TARGET_M6812 && !z_dies_here
4327 && ((this_insn_uses_z && side_effects_p (src))
4328 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4330 info->need_save_z = 1;
4331 info->z_set_count++;
4333 this_insn_uses_z |= this_insn_uses_z_in_dst;
4335 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4337 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4340 if (this_insn_uses_d)
4341 info->can_use_d = 0;
4343 /* IX and IY are used at the same time, we have to restore
4344 the value of the scratch register before this insn. */
4345 if (this_insn_uses_ix && this_insn_uses_iy)
4347 return 0;
4350 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4351 info->can_use_d = 0;
4353 if (info->x_used == 0 && this_insn_uses_ix)
4355 if (info->y_used)
4357 /* We have a (set (REG:HI X) (REG:HI Z)).
4358 Since we use Z as the replacement register, this insn
4359 is no longer necessary. We turn it into a note. We must
4360 not reload the old value of X. */
4361 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4363 if (z_dies_here)
4365 info->need_save_z = 0;
4366 info->z_died = 1;
4368 info->must_save_reg = 0;
4369 info->must_restore_reg = 0;
4370 info->found_call = 1;
4371 info->can_use_d = 0;
4372 PUT_CODE (insn, NOTE);
4373 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4374 NOTE_SOURCE_FILE (insn) = 0;
4375 info->last = NEXT_INSN (insn);
4376 return 0;
4379 if (X_REG_P (dst)
4380 && (rtx_equal_p (src, z_reg)
4381 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4383 if (z_dies_here)
4385 info->need_save_z = 0;
4386 info->z_died = 1;
4388 info->last = NEXT_INSN (insn);
4389 info->must_save_reg = 0;
4390 info->must_restore_reg = 0;
4392 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4393 && !reg_mentioned_p (ix_reg, src))
4395 if (z_dies_here)
4397 info->z_died = 1;
4398 info->need_save_z = 0;
4400 else if (TARGET_M6812 && side_effects_p (src))
4402 info->last = 0;
4403 info->must_restore_reg = 0;
4404 return 0;
4406 else
4408 info->save_before_last = 1;
4410 info->must_restore_reg = 0;
4411 info->last = NEXT_INSN (insn);
4413 else if (info->can_use_d)
4415 info->last = NEXT_INSN (insn);
4416 info->x_used = 1;
4418 return 0;
4420 info->x_used = 1;
4421 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4422 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4424 info->need_save_z = 0;
4425 info->z_died = 1;
4426 info->last = NEXT_INSN (insn);
4427 info->regno = HARD_X_REGNUM;
4428 info->must_save_reg = 0;
4429 info->must_restore_reg = 0;
4430 return 0;
4432 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4434 info->regno = HARD_X_REGNUM;
4435 info->must_restore_reg = 0;
4436 info->must_save_reg = 0;
4437 return 0;
4440 if (info->y_used == 0 && this_insn_uses_iy)
4442 if (info->x_used)
4444 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4446 if (z_dies_here)
4448 info->need_save_z = 0;
4449 info->z_died = 1;
4451 info->must_save_reg = 0;
4452 info->must_restore_reg = 0;
4453 info->found_call = 1;
4454 info->can_use_d = 0;
4455 PUT_CODE (insn, NOTE);
4456 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4457 NOTE_SOURCE_FILE (insn) = 0;
4458 info->last = NEXT_INSN (insn);
4459 return 0;
4462 if (Y_REG_P (dst)
4463 && (rtx_equal_p (src, z_reg)
4464 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4466 if (z_dies_here)
4468 info->z_died = 1;
4469 info->need_save_z = 0;
4471 info->last = NEXT_INSN (insn);
4472 info->must_save_reg = 0;
4473 info->must_restore_reg = 0;
4475 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4476 && !reg_mentioned_p (iy_reg, src))
4478 if (z_dies_here)
4480 info->z_died = 1;
4481 info->need_save_z = 0;
4483 else if (TARGET_M6812 && side_effects_p (src))
4485 info->last = 0;
4486 info->must_restore_reg = 0;
4487 return 0;
4489 else
4491 info->save_before_last = 1;
4493 info->must_restore_reg = 0;
4494 info->last = NEXT_INSN (insn);
4496 else if (info->can_use_d)
4498 info->last = NEXT_INSN (insn);
4499 info->y_used = 1;
4502 return 0;
4504 info->y_used = 1;
4505 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4506 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4508 info->need_save_z = 0;
4509 info->z_died = 1;
4510 info->last = NEXT_INSN (insn);
4511 info->regno = HARD_Y_REGNUM;
4512 info->must_save_reg = 0;
4513 info->must_restore_reg = 0;
4514 return 0;
4516 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4518 info->regno = HARD_Y_REGNUM;
4519 info->must_restore_reg = 0;
4520 info->must_save_reg = 0;
4521 return 0;
4524 if (z_dies_here)
4526 info->need_save_z = 0;
4527 info->z_died = 1;
4528 if (info->last == 0)
4529 info->last = NEXT_INSN (insn);
4530 return 0;
4532 return info->last != NULL_RTX ? 0 : 1;
4534 if (GET_CODE (body) == PARALLEL)
4536 int i;
4537 char ix_clobber = 0;
4538 char iy_clobber = 0;
4539 char z_clobber = 0;
4540 this_insn_uses_iy = 0;
4541 this_insn_uses_ix = 0;
4542 this_insn_uses_z = 0;
4544 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4546 rtx x;
4547 int uses_ix, uses_iy, uses_z;
4549 x = XVECEXP (body, 0, i);
4551 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4552 info->can_use_d = 0;
4554 uses_ix = reg_mentioned_p (ix_reg, x);
4555 uses_iy = reg_mentioned_p (iy_reg, x);
4556 uses_z = reg_mentioned_p (z_reg, x);
4557 if (GET_CODE (x) == CLOBBER)
4559 ix_clobber |= uses_ix;
4560 iy_clobber |= uses_iy;
4561 z_clobber |= uses_z;
4563 else
4565 this_insn_uses_ix |= uses_ix;
4566 this_insn_uses_iy |= uses_iy;
4567 this_insn_uses_z |= uses_z;
4569 if (uses_z && GET_CODE (x) == SET)
4571 rtx dst = XEXP (x, 0);
4573 if (Z_REG_P (dst))
4574 info->z_set_count++;
4576 if (TARGET_M6812 && uses_z && side_effects_p (x))
4577 info->need_save_z = 1;
4579 if (z_clobber)
4580 info->need_save_z = 0;
4582 if (debug_m6811)
4584 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4585 this_insn_uses_ix, this_insn_uses_iy,
4586 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4587 debug_rtx (insn);
4589 if (this_insn_uses_z)
4590 info->can_use_d = 0;
4592 if (z_clobber && info->first != insn)
4594 info->need_save_z = 0;
4595 info->last = insn;
4596 return 0;
4598 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4600 if (this_insn_uses_z == 0 && insn == info->first)
4602 info->must_load_z = 0;
4604 if (dead_register_here (insn, d_reg))
4606 info->regno = HARD_D_REGNUM;
4607 info->must_save_reg = 0;
4608 info->must_restore_reg = 0;
4610 else if (dead_register_here (insn, ix_reg))
4612 info->regno = HARD_X_REGNUM;
4613 info->must_save_reg = 0;
4614 info->must_restore_reg = 0;
4616 else if (dead_register_here (insn, iy_reg))
4618 info->regno = HARD_Y_REGNUM;
4619 info->must_save_reg = 0;
4620 info->must_restore_reg = 0;
4622 if (info->regno >= 0)
4624 info->last = NEXT_INSN (insn);
4625 return 0;
4627 if (this_insn_uses_ix == 0)
4629 info->regno = HARD_X_REGNUM;
4630 info->must_save_reg = 1;
4631 info->must_restore_reg = 1;
4633 else if (this_insn_uses_iy == 0)
4635 info->regno = HARD_Y_REGNUM;
4636 info->must_save_reg = 1;
4637 info->must_restore_reg = 1;
4639 else
4641 info->regno = HARD_D_REGNUM;
4642 info->must_save_reg = 1;
4643 info->must_restore_reg = 1;
4645 info->last = NEXT_INSN (insn);
4646 return 0;
4649 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4650 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4652 if (this_insn_uses_z)
4654 if (info->y_used == 0 && iy_clobber)
4656 info->regno = HARD_Y_REGNUM;
4657 info->must_save_reg = 0;
4658 info->must_restore_reg = 0;
4660 if (info->first != insn
4661 && ((info->y_used && ix_clobber)
4662 || (info->x_used && iy_clobber)))
4663 info->last = insn;
4664 else
4665 info->last = NEXT_INSN (insn);
4666 info->save_before_last = 1;
4668 return 0;
4670 if (this_insn_uses_ix && this_insn_uses_iy)
4672 if (this_insn_uses_z)
4674 fatal_insn ("cannot do z-register replacement", insn);
4676 return 0;
4678 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4680 if (info->y_used)
4682 return 0;
4684 info->x_used = 1;
4685 if (iy_clobber || z_clobber)
4687 info->last = NEXT_INSN (insn);
4688 info->save_before_last = 1;
4689 return 0;
4693 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4695 if (info->x_used)
4697 return 0;
4699 info->y_used = 1;
4700 if (ix_clobber || z_clobber)
4702 info->last = NEXT_INSN (insn);
4703 info->save_before_last = 1;
4704 return 0;
4707 if (z_dies_here)
4709 info->z_died = 1;
4710 info->need_save_z = 0;
4712 return 1;
4714 if (GET_CODE (body) == CLOBBER)
4717 /* IX and IY are used at the same time, we have to restore
4718 the value of the scratch register before this insn. */
4719 if (this_insn_uses_ix && this_insn_uses_iy)
4721 return 0;
4723 if (info->x_used == 0 && this_insn_uses_ix)
4725 if (info->y_used)
4727 return 0;
4729 info->x_used = 1;
4731 if (info->y_used == 0 && this_insn_uses_iy)
4733 if (info->x_used)
4735 return 0;
4737 info->y_used = 1;
4739 return 1;
4741 return 1;
4744 static void
4745 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4747 int reg;
4749 info->replace_reg = NULL_RTX;
4750 info->must_load_z = 1;
4751 info->need_save_z = 1;
4752 info->must_save_reg = 1;
4753 info->must_restore_reg = 1;
4754 info->first = insn;
4755 info->x_used = 0;
4756 info->y_used = 0;
4757 info->can_use_d = TARGET_M6811 ? 1 : 0;
4758 info->found_call = 0;
4759 info->z_died = 0;
4760 info->last = 0;
4761 info->regno = -1;
4762 info->z_set_count = 0;
4763 info->z_value = NULL_RTX;
4764 info->must_push_reg = 0;
4765 info->save_before_last = 0;
4766 info->z_loaded_with_sp = 0;
4768 /* Scan the insn forward to find an address register that is not used.
4769 Stop when:
4770 - the flow of the program changes,
4771 - when we detect that both X and Y are necessary,
4772 - when the Z register dies,
4773 - when the condition codes are set. */
4775 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4777 if (m68hc11_check_z_replacement (insn, info) == 0)
4778 break;
4781 /* May be we can use Y or X if they contain the same value as Z.
4782 This happens very often after the reload. */
4783 if (info->z_set_count == 1)
4785 rtx p = info->first;
4786 rtx v = 0;
4788 if (info->x_used)
4790 v = find_last_value (iy_reg, &p, insn, 1);
4792 else if (info->y_used)
4794 v = find_last_value (ix_reg, &p, insn, 1);
4796 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4798 if (info->x_used)
4799 info->regno = HARD_Y_REGNUM;
4800 else
4801 info->regno = HARD_X_REGNUM;
4802 info->must_load_z = 0;
4803 info->must_save_reg = 0;
4804 info->must_restore_reg = 0;
4805 info->found_call = 1;
4808 if (info->z_set_count == 0)
4809 info->need_save_z = 0;
4811 if (insn == 0)
4812 info->need_save_z = 0;
4814 if (info->last == 0)
4815 info->last = insn;
4817 if (info->regno >= 0)
4819 reg = info->regno;
4820 info->replace_reg = gen_rtx (REG, HImode, reg);
4822 else if (info->can_use_d)
4824 reg = HARD_D_REGNUM;
4825 info->replace_reg = d_reg;
4827 else if (info->x_used)
4829 reg = HARD_Y_REGNUM;
4830 info->replace_reg = iy_reg;
4832 else
4834 reg = HARD_X_REGNUM;
4835 info->replace_reg = ix_reg;
4837 info->regno = reg;
4839 if (info->must_save_reg && info->must_restore_reg)
4841 if (insn && dead_register_here (insn, info->replace_reg))
4843 info->must_save_reg = 0;
4844 info->must_restore_reg = 0;
4849 /* The insn uses the Z register. Find a replacement register for it
4850 (either X or Y) and replace it in the insn and the next ones until
4851 the flow changes or the replacement register is used. Instructions
4852 are emitted before and after the Z-block to preserve the value of
4853 Z and of the replacement register. */
4855 static void
4856 m68hc11_z_replacement (rtx insn)
4858 rtx replace_reg_qi;
4859 rtx replace_reg;
4860 struct replace_info info;
4862 /* Find trivial case where we only need to replace z with the
4863 equivalent soft register. */
4864 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4866 rtx body = PATTERN (insn);
4867 rtx src = XEXP (body, 1);
4868 rtx dst = XEXP (body, 0);
4870 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4872 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4873 return;
4875 else if (Z_REG_P (src)
4876 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4878 XEXP (body, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4879 return;
4881 else if (D_REG_P (dst)
4882 && m68hc11_arith_operator (src, GET_MODE (src))
4883 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4885 XEXP (src, 1) = gen_rtx (REG, GET_MODE (src), SOFT_Z_REGNUM);
4886 return;
4888 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4889 && INTVAL (src) == 0)
4891 XEXP (body, 0) = gen_rtx (REG, GET_MODE (dst), SOFT_Z_REGNUM);
4892 /* Force it to be re-recognized. */
4893 INSN_CODE (insn) = -1;
4894 return;
4898 m68hc11_find_z_replacement (insn, &info);
4900 replace_reg = info.replace_reg;
4901 replace_reg_qi = NULL_RTX;
4903 /* Save the X register in a .page0 location. */
4904 if (info.must_save_reg && !info.must_push_reg)
4906 rtx dst;
4908 if (info.must_push_reg && 0)
4909 dst = gen_rtx (MEM, HImode,
4910 gen_rtx (PRE_DEC, HImode,
4911 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
4912 else
4913 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
4915 emit_insn_before (gen_movhi (dst,
4916 gen_rtx (REG, HImode, info.regno)), insn);
4918 if (info.must_load_z && !info.must_push_reg)
4920 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
4921 gen_rtx (REG, HImode, SOFT_Z_REGNUM)),
4922 insn);
4926 /* Replace all occurrence of Z by replace_reg.
4927 Stop when the last instruction to replace is reached.
4928 Also stop when we detect a change in the flow (but it's not
4929 necessary; just safeguard). */
4931 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4933 rtx body;
4935 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4936 break;
4938 if (GET_CODE (insn) != INSN
4939 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4940 continue;
4942 body = PATTERN (insn);
4943 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4944 || GET_CODE (body) == ASM_OPERANDS
4945 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4947 rtx note;
4949 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4951 printf ("Reg mentioned here...:\n");
4952 fflush (stdout);
4953 debug_rtx (insn);
4956 /* Stack pointer was decremented by 2 due to the push.
4957 Correct that by adding 2 to the destination. */
4958 if (info.must_push_reg
4959 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4961 rtx src, dst;
4963 src = SET_SRC (body);
4964 dst = SET_DEST (body);
4965 if (SP_REG_P (src) && Z_REG_P (dst))
4966 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4969 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4970 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4972 INSN_CODE (insn) = -1;
4973 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4974 fatal_insn ("cannot do z-register replacement", insn);
4977 /* Likewise for (REG:QI Z). */
4978 if (reg_mentioned_p (z_reg, insn))
4980 if (replace_reg_qi == NULL_RTX)
4981 replace_reg_qi = gen_rtx (REG, QImode, REGNO (replace_reg));
4982 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4985 /* If there is a REG_INC note on Z, replace it with a
4986 REG_INC note on the replacement register. This is necessary
4987 to make sure that the flow pass will identify the change
4988 and it will not remove a possible insn that saves Z. */
4989 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4991 if (REG_NOTE_KIND (note) == REG_INC
4992 && GET_CODE (XEXP (note, 0)) == REG
4993 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4995 XEXP (note, 0) = replace_reg;
4999 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5000 break;
5003 /* Save Z before restoring the old value. */
5004 if (insn && info.need_save_z && !info.must_push_reg)
5006 rtx save_pos_insn = insn;
5008 /* If Z is clobber by the last insn, we have to save its value
5009 before the last instruction. */
5010 if (info.save_before_last)
5011 save_pos_insn = PREV_INSN (save_pos_insn);
5013 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, SOFT_Z_REGNUM),
5014 gen_rtx (REG, HImode, info.regno)),
5015 save_pos_insn);
5018 if (info.must_push_reg && info.last)
5020 rtx new_body, body;
5022 body = PATTERN (info.last);
5023 new_body = gen_rtx (PARALLEL, VOIDmode,
5024 gen_rtvec (3, body,
5025 gen_rtx (USE, VOIDmode,
5026 replace_reg),
5027 gen_rtx (USE, VOIDmode,
5028 gen_rtx (REG, HImode,
5029 SOFT_Z_REGNUM))));
5030 PATTERN (info.last) = new_body;
5032 /* Force recognition on insn since we changed it. */
5033 INSN_CODE (insn) = -1;
5035 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
5037 fatal_insn ("invalid Z register replacement for insn", insn);
5039 insn = NEXT_INSN (info.last);
5042 /* Restore replacement register unless it was died. */
5043 if (insn && info.must_restore_reg && !info.must_push_reg)
5045 rtx dst;
5047 if (info.must_push_reg && 0)
5048 dst = gen_rtx (MEM, HImode,
5049 gen_rtx (POST_INC, HImode,
5050 gen_rtx (REG, HImode, HARD_SP_REGNUM)));
5051 else
5052 dst = gen_rtx (REG, HImode, SOFT_SAVED_XY_REGNUM);
5054 emit_insn_before (gen_movhi (gen_rtx (REG, HImode, info.regno),
5055 dst), insn);
5061 /* Scan all the insn and re-affects some registers
5062 - The Z register (if it was used), is affected to X or Y depending
5063 on the instruction. */
5065 static void
5066 m68hc11_reassign_regs (rtx first)
5068 rtx insn;
5070 ix_reg = gen_rtx (REG, HImode, HARD_X_REGNUM);
5071 iy_reg = gen_rtx (REG, HImode, HARD_Y_REGNUM);
5072 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5073 z_reg_qi = gen_rtx (REG, QImode, HARD_Z_REGNUM);
5075 /* Scan all insns to replace Z by X or Y preserving the old value
5076 of X/Y and restoring it afterward. */
5078 for (insn = first; insn; insn = NEXT_INSN (insn))
5080 rtx body;
5082 if (GET_CODE (insn) == CODE_LABEL
5083 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
5084 continue;
5086 if (!INSN_P (insn))
5087 continue;
5089 body = PATTERN (insn);
5090 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5091 continue;
5093 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5094 || GET_CODE (body) == ASM_OPERANDS
5095 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5096 continue;
5098 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5099 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5102 /* If Z appears in this insn, replace it in the current insn
5103 and the next ones until the flow changes or we have to
5104 restore back the replacement register. */
5106 if (reg_mentioned_p (z_reg, body))
5108 m68hc11_z_replacement (insn);
5111 else
5113 printf ("insn not handled by Z replacement:\n");
5114 fflush (stdout);
5115 debug_rtx (insn);
5121 /* Machine-dependent reorg pass.
5122 Specific optimizations are defined here:
5123 - this pass changes the Z register into either X or Y
5124 (it preserves X/Y previous values in a memory slot in page0).
5126 When this pass is finished, the global variable
5127 'z_replacement_completed' is set to 2. */
5129 static void
5130 m68hc11_reorg (void)
5132 int split_done = 0;
5133 rtx insn, first;
5135 z_replacement_completed = 0;
5136 z_reg = gen_rtx (REG, HImode, HARD_Z_REGNUM);
5137 first = get_insns ();
5139 /* Some RTX are shared at this point. This breaks the Z register
5140 replacement, unshare everything. */
5141 unshare_all_rtl_again (first);
5143 /* Force a split of all splitable insn. This is necessary for the
5144 Z register replacement mechanism because we end up with basic insns. */
5145 split_all_insns_noflow ();
5146 split_done = 1;
5148 z_replacement_completed = 1;
5149 m68hc11_reassign_regs (first);
5151 if (optimize)
5152 compute_bb_for_insn ();
5154 /* After some splitting, there are some opportunities for CSE pass.
5155 This happens quite often when 32-bit or above patterns are split. */
5156 if (optimize > 0 && split_done)
5158 reload_cse_regs (first);
5161 /* Re-create the REG_DEAD notes. These notes are used in the machine
5162 description to use the best assembly directives. */
5163 if (optimize)
5165 /* Before recomputing the REG_DEAD notes, remove all of them.
5166 This is necessary because the reload_cse_regs() pass can
5167 have replaced some (MEM) with a register. In that case,
5168 the REG_DEAD that could exist for that register may become
5169 wrong. */
5170 for (insn = first; insn; insn = NEXT_INSN (insn))
5172 if (INSN_P (insn))
5174 rtx *pnote;
5176 pnote = &REG_NOTES (insn);
5177 while (*pnote != 0)
5179 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5180 *pnote = XEXP (*pnote, 1);
5181 else
5182 pnote = &XEXP (*pnote, 1);
5187 life_analysis (first, 0, PROP_REG_INFO | PROP_DEATH_NOTES);
5190 z_replacement_completed = 2;
5192 /* If optimizing, then go ahead and split insns that must be
5193 split after Z register replacement. This gives more opportunities
5194 for peephole (in particular for consecutives xgdx/xgdy). */
5195 if (optimize > 0)
5196 split_all_insns_noflow ();
5198 /* Once insns are split after the z_replacement_completed == 2,
5199 we must not re-run the life_analysis. The xgdx/xgdy patterns
5200 are not recognized and the life_analysis pass removes some
5201 insns because it thinks some (SETs) are noops or made to dead
5202 stores (which is false due to the swap).
5204 Do a simple pass to eliminate the noop set that the final
5205 split could generate (because it was easier for split definition). */
5207 rtx insn;
5209 for (insn = first; insn; insn = NEXT_INSN (insn))
5211 rtx body;
5213 if (INSN_DELETED_P (insn))
5214 continue;
5215 if (!INSN_P (insn))
5216 continue;
5218 /* Remove the (set (R) (R)) insns generated by some splits. */
5219 body = PATTERN (insn);
5220 if (GET_CODE (body) == SET
5221 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5223 PUT_CODE (insn, NOTE);
5224 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5225 NOTE_SOURCE_FILE (insn) = 0;
5226 continue;
5232 /* Override memcpy */
5234 static void
5235 m68hc11_init_libfuncs (void)
5237 memcpy_libfunc = init_one_libfunc ("__memcpy");
5238 memcmp_libfunc = init_one_libfunc ("__memcmp");
5239 memset_libfunc = init_one_libfunc ("__memset");
5244 /* Cost functions. */
5246 /* Cost of moving memory. */
5248 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class class,
5249 int in ATTRIBUTE_UNUSED)
5251 if (class <= H_REGS && class > NO_REGS)
5253 if (GET_MODE_SIZE (mode) <= 2)
5254 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5255 else
5256 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5258 else
5260 if (GET_MODE_SIZE (mode) <= 2)
5261 return COSTS_N_INSNS (3);
5262 else
5263 return COSTS_N_INSNS (4);
5268 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5269 Reload does not check the constraint of set insns when the two registers
5270 have a move cost of 2. Setting a higher cost will force reload to check
5271 the constraints. */
5273 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5274 enum reg_class to)
5276 /* All costs are symmetric, so reduce cases by putting the
5277 lower number class as the destination. */
5278 if (from < to)
5280 enum reg_class tmp = to;
5281 to = from, from = tmp;
5283 if (to >= S_REGS)
5284 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5285 else if (from <= S_REGS)
5286 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5287 else
5288 return COSTS_N_INSNS (2);
5292 /* Provide the costs of an addressing mode that contains ADDR.
5293 If ADDR is not a valid address, its cost is irrelevant. */
5295 static int
5296 m68hc11_address_cost (rtx addr)
5298 int cost = 4;
5300 switch (GET_CODE (addr))
5302 case REG:
5303 /* Make the cost of hard registers and specially SP, FP small. */
5304 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5305 cost = 0;
5306 else
5307 cost = 1;
5308 break;
5310 case SYMBOL_REF:
5311 cost = 8;
5312 break;
5314 case LABEL_REF:
5315 case CONST:
5316 cost = 0;
5317 break;
5319 case PLUS:
5321 register rtx plus0 = XEXP (addr, 0);
5322 register rtx plus1 = XEXP (addr, 1);
5324 if (GET_CODE (plus0) != REG)
5325 break;
5327 switch (GET_CODE (plus1))
5329 case CONST_INT:
5330 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5331 || INTVAL (plus1) < m68hc11_min_offset)
5332 cost = 3;
5333 else if (INTVAL (plus1) >= m68hc11_max_offset)
5334 cost = 2;
5335 else
5336 cost = 1;
5337 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5338 cost += 0;
5339 else
5340 cost += 1;
5341 break;
5343 case SYMBOL_REF:
5344 cost = 8;
5345 break;
5347 case CONST:
5348 case LABEL_REF:
5349 cost = 0;
5350 break;
5352 default:
5353 break;
5355 break;
5357 case PRE_DEC:
5358 case PRE_INC:
5359 if (SP_REG_P (XEXP (addr, 0)))
5360 cost = 1;
5361 break;
5363 default:
5364 break;
5366 if (debug_m6811)
5368 printf ("Address cost: %d for :", cost);
5369 fflush (stdout);
5370 debug_rtx (addr);
5373 return cost;
5376 static int
5377 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5379 int total;
5381 total = rtx_cost (x, SET);
5382 if (mode == QImode)
5383 total += m68hc11_cost->shiftQI_const[shift % 8];
5384 else if (mode == HImode)
5385 total += m68hc11_cost->shiftHI_const[shift % 16];
5386 else if (shift == 8 || shift == 16 || shift == 32)
5387 total += m68hc11_cost->shiftHI_const[8];
5388 else if (shift != 0 && shift != 16 && shift != 32)
5390 total += m68hc11_cost->shiftHI_const[1] * shift;
5393 /* For SI and others, the cost is higher. */
5394 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5395 total *= GET_MODE_SIZE (mode) / 2;
5397 /* When optimizing for size, make shift more costly so that
5398 multiplications are preferred. */
5399 if (optimize_size && (shift % 8) != 0)
5400 total *= 2;
5402 return total;
5405 static int
5406 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5407 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5409 enum machine_mode mode = GET_MODE (x);
5410 int extra_cost = 0;
5411 int total;
5413 switch (code)
5415 case ROTATE:
5416 case ROTATERT:
5417 case ASHIFT:
5418 case LSHIFTRT:
5419 case ASHIFTRT:
5420 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5422 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5425 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5426 total += m68hc11_cost->shift_var;
5427 return total;
5429 case AND:
5430 case XOR:
5431 case IOR:
5432 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5433 total += m68hc11_cost->logical;
5435 /* Logical instructions are byte instructions only. */
5436 total *= GET_MODE_SIZE (mode);
5437 return total;
5439 case MINUS:
5440 case PLUS:
5441 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5442 total += m68hc11_cost->add;
5443 if (GET_MODE_SIZE (mode) > 2)
5445 total *= GET_MODE_SIZE (mode) / 2;
5447 return total;
5449 case UDIV:
5450 case DIV:
5451 case MOD:
5452 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5453 switch (mode)
5455 case QImode:
5456 total += m68hc11_cost->divQI;
5457 break;
5459 case HImode:
5460 total += m68hc11_cost->divHI;
5461 break;
5463 case SImode:
5464 default:
5465 total += m68hc11_cost->divSI;
5466 break;
5468 return total;
5470 case MULT:
5471 /* mul instruction produces 16-bit result. */
5472 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5473 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5474 return m68hc11_cost->multQI
5475 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5476 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5478 /* emul instruction produces 32-bit result for 68HC12. */
5479 if (TARGET_M6812 && mode == SImode
5480 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5481 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5482 return m68hc11_cost->multHI
5483 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5484 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5486 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5487 switch (mode)
5489 case QImode:
5490 total += m68hc11_cost->multQI;
5491 break;
5493 case HImode:
5494 total += m68hc11_cost->multHI;
5495 break;
5497 case SImode:
5498 default:
5499 total += m68hc11_cost->multSI;
5500 break;
5502 return total;
5504 case NEG:
5505 case SIGN_EXTEND:
5506 extra_cost = COSTS_N_INSNS (2);
5508 /* Fall through */
5509 case NOT:
5510 case COMPARE:
5511 case ABS:
5512 case ZERO_EXTEND:
5513 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5514 if (mode == QImode)
5516 return total + COSTS_N_INSNS (1);
5518 if (mode == HImode)
5520 return total + COSTS_N_INSNS (2);
5522 if (mode == SImode)
5524 return total + COSTS_N_INSNS (4);
5526 return total + COSTS_N_INSNS (8);
5528 case IF_THEN_ELSE:
5529 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5530 return COSTS_N_INSNS (1);
5532 return COSTS_N_INSNS (1);
5534 default:
5535 return COSTS_N_INSNS (4);
5539 static bool
5540 m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total)
5542 switch (code)
5544 /* Constants are cheap. Moving them in registers must be avoided
5545 because most instructions do not handle two register operands. */
5546 case CONST_INT:
5547 case CONST:
5548 case LABEL_REF:
5549 case SYMBOL_REF:
5550 case CONST_DOUBLE:
5551 /* Logical and arithmetic operations with a constant operand are
5552 better because they are not supported with two registers. */
5553 /* 'clr' is slow */
5554 if (outer_code == SET && x == const0_rtx)
5555 /* After reload, the reload_cse pass checks the cost to change
5556 a SET into a PLUS. Make const0 cheap then. */
5557 *total = 1 - reload_completed;
5558 else
5559 *total = 0;
5560 return true;
5562 case ROTATE:
5563 case ROTATERT:
5564 case ASHIFT:
5565 case LSHIFTRT:
5566 case ASHIFTRT:
5567 case MINUS:
5568 case PLUS:
5569 case AND:
5570 case XOR:
5571 case IOR:
5572 case UDIV:
5573 case DIV:
5574 case MOD:
5575 case MULT:
5576 case NEG:
5577 case SIGN_EXTEND:
5578 case NOT:
5579 case COMPARE:
5580 case ZERO_EXTEND:
5581 case IF_THEN_ELSE:
5582 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5583 return true;
5585 default:
5586 return false;
5591 static void
5592 m68hc11_file_start (void)
5594 default_file_start ();
5596 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5600 static void
5601 m68hc11_asm_out_constructor (rtx symbol, int priority)
5603 default_ctor_section_asm_out_constructor (symbol, priority);
5604 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5607 static void
5608 m68hc11_asm_out_destructor (rtx symbol, int priority)
5610 default_dtor_section_asm_out_destructor (symbol, priority);
5611 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5614 #include "gt-m68hc11.h"