* config/darwin-c.c, config/arc/arc.c, config/arc/arc.md,
[official-gcc.git] / gcc / config / m68hc11 / m68hc11.c
blob651c642d953f4a10da99afea5bc2971cd888f5ac
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 const char *m68hc11_strip_name_encoding (const char* str);
88 static unsigned int m68hc11_section_type_flags (tree, const char*, int);
89 static int autoinc_mode (rtx);
90 static int m68hc11_make_autoinc_notes (rtx *, void *);
91 static void m68hc11_init_libfuncs (void);
92 static rtx m68hc11_struct_value_rtx (tree, int);
93 static bool m68hc11_return_in_memory (tree, tree);
95 /* Must be set to 1 to produce debug messages. */
96 int debug_m6811 = 0;
98 extern FILE *asm_out_file;
100 rtx ix_reg;
101 rtx iy_reg;
102 rtx d_reg;
103 rtx m68hc11_soft_tmp_reg;
104 static GTY(()) rtx stack_push_word;
105 static GTY(()) rtx stack_pop_word;
106 static GTY(()) rtx z_reg;
107 static GTY(()) rtx z_reg_qi;
108 static int regs_inited = 0;
110 /* Set to 1 by expand_prologue() when the function is an interrupt handler. */
111 int current_function_interrupt;
113 /* Set to 1 by expand_prologue() when the function is a trap handler. */
114 int current_function_trap;
116 /* Set to 1 when the current function is placed in 68HC12 banked
117 memory and must return with rtc. */
118 int current_function_far;
120 /* Min offset that is valid for the indirect addressing mode. */
121 HOST_WIDE_INT m68hc11_min_offset = 0;
123 /* Max offset that is valid for the indirect addressing mode. */
124 HOST_WIDE_INT m68hc11_max_offset = 256;
126 /* The class value for base registers. */
127 enum reg_class m68hc11_base_reg_class = A_REGS;
129 /* The class value for index registers. This is NO_REGS for 68HC11. */
130 enum reg_class m68hc11_index_reg_class = NO_REGS;
132 enum reg_class m68hc11_tmp_regs_class = NO_REGS;
134 /* Tables that tell whether a given hard register is valid for
135 a base or an index register. It is filled at init time depending
136 on the target processor. */
137 unsigned char m68hc11_reg_valid_for_base[FIRST_PSEUDO_REGISTER];
138 unsigned char m68hc11_reg_valid_for_index[FIRST_PSEUDO_REGISTER];
140 /* A correction offset which is applied to the stack pointer.
141 This is 1 for 68HC11 and 0 for 68HC12. */
142 int m68hc11_sp_correction;
144 #define ADDR_STRICT 0x01 /* Accept only registers in class A_REGS */
145 #define ADDR_INCDEC 0x02 /* Post/Pre inc/dec */
146 #define ADDR_INDEXED 0x04 /* D-reg index */
147 #define ADDR_OFFSET 0x08
148 #define ADDR_INDIRECT 0x10 /* Accept (mem (mem ...)) for [n,X] */
149 #define ADDR_CONST 0x20 /* Accept const and symbol_ref */
151 int m68hc11_addr_mode;
152 int m68hc11_mov_addr_mode;
154 /* Comparison operands saved by the "tstxx" and "cmpxx" expand patterns. */
155 rtx m68hc11_compare_op0;
156 rtx m68hc11_compare_op1;
159 const struct processor_costs *m68hc11_cost;
161 /* Costs for a 68HC11. */
162 static const struct processor_costs m6811_cost = {
163 /* add */
164 COSTS_N_INSNS (2),
165 /* logical */
166 COSTS_N_INSNS (2),
167 /* non-constant shift */
168 COSTS_N_INSNS (20),
169 /* shiftQI const */
170 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
171 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
172 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
174 /* shiftHI const */
175 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
176 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
177 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
178 COSTS_N_INSNS (2), COSTS_N_INSNS (4),
179 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (10),
180 COSTS_N_INSNS (8), COSTS_N_INSNS (6), COSTS_N_INSNS (4)
182 /* mulQI */
183 COSTS_N_INSNS (20),
184 /* mulHI */
185 COSTS_N_INSNS (20 * 4),
186 /* mulSI */
187 COSTS_N_INSNS (20 * 16),
188 /* divQI */
189 COSTS_N_INSNS (20),
190 /* divHI */
191 COSTS_N_INSNS (80),
192 /* divSI */
193 COSTS_N_INSNS (100)
196 /* Costs for a 68HC12. */
197 static const struct processor_costs m6812_cost = {
198 /* add */
199 COSTS_N_INSNS (2),
200 /* logical */
201 COSTS_N_INSNS (2),
202 /* non-constant shift */
203 COSTS_N_INSNS (20),
204 /* shiftQI const */
205 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (2),
206 COSTS_N_INSNS (3), COSTS_N_INSNS (4), COSTS_N_INSNS (3),
207 COSTS_N_INSNS (2), COSTS_N_INSNS (1) },
209 /* shiftHI const */
210 { COSTS_N_INSNS (0), COSTS_N_INSNS (1), COSTS_N_INSNS (4),
211 COSTS_N_INSNS (6), COSTS_N_INSNS (8), COSTS_N_INSNS (6),
212 COSTS_N_INSNS (4), COSTS_N_INSNS (2),
213 COSTS_N_INSNS (2), COSTS_N_INSNS (4), COSTS_N_INSNS (6),
214 COSTS_N_INSNS (8), COSTS_N_INSNS (10), COSTS_N_INSNS (8),
215 COSTS_N_INSNS (6), COSTS_N_INSNS (4)
217 /* mulQI */
218 COSTS_N_INSNS (3),
219 /* mulHI */
220 COSTS_N_INSNS (3),
221 /* mulSI */
222 COSTS_N_INSNS (3 * 4),
223 /* divQI */
224 COSTS_N_INSNS (12),
225 /* divHI */
226 COSTS_N_INSNS (12),
227 /* divSI */
228 COSTS_N_INSNS (100)
231 /* Machine specific options */
233 const char *m68hc11_regparm_string;
234 const char *m68hc11_reg_alloc_order;
235 const char *m68hc11_soft_reg_count;
237 static int nb_soft_regs;
239 /* Initialize the GCC target structure. */
240 #undef TARGET_ATTRIBUTE_TABLE
241 #define TARGET_ATTRIBUTE_TABLE m68hc11_attribute_table
243 #undef TARGET_ASM_ALIGNED_HI_OP
244 #define TARGET_ASM_ALIGNED_HI_OP "\t.word\t"
246 #undef TARGET_ASM_FUNCTION_EPILOGUE
247 #define TARGET_ASM_FUNCTION_EPILOGUE m68hc11_output_function_epilogue
249 #undef TARGET_ASM_FILE_START
250 #define TARGET_ASM_FILE_START m68hc11_file_start
251 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
252 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
254 #undef TARGET_ENCODE_SECTION_INFO
255 #define TARGET_ENCODE_SECTION_INFO m68hc11_encode_section_info
257 #undef TARGET_SECTION_TYPE_FLAGS
258 #define TARGET_SECTION_TYPE_FLAGS m68hc11_section_type_flags
260 #undef TARGET_RTX_COSTS
261 #define TARGET_RTX_COSTS m68hc11_rtx_costs
262 #undef TARGET_ADDRESS_COST
263 #define TARGET_ADDRESS_COST m68hc11_address_cost
265 #undef TARGET_MACHINE_DEPENDENT_REORG
266 #define TARGET_MACHINE_DEPENDENT_REORG m68hc11_reorg
268 #undef TARGET_INIT_LIBFUNCS
269 #define TARGET_INIT_LIBFUNCS m68hc11_init_libfuncs
271 #undef TARGET_STRUCT_VALUE_RTX
272 #define TARGET_STRUCT_VALUE_RTX m68hc11_struct_value_rtx
273 #undef TARGET_RETURN_IN_MEMORY
274 #define TARGET_RETURN_IN_MEMORY m68hc11_return_in_memory
275 #undef TARGET_CALLEE_COPIES
276 #define TARGET_CALLEE_COPIES hook_callee_copies_named
278 #undef TARGET_STRIP_NAME_ENCODING
279 #define TARGET_STRIP_NAME_ENCODING m68hc11_strip_name_encoding
281 struct gcc_target targetm = TARGET_INITIALIZER;
284 m68hc11_override_options (void)
286 memset (m68hc11_reg_valid_for_index, 0,
287 sizeof (m68hc11_reg_valid_for_index));
288 memset (m68hc11_reg_valid_for_base, 0, sizeof (m68hc11_reg_valid_for_base));
290 /* Compilation with -fpic generates a wrong code. */
291 if (flag_pic)
293 warning ("-f%s ignored for 68HC11/68HC12 (not supported)",
294 (flag_pic > 1) ? "PIC" : "pic");
295 flag_pic = 0;
298 /* Do not enable -fweb because it breaks the 32-bit shift patterns
299 by breaking the match_dup of those patterns. The shift patterns
300 will no longer be recognized after that. */
301 flag_web = 0;
303 /* Configure for a 68hc11 processor. */
304 if (TARGET_M6811)
306 /* If gcc was built for a 68hc12, invalidate that because
307 a -m68hc11 option was specified on the command line. */
308 if (TARGET_DEFAULT != MASK_M6811)
309 target_flags &= ~TARGET_DEFAULT;
311 if (!TARGET_M6812)
312 target_flags &= ~(TARGET_AUTO_INC_DEC | TARGET_MIN_MAX);
313 m68hc11_cost = &m6811_cost;
314 m68hc11_min_offset = 0;
315 m68hc11_max_offset = 256;
316 m68hc11_index_reg_class = NO_REGS;
317 m68hc11_base_reg_class = A_REGS;
318 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
319 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
320 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
321 m68hc11_sp_correction = 1;
322 m68hc11_tmp_regs_class = D_REGS;
323 m68hc11_addr_mode = ADDR_OFFSET;
324 m68hc11_mov_addr_mode = 0;
325 if (m68hc11_soft_reg_count == 0 && !TARGET_M6812)
326 m68hc11_soft_reg_count = "4";
329 /* Configure for a 68hc12 processor. */
330 if (TARGET_M6812)
332 m68hc11_cost = &m6812_cost;
333 m68hc11_min_offset = -65536;
334 m68hc11_max_offset = 65536;
335 m68hc11_index_reg_class = D_REGS;
336 m68hc11_base_reg_class = A_OR_SP_REGS;
337 m68hc11_reg_valid_for_base[HARD_X_REGNUM] = 1;
338 m68hc11_reg_valid_for_base[HARD_Y_REGNUM] = 1;
339 m68hc11_reg_valid_for_base[HARD_Z_REGNUM] = 1;
340 m68hc11_reg_valid_for_base[HARD_SP_REGNUM] = 1;
341 m68hc11_reg_valid_for_index[HARD_D_REGNUM] = 1;
342 m68hc11_sp_correction = 0;
343 m68hc11_tmp_regs_class = TMP_REGS;
344 m68hc11_addr_mode = ADDR_INDIRECT | ADDR_OFFSET | ADDR_CONST
345 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
346 m68hc11_mov_addr_mode = ADDR_OFFSET | ADDR_CONST
347 | (TARGET_AUTO_INC_DEC ? ADDR_INCDEC : 0);
348 target_flags &= ~MASK_M6811;
349 target_flags |= MASK_NO_DIRECT_MODE;
350 if (m68hc11_soft_reg_count == 0)
351 m68hc11_soft_reg_count = "0";
353 if (TARGET_LONG_CALLS)
354 current_function_far = 1;
356 return 0;
360 void
361 m68hc11_conditional_register_usage (void)
363 int i;
364 int cnt = atoi (m68hc11_soft_reg_count);
366 if (cnt < 0)
367 cnt = 0;
368 if (cnt > SOFT_REG_LAST - SOFT_REG_FIRST)
369 cnt = SOFT_REG_LAST - SOFT_REG_FIRST;
371 nb_soft_regs = cnt;
372 for (i = SOFT_REG_FIRST + cnt; i < SOFT_REG_LAST; i++)
374 fixed_regs[i] = 1;
375 call_used_regs[i] = 1;
378 /* For 68HC12, the Z register emulation is not necessary when the
379 frame pointer is not used. The frame pointer is eliminated and
380 replaced by the stack register (which is a BASE_REG_CLASS). */
381 if (TARGET_M6812 && flag_omit_frame_pointer && optimize)
383 fixed_regs[HARD_Z_REGNUM] = 1;
388 /* Reload and register operations. */
390 static const char *const reg_class_names[] = REG_CLASS_NAMES;
393 void
394 create_regs_rtx (void)
396 /* regs_inited = 1; */
397 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
398 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
399 d_reg = gen_rtx_REG (HImode, HARD_D_REGNUM);
400 m68hc11_soft_tmp_reg = gen_rtx_REG (HImode, SOFT_TMP_REGNUM);
402 stack_push_word = gen_rtx_MEM (HImode,
403 gen_rtx_PRE_DEC (HImode,
404 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
405 stack_pop_word = gen_rtx_MEM (HImode,
406 gen_rtx_POST_INC (HImode,
407 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
411 /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
412 - 8 bit values are stored anywhere (except the SP register).
413 - 16 bit values can be stored in any register whose mode is 16
414 - 32 bit values can be stored in D, X registers or in a soft register
415 (except the last one because we need 2 soft registers)
416 - Values whose size is > 32 bit are not stored in real hard
417 registers. They may be stored in soft registers if there are
418 enough of them. */
420 hard_regno_mode_ok (int regno, enum machine_mode mode)
422 switch (GET_MODE_SIZE (mode))
424 case 8:
425 return S_REGNO_P (regno) && nb_soft_regs >= 4;
427 case 4:
428 return X_REGNO_P (regno) || (S_REGNO_P (regno) && nb_soft_regs >= 2);
430 case 2:
431 return G_REGNO_P (regno);
433 case 1:
434 /* We have to accept a QImode in X or Y registers. Otherwise, the
435 reload pass will fail when some (SUBREG:QI (REG:HI X)) are defined
436 in the insns. Reload fails if the insn rejects the register class 'a'
437 as well as if it accepts it. Patterns that failed were
438 zero_extend_qihi2 and iorqi3. */
440 return G_REGNO_P (regno) && !SP_REGNO_P (regno);
442 default:
443 return 0;
448 m68hc11_hard_regno_rename_ok (int reg1, int reg2)
450 /* Don't accept renaming to Z register. We will replace it to
451 X,Y or D during machine reorg pass. */
452 if (reg2 == HARD_Z_REGNUM)
453 return 0;
455 /* Don't accept renaming D,X to Y register as the code will be bigger. */
456 if (TARGET_M6811 && reg2 == HARD_Y_REGNUM
457 && (D_REGNO_P (reg1) || X_REGNO_P (reg1)))
458 return 0;
460 return 1;
463 enum reg_class
464 preferred_reload_class (rtx operand, enum reg_class class)
466 enum machine_mode mode;
468 mode = GET_MODE (operand);
470 if (debug_m6811)
472 printf ("Preferred reload: (class=%s): ", reg_class_names[class]);
475 if (class == D_OR_A_OR_S_REGS && SP_REG_P (operand))
476 return m68hc11_base_reg_class;
478 if (class >= S_REGS && (GET_CODE (operand) == MEM
479 || GET_CODE (operand) == CONST_INT))
481 /* S_REGS class must not be used. The movhi template does not
482 work to move a memory to a soft register.
483 Restrict to a hard reg. */
484 switch (class)
486 default:
487 case G_REGS:
488 case D_OR_A_OR_S_REGS:
489 class = A_OR_D_REGS;
490 break;
491 case A_OR_S_REGS:
492 class = A_REGS;
493 break;
494 case D_OR_SP_OR_S_REGS:
495 class = D_OR_SP_REGS;
496 break;
497 case D_OR_Y_OR_S_REGS:
498 class = D_OR_Y_REGS;
499 break;
500 case D_OR_X_OR_S_REGS:
501 class = D_OR_X_REGS;
502 break;
503 case SP_OR_S_REGS:
504 class = SP_REGS;
505 break;
506 case Y_OR_S_REGS:
507 class = Y_REGS;
508 break;
509 case X_OR_S_REGS:
510 class = X_REGS;
511 break;
512 case D_OR_S_REGS:
513 class = D_REGS;
516 else if (class == Y_REGS && GET_CODE (operand) == MEM)
518 class = Y_REGS;
520 else if (class == A_OR_D_REGS && GET_MODE_SIZE (mode) == 4)
522 class = D_OR_X_REGS;
524 else if (class >= S_REGS && S_REG_P (operand))
526 switch (class)
528 default:
529 case G_REGS:
530 case D_OR_A_OR_S_REGS:
531 class = A_OR_D_REGS;
532 break;
533 case A_OR_S_REGS:
534 class = A_REGS;
535 break;
536 case D_OR_SP_OR_S_REGS:
537 class = D_OR_SP_REGS;
538 break;
539 case D_OR_Y_OR_S_REGS:
540 class = D_OR_Y_REGS;
541 break;
542 case D_OR_X_OR_S_REGS:
543 class = D_OR_X_REGS;
544 break;
545 case SP_OR_S_REGS:
546 class = SP_REGS;
547 break;
548 case Y_OR_S_REGS:
549 class = Y_REGS;
550 break;
551 case X_OR_S_REGS:
552 class = X_REGS;
553 break;
554 case D_OR_S_REGS:
555 class = D_REGS;
558 else if (class >= S_REGS)
560 if (debug_m6811)
562 printf ("Class = %s for: ", reg_class_names[class]);
563 fflush (stdout);
564 debug_rtx (operand);
568 if (debug_m6811)
570 printf (" => class=%s\n", reg_class_names[class]);
571 fflush (stdout);
572 debug_rtx (operand);
575 return class;
578 /* Return 1 if the operand is a valid indexed addressing mode.
579 For 68hc11: n,r with n in [0..255] and r in A_REGS class
580 For 68hc12: n,r no constraint on the constant, r in A_REGS class. */
581 static int
582 register_indirect_p (rtx operand, enum machine_mode mode, int addr_mode)
584 rtx base, offset;
586 switch (GET_CODE (operand))
588 case MEM:
589 if ((addr_mode & ADDR_INDIRECT) && GET_MODE_SIZE (mode) <= 2)
590 return register_indirect_p (XEXP (operand, 0), mode,
591 addr_mode & (ADDR_STRICT | ADDR_OFFSET));
592 return 0;
594 case POST_INC:
595 case PRE_INC:
596 case POST_DEC:
597 case PRE_DEC:
598 if (addr_mode & ADDR_INCDEC)
599 return register_indirect_p (XEXP (operand, 0), mode,
600 addr_mode & ADDR_STRICT);
601 return 0;
603 case PLUS:
604 base = XEXP (operand, 0);
605 if (GET_CODE (base) == MEM)
606 return 0;
608 offset = XEXP (operand, 1);
609 if (GET_CODE (offset) == MEM)
610 return 0;
612 /* Indexed addressing mode with 2 registers. */
613 if (GET_CODE (base) == REG && GET_CODE (offset) == REG)
615 if (!(addr_mode & ADDR_INDEXED))
616 return 0;
618 addr_mode &= ADDR_STRICT;
619 if (REGNO_OK_FOR_BASE_P2 (REGNO (base), addr_mode)
620 && REGNO_OK_FOR_INDEX_P2 (REGNO (offset), addr_mode))
621 return 1;
623 if (REGNO_OK_FOR_BASE_P2 (REGNO (offset), addr_mode)
624 && REGNO_OK_FOR_INDEX_P2 (REGNO (base), addr_mode))
625 return 1;
627 return 0;
630 if (!(addr_mode & ADDR_OFFSET))
631 return 0;
633 if (GET_CODE (base) == REG)
635 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
636 return 0;
638 if (!(addr_mode & ADDR_STRICT))
639 return 1;
641 return REGNO_OK_FOR_BASE_P2 (REGNO (base), 1);
644 if (GET_CODE (offset) == REG)
646 if (!VALID_CONSTANT_OFFSET_P (base, mode))
647 return 0;
649 if (!(addr_mode & ADDR_STRICT))
650 return 1;
652 return REGNO_OK_FOR_BASE_P2 (REGNO (offset), 1);
654 return 0;
656 case REG:
657 return REGNO_OK_FOR_BASE_P2 (REGNO (operand), addr_mode & ADDR_STRICT);
659 case CONST_INT:
660 if (addr_mode & ADDR_CONST)
661 return VALID_CONSTANT_OFFSET_P (operand, mode);
662 return 0;
664 default:
665 return 0;
669 /* Returns 1 if the operand fits in a 68HC11 indirect mode or in
670 a 68HC12 1-byte index addressing mode. */
672 m68hc11_small_indexed_indirect_p (rtx operand, enum machine_mode mode)
674 rtx base, offset;
675 int addr_mode;
677 if (GET_CODE (operand) == REG && reload_in_progress
678 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
679 && reg_equiv_memory_loc[REGNO (operand)])
681 operand = reg_equiv_memory_loc[REGNO (operand)];
682 operand = eliminate_regs (operand, 0, NULL_RTX);
685 if (GET_CODE (operand) != MEM)
686 return 0;
688 operand = XEXP (operand, 0);
689 if (CONSTANT_ADDRESS_P (operand))
690 return 1;
692 if (PUSH_POP_ADDRESS_P (operand))
693 return 1;
695 addr_mode = m68hc11_mov_addr_mode | (reload_completed ? ADDR_STRICT : 0);
696 if (!register_indirect_p (operand, mode, addr_mode))
697 return 0;
699 if (TARGET_M6812 && GET_CODE (operand) == PLUS
700 && (reload_completed | reload_in_progress))
702 base = XEXP (operand, 0);
703 offset = XEXP (operand, 1);
705 /* The offset can be a symbol address and this is too big
706 for the operand constraint. */
707 if (GET_CODE (base) != CONST_INT && GET_CODE (offset) != CONST_INT)
708 return 0;
710 if (GET_CODE (base) == CONST_INT)
711 offset = base;
713 switch (GET_MODE_SIZE (mode))
715 case 8:
716 if (INTVAL (offset) < -16 + 6 || INTVAL (offset) > 15 - 6)
717 return 0;
718 break;
720 case 4:
721 if (INTVAL (offset) < -16 + 2 || INTVAL (offset) > 15 - 2)
722 return 0;
723 break;
725 default:
726 if (INTVAL (offset) < -16 || INTVAL (offset) > 15)
727 return 0;
728 break;
731 return 1;
735 m68hc11_register_indirect_p (rtx operand, enum machine_mode mode)
737 int addr_mode;
739 if (GET_CODE (operand) == REG && reload_in_progress
740 && REGNO (operand) >= FIRST_PSEUDO_REGISTER
741 && reg_equiv_memory_loc[REGNO (operand)])
743 operand = reg_equiv_memory_loc[REGNO (operand)];
744 operand = eliminate_regs (operand, 0, NULL_RTX);
746 if (GET_CODE (operand) != MEM)
747 return 0;
749 operand = XEXP (operand, 0);
750 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
751 return register_indirect_p (operand, mode, addr_mode);
754 static int
755 go_if_legitimate_address_internal (rtx operand, enum machine_mode mode,
756 int strict)
758 int addr_mode;
760 if (CONSTANT_ADDRESS_P (operand) && TARGET_M6812)
762 /* Reject the global variables if they are too wide. This forces
763 a load of their address in a register and generates smaller code. */
764 if (GET_MODE_SIZE (mode) == 8)
765 return 0;
767 return 1;
769 addr_mode = m68hc11_addr_mode | (strict ? ADDR_STRICT : 0);
770 if (register_indirect_p (operand, mode, addr_mode))
772 return 1;
774 if (PUSH_POP_ADDRESS_P (operand))
776 return 1;
778 if (symbolic_memory_operand (operand, mode))
780 return 1;
782 return 0;
786 m68hc11_go_if_legitimate_address (rtx operand, enum machine_mode mode,
787 int strict)
789 int result;
791 if (debug_m6811)
793 printf ("Checking: ");
794 fflush (stdout);
795 debug_rtx (operand);
798 result = go_if_legitimate_address_internal (operand, mode, strict);
800 if (debug_m6811)
802 printf (" -> %s\n", result == 0 ? "NO" : "YES");
805 if (result == 0)
807 if (debug_m6811)
809 printf ("go_if_legitimate%s, ret 0: %d:",
810 (strict ? "_strict" : ""), mode);
811 fflush (stdout);
812 debug_rtx (operand);
815 return result;
819 m68hc11_legitimize_address (rtx *operand ATTRIBUTE_UNUSED,
820 rtx old_operand ATTRIBUTE_UNUSED,
821 enum machine_mode mode ATTRIBUTE_UNUSED)
823 return 0;
828 m68hc11_reload_operands (rtx operands[])
830 enum machine_mode mode;
832 if (regs_inited == 0)
833 create_regs_rtx ();
835 mode = GET_MODE (operands[1]);
837 /* Input reload of indirect addressing (MEM (PLUS (REG) (CONST))). */
838 if (A_REG_P (operands[0]) && memory_reload_operand (operands[1], mode))
840 rtx big_offset = XEXP (XEXP (operands[1], 0), 1);
841 rtx base = XEXP (XEXP (operands[1], 0), 0);
843 if (GET_CODE (base) != REG)
845 rtx tmp = base;
846 base = big_offset;
847 big_offset = tmp;
850 /* If the offset is out of range, we have to compute the address
851 with a separate add instruction. We try to do with with an 8-bit
852 add on the A register. This is possible only if the lowest part
853 of the offset (i.e., big_offset % 256) is a valid constant offset
854 with respect to the mode. If it's not, we have to generate a
855 16-bit add on the D register. From:
857 (SET (REG X (MEM (PLUS (REG X) (CONST_INT 1000)))))
859 we generate:
861 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
862 (SET (REG A) (PLUS (REG A) (CONST_INT 1000 / 256)))
863 [(SET (REG D) (REG X)) (SET (REG X) (REG D))]
864 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256)))
866 (SET (REG X) (PLUS (REG X) (CONST_INT 1000 / 256 * 256)))
867 (SET (REG X) (MEM (PLUS (REG X) (CONST_INT 1000 % 256))))
870 if (!VALID_CONSTANT_OFFSET_P (big_offset, mode))
872 int vh, vl;
873 rtx reg = operands[0];
874 rtx offset;
875 int val = INTVAL (big_offset);
878 /* We use the 'operands[0]' as a scratch register to compute the
879 address. Make sure 'base' is in that register. */
880 if (!rtx_equal_p (base, operands[0]))
882 emit_move_insn (reg, base);
885 if (val > 0)
887 vh = val >> 8;
888 vl = val & 0x0FF;
890 else
892 vh = (val >> 8) & 0x0FF;
893 vl = val & 0x0FF;
896 /* Create the lowest part offset that still remains to be added.
897 If it's not a valid offset, do a 16-bit add. */
898 offset = GEN_INT (vl);
899 if (!VALID_CONSTANT_OFFSET_P (offset, mode))
901 emit_insn (gen_rtx_SET (VOIDmode, reg,
902 gen_rtx_PLUS (HImode, reg, big_offset)));
903 offset = const0_rtx;
905 else
907 emit_insn (gen_rtx_SET (VOIDmode, reg,
908 gen_rtx_PLUS (HImode, reg,
909 GEN_INT (vh << 8))));
911 emit_move_insn (operands[0],
912 gen_rtx_MEM (GET_MODE (operands[1]),
913 gen_rtx_PLUS (Pmode, reg, offset)));
914 return 1;
918 /* Use the normal gen_movhi pattern. */
919 return 0;
922 void
923 m68hc11_emit_libcall (const char *name, enum rtx_code code,
924 enum machine_mode dmode, enum machine_mode smode,
925 int noperands, rtx *operands)
927 rtx ret;
928 rtx insns;
929 rtx libcall;
930 rtx equiv;
932 start_sequence ();
933 libcall = gen_rtx_SYMBOL_REF (Pmode, name);
934 switch (noperands)
936 case 2:
937 ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
938 dmode, 1, operands[1], smode);
939 equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
940 break;
942 case 3:
943 ret = emit_library_call_value (libcall, NULL_RTX,
944 LCT_CONST, dmode, 2,
945 operands[1], smode, operands[2],
946 smode);
947 equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
948 break;
950 default:
951 abort ();
954 insns = get_insns ();
955 end_sequence ();
956 emit_libcall_block (insns, operands[0], ret, equiv);
959 /* Returns true if X is a PRE/POST increment decrement
960 (same as auto_inc_p() in rtlanal.c but do not take into
961 account the stack). */
962 static int
963 m68hc11_auto_inc_p (rtx x)
965 return GET_CODE (x) == PRE_DEC
966 || GET_CODE (x) == POST_INC
967 || GET_CODE (x) == POST_DEC || GET_CODE (x) == PRE_INC;
971 /* Predicates for machine description. */
974 memory_reload_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
976 return GET_CODE (operand) == MEM
977 && GET_CODE (XEXP (operand, 0)) == PLUS
978 && ((GET_CODE (XEXP (XEXP (operand, 0), 0)) == REG
979 && GET_CODE (XEXP (XEXP (operand, 0), 1)) == CONST_INT)
980 || (GET_CODE (XEXP (XEXP (operand, 0), 1)) == REG
981 && GET_CODE (XEXP (XEXP (operand, 0), 0)) == CONST_INT));
985 tst_operand (rtx operand, enum machine_mode mode)
987 if (GET_CODE (operand) == MEM && reload_completed == 0)
989 rtx addr = XEXP (operand, 0);
990 if (m68hc11_auto_inc_p (addr))
991 return 0;
993 return nonimmediate_operand (operand, mode);
997 cmp_operand (rtx operand, enum machine_mode mode)
999 if (GET_CODE (operand) == MEM)
1001 rtx addr = XEXP (operand, 0);
1002 if (m68hc11_auto_inc_p (addr))
1003 return 0;
1005 return general_operand (operand, mode);
1009 non_push_operand (rtx operand, enum machine_mode mode)
1011 if (general_operand (operand, mode) == 0)
1012 return 0;
1014 if (push_operand (operand, mode) == 1)
1015 return 0;
1016 return 1;
1020 splitable_operand (rtx operand, enum machine_mode mode)
1022 if (general_operand (operand, mode) == 0)
1023 return 0;
1025 if (push_operand (operand, mode) == 1)
1026 return 0;
1028 /* Reject a (MEM (MEM X)) because the patterns that use non_push_operand
1029 need to split such addresses to access the low and high part but it
1030 is not possible to express a valid address for the low part. */
1031 if (mode != QImode && GET_CODE (operand) == MEM
1032 && GET_CODE (XEXP (operand, 0)) == MEM)
1033 return 0;
1034 return 1;
1038 reg_or_some_mem_operand (rtx operand, enum machine_mode mode)
1040 if (GET_CODE (operand) == MEM)
1042 rtx op = XEXP (operand, 0);
1044 if (symbolic_memory_operand (op, mode))
1045 return 1;
1047 if (IS_STACK_PUSH (operand))
1048 return 1;
1050 if (m68hc11_register_indirect_p (operand, mode))
1051 return 1;
1053 return 0;
1056 return register_operand (operand, mode);
1060 m68hc11_symbolic_p (rtx operand, enum machine_mode mode)
1062 if (GET_CODE (operand) == MEM)
1064 rtx op = XEXP (operand, 0);
1066 if (symbolic_memory_operand (op, mode))
1067 return 1;
1069 return 0;
1073 m68hc11_indirect_p (rtx operand, enum machine_mode mode)
1075 if (GET_CODE (operand) == MEM && GET_MODE (operand) == mode)
1077 rtx op = XEXP (operand, 0);
1078 int addr_mode;
1080 if (m68hc11_page0_symbol_p (op))
1081 return 1;
1083 if (symbolic_memory_operand (op, mode))
1084 return TARGET_M6812;
1086 if (reload_in_progress)
1087 return 1;
1089 operand = XEXP (operand, 0);
1090 addr_mode = m68hc11_addr_mode | (reload_completed ? ADDR_STRICT : 0);
1091 return register_indirect_p (operand, mode, addr_mode);
1093 return 0;
1097 stack_register_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1099 return SP_REG_P (operand);
1103 d_register_operand (rtx operand, enum machine_mode mode)
1105 if (GET_MODE (operand) != mode && mode != VOIDmode)
1106 return 0;
1108 if (GET_CODE (operand) == SUBREG)
1109 operand = XEXP (operand, 0);
1111 return GET_CODE (operand) == REG
1112 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1113 || REGNO (operand) == HARD_D_REGNUM
1114 || (mode == QImode && REGNO (operand) == HARD_B_REGNUM));
1118 hard_addr_reg_operand (rtx operand, enum machine_mode mode)
1120 if (GET_MODE (operand) != mode && mode != VOIDmode)
1121 return 0;
1123 if (GET_CODE (operand) == SUBREG)
1124 operand = XEXP (operand, 0);
1126 return GET_CODE (operand) == REG
1127 && (REGNO (operand) == HARD_X_REGNUM
1128 || REGNO (operand) == HARD_Y_REGNUM
1129 || REGNO (operand) == HARD_Z_REGNUM);
1133 hard_reg_operand (rtx operand, enum machine_mode mode)
1135 if (GET_MODE (operand) != mode && mode != VOIDmode)
1136 return 0;
1138 if (GET_CODE (operand) == SUBREG)
1139 operand = XEXP (operand, 0);
1141 return GET_CODE (operand) == REG
1142 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1143 || H_REGNO_P (REGNO (operand)));
1147 memory_indexed_operand (rtx operand, enum machine_mode mode ATTRIBUTE_UNUSED)
1149 if (GET_CODE (operand) != MEM)
1150 return 0;
1152 operand = XEXP (operand, 0);
1153 if (GET_CODE (operand) == PLUS)
1155 if (GET_CODE (XEXP (operand, 0)) == REG)
1156 operand = XEXP (operand, 0);
1157 else if (GET_CODE (XEXP (operand, 1)) == REG)
1158 operand = XEXP (operand, 1);
1160 return GET_CODE (operand) == REG
1161 && (REGNO (operand) >= FIRST_PSEUDO_REGISTER
1162 || A_REGNO_P (REGNO (operand)));
1166 push_pop_operand_p (rtx operand)
1168 if (GET_CODE (operand) != MEM)
1170 return 0;
1172 operand = XEXP (operand, 0);
1173 return PUSH_POP_ADDRESS_P (operand);
1176 /* Returns 1 if OP is either a symbol reference or a sum of a symbol
1177 reference and a constant. */
1180 symbolic_memory_operand (rtx op, enum machine_mode mode)
1182 switch (GET_CODE (op))
1184 case SYMBOL_REF:
1185 case LABEL_REF:
1186 return 1;
1188 case CONST:
1189 op = XEXP (op, 0);
1190 return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
1191 || GET_CODE (XEXP (op, 0)) == LABEL_REF)
1192 && GET_CODE (XEXP (op, 1)) == CONST_INT);
1194 /* ??? This clause seems to be irrelevant. */
1195 case CONST_DOUBLE:
1196 return GET_MODE (op) == mode;
1198 case PLUS:
1199 return symbolic_memory_operand (XEXP (op, 0), mode)
1200 && symbolic_memory_operand (XEXP (op, 1), mode);
1202 default:
1203 return 0;
1208 m68hc11_eq_compare_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1210 return GET_CODE (op) == EQ || GET_CODE (op) == NE;
1214 m68hc11_logical_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1216 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
1220 m68hc11_arith_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1222 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1223 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS
1224 || GET_CODE (op) == ASHIFT || GET_CODE (op) == ASHIFTRT
1225 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ROTATE
1226 || GET_CODE (op) == ROTATERT;
1230 m68hc11_non_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1232 return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR
1233 || GET_CODE (op) == PLUS || GET_CODE (op) == MINUS;
1236 /* Return true if op is a shift operator. */
1238 m68hc11_shift_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1240 return GET_CODE (op) == ROTATE || GET_CODE (op) == ROTATERT
1241 || GET_CODE (op) == LSHIFTRT || GET_CODE (op) == ASHIFT
1242 || GET_CODE (op) == ASHIFTRT;
1246 m68hc11_unary_operator (rtx op, enum machine_mode mode ATTRIBUTE_UNUSED)
1248 return GET_CODE (op) == NEG || GET_CODE (op) == NOT
1249 || GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND;
1252 /* Emit the code to build the trampoline used to call a nested function.
1254 68HC11 68HC12
1256 ldy #&CXT movw #&CXT,*_.d1
1257 sty *_.d1 jmp FNADDR
1258 jmp FNADDR
1261 void
1262 m68hc11_initialize_trampoline (rtx tramp, rtx fnaddr, rtx cxt)
1264 const char *static_chain_reg = reg_names[STATIC_CHAIN_REGNUM];
1266 /* Skip the '*'. */
1267 if (*static_chain_reg == '*')
1268 static_chain_reg++;
1269 if (TARGET_M6811)
1271 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x18ce));
1272 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1273 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1274 GEN_INT (0x18df));
1275 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1276 gen_rtx_CONST (QImode,
1277 gen_rtx_SYMBOL_REF (Pmode,
1278 static_chain_reg)));
1279 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 7)),
1280 GEN_INT (0x7e));
1281 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 8)), fnaddr);
1283 else
1285 emit_move_insn (gen_rtx_MEM (HImode, tramp), GEN_INT (0x1803));
1286 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 2)), cxt);
1287 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 4)),
1288 gen_rtx_CONST (HImode,
1289 gen_rtx_SYMBOL_REF (Pmode,
1290 static_chain_reg)));
1291 emit_move_insn (gen_rtx_MEM (QImode, plus_constant (tramp, 6)),
1292 GEN_INT (0x06));
1293 emit_move_insn (gen_rtx_MEM (HImode, plus_constant (tramp, 7)), fnaddr);
1297 /* Declaration of types. */
1299 /* Handle an "tiny_data" attribute; arguments as in
1300 struct attribute_spec.handler. */
1301 static tree
1302 m68hc11_handle_page0_attribute (tree *node, tree name,
1303 tree args ATTRIBUTE_UNUSED,
1304 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
1306 tree decl = *node;
1308 if (TREE_STATIC (decl) || DECL_EXTERNAL (decl))
1310 DECL_SECTION_NAME (decl) = build_string (6, ".page0");
1312 else
1314 warning ("`%s' attribute ignored", IDENTIFIER_POINTER (name));
1315 *no_add_attrs = true;
1318 return NULL_TREE;
1321 const struct attribute_spec m68hc11_attribute_table[] =
1323 /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
1324 { "interrupt", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1325 { "trap", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1326 { "far", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1327 { "near", 0, 0, false, true, true, m68hc11_handle_fntype_attribute },
1328 { "page0", 0, 0, false, false, false, m68hc11_handle_page0_attribute },
1329 { NULL, 0, 0, false, false, false, NULL }
1332 /* Keep track of the symbol which has a `trap' attribute and which uses
1333 the `swi' calling convention. Since there is only one trap, we only
1334 record one such symbol. If there are several, a warning is reported. */
1335 static rtx trap_handler_symbol = 0;
1337 /* Handle an attribute requiring a FUNCTION_TYPE, FIELD_DECL or TYPE_DECL;
1338 arguments as in struct attribute_spec.handler. */
1339 static tree
1340 m68hc11_handle_fntype_attribute (tree *node, tree name,
1341 tree args ATTRIBUTE_UNUSED,
1342 int flags ATTRIBUTE_UNUSED,
1343 bool *no_add_attrs)
1345 if (TREE_CODE (*node) != FUNCTION_TYPE
1346 && TREE_CODE (*node) != METHOD_TYPE
1347 && TREE_CODE (*node) != FIELD_DECL
1348 && TREE_CODE (*node) != TYPE_DECL)
1350 warning ("`%s' attribute only applies to functions",
1351 IDENTIFIER_POINTER (name));
1352 *no_add_attrs = true;
1355 return NULL_TREE;
1357 /* Undo the effects of the above. */
1359 static const char *
1360 m68hc11_strip_name_encoding (const char *str)
1362 return str + (*str == '*' || *str == '@' || *str == '&');
1365 static void
1366 m68hc11_encode_label (tree decl)
1368 const char *str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
1369 int len = strlen (str);
1370 char *newstr = alloca (len + 2);
1372 newstr[0] = '@';
1373 strcpy (&newstr[1], str);
1375 XSTR (XEXP (DECL_RTL (decl), 0), 0) = ggc_alloc_string (newstr, len + 1);
1378 /* Return 1 if this is a symbol in page0 */
1380 m68hc11_page0_symbol_p (rtx x)
1382 switch (GET_CODE (x))
1384 case SYMBOL_REF:
1385 return XSTR (x, 0) != 0 && XSTR (x, 0)[0] == '@';
1387 case CONST:
1388 return m68hc11_page0_symbol_p (XEXP (x, 0));
1390 case PLUS:
1391 if (!m68hc11_page0_symbol_p (XEXP (x, 0)))
1392 return 0;
1394 return GET_CODE (XEXP (x, 1)) == CONST_INT
1395 && INTVAL (XEXP (x, 1)) < 256
1396 && INTVAL (XEXP (x, 1)) >= 0;
1398 default:
1399 return 0;
1403 /* We want to recognize trap handlers so that we handle calls to traps
1404 in a special manner (by issuing the trap). This information is stored
1405 in SYMBOL_REF_FLAG. */
1407 static void
1408 m68hc11_encode_section_info (tree decl, rtx rtl, int first ATTRIBUTE_UNUSED)
1410 tree func_attr;
1411 int trap_handler;
1412 int is_far = 0;
1414 if (TREE_CODE (decl) == VAR_DECL)
1416 if (lookup_attribute ("page0", DECL_ATTRIBUTES (decl)) != 0)
1417 m68hc11_encode_label (decl);
1418 return;
1421 if (TREE_CODE (decl) != FUNCTION_DECL)
1422 return;
1424 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (decl));
1427 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1428 is_far = 1;
1429 else if (lookup_attribute ("near", func_attr) == NULL_TREE)
1430 is_far = TARGET_LONG_CALLS != 0;
1432 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1433 if (trap_handler && is_far)
1435 warning ("`trap' and `far' attributes are not compatible, ignoring `far'");
1436 trap_handler = 0;
1438 if (trap_handler)
1440 if (trap_handler_symbol != 0)
1441 warning ("`trap' attribute is already used");
1442 else
1443 trap_handler_symbol = XEXP (rtl, 0);
1445 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = is_far;
1448 static unsigned int
1449 m68hc11_section_type_flags (tree decl, const char *name, int reloc)
1451 unsigned int flags = default_section_type_flags (decl, name, reloc);
1453 if (strncmp (name, ".eeprom", 7) == 0)
1455 flags |= SECTION_WRITE | SECTION_CODE | SECTION_OVERRIDE;
1458 return flags;
1462 m68hc11_is_far_symbol (rtx sym)
1464 if (GET_CODE (sym) == MEM)
1465 sym = XEXP (sym, 0);
1467 return SYMBOL_REF_FLAG (sym);
1471 m68hc11_is_trap_symbol (rtx sym)
1473 if (GET_CODE (sym) == MEM)
1474 sym = XEXP (sym, 0);
1476 return trap_handler_symbol != 0 && rtx_equal_p (trap_handler_symbol, sym);
1480 /* Argument support functions. */
1482 /* Define the offset between two registers, one to be eliminated, and the
1483 other its replacement, at the start of a routine. */
1485 m68hc11_initial_elimination_offset (int from, int to)
1487 int trap_handler;
1488 tree func_attr;
1489 int size;
1490 int regno;
1492 /* For a trap handler, we must take into account the registers which
1493 are pushed on the stack during the trap (except the PC). */
1494 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1495 current_function_interrupt = lookup_attribute ("interrupt",
1496 func_attr) != NULL_TREE;
1497 trap_handler = lookup_attribute ("trap", func_attr) != NULL_TREE;
1499 if (lookup_attribute ("far", func_attr) != 0)
1500 current_function_far = 1;
1501 else if (lookup_attribute ("near", func_attr) != 0)
1502 current_function_far = 0;
1503 else
1504 current_function_far = (TARGET_LONG_CALLS != 0
1505 && !current_function_interrupt
1506 && !trap_handler);
1508 if (trap_handler && from == ARG_POINTER_REGNUM)
1509 size = 7;
1511 /* For a function using 'call/rtc' we must take into account the
1512 page register which is pushed in the call. */
1513 else if (current_function_far && from == ARG_POINTER_REGNUM)
1514 size = 1;
1515 else
1516 size = 0;
1518 if (from == ARG_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1520 /* 2 is for the saved frame.
1521 1 is for the 'sts' correction when creating the frame. */
1522 return get_frame_size () + 2 + m68hc11_sp_correction + size;
1525 if (from == FRAME_POINTER_REGNUM && to == HARD_FRAME_POINTER_REGNUM)
1527 return m68hc11_sp_correction;
1530 /* Push any 2 byte pseudo hard registers that we need to save. */
1531 for (regno = SOFT_REG_FIRST; regno < SOFT_REG_LAST; regno++)
1533 if (regs_ever_live[regno] && !call_used_regs[regno])
1535 size += 2;
1539 if (from == ARG_POINTER_REGNUM && to == HARD_SP_REGNUM)
1541 return get_frame_size () + size;
1544 if (from == FRAME_POINTER_REGNUM && to == HARD_SP_REGNUM)
1546 return size;
1548 return 0;
1551 /* Initialize a variable CUM of type CUMULATIVE_ARGS
1552 for a call to a function whose data type is FNTYPE.
1553 For a library call, FNTYPE is 0. */
1555 void
1556 m68hc11_init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype, rtx libname)
1558 tree ret_type;
1560 z_replacement_completed = 0;
1561 cum->words = 0;
1562 cum->nregs = 0;
1564 /* For a library call, we must find out the type of the return value.
1565 When the return value is bigger than 4 bytes, it is returned in
1566 memory. In that case, the first argument of the library call is a
1567 pointer to the memory location. Because the first argument is passed in
1568 register D, we have to identify this, so that the first function
1569 parameter is not passed in D either. */
1570 if (fntype == 0)
1572 const char *name;
1573 size_t len;
1575 if (libname == 0 || GET_CODE (libname) != SYMBOL_REF)
1576 return;
1578 /* If the library ends in 'di' or in 'df', we assume it's
1579 returning some DImode or some DFmode which are 64-bit wide. */
1580 name = XSTR (libname, 0);
1581 len = strlen (name);
1582 if (len > 3
1583 && ((name[len - 2] == 'd'
1584 && (name[len - 1] == 'f' || name[len - 1] == 'i'))
1585 || (name[len - 3] == 'd'
1586 && (name[len - 2] == 'i' || name[len - 2] == 'f'))))
1588 /* We are in. Mark the first parameter register as already used. */
1589 cum->words = 1;
1590 cum->nregs = 1;
1592 return;
1595 ret_type = TREE_TYPE (fntype);
1597 if (ret_type && aggregate_value_p (ret_type, fntype))
1599 cum->words = 1;
1600 cum->nregs = 1;
1604 /* Update the data in CUM to advance over an argument
1605 of mode MODE and data type TYPE.
1606 (TYPE is null for libcalls where that information may not be available.) */
1608 void
1609 m68hc11_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
1610 tree type, int named ATTRIBUTE_UNUSED)
1612 if (mode != BLKmode)
1614 if (cum->words == 0 && GET_MODE_SIZE (mode) == 4)
1616 cum->nregs = 2;
1617 cum->words = GET_MODE_SIZE (mode);
1619 else
1621 cum->words += GET_MODE_SIZE (mode);
1622 if (cum->words <= HARD_REG_SIZE)
1623 cum->nregs = 1;
1626 else
1628 cum->words += int_size_in_bytes (type);
1630 return;
1633 /* Define where to put the arguments to a function.
1634 Value is zero to push the argument on the stack,
1635 or a hard register in which to store the argument.
1637 MODE is the argument's machine mode.
1638 TYPE is the data type of the argument (as a tree).
1639 This is null for libcalls where that information may
1640 not be available.
1641 CUM is a variable of type CUMULATIVE_ARGS which gives info about
1642 the preceding args and about the function being called.
1643 NAMED is nonzero if this argument is a named parameter
1644 (otherwise it is an extra parameter matching an ellipsis). */
1646 struct rtx_def *
1647 m68hc11_function_arg (const CUMULATIVE_ARGS *cum, enum machine_mode mode,
1648 tree type ATTRIBUTE_UNUSED, int named ATTRIBUTE_UNUSED)
1650 if (cum->words != 0)
1652 return NULL_RTX;
1655 if (mode != BLKmode)
1657 if (GET_MODE_SIZE (mode) == 2 * HARD_REG_SIZE)
1658 return gen_rtx_REG (mode, HARD_X_REGNUM);
1660 if (GET_MODE_SIZE (mode) > HARD_REG_SIZE)
1662 return NULL_RTX;
1664 return gen_rtx_REG (mode, HARD_D_REGNUM);
1666 return NULL_RTX;
1669 /* If defined, a C expression which determines whether, and in which direction,
1670 to pad out an argument with extra space. The value should be of type
1671 `enum direction': either `upward' to pad above the argument,
1672 `downward' to pad below, or `none' to inhibit padding.
1674 Structures are stored left shifted in their argument slot. */
1676 m68hc11_function_arg_padding (enum machine_mode mode, tree type)
1678 if (type != 0 && AGGREGATE_TYPE_P (type))
1679 return upward;
1681 /* Fall back to the default. */
1682 return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
1686 /* Function prologue and epilogue. */
1688 /* Emit a move after the reload pass has completed. This is used to
1689 emit the prologue and epilogue. */
1690 static void
1691 emit_move_after_reload (rtx to, rtx from, rtx scratch)
1693 rtx insn;
1695 if (TARGET_M6812 || H_REG_P (to) || H_REG_P (from))
1697 insn = emit_move_insn (to, from);
1699 else
1701 emit_move_insn (scratch, from);
1702 insn = emit_move_insn (to, scratch);
1705 /* Put a REG_INC note to tell the flow analysis that the instruction
1706 is necessary. */
1707 if (IS_STACK_PUSH (to))
1709 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1710 XEXP (XEXP (to, 0), 0),
1711 REG_NOTES (insn));
1713 else if (IS_STACK_POP (from))
1715 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1716 XEXP (XEXP (from, 0), 0),
1717 REG_NOTES (insn));
1720 /* For 68HC11, put a REG_INC note on `sts _.frame' to prevent the cse-reg
1721 to think that sp == _.frame and later replace a x = sp with x = _.frame.
1722 The problem is that we are lying to gcc and use `txs' for x = sp
1723 (which is not really true because txs is really x = sp + 1). */
1724 else if (TARGET_M6811 && SP_REG_P (from))
1726 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_INC,
1727 from,
1728 REG_NOTES (insn));
1733 m68hc11_total_frame_size (void)
1735 int size;
1736 int regno;
1738 size = get_frame_size ();
1739 if (current_function_interrupt)
1741 size += 3 * HARD_REG_SIZE;
1743 if (frame_pointer_needed)
1744 size += HARD_REG_SIZE;
1746 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1747 if (regs_ever_live[regno] && !call_used_regs[regno])
1748 size += HARD_REG_SIZE;
1750 return size;
1753 static void
1754 m68hc11_output_function_epilogue (FILE *out ATTRIBUTE_UNUSED,
1755 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
1757 /* We catch the function epilogue generation to have a chance
1758 to clear the z_replacement_completed flag. */
1759 z_replacement_completed = 0;
1762 void
1763 expand_prologue (void)
1765 tree func_attr;
1766 int size;
1767 int regno;
1768 rtx scratch;
1770 if (reload_completed != 1)
1771 abort ();
1773 size = get_frame_size ();
1775 create_regs_rtx ();
1777 /* Generate specific prologue for interrupt handlers. */
1778 func_attr = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
1779 current_function_interrupt = lookup_attribute ("interrupt",
1780 func_attr) != NULL_TREE;
1781 current_function_trap = lookup_attribute ("trap", func_attr) != NULL_TREE;
1782 if (lookup_attribute ("far", func_attr) != NULL_TREE)
1783 current_function_far = 1;
1784 else if (lookup_attribute ("near", func_attr) != NULL_TREE)
1785 current_function_far = 0;
1786 else
1787 current_function_far = (TARGET_LONG_CALLS != 0
1788 && !current_function_interrupt
1789 && !current_function_trap);
1791 /* Get the scratch register to build the frame and push registers.
1792 If the first argument is a 32-bit quantity, the D+X registers
1793 are used. Use Y to compute the frame. Otherwise, X is cheaper.
1794 For 68HC12, this scratch register is not used. */
1795 if (current_function_args_info.nregs == 2)
1796 scratch = iy_reg;
1797 else
1798 scratch = ix_reg;
1800 /* Save current stack frame. */
1801 if (frame_pointer_needed)
1802 emit_move_after_reload (stack_push_word, hard_frame_pointer_rtx, scratch);
1804 /* For an interrupt handler, we must preserve _.tmp, _.z and _.xy.
1805 Other soft registers in page0 need not to be saved because they
1806 will be restored by C functions. For a trap handler, we don't
1807 need to preserve these registers because this is a synchronous call. */
1808 if (current_function_interrupt)
1810 emit_move_after_reload (stack_push_word, m68hc11_soft_tmp_reg, scratch);
1811 emit_move_after_reload (stack_push_word,
1812 gen_rtx_REG (HImode, SOFT_Z_REGNUM), scratch);
1813 emit_move_after_reload (stack_push_word,
1814 gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1815 scratch);
1818 /* Allocate local variables. */
1819 if (TARGET_M6812 && (size > 4 || size == 3))
1821 emit_insn (gen_addhi3 (stack_pointer_rtx,
1822 stack_pointer_rtx, GEN_INT (-size)));
1824 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1826 rtx insn;
1828 insn = gen_rtx_PARALLEL
1829 (VOIDmode,
1830 gen_rtvec (2,
1831 gen_rtx_SET (VOIDmode,
1832 stack_pointer_rtx,
1833 gen_rtx_PLUS (HImode,
1834 stack_pointer_rtx,
1835 GEN_INT (-size))),
1836 gen_rtx_CLOBBER (VOIDmode, scratch)));
1837 emit_insn (insn);
1839 else
1841 int i;
1843 /* Allocate by pushing scratch values. */
1844 for (i = 2; i <= size; i += 2)
1845 emit_move_after_reload (stack_push_word, ix_reg, 0);
1847 if (size & 1)
1848 emit_insn (gen_addhi3 (stack_pointer_rtx,
1849 stack_pointer_rtx, constm1_rtx));
1852 /* Create the frame pointer. */
1853 if (frame_pointer_needed)
1854 emit_move_after_reload (hard_frame_pointer_rtx,
1855 stack_pointer_rtx, scratch);
1857 /* Push any 2 byte pseudo hard registers that we need to save. */
1858 for (regno = SOFT_REG_FIRST; regno <= SOFT_REG_LAST; regno++)
1860 if (regs_ever_live[regno] && !call_used_regs[regno])
1862 emit_move_after_reload (stack_push_word,
1863 gen_rtx_REG (HImode, regno), scratch);
1868 void
1869 expand_epilogue (void)
1871 int size;
1872 register int regno;
1873 int return_size;
1874 rtx scratch;
1876 if (reload_completed != 1)
1877 abort ();
1879 size = get_frame_size ();
1881 /* If we are returning a value in two registers, we have to preserve the
1882 X register and use the Y register to restore the stack and the saved
1883 registers. Otherwise, use X because it's faster (and smaller). */
1884 if (current_function_return_rtx == 0)
1885 return_size = 0;
1886 else if (GET_CODE (current_function_return_rtx) == MEM)
1887 return_size = HARD_REG_SIZE;
1888 else
1889 return_size = GET_MODE_SIZE (GET_MODE (current_function_return_rtx));
1891 if (return_size > HARD_REG_SIZE && return_size <= 2 * HARD_REG_SIZE)
1892 scratch = iy_reg;
1893 else
1894 scratch = ix_reg;
1896 /* Pop any 2 byte pseudo hard registers that we saved. */
1897 for (regno = SOFT_REG_LAST; regno >= SOFT_REG_FIRST; regno--)
1899 if (regs_ever_live[regno] && !call_used_regs[regno])
1901 emit_move_after_reload (gen_rtx_REG (HImode, regno),
1902 stack_pop_word, scratch);
1906 /* de-allocate auto variables */
1907 if (TARGET_M6812 && (size > 4 || size == 3))
1909 emit_insn (gen_addhi3 (stack_pointer_rtx,
1910 stack_pointer_rtx, GEN_INT (size)));
1912 else if ((!optimize_size && size > 8) || (optimize_size && size > 10))
1914 rtx insn;
1916 insn = gen_rtx_PARALLEL
1917 (VOIDmode,
1918 gen_rtvec (2,
1919 gen_rtx_SET (VOIDmode,
1920 stack_pointer_rtx,
1921 gen_rtx_PLUS (HImode,
1922 stack_pointer_rtx,
1923 GEN_INT (size))),
1924 gen_rtx_CLOBBER (VOIDmode, scratch)));
1925 emit_insn (insn);
1927 else
1929 int i;
1931 for (i = 2; i <= size; i += 2)
1932 emit_move_after_reload (scratch, stack_pop_word, scratch);
1933 if (size & 1)
1934 emit_insn (gen_addhi3 (stack_pointer_rtx,
1935 stack_pointer_rtx, const1_rtx));
1938 /* For an interrupt handler, restore ZTMP, ZREG and XYREG. */
1939 if (current_function_interrupt)
1941 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM),
1942 stack_pop_word, scratch);
1943 emit_move_after_reload (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
1944 stack_pop_word, scratch);
1945 emit_move_after_reload (m68hc11_soft_tmp_reg, stack_pop_word, scratch);
1948 /* Restore previous frame pointer. */
1949 if (frame_pointer_needed)
1950 emit_move_after_reload (hard_frame_pointer_rtx, stack_pop_word, scratch);
1952 /* If the trap handler returns some value, copy the value
1953 in D, X onto the stack so that the rti will pop the return value
1954 correctly. */
1955 else if (current_function_trap && return_size != 0)
1957 rtx addr_reg = stack_pointer_rtx;
1959 if (!TARGET_M6812)
1961 emit_move_after_reload (scratch, stack_pointer_rtx, 0);
1962 addr_reg = scratch;
1964 emit_move_after_reload (gen_rtx_MEM (HImode,
1965 gen_rtx_PLUS (HImode, addr_reg,
1966 const1_rtx)), d_reg, 0);
1967 if (return_size > HARD_REG_SIZE)
1968 emit_move_after_reload (gen_rtx_MEM (HImode,
1969 gen_rtx_PLUS (HImode, addr_reg,
1970 GEN_INT (3))), ix_reg, 0);
1973 emit_jump_insn (gen_return ());
1977 /* Low and High part extraction for 68HC11. These routines are
1978 similar to gen_lowpart and gen_highpart but they have been
1979 fixed to work for constants and 68HC11 specific registers. */
1982 m68hc11_gen_lowpart (enum machine_mode mode, rtx x)
1984 /* We assume that the low part of an auto-inc mode is the same with
1985 the mode changed and that the caller split the larger mode in the
1986 correct order. */
1987 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
1989 return gen_rtx_MEM (mode, XEXP (x, 0));
1992 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
1993 floating-point constant. A CONST_DOUBLE is used whenever the
1994 constant requires more than one word in order to be adequately
1995 represented. */
1996 if (GET_CODE (x) == CONST_DOUBLE)
1998 long l[2];
2000 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2002 REAL_VALUE_TYPE r;
2004 if (GET_MODE (x) == SFmode)
2006 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
2007 REAL_VALUE_TO_TARGET_SINGLE (r, l[0]);
2009 else
2011 rtx first, second;
2013 split_double (x, &first, &second);
2014 return second;
2016 if (mode == SImode)
2017 return GEN_INT (l[0]);
2019 return gen_int_mode (l[0], HImode);
2021 else
2023 l[0] = CONST_DOUBLE_LOW (x);
2025 if (mode == SImode)
2026 return GEN_INT (l[0]);
2027 else if (mode == HImode && GET_MODE (x) == SFmode)
2028 return gen_int_mode (l[0], HImode);
2029 else
2030 abort ();
2033 if (mode == QImode && D_REG_P (x))
2034 return gen_rtx_REG (mode, HARD_B_REGNUM);
2036 /* gen_lowpart crashes when it is called with a SUBREG. */
2037 if (GET_CODE (x) == SUBREG && SUBREG_BYTE (x) != 0)
2039 if (mode == SImode)
2040 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 4);
2041 else if (mode == HImode)
2042 return gen_rtx_SUBREG (mode, SUBREG_REG (x), SUBREG_BYTE (x) + 2);
2043 else
2044 abort ();
2046 x = gen_lowpart (mode, x);
2048 /* Return a different rtx to avoid to share it in several insns
2049 (when used by a split pattern). Sharing addresses within
2050 a MEM breaks the Z register replacement (and reloading). */
2051 if (GET_CODE (x) == MEM)
2052 x = copy_rtx (x);
2053 return x;
2057 m68hc11_gen_highpart (enum machine_mode mode, rtx x)
2059 /* We assume that the high part of an auto-inc mode is the same with
2060 the mode changed and that the caller split the larger mode in the
2061 correct order. */
2062 if (GET_CODE (x) == MEM && m68hc11_auto_inc_p (XEXP (x, 0)))
2064 return gen_rtx_MEM (mode, XEXP (x, 0));
2067 /* Note that a CONST_DOUBLE rtx could represent either an integer or a
2068 floating-point constant. A CONST_DOUBLE is used whenever the
2069 constant requires more than one word in order to be adequately
2070 represented. */
2071 if (GET_CODE (x) == CONST_DOUBLE)
2073 long l[2];
2075 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2077 REAL_VALUE_TYPE r;
2079 if (GET_MODE (x) == SFmode)
2081 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
2082 REAL_VALUE_TO_TARGET_SINGLE (r, l[1]);
2084 else
2086 rtx first, second;
2088 split_double (x, &first, &second);
2089 return first;
2091 if (mode == SImode)
2092 return GEN_INT (l[1]);
2094 return gen_int_mode ((l[1] >> 16), HImode);
2096 else
2098 l[1] = CONST_DOUBLE_HIGH (x);
2101 if (mode == SImode)
2102 return GEN_INT (l[1]);
2103 else if (mode == HImode && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
2104 return gen_int_mode ((l[0] >> 16), HImode);
2105 else
2106 abort ();
2108 if (GET_CODE (x) == CONST_INT)
2110 HOST_WIDE_INT val = INTVAL (x);
2112 if (mode == QImode)
2114 return gen_int_mode (val >> 8, QImode);
2116 else if (mode == HImode)
2118 return gen_int_mode (val >> 16, HImode);
2121 if (mode == QImode && D_REG_P (x))
2122 return gen_rtx_REG (mode, HARD_A_REGNUM);
2124 /* There is no way in GCC to represent the upper part of a word register.
2125 To obtain the 8-bit upper part of a soft register, we change the
2126 reg into a mem rtx. This is possible because they are physically
2127 located in memory. There is no offset because we are big-endian. */
2128 if (mode == QImode && S_REG_P (x))
2130 int pos;
2132 /* Avoid the '*' for direct addressing mode when this
2133 addressing mode is disabled. */
2134 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
2135 return gen_rtx_MEM (QImode,
2136 gen_rtx_SYMBOL_REF (Pmode,
2137 &reg_names[REGNO (x)][pos]));
2140 /* gen_highpart crashes when it is called with a SUBREG. */
2141 if (GET_CODE (x) == SUBREG)
2143 return gen_rtx_SUBREG (mode, XEXP (x, 0), XEXP (x, 1));
2145 if (GET_CODE (x) == REG)
2147 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
2148 return gen_rtx_REG (mode, REGNO (x));
2149 else
2150 return gen_rtx_SUBREG (mode, x, 0);
2153 if (GET_CODE (x) == MEM)
2155 x = change_address (x, mode, 0);
2157 /* Return a different rtx to avoid to share it in several insns
2158 (when used by a split pattern). Sharing addresses within
2159 a MEM breaks the Z register replacement (and reloading). */
2160 if (GET_CODE (x) == MEM)
2161 x = copy_rtx (x);
2162 return x;
2164 abort ();
2168 /* Obscure register manipulation. */
2170 /* Finds backward in the instructions to see if register 'reg' is
2171 dead. This is used when generating code to see if we can use 'reg'
2172 as a scratch register. This allows us to choose a better generation
2173 of code when we know that some register dies or can be clobbered. */
2176 dead_register_here (rtx x, rtx reg)
2178 rtx x_reg;
2179 rtx p;
2181 if (D_REG_P (reg))
2182 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
2183 else
2184 x_reg = 0;
2186 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
2187 if (INSN_P (p))
2189 rtx body;
2191 body = PATTERN (p);
2193 if (GET_CODE (body) == CALL_INSN)
2194 break;
2195 if (GET_CODE (body) == JUMP_INSN)
2196 break;
2198 if (GET_CODE (body) == SET)
2200 rtx dst = XEXP (body, 0);
2202 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2203 break;
2204 if (x_reg && rtx_equal_p (dst, x_reg))
2205 break;
2207 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2208 return 1;
2210 else if (reg_mentioned_p (reg, p)
2211 || (x_reg && reg_mentioned_p (x_reg, p)))
2212 break;
2215 /* Scan forward to see if the register is set in some insns and never
2216 used since then. */
2217 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2219 rtx body;
2221 if (GET_CODE (p) == CODE_LABEL
2222 || GET_CODE (p) == JUMP_INSN
2223 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2224 break;
2226 if (GET_CODE (p) != INSN)
2227 continue;
2229 body = PATTERN (p);
2230 if (GET_CODE (body) == SET)
2232 rtx src = XEXP (body, 1);
2233 rtx dst = XEXP (body, 0);
2235 if (GET_CODE (dst) == REG
2236 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2237 return 1;
2240 /* Register is used (may be in source or in dest). */
2241 if (reg_mentioned_p (reg, p)
2242 || (x_reg != 0 && GET_MODE (p) == SImode
2243 && reg_mentioned_p (x_reg, p)))
2244 break;
2246 return p == 0 ? 1 : 0;
2250 /* Code generation operations called from machine description file. */
2252 /* Print the name of register 'regno' in the assembly file. */
2253 static void
2254 asm_print_register (FILE *file, int regno)
2256 const char *name = reg_names[regno];
2258 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2259 name++;
2261 fprintf (file, "%s", name);
2264 /* A C compound statement to output to stdio stream STREAM the
2265 assembler syntax for an instruction operand X. X is an RTL
2266 expression.
2268 CODE is a value that can be used to specify one of several ways
2269 of printing the operand. It is used when identical operands
2270 must be printed differently depending on the context. CODE
2271 comes from the `%' specification that was used to request
2272 printing of the operand. If the specification was just `%DIGIT'
2273 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2274 is the ASCII code for LTR.
2276 If X is a register, this macro should print the register's name.
2277 The names can be found in an array `reg_names' whose type is
2278 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2280 When the machine description has a specification `%PUNCT' (a `%'
2281 followed by a punctuation character), this macro is called with
2282 a null pointer for X and the punctuation character for CODE.
2284 The M68HC11 specific codes are:
2286 'b' for the low part of the operand.
2287 'h' for the high part of the operand
2288 The 'b' or 'h' modifiers have no effect if the operand has
2289 the QImode and is not a S_REG_P (soft register). If the
2290 operand is a hard register, these two modifiers have no effect.
2291 't' generate the temporary scratch register. The operand is
2292 ignored.
2293 'T' generate the low-part temporary scratch register. The operand is
2294 ignored. */
2296 void
2297 print_operand (FILE *file, rtx op, int letter)
2299 if (letter == 't')
2301 asm_print_register (file, SOFT_TMP_REGNUM);
2302 return;
2304 else if (letter == 'T')
2306 asm_print_register (file, SOFT_TMP_REGNUM);
2307 fprintf (file, "+1");
2308 return;
2310 else if (letter == '#')
2312 asm_fprintf (file, "%I");
2315 if (GET_CODE (op) == REG)
2317 if (letter == 'b' && S_REG_P (op))
2319 asm_print_register (file, REGNO (op));
2320 fprintf (file, "+1");
2322 else if (letter == 'b' && D_REG_P (op))
2324 asm_print_register (file, HARD_B_REGNUM);
2326 else
2328 asm_print_register (file, REGNO (op));
2330 return;
2333 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2335 if (letter == 'b')
2336 asm_fprintf (file, "%I%%lo(");
2337 else
2338 asm_fprintf (file, "%I%%hi(");
2340 output_addr_const (file, op);
2341 fprintf (file, ")");
2342 return;
2345 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2346 are specified. If we already have a QImode, there is nothing to do. */
2347 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2349 if (letter == 'b')
2351 op = m68hc11_gen_lowpart (QImode, op);
2353 else if (letter == 'h')
2355 op = m68hc11_gen_highpart (QImode, op);
2359 if (GET_CODE (op) == MEM)
2361 rtx base = XEXP (op, 0);
2362 switch (GET_CODE (base))
2364 case PRE_DEC:
2365 if (TARGET_M6812)
2367 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2368 asm_print_register (file, REGNO (XEXP (base, 0)));
2370 else
2371 abort ();
2372 break;
2374 case POST_DEC:
2375 if (TARGET_M6812)
2377 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2378 asm_print_register (file, REGNO (XEXP (base, 0)));
2379 fprintf (file, "-");
2381 else
2382 abort ();
2383 break;
2385 case POST_INC:
2386 if (TARGET_M6812)
2388 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2389 asm_print_register (file, REGNO (XEXP (base, 0)));
2390 fprintf (file, "+");
2392 else
2393 abort ();
2394 break;
2396 case PRE_INC:
2397 if (TARGET_M6812)
2399 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2400 asm_print_register (file, REGNO (XEXP (base, 0)));
2402 else
2403 abort ();
2404 break;
2406 case MEM:
2407 if (TARGET_M6812)
2409 fprintf (file, "[");
2410 print_operand_address (file, XEXP (base, 0));
2411 fprintf (file, "]");
2413 else
2414 abort ();
2415 break;
2417 default:
2418 if (m68hc11_page0_symbol_p (base))
2419 fprintf (file, "*");
2421 output_address (base);
2422 break;
2425 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2427 REAL_VALUE_TYPE r;
2428 long l;
2430 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2431 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2432 asm_fprintf (file, "%I0x%lx", l);
2434 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2436 char dstr[30];
2438 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2439 sizeof (dstr), 0, 1);
2440 asm_fprintf (file, "%I0r%s", dstr);
2442 else
2444 int need_parenthesize = 0;
2446 if (letter != 'i')
2447 asm_fprintf (file, "%I");
2448 else
2449 need_parenthesize = must_parenthesize (op);
2451 if (need_parenthesize)
2452 fprintf (file, "(");
2454 output_addr_const (file, op);
2455 if (need_parenthesize)
2456 fprintf (file, ")");
2460 /* Returns true if the operand 'op' must be printed with parenthesis
2461 around it. This must be done only if there is a symbol whose name
2462 is a processor register. */
2463 static int
2464 must_parenthesize (rtx op)
2466 const char *name;
2468 switch (GET_CODE (op))
2470 case SYMBOL_REF:
2471 name = XSTR (op, 0);
2472 /* Avoid a conflict between symbol name and a possible
2473 register. */
2474 return (strcasecmp (name, "a") == 0
2475 || strcasecmp (name, "b") == 0
2476 || strcasecmp (name, "d") == 0
2477 || strcasecmp (name, "x") == 0
2478 || strcasecmp (name, "y") == 0
2479 || strcasecmp (name, "ix") == 0
2480 || strcasecmp (name, "iy") == 0
2481 || strcasecmp (name, "pc") == 0
2482 || strcasecmp (name, "sp") == 0
2483 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2485 case PLUS:
2486 case MINUS:
2487 return must_parenthesize (XEXP (op, 0))
2488 || must_parenthesize (XEXP (op, 1));
2490 case MEM:
2491 case CONST:
2492 case ZERO_EXTEND:
2493 case SIGN_EXTEND:
2494 return must_parenthesize (XEXP (op, 0));
2496 case CONST_DOUBLE:
2497 case CONST_INT:
2498 case LABEL_REF:
2499 case CODE_LABEL:
2500 default:
2501 return 0;
2505 /* A C compound statement to output to stdio stream STREAM the
2506 assembler syntax for an instruction operand that is a memory
2507 reference whose address is ADDR. ADDR is an RTL expression. */
2509 void
2510 print_operand_address (FILE *file, rtx addr)
2512 rtx base;
2513 rtx offset;
2514 int need_parenthesis = 0;
2516 switch (GET_CODE (addr))
2518 case REG:
2519 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2520 abort ();
2522 fprintf (file, "0,");
2523 asm_print_register (file, REGNO (addr));
2524 break;
2526 case MEM:
2527 base = XEXP (addr, 0);
2528 switch (GET_CODE (base))
2530 case PRE_DEC:
2531 if (TARGET_M6812)
2533 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2534 asm_print_register (file, REGNO (XEXP (base, 0)));
2536 else
2537 abort ();
2538 break;
2540 case POST_DEC:
2541 if (TARGET_M6812)
2543 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2544 asm_print_register (file, REGNO (XEXP (base, 0)));
2545 fprintf (file, "-");
2547 else
2548 abort ();
2549 break;
2551 case POST_INC:
2552 if (TARGET_M6812)
2554 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2555 asm_print_register (file, REGNO (XEXP (base, 0)));
2556 fprintf (file, "+");
2558 else
2559 abort ();
2560 break;
2562 case PRE_INC:
2563 if (TARGET_M6812)
2565 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2566 asm_print_register (file, REGNO (XEXP (base, 0)));
2568 else
2569 abort ();
2570 break;
2572 default:
2573 need_parenthesis = must_parenthesize (base);
2574 if (need_parenthesis)
2575 fprintf (file, "(");
2577 output_addr_const (file, base);
2578 if (need_parenthesis)
2579 fprintf (file, ")");
2580 break;
2582 break;
2584 case PLUS:
2585 base = XEXP (addr, 0);
2586 offset = XEXP (addr, 1);
2587 if (!G_REG_P (base) && G_REG_P (offset))
2589 base = XEXP (addr, 1);
2590 offset = XEXP (addr, 0);
2592 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2594 need_parenthesis = must_parenthesize (addr);
2596 if (need_parenthesis)
2597 fprintf (file, "(");
2599 output_addr_const (file, base);
2600 fprintf (file, "+");
2601 output_addr_const (file, offset);
2602 if (need_parenthesis)
2603 fprintf (file, ")");
2605 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2607 if (REG_P (offset))
2609 if (TARGET_M6812)
2611 asm_print_register (file, REGNO (offset));
2612 fprintf (file, ",");
2613 asm_print_register (file, REGNO (base));
2615 else
2616 abort ();
2618 else
2620 need_parenthesis = must_parenthesize (offset);
2621 if (need_parenthesis)
2622 fprintf (file, "(");
2624 output_addr_const (file, offset);
2625 if (need_parenthesis)
2626 fprintf (file, ")");
2627 fprintf (file, ",");
2628 asm_print_register (file, REGNO (base));
2631 else
2633 abort ();
2635 break;
2637 default:
2638 if (GET_CODE (addr) == CONST_INT
2639 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2641 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2643 else
2645 need_parenthesis = must_parenthesize (addr);
2646 if (need_parenthesis)
2647 fprintf (file, "(");
2649 output_addr_const (file, addr);
2650 if (need_parenthesis)
2651 fprintf (file, ")");
2653 break;
2658 /* Splitting of some instructions. */
2660 static rtx
2661 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2663 rtx ret = 0;
2665 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2666 abort ();
2667 else
2669 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2670 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2671 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2674 return ret;
2678 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2679 rtx label)
2681 rtx tmp;
2683 switch (GET_MODE (op0))
2685 case QImode:
2686 case HImode:
2687 tmp = m68hc11_expand_compare (code, op0, op1);
2688 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2689 gen_rtx_LABEL_REF (VOIDmode, label),
2690 pc_rtx);
2691 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2692 return 0;
2693 #if 0
2695 /* SCz: from i386.c */
2696 case SFmode:
2697 case DFmode:
2698 /* Don't expand the comparison early, so that we get better code
2699 when jump or whoever decides to reverse the comparison. */
2701 rtvec vec;
2702 int use_fcomi;
2704 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2705 &m68hc11_compare_op1);
2707 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2708 m68hc11_compare_op0, m68hc11_compare_op1);
2709 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2710 gen_rtx_LABEL_REF (VOIDmode, label),
2711 pc_rtx);
2712 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2714 use_fcomi = ix86_use_fcomi_compare (code);
2715 vec = rtvec_alloc (3 + !use_fcomi);
2716 RTVEC_ELT (vec, 0) = tmp;
2717 RTVEC_ELT (vec, 1)
2718 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2719 RTVEC_ELT (vec, 2)
2720 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2721 if (!use_fcomi)
2722 RTVEC_ELT (vec, 3)
2723 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2725 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2726 return;
2728 #endif
2730 case SImode:
2731 /* Expand SImode branch into multiple compare+branch. */
2733 rtx lo[2], hi[2], label2;
2734 enum rtx_code code1, code2, code3;
2736 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2738 tmp = op0;
2739 op0 = op1;
2740 op1 = tmp;
2741 code = swap_condition (code);
2743 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2744 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2745 hi[0] = m68hc11_gen_highpart (HImode, op0);
2746 hi[1] = m68hc11_gen_highpart (HImode, op1);
2748 /* Otherwise, if we are doing less-than, op1 is a constant and the
2749 low word is zero, then we can just examine the high word. */
2751 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2752 && (code == LT || code == LTU))
2754 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2755 label);
2758 /* Otherwise, we need two or three jumps. */
2760 label2 = gen_label_rtx ();
2762 code1 = code;
2763 code2 = swap_condition (code);
2764 code3 = unsigned_condition (code);
2766 switch (code)
2768 case LT:
2769 case GT:
2770 case LTU:
2771 case GTU:
2772 break;
2774 case LE:
2775 code1 = LT;
2776 code2 = GT;
2777 break;
2778 case GE:
2779 code1 = GT;
2780 code2 = LT;
2781 break;
2782 case LEU:
2783 code1 = LTU;
2784 code2 = GTU;
2785 break;
2786 case GEU:
2787 code1 = GTU;
2788 code2 = LTU;
2789 break;
2791 case EQ:
2792 code1 = UNKNOWN;
2793 code2 = NE;
2794 break;
2795 case NE:
2796 code2 = UNKNOWN;
2797 break;
2799 default:
2800 abort ();
2804 * a < b =>
2805 * if (hi(a) < hi(b)) goto true;
2806 * if (hi(a) > hi(b)) goto false;
2807 * if (lo(a) < lo(b)) goto true;
2808 * false:
2810 if (code1 != UNKNOWN)
2811 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2812 if (code2 != UNKNOWN)
2813 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2815 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2817 if (code2 != UNKNOWN)
2818 emit_label (label2);
2819 return 0;
2822 default:
2823 abort ();
2825 return 0;
2828 /* Return the increment/decrement mode of a MEM if it is such.
2829 Return CONST if it is anything else. */
2830 static int
2831 autoinc_mode (rtx x)
2833 if (GET_CODE (x) != MEM)
2834 return CONST;
2836 x = XEXP (x, 0);
2837 if (GET_CODE (x) == PRE_INC
2838 || GET_CODE (x) == PRE_DEC
2839 || GET_CODE (x) == POST_INC
2840 || GET_CODE (x) == POST_DEC)
2841 return GET_CODE (x);
2843 return CONST;
2846 static int
2847 m68hc11_make_autoinc_notes (rtx *x, void *data)
2849 rtx insn;
2851 switch (GET_CODE (*x))
2853 case PRE_DEC:
2854 case PRE_INC:
2855 case POST_DEC:
2856 case POST_INC:
2857 insn = (rtx) data;
2858 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2859 REG_NOTES (insn));
2860 return -1;
2862 default:
2863 return 0;
2867 /* Split a DI, SI or HI move into several smaller move operations.
2868 The scratch register 'scratch' is used as a temporary to load
2869 store intermediate values. It must be a hard register. */
2870 void
2871 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2873 rtx low_to, low_from;
2874 rtx high_to, high_from;
2875 rtx insn;
2876 enum machine_mode mode;
2877 int offset = 0;
2878 int autoinc_from = autoinc_mode (from);
2879 int autoinc_to = autoinc_mode (to);
2881 mode = GET_MODE (to);
2883 /* If the TO and FROM contain autoinc modes that are not compatible
2884 together (one pop and the other a push), we must change one to
2885 an offsetable operand and generate an appropriate add at the end. */
2886 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2888 rtx reg;
2889 int code;
2891 /* The source uses an autoinc mode which is not compatible with
2892 a split (this would result in a word swap). */
2893 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2895 code = GET_CODE (XEXP (from, 0));
2896 reg = XEXP (XEXP (from, 0), 0);
2897 offset = GET_MODE_SIZE (GET_MODE (from));
2898 if (code == POST_DEC)
2899 offset = -offset;
2901 if (code == PRE_INC)
2902 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2904 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2905 if (code == POST_DEC)
2906 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2907 return;
2910 /* Likewise for destination. */
2911 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2913 code = GET_CODE (XEXP (to, 0));
2914 reg = XEXP (XEXP (to, 0), 0);
2915 offset = GET_MODE_SIZE (GET_MODE (to));
2916 if (code == POST_DEC)
2917 offset = -offset;
2919 if (code == PRE_INC)
2920 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2922 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2923 if (code == POST_DEC)
2924 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2925 return;
2928 /* The source and destination auto increment modes must be compatible
2929 with each other: same direction. */
2930 if ((autoinc_to != autoinc_from
2931 && autoinc_to != CONST && autoinc_from != CONST)
2932 /* The destination address register must not be used within
2933 the source operand because the source address would change
2934 while doing the copy. */
2935 || (autoinc_to != CONST
2936 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2937 && !IS_STACK_PUSH (to)))
2939 /* Must change the destination. */
2940 code = GET_CODE (XEXP (to, 0));
2941 reg = XEXP (XEXP (to, 0), 0);
2942 offset = GET_MODE_SIZE (GET_MODE (to));
2943 if (code == PRE_DEC || code == POST_DEC)
2944 offset = -offset;
2946 if (code == PRE_DEC || code == PRE_INC)
2947 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2948 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2949 if (code == POST_DEC || code == POST_INC)
2950 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2952 return;
2955 /* Likewise, the source address register must not be used within
2956 the destination operand. */
2957 if (autoinc_from != CONST
2958 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2959 && !IS_STACK_PUSH (to))
2961 /* Must change the source. */
2962 code = GET_CODE (XEXP (from, 0));
2963 reg = XEXP (XEXP (from, 0), 0);
2964 offset = GET_MODE_SIZE (GET_MODE (from));
2965 if (code == PRE_DEC || code == POST_DEC)
2966 offset = -offset;
2968 if (code == PRE_DEC || code == PRE_INC)
2969 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2970 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2971 if (code == POST_DEC || code == POST_INC)
2972 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2974 return;
2978 if (GET_MODE_SIZE (mode) == 8)
2979 mode = SImode;
2980 else if (GET_MODE_SIZE (mode) == 4)
2981 mode = HImode;
2982 else
2983 mode = QImode;
2985 if (TARGET_M6812
2986 && IS_STACK_PUSH (to)
2987 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2989 if (mode == SImode)
2991 offset = 4;
2993 else if (mode == HImode)
2995 offset = 2;
2997 else
2998 offset = 0;
3001 low_to = m68hc11_gen_lowpart (mode, to);
3002 high_to = m68hc11_gen_highpart (mode, to);
3004 low_from = m68hc11_gen_lowpart (mode, from);
3005 if (mode == SImode && GET_CODE (from) == CONST_INT)
3007 if (INTVAL (from) >= 0)
3008 high_from = const0_rtx;
3009 else
3010 high_from = constm1_rtx;
3012 else
3013 high_from = m68hc11_gen_highpart (mode, from);
3015 if (offset)
3017 high_from = adjust_address (high_from, mode, offset);
3018 low_from = high_from;
3021 /* When copying with a POST_INC mode, we must copy the
3022 high part and then the low part to guarantee a correct
3023 32/64-bit copy. */
3024 if (TARGET_M6812
3025 && GET_MODE_SIZE (mode) >= 2
3026 && autoinc_from != autoinc_to
3027 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
3029 rtx swap;
3031 swap = low_to;
3032 low_to = high_to;
3033 high_to = swap;
3035 swap = low_from;
3036 low_from = high_from;
3037 high_from = swap;
3039 if (mode == SImode)
3041 m68hc11_split_move (low_to, low_from, scratch);
3042 m68hc11_split_move (high_to, high_from, scratch);
3044 else if (H_REG_P (to) || H_REG_P (from)
3045 || (low_from == const0_rtx
3046 && high_from == const0_rtx
3047 && ! push_operand (to, GET_MODE (to))
3048 && ! H_REG_P (scratch))
3049 || (TARGET_M6812
3050 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
3051 || m68hc11_small_indexed_indirect_p (from,
3052 GET_MODE (from)))
3053 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
3054 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
3056 insn = emit_move_insn (low_to, low_from);
3057 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3059 insn = emit_move_insn (high_to, high_from);
3060 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3062 else
3064 insn = emit_move_insn (scratch, low_from);
3065 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3066 insn = emit_move_insn (low_to, scratch);
3067 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3069 insn = emit_move_insn (scratch, high_from);
3070 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3071 insn = emit_move_insn (high_to, scratch);
3072 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
3076 static rtx
3077 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
3079 int val;
3080 int mask;
3082 *result = 0;
3083 if (GET_CODE (operand) != CONST_INT)
3084 return operand;
3086 if (mode == HImode)
3087 mask = 0x0ffff;
3088 else
3089 mask = 0x0ff;
3091 val = INTVAL (operand);
3092 switch (code)
3094 case IOR:
3095 if ((val & mask) == 0)
3096 return 0;
3097 if ((val & mask) == mask)
3098 *result = constm1_rtx;
3099 break;
3101 case AND:
3102 if ((val & mask) == 0)
3103 *result = const0_rtx;
3104 if ((val & mask) == mask)
3105 return 0;
3106 break;
3108 case XOR:
3109 if ((val & mask) == 0)
3110 return 0;
3111 break;
3113 return operand;
3116 static void
3117 m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
3119 rtx result;
3120 int need_copy;
3122 need_copy = (rtx_equal_p (operands[0], operands[1])
3123 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
3125 operands[1] = simplify_logical (mode, code, operands[1], &result);
3126 operands[2] = simplify_logical (mode, code, operands[2], &result);
3128 if (result && GET_CODE (result) == CONST_INT)
3130 if (!H_REG_P (operands[0]) && operands[3]
3131 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
3133 emit_move_insn (operands[3], result);
3134 emit_move_insn (operands[0], operands[3]);
3136 else
3138 emit_move_insn (operands[0], result);
3141 else if (operands[1] != 0 && operands[2] != 0)
3143 rtx insn;
3145 if (!H_REG_P (operands[0]) && operands[3])
3147 emit_move_insn (operands[3], operands[1]);
3148 emit_insn (gen_rtx_SET (mode,
3149 operands[3],
3150 gen_rtx_fmt_ee (code, mode,
3151 operands[3], operands[2])));
3152 insn = emit_move_insn (operands[0], operands[3]);
3154 else
3156 insn = emit_insn (gen_rtx_SET (mode,
3157 operands[0],
3158 gen_rtx_fmt_ee (code, mode,
3159 operands[0],
3160 operands[2])));
3164 /* The logical operation is similar to a copy. */
3165 else if (need_copy)
3167 rtx src;
3169 if (GET_CODE (operands[1]) == CONST_INT)
3170 src = operands[2];
3171 else
3172 src = operands[1];
3174 if (!H_REG_P (operands[0]) && !H_REG_P (src))
3176 emit_move_insn (operands[3], src);
3177 emit_move_insn (operands[0], operands[3]);
3179 else
3181 emit_move_insn (operands[0], src);
3186 void
3187 m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
3189 rtx low[4];
3190 rtx high[4];
3192 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3193 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3194 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3196 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3198 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3200 if (INTVAL (operands[1]) >= 0)
3201 high[1] = const0_rtx;
3202 else
3203 high[1] = constm1_rtx;
3205 else
3206 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3208 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3210 if (INTVAL (operands[2]) >= 0)
3211 high[2] = const0_rtx;
3212 else
3213 high[2] = constm1_rtx;
3215 else
3216 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3218 low[3] = operands[3];
3219 high[3] = operands[3];
3220 if (mode == SImode)
3222 m68hc11_split_logical (HImode, code, low);
3223 m68hc11_split_logical (HImode, code, high);
3224 return;
3227 m68hc11_emit_logical (mode, code, low);
3228 m68hc11_emit_logical (mode, code, high);
3232 /* Code generation. */
3234 void
3235 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3237 /* We have to be careful with the cc_status. An address register swap
3238 is generated for some comparison. The comparison is made with D
3239 but the branch really uses the address register. See the split
3240 pattern for compare. The xgdx/xgdy preserve the flags but after
3241 the exchange, the flags will reflect to the value of X and not D.
3242 Tell this by setting the cc_status according to the cc_prev_status. */
3243 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3245 if (cc_prev_status.value1 != 0
3246 && (D_REG_P (cc_prev_status.value1)
3247 || X_REG_P (cc_prev_status.value1)))
3249 cc_status = cc_prev_status;
3250 if (D_REG_P (cc_status.value1))
3251 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3252 HARD_X_REGNUM);
3253 else
3254 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3255 HARD_D_REGNUM);
3257 else
3258 CC_STATUS_INIT;
3260 output_asm_insn ("xgdx", operands);
3262 else
3264 if (cc_prev_status.value1 != 0
3265 && (D_REG_P (cc_prev_status.value1)
3266 || Y_REG_P (cc_prev_status.value1)))
3268 cc_status = cc_prev_status;
3269 if (D_REG_P (cc_status.value1))
3270 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3271 HARD_Y_REGNUM);
3272 else
3273 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3274 HARD_D_REGNUM);
3276 else
3277 CC_STATUS_INIT;
3279 output_asm_insn ("xgdy", operands);
3283 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3284 This is used to decide whether a move that set flags should be used
3285 instead. */
3287 next_insn_test_reg (rtx insn, rtx reg)
3289 rtx body;
3291 insn = next_nonnote_insn (insn);
3292 if (GET_CODE (insn) != INSN)
3293 return 0;
3295 body = PATTERN (insn);
3296 if (sets_cc0_p (body) != 1)
3297 return 0;
3299 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3300 return 0;
3302 return 1;
3305 /* Generate the code to move a 16-bit operand into another one. */
3307 void
3308 m68hc11_gen_movhi (rtx insn, rtx *operands)
3310 int reg;
3312 /* Move a register or memory to the same location.
3313 This is possible because such insn can appear
3314 in a non-optimizing mode. */
3315 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3317 cc_status = cc_prev_status;
3318 return;
3321 if (TARGET_M6812)
3323 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3325 cc_status = cc_prev_status;
3326 switch (REGNO (operands[1]))
3328 case HARD_X_REGNUM:
3329 case HARD_Y_REGNUM:
3330 case HARD_D_REGNUM:
3331 output_asm_insn ("psh%1", operands);
3332 break;
3333 case HARD_SP_REGNUM:
3334 output_asm_insn ("sts\t2,-sp", operands);
3335 break;
3336 default:
3337 abort ();
3339 return;
3341 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3343 cc_status = cc_prev_status;
3344 switch (REGNO (operands[0]))
3346 case HARD_X_REGNUM:
3347 case HARD_Y_REGNUM:
3348 case HARD_D_REGNUM:
3349 output_asm_insn ("pul%0", operands);
3350 break;
3351 default:
3352 abort ();
3354 return;
3356 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3358 m68hc11_notice_keep_cc (operands[0]);
3359 output_asm_insn ("tfr\t%1,%0", operands);
3361 else if (H_REG_P (operands[0]))
3363 if (SP_REG_P (operands[0]))
3364 output_asm_insn ("lds\t%1", operands);
3365 else
3366 output_asm_insn ("ld%0\t%1", operands);
3368 else if (H_REG_P (operands[1]))
3370 if (SP_REG_P (operands[1]))
3371 output_asm_insn ("sts\t%0", operands);
3372 else
3373 output_asm_insn ("st%1\t%0", operands);
3375 else
3377 rtx from = operands[1];
3378 rtx to = operands[0];
3380 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3381 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3382 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3383 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3385 rtx ops[3];
3387 if (operands[2])
3389 ops[0] = operands[2];
3390 ops[1] = from;
3391 ops[2] = 0;
3392 m68hc11_gen_movhi (insn, ops);
3393 ops[0] = to;
3394 ops[1] = operands[2];
3395 m68hc11_gen_movhi (insn, ops);
3397 else
3399 /* !!!! SCz wrong here. */
3400 fatal_insn ("move insn not handled", insn);
3403 else
3405 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3407 output_asm_insn ("clr\t%h0", operands);
3408 output_asm_insn ("clr\t%b0", operands);
3410 else
3412 m68hc11_notice_keep_cc (operands[0]);
3413 output_asm_insn ("movw\t%1,%0", operands);
3417 return;
3420 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3422 cc_status = cc_prev_status;
3423 switch (REGNO (operands[0]))
3425 case HARD_X_REGNUM:
3426 case HARD_Y_REGNUM:
3427 output_asm_insn ("pul%0", operands);
3428 break;
3429 case HARD_D_REGNUM:
3430 output_asm_insn ("pula", operands);
3431 output_asm_insn ("pulb", operands);
3432 break;
3433 default:
3434 abort ();
3436 return;
3438 /* Some moves to a hard register are special. Not all of them
3439 are really supported and we have to use a temporary
3440 location to provide them (either the stack of a temp var). */
3441 if (H_REG_P (operands[0]))
3443 switch (REGNO (operands[0]))
3445 case HARD_D_REGNUM:
3446 if (X_REG_P (operands[1]))
3448 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3450 m68hc11_output_swap (insn, operands);
3452 else if (next_insn_test_reg (insn, operands[0]))
3454 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3456 else
3458 m68hc11_notice_keep_cc (operands[0]);
3459 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3462 else if (Y_REG_P (operands[1]))
3464 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3466 m68hc11_output_swap (insn, operands);
3468 else
3470 /* %t means *ZTMP scratch register. */
3471 output_asm_insn ("sty\t%t1", operands);
3472 output_asm_insn ("ldd\t%t1", operands);
3475 else if (SP_REG_P (operands[1]))
3477 CC_STATUS_INIT;
3478 if (ix_reg == 0)
3479 create_regs_rtx ();
3480 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3481 output_asm_insn ("xgdx", operands);
3482 output_asm_insn ("tsx", operands);
3483 output_asm_insn ("xgdx", operands);
3485 else if (IS_STACK_POP (operands[1]))
3487 output_asm_insn ("pula\n\tpulb", operands);
3489 else if (GET_CODE (operands[1]) == CONST_INT
3490 && INTVAL (operands[1]) == 0)
3492 output_asm_insn ("clra\n\tclrb", operands);
3494 else
3496 output_asm_insn ("ldd\t%1", operands);
3498 break;
3500 case HARD_X_REGNUM:
3501 if (D_REG_P (operands[1]))
3503 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3505 m68hc11_output_swap (insn, operands);
3507 else if (next_insn_test_reg (insn, operands[0]))
3509 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3511 else
3513 m68hc11_notice_keep_cc (operands[0]);
3514 output_asm_insn ("pshb", operands);
3515 output_asm_insn ("psha", operands);
3516 output_asm_insn ("pulx", operands);
3519 else if (Y_REG_P (operands[1]))
3521 /* When both D and Y are dead, use the sequence xgdy, xgdx
3522 to move Y into X. The D and Y registers are modified. */
3523 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3524 && dead_register_here (insn, d_reg))
3526 output_asm_insn ("xgdy", operands);
3527 output_asm_insn ("xgdx", operands);
3528 CC_STATUS_INIT;
3530 else if (!optimize_size)
3532 output_asm_insn ("sty\t%t1", operands);
3533 output_asm_insn ("ldx\t%t1", operands);
3535 else
3537 CC_STATUS_INIT;
3538 output_asm_insn ("pshy", operands);
3539 output_asm_insn ("pulx", operands);
3542 else if (SP_REG_P (operands[1]))
3544 /* tsx, tsy preserve the flags */
3545 cc_status = cc_prev_status;
3546 output_asm_insn ("tsx", operands);
3548 else
3550 output_asm_insn ("ldx\t%1", operands);
3552 break;
3554 case HARD_Y_REGNUM:
3555 if (D_REG_P (operands[1]))
3557 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3559 m68hc11_output_swap (insn, operands);
3561 else
3563 output_asm_insn ("std\t%t1", operands);
3564 output_asm_insn ("ldy\t%t1", operands);
3567 else if (X_REG_P (operands[1]))
3569 /* When both D and X are dead, use the sequence xgdx, xgdy
3570 to move X into Y. The D and X registers are modified. */
3571 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3572 && dead_register_here (insn, d_reg))
3574 output_asm_insn ("xgdx", operands);
3575 output_asm_insn ("xgdy", operands);
3576 CC_STATUS_INIT;
3578 else if (!optimize_size)
3580 output_asm_insn ("stx\t%t1", operands);
3581 output_asm_insn ("ldy\t%t1", operands);
3583 else
3585 CC_STATUS_INIT;
3586 output_asm_insn ("pshx", operands);
3587 output_asm_insn ("puly", operands);
3590 else if (SP_REG_P (operands[1]))
3592 /* tsx, tsy preserve the flags */
3593 cc_status = cc_prev_status;
3594 output_asm_insn ("tsy", operands);
3596 else
3598 output_asm_insn ("ldy\t%1", operands);
3600 break;
3602 case HARD_SP_REGNUM:
3603 if (D_REG_P (operands[1]))
3605 m68hc11_notice_keep_cc (operands[0]);
3606 output_asm_insn ("xgdx", operands);
3607 output_asm_insn ("txs", operands);
3608 output_asm_insn ("xgdx", operands);
3610 else if (X_REG_P (operands[1]))
3612 /* tys, txs preserve the flags */
3613 cc_status = cc_prev_status;
3614 output_asm_insn ("txs", operands);
3616 else if (Y_REG_P (operands[1]))
3618 /* tys, txs preserve the flags */
3619 cc_status = cc_prev_status;
3620 output_asm_insn ("tys", operands);
3622 else
3624 /* lds sets the flags but the des does not. */
3625 CC_STATUS_INIT;
3626 output_asm_insn ("lds\t%1", operands);
3627 output_asm_insn ("des", operands);
3629 break;
3631 default:
3632 fatal_insn ("invalid register in the move instruction", insn);
3633 break;
3635 return;
3637 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3638 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3640 output_asm_insn ("sts\t%0", operands);
3641 return;
3644 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3646 cc_status = cc_prev_status;
3647 switch (REGNO (operands[1]))
3649 case HARD_X_REGNUM:
3650 case HARD_Y_REGNUM:
3651 output_asm_insn ("psh%1", operands);
3652 break;
3653 case HARD_D_REGNUM:
3654 output_asm_insn ("pshb", operands);
3655 output_asm_insn ("psha", operands);
3656 break;
3657 default:
3658 abort ();
3660 return;
3663 /* Operand 1 must be a hard register. */
3664 if (!H_REG_P (operands[1]))
3666 fatal_insn ("invalid operand in the instruction", insn);
3669 reg = REGNO (operands[1]);
3670 switch (reg)
3672 case HARD_D_REGNUM:
3673 output_asm_insn ("std\t%0", operands);
3674 break;
3676 case HARD_X_REGNUM:
3677 output_asm_insn ("stx\t%0", operands);
3678 break;
3680 case HARD_Y_REGNUM:
3681 output_asm_insn ("sty\t%0", operands);
3682 break;
3684 case HARD_SP_REGNUM:
3685 if (ix_reg == 0)
3686 create_regs_rtx ();
3688 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3690 output_asm_insn ("pshx", operands);
3691 output_asm_insn ("tsx", operands);
3692 output_asm_insn ("inx", operands);
3693 output_asm_insn ("inx", operands);
3694 output_asm_insn ("stx\t%0", operands);
3695 output_asm_insn ("pulx", operands);
3698 else if (reg_mentioned_p (ix_reg, operands[0]))
3700 output_asm_insn ("sty\t%t0", operands);
3701 output_asm_insn ("tsy", operands);
3702 output_asm_insn ("sty\t%0", operands);
3703 output_asm_insn ("ldy\t%t0", operands);
3705 else
3707 output_asm_insn ("stx\t%t0", operands);
3708 output_asm_insn ("tsx", operands);
3709 output_asm_insn ("stx\t%0", operands);
3710 output_asm_insn ("ldx\t%t0", operands);
3712 CC_STATUS_INIT;
3713 break;
3715 default:
3716 fatal_insn ("invalid register in the move instruction", insn);
3717 break;
3721 void
3722 m68hc11_gen_movqi (rtx insn, rtx *operands)
3724 /* Move a register or memory to the same location.
3725 This is possible because such insn can appear
3726 in a non-optimizing mode. */
3727 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3729 cc_status = cc_prev_status;
3730 return;
3733 if (TARGET_M6812)
3736 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3738 m68hc11_notice_keep_cc (operands[0]);
3739 output_asm_insn ("tfr\t%1,%0", operands);
3741 else if (H_REG_P (operands[0]))
3743 if (Q_REG_P (operands[0]))
3744 output_asm_insn ("lda%0\t%b1", operands);
3745 else if (D_REG_P (operands[0]))
3746 output_asm_insn ("ldab\t%b1", operands);
3747 else
3748 goto m6811_move;
3750 else if (H_REG_P (operands[1]))
3752 if (Q_REG_P (operands[1]))
3753 output_asm_insn ("sta%1\t%b0", operands);
3754 else if (D_REG_P (operands[1]))
3755 output_asm_insn ("stab\t%b0", operands);
3756 else
3757 goto m6811_move;
3759 else
3761 rtx from = operands[1];
3762 rtx to = operands[0];
3764 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3765 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3766 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3767 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3769 rtx ops[3];
3771 if (operands[2])
3773 ops[0] = operands[2];
3774 ops[1] = from;
3775 ops[2] = 0;
3776 m68hc11_gen_movqi (insn, ops);
3777 ops[0] = to;
3778 ops[1] = operands[2];
3779 m68hc11_gen_movqi (insn, ops);
3781 else
3783 /* !!!! SCz wrong here. */
3784 fatal_insn ("move insn not handled", insn);
3787 else
3789 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3791 output_asm_insn ("clr\t%b0", operands);
3793 else
3795 m68hc11_notice_keep_cc (operands[0]);
3796 output_asm_insn ("movb\t%b1,%b0", operands);
3800 return;
3803 m6811_move:
3804 if (H_REG_P (operands[0]))
3806 switch (REGNO (operands[0]))
3808 case HARD_B_REGNUM:
3809 case HARD_D_REGNUM:
3810 if (X_REG_P (operands[1]))
3812 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3814 m68hc11_output_swap (insn, operands);
3816 else
3818 output_asm_insn ("stx\t%t1", operands);
3819 output_asm_insn ("ldab\t%T0", operands);
3822 else if (Y_REG_P (operands[1]))
3824 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3826 m68hc11_output_swap (insn, operands);
3828 else
3830 output_asm_insn ("sty\t%t1", operands);
3831 output_asm_insn ("ldab\t%T0", operands);
3834 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3835 && !DA_REG_P (operands[1]))
3837 output_asm_insn ("ldab\t%b1", operands);
3839 else if (DA_REG_P (operands[1]))
3841 output_asm_insn ("tab", operands);
3843 else
3845 cc_status = cc_prev_status;
3846 return;
3848 break;
3850 case HARD_A_REGNUM:
3851 if (X_REG_P (operands[1]))
3853 output_asm_insn ("stx\t%t1", operands);
3854 output_asm_insn ("ldaa\t%T0", operands);
3856 else if (Y_REG_P (operands[1]))
3858 output_asm_insn ("sty\t%t1", operands);
3859 output_asm_insn ("ldaa\t%T0", operands);
3861 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3862 && !DA_REG_P (operands[1]))
3864 output_asm_insn ("ldaa\t%b1", operands);
3866 else if (!DA_REG_P (operands[1]))
3868 output_asm_insn ("tba", operands);
3870 else
3872 cc_status = cc_prev_status;
3874 break;
3876 case HARD_X_REGNUM:
3877 if (D_REG_P (operands[1]))
3879 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3881 m68hc11_output_swap (insn, operands);
3883 else
3885 output_asm_insn ("stab\t%T1", operands);
3886 output_asm_insn ("ldx\t%t1", operands);
3888 CC_STATUS_INIT;
3890 else if (Y_REG_P (operands[1]))
3892 output_asm_insn ("sty\t%t0", operands);
3893 output_asm_insn ("ldx\t%t0", operands);
3895 else if (GET_CODE (operands[1]) == CONST_INT)
3897 output_asm_insn ("ldx\t%1", operands);
3899 else if (dead_register_here (insn, d_reg))
3901 output_asm_insn ("ldab\t%b1", operands);
3902 output_asm_insn ("xgdx", operands);
3904 else if (!reg_mentioned_p (operands[0], operands[1]))
3906 output_asm_insn ("xgdx", operands);
3907 output_asm_insn ("ldab\t%b1", operands);
3908 output_asm_insn ("xgdx", operands);
3910 else
3912 output_asm_insn ("pshb", operands);
3913 output_asm_insn ("ldab\t%b1", operands);
3914 output_asm_insn ("stab\t%T1", operands);
3915 output_asm_insn ("ldx\t%t1", operands);
3916 output_asm_insn ("pulb", operands);
3917 CC_STATUS_INIT;
3919 break;
3921 case HARD_Y_REGNUM:
3922 if (D_REG_P (operands[1]))
3924 output_asm_insn ("stab\t%T1", operands);
3925 output_asm_insn ("ldy\t%t1", operands);
3926 CC_STATUS_INIT;
3928 else if (X_REG_P (operands[1]))
3930 output_asm_insn ("stx\t%t1", operands);
3931 output_asm_insn ("ldy\t%t1", operands);
3932 CC_STATUS_INIT;
3934 else if (GET_CODE (operands[1]) == CONST_INT)
3936 output_asm_insn ("ldy\t%1", operands);
3938 else if (dead_register_here (insn, d_reg))
3940 output_asm_insn ("ldab\t%b1", operands);
3941 output_asm_insn ("xgdy", operands);
3943 else if (!reg_mentioned_p (operands[0], operands[1]))
3945 output_asm_insn ("xgdy", operands);
3946 output_asm_insn ("ldab\t%b1", operands);
3947 output_asm_insn ("xgdy", operands);
3949 else
3951 output_asm_insn ("pshb", operands);
3952 output_asm_insn ("ldab\t%b1", operands);
3953 output_asm_insn ("stab\t%T1", operands);
3954 output_asm_insn ("ldy\t%t1", operands);
3955 output_asm_insn ("pulb", operands);
3956 CC_STATUS_INIT;
3958 break;
3960 default:
3961 fatal_insn ("invalid register in the instruction", insn);
3962 break;
3965 else if (H_REG_P (operands[1]))
3967 switch (REGNO (operands[1]))
3969 case HARD_D_REGNUM:
3970 case HARD_B_REGNUM:
3971 output_asm_insn ("stab\t%b0", operands);
3972 break;
3974 case HARD_A_REGNUM:
3975 output_asm_insn ("staa\t%b0", operands);
3976 break;
3978 case HARD_X_REGNUM:
3979 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3980 break;
3982 case HARD_Y_REGNUM:
3983 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3984 break;
3986 default:
3987 fatal_insn ("invalid register in the move instruction", insn);
3988 break;
3990 return;
3992 else
3994 fatal_insn ("operand 1 must be a hard register", insn);
3998 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3999 The source and destination must be D or A and the shift must
4000 be a constant. */
4001 void
4002 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
4004 int val;
4006 if (GET_CODE (operands[2]) != CONST_INT
4007 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
4008 fatal_insn ("invalid rotate insn", insn);
4010 val = INTVAL (operands[2]);
4011 if (code == ROTATERT)
4012 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
4014 if (GET_MODE (operands[0]) != QImode)
4015 CC_STATUS_INIT;
4017 /* Rotate by 8-bits if the shift is within [5..11]. */
4018 if (val >= 5 && val <= 11)
4020 if (TARGET_M6812)
4021 output_asm_insn ("exg\ta,b", operands);
4022 else
4024 output_asm_insn ("psha", operands);
4025 output_asm_insn ("tba", operands);
4026 output_asm_insn ("pulb", operands);
4028 val -= 8;
4031 /* If the shift is big, invert the rotation. */
4032 else if (val >= 12)
4034 val = val - 16;
4037 if (val > 0)
4039 while (--val >= 0)
4041 /* Set the carry to bit-15, but don't change D yet. */
4042 if (GET_MODE (operands[0]) != QImode)
4044 output_asm_insn ("asra", operands);
4045 output_asm_insn ("rola", operands);
4048 /* Rotate B first to move the carry to bit-0. */
4049 if (D_REG_P (operands[0]))
4050 output_asm_insn ("rolb", operands);
4052 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
4053 output_asm_insn ("rola", operands);
4056 else
4058 while (++val <= 0)
4060 /* Set the carry to bit-8 of D. */
4061 if (GET_MODE (operands[0]) != QImode)
4062 output_asm_insn ("tap", operands);
4064 /* Rotate B first to move the carry to bit-7. */
4065 if (D_REG_P (operands[0]))
4066 output_asm_insn ("rorb", operands);
4068 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
4069 output_asm_insn ("rora", operands);
4076 /* Store in cc_status the expressions that the condition codes will
4077 describe after execution of an instruction whose pattern is EXP.
4078 Do not alter them if the instruction would not alter the cc's. */
4080 void
4081 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
4083 /* recognize SET insn's. */
4084 if (GET_CODE (exp) == SET)
4086 /* Jumps do not alter the cc's. */
4087 if (SET_DEST (exp) == pc_rtx)
4090 /* NOTE: most instructions don't affect the carry bit, but the
4091 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
4092 the conditions.h header. */
4094 /* Function calls clobber the cc's. */
4095 else if (GET_CODE (SET_SRC (exp)) == CALL)
4097 CC_STATUS_INIT;
4100 /* Tests and compares set the cc's in predictable ways. */
4101 else if (SET_DEST (exp) == cc0_rtx)
4103 cc_status.flags = 0;
4104 cc_status.value1 = XEXP (exp, 0);
4105 cc_status.value2 = XEXP (exp, 1);
4107 else
4109 /* All other instructions affect the condition codes. */
4110 cc_status.flags = 0;
4111 cc_status.value1 = XEXP (exp, 0);
4112 cc_status.value2 = XEXP (exp, 1);
4115 else
4117 /* Default action if we haven't recognized something
4118 and returned earlier. */
4119 CC_STATUS_INIT;
4122 if (cc_status.value2 != 0)
4123 switch (GET_CODE (cc_status.value2))
4125 /* These logical operations can generate several insns.
4126 The flags are setup according to what is generated. */
4127 case IOR:
4128 case XOR:
4129 case AND:
4130 break;
4132 /* The (not ...) generates several 'com' instructions for
4133 non QImode. We have to invalidate the flags. */
4134 case NOT:
4135 if (GET_MODE (cc_status.value2) != QImode)
4136 CC_STATUS_INIT;
4137 break;
4139 case PLUS:
4140 case MINUS:
4141 case MULT:
4142 case DIV:
4143 case UDIV:
4144 case MOD:
4145 case UMOD:
4146 case NEG:
4147 if (GET_MODE (cc_status.value2) != VOIDmode)
4148 cc_status.flags |= CC_NO_OVERFLOW;
4149 break;
4151 /* The asl sets the overflow bit in such a way that this
4152 makes the flags unusable for a next compare insn. */
4153 case ASHIFT:
4154 case ROTATE:
4155 case ROTATERT:
4156 if (GET_MODE (cc_status.value2) != VOIDmode)
4157 cc_status.flags |= CC_NO_OVERFLOW;
4158 break;
4160 /* A load/store instruction does not affect the carry. */
4161 case MEM:
4162 case SYMBOL_REF:
4163 case REG:
4164 case CONST_INT:
4165 cc_status.flags |= CC_NO_OVERFLOW;
4166 break;
4168 default:
4169 break;
4171 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
4172 && cc_status.value2
4173 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
4174 cc_status.value2 = 0;
4176 else if (cc_status.value1 && side_effects_p (cc_status.value1))
4177 cc_status.value1 = 0;
4179 else if (cc_status.value2 && side_effects_p (cc_status.value2))
4180 cc_status.value2 = 0;
4183 /* The current instruction does not affect the flags but changes
4184 the register 'reg'. See if the previous flags can be kept for the
4185 next instruction to avoid a comparison. */
4186 void
4187 m68hc11_notice_keep_cc (rtx reg)
4189 if (reg == 0
4190 || cc_prev_status.value1 == 0
4191 || rtx_equal_p (reg, cc_prev_status.value1)
4192 || (cc_prev_status.value2
4193 && reg_mentioned_p (reg, cc_prev_status.value2)))
4194 CC_STATUS_INIT;
4195 else
4196 cc_status = cc_prev_status;
4201 /* Machine Specific Reorg. */
4203 /* Z register replacement:
4205 GCC treats the Z register as an index base address register like
4206 X or Y. In general, it uses it during reload to compute the address
4207 of some operand. This helps the reload pass to avoid to fall into the
4208 register spill failure.
4210 The Z register is in the A_REGS class. In the machine description,
4211 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4213 It can appear everywhere an X or Y register can appear, except for
4214 some templates in the clobber section (when a clobber of X or Y is asked).
4215 For a given instruction, the template must ensure that no more than
4216 2 'A' registers are used. Otherwise, the register replacement is not
4217 possible.
4219 To replace the Z register, the algorithm is not terrific:
4220 1. Insns that do not use the Z register are not changed
4221 2. When a Z register is used, we scan forward the insns to see
4222 a potential register to use: either X or Y and sometimes D.
4223 We stop when a call, a label or a branch is seen, or when we
4224 detect that both X and Y are used (probably at different times, but it does
4225 not matter).
4226 3. The register that will be used for the replacement of Z is saved
4227 in a .page0 register or on the stack. If the first instruction that
4228 used Z, uses Z as an input, the value is loaded from another .page0
4229 register. The replacement register is pushed on the stack in the
4230 rare cases where a compare insn uses Z and we couldn't find if X/Y
4231 are dead.
4232 4. The Z register is replaced in all instructions until we reach
4233 the end of the Z-block, as detected by step 2.
4234 5. If we detect that Z is still alive, its value is saved.
4235 If the replacement register is alive, its old value is loaded.
4237 The Z register can be disabled with -ffixed-z.
4240 struct replace_info
4242 rtx first;
4243 rtx replace_reg;
4244 int need_save_z;
4245 int must_load_z;
4246 int must_save_reg;
4247 int must_restore_reg;
4248 rtx last;
4249 int regno;
4250 int x_used;
4251 int y_used;
4252 int can_use_d;
4253 int found_call;
4254 int z_died;
4255 int z_set_count;
4256 rtx z_value;
4257 int must_push_reg;
4258 int save_before_last;
4259 int z_loaded_with_sp;
4262 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4263 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4264 static void m68hc11_z_replacement (rtx);
4265 static void m68hc11_reassign_regs (rtx);
4267 int z_replacement_completed = 0;
4269 /* Analyze the insn to find out which replacement register to use and
4270 the boundaries of the replacement.
4271 Returns 0 if we reached the last insn to be replaced, 1 if we can
4272 continue replacement in next insns. */
4274 static int
4275 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4277 int this_insn_uses_ix;
4278 int this_insn_uses_iy;
4279 int this_insn_uses_z;
4280 int this_insn_uses_z_in_dst;
4281 int this_insn_uses_d;
4282 rtx body;
4283 int z_dies_here;
4285 /* A call is said to clobber the Z register, we don't need
4286 to save the value of Z. We also don't need to restore
4287 the replacement register (unless it is used by the call). */
4288 if (GET_CODE (insn) == CALL_INSN)
4290 body = PATTERN (insn);
4292 info->can_use_d = 0;
4294 /* If the call is an indirect call with Z, we have to use the
4295 Y register because X can be used as an input (D+X).
4296 We also must not save Z nor restore Y. */
4297 if (reg_mentioned_p (z_reg, body))
4299 insn = NEXT_INSN (insn);
4300 info->x_used = 1;
4301 info->y_used = 0;
4302 info->found_call = 1;
4303 info->must_restore_reg = 0;
4304 info->last = NEXT_INSN (insn);
4306 info->need_save_z = 0;
4307 return 0;
4309 if (GET_CODE (insn) == CODE_LABEL
4310 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4311 return 0;
4313 if (GET_CODE (insn) == JUMP_INSN)
4315 if (reg_mentioned_p (z_reg, insn) == 0)
4316 return 0;
4318 info->can_use_d = 0;
4319 info->must_save_reg = 0;
4320 info->must_restore_reg = 0;
4321 info->need_save_z = 0;
4322 info->last = NEXT_INSN (insn);
4323 return 0;
4325 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4327 return 1;
4330 /* Z register dies here. */
4331 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4333 body = PATTERN (insn);
4334 if (GET_CODE (body) == SET)
4336 rtx src = XEXP (body, 1);
4337 rtx dst = XEXP (body, 0);
4339 /* Condition code is set here. We have to restore the X/Y and
4340 save into Z before any test/compare insn because once we save/restore
4341 we can change the condition codes. When the compare insn uses Z and
4342 we can't use X/Y, the comparison is made with the *ZREG soft register
4343 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4344 if (dst == cc0_rtx)
4346 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4347 || (GET_CODE (src) == COMPARE &&
4348 ((rtx_equal_p (XEXP (src, 0), z_reg)
4349 && H_REG_P (XEXP (src, 1)))
4350 || (rtx_equal_p (XEXP (src, 1), z_reg)
4351 && H_REG_P (XEXP (src, 0))))))
4353 if (insn == info->first)
4355 info->must_load_z = 0;
4356 info->must_save_reg = 0;
4357 info->must_restore_reg = 0;
4358 info->need_save_z = 0;
4359 info->found_call = 1;
4360 info->regno = SOFT_Z_REGNUM;
4361 info->last = NEXT_INSN (insn);
4363 return 0;
4365 if (reg_mentioned_p (z_reg, src) == 0)
4367 info->can_use_d = 0;
4368 return 0;
4371 if (insn != info->first)
4372 return 0;
4374 /* Compare insn which uses Z. We have to save/restore the X/Y
4375 register without modifying the condition codes. For this
4376 we have to use a push/pop insn. */
4377 info->must_push_reg = 1;
4378 info->last = insn;
4381 /* Z reg is set to something new. We don't need to load it. */
4382 if (Z_REG_P (dst))
4384 if (!reg_mentioned_p (z_reg, src))
4386 /* Z reg is used before being set. Treat this as
4387 a new sequence of Z register replacement. */
4388 if (insn != info->first)
4390 return 0;
4392 info->must_load_z = 0;
4394 info->z_set_count++;
4395 info->z_value = src;
4396 if (SP_REG_P (src))
4397 info->z_loaded_with_sp = 1;
4399 else if (reg_mentioned_p (z_reg, dst))
4400 info->can_use_d = 0;
4402 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4403 | reg_mentioned_p (d_reg, dst);
4404 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4405 | reg_mentioned_p (ix_reg, dst);
4406 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4407 | reg_mentioned_p (iy_reg, dst);
4408 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4410 /* If z is used as an address operand (like (MEM (reg z))),
4411 we can't replace it with d. */
4412 if (this_insn_uses_z && !Z_REG_P (src)
4413 && !(m68hc11_arith_operator (src, GET_MODE (src))
4414 && Z_REG_P (XEXP (src, 0))
4415 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4416 && insn == info->first
4417 && dead_register_here (insn, d_reg)))
4418 info->can_use_d = 0;
4420 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4421 if (TARGET_M6812 && !z_dies_here
4422 && ((this_insn_uses_z && side_effects_p (src))
4423 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4425 info->need_save_z = 1;
4426 info->z_set_count++;
4428 this_insn_uses_z |= this_insn_uses_z_in_dst;
4430 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4432 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4435 if (this_insn_uses_d)
4436 info->can_use_d = 0;
4438 /* IX and IY are used at the same time, we have to restore
4439 the value of the scratch register before this insn. */
4440 if (this_insn_uses_ix && this_insn_uses_iy)
4442 return 0;
4445 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4446 info->can_use_d = 0;
4448 if (info->x_used == 0 && this_insn_uses_ix)
4450 if (info->y_used)
4452 /* We have a (set (REG:HI X) (REG:HI Z)).
4453 Since we use Z as the replacement register, this insn
4454 is no longer necessary. We turn it into a note. We must
4455 not reload the old value of X. */
4456 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4458 if (z_dies_here)
4460 info->need_save_z = 0;
4461 info->z_died = 1;
4463 info->must_save_reg = 0;
4464 info->must_restore_reg = 0;
4465 info->found_call = 1;
4466 info->can_use_d = 0;
4467 PUT_CODE (insn, NOTE);
4468 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4469 NOTE_SOURCE_FILE (insn) = 0;
4470 info->last = NEXT_INSN (insn);
4471 return 0;
4474 if (X_REG_P (dst)
4475 && (rtx_equal_p (src, z_reg)
4476 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4478 if (z_dies_here)
4480 info->need_save_z = 0;
4481 info->z_died = 1;
4483 info->last = NEXT_INSN (insn);
4484 info->must_save_reg = 0;
4485 info->must_restore_reg = 0;
4487 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4488 && !reg_mentioned_p (ix_reg, src))
4490 if (z_dies_here)
4492 info->z_died = 1;
4493 info->need_save_z = 0;
4495 else if (TARGET_M6812 && side_effects_p (src))
4497 info->last = 0;
4498 info->must_restore_reg = 0;
4499 return 0;
4501 else
4503 info->save_before_last = 1;
4505 info->must_restore_reg = 0;
4506 info->last = NEXT_INSN (insn);
4508 else if (info->can_use_d)
4510 info->last = NEXT_INSN (insn);
4511 info->x_used = 1;
4513 return 0;
4515 info->x_used = 1;
4516 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4517 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4519 info->need_save_z = 0;
4520 info->z_died = 1;
4521 info->last = NEXT_INSN (insn);
4522 info->regno = HARD_X_REGNUM;
4523 info->must_save_reg = 0;
4524 info->must_restore_reg = 0;
4525 return 0;
4527 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4529 info->regno = HARD_X_REGNUM;
4530 info->must_restore_reg = 0;
4531 info->must_save_reg = 0;
4532 return 0;
4535 if (info->y_used == 0 && this_insn_uses_iy)
4537 if (info->x_used)
4539 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4541 if (z_dies_here)
4543 info->need_save_z = 0;
4544 info->z_died = 1;
4546 info->must_save_reg = 0;
4547 info->must_restore_reg = 0;
4548 info->found_call = 1;
4549 info->can_use_d = 0;
4550 PUT_CODE (insn, NOTE);
4551 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4552 NOTE_SOURCE_FILE (insn) = 0;
4553 info->last = NEXT_INSN (insn);
4554 return 0;
4557 if (Y_REG_P (dst)
4558 && (rtx_equal_p (src, z_reg)
4559 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4561 if (z_dies_here)
4563 info->z_died = 1;
4564 info->need_save_z = 0;
4566 info->last = NEXT_INSN (insn);
4567 info->must_save_reg = 0;
4568 info->must_restore_reg = 0;
4570 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4571 && !reg_mentioned_p (iy_reg, src))
4573 if (z_dies_here)
4575 info->z_died = 1;
4576 info->need_save_z = 0;
4578 else if (TARGET_M6812 && side_effects_p (src))
4580 info->last = 0;
4581 info->must_restore_reg = 0;
4582 return 0;
4584 else
4586 info->save_before_last = 1;
4588 info->must_restore_reg = 0;
4589 info->last = NEXT_INSN (insn);
4591 else if (info->can_use_d)
4593 info->last = NEXT_INSN (insn);
4594 info->y_used = 1;
4597 return 0;
4599 info->y_used = 1;
4600 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4601 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4603 info->need_save_z = 0;
4604 info->z_died = 1;
4605 info->last = NEXT_INSN (insn);
4606 info->regno = HARD_Y_REGNUM;
4607 info->must_save_reg = 0;
4608 info->must_restore_reg = 0;
4609 return 0;
4611 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4613 info->regno = HARD_Y_REGNUM;
4614 info->must_restore_reg = 0;
4615 info->must_save_reg = 0;
4616 return 0;
4619 if (z_dies_here)
4621 info->need_save_z = 0;
4622 info->z_died = 1;
4623 if (info->last == 0)
4624 info->last = NEXT_INSN (insn);
4625 return 0;
4627 return info->last != NULL_RTX ? 0 : 1;
4629 if (GET_CODE (body) == PARALLEL)
4631 int i;
4632 char ix_clobber = 0;
4633 char iy_clobber = 0;
4634 char z_clobber = 0;
4635 this_insn_uses_iy = 0;
4636 this_insn_uses_ix = 0;
4637 this_insn_uses_z = 0;
4639 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4641 rtx x;
4642 int uses_ix, uses_iy, uses_z;
4644 x = XVECEXP (body, 0, i);
4646 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4647 info->can_use_d = 0;
4649 uses_ix = reg_mentioned_p (ix_reg, x);
4650 uses_iy = reg_mentioned_p (iy_reg, x);
4651 uses_z = reg_mentioned_p (z_reg, x);
4652 if (GET_CODE (x) == CLOBBER)
4654 ix_clobber |= uses_ix;
4655 iy_clobber |= uses_iy;
4656 z_clobber |= uses_z;
4658 else
4660 this_insn_uses_ix |= uses_ix;
4661 this_insn_uses_iy |= uses_iy;
4662 this_insn_uses_z |= uses_z;
4664 if (uses_z && GET_CODE (x) == SET)
4666 rtx dst = XEXP (x, 0);
4668 if (Z_REG_P (dst))
4669 info->z_set_count++;
4671 if (TARGET_M6812 && uses_z && side_effects_p (x))
4672 info->need_save_z = 1;
4674 if (z_clobber)
4675 info->need_save_z = 0;
4677 if (debug_m6811)
4679 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4680 this_insn_uses_ix, this_insn_uses_iy,
4681 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4682 debug_rtx (insn);
4684 if (this_insn_uses_z)
4685 info->can_use_d = 0;
4687 if (z_clobber && info->first != insn)
4689 info->need_save_z = 0;
4690 info->last = insn;
4691 return 0;
4693 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4695 if (this_insn_uses_z == 0 && insn == info->first)
4697 info->must_load_z = 0;
4699 if (dead_register_here (insn, d_reg))
4701 info->regno = HARD_D_REGNUM;
4702 info->must_save_reg = 0;
4703 info->must_restore_reg = 0;
4705 else if (dead_register_here (insn, ix_reg))
4707 info->regno = HARD_X_REGNUM;
4708 info->must_save_reg = 0;
4709 info->must_restore_reg = 0;
4711 else if (dead_register_here (insn, iy_reg))
4713 info->regno = HARD_Y_REGNUM;
4714 info->must_save_reg = 0;
4715 info->must_restore_reg = 0;
4717 if (info->regno >= 0)
4719 info->last = NEXT_INSN (insn);
4720 return 0;
4722 if (this_insn_uses_ix == 0)
4724 info->regno = HARD_X_REGNUM;
4725 info->must_save_reg = 1;
4726 info->must_restore_reg = 1;
4728 else if (this_insn_uses_iy == 0)
4730 info->regno = HARD_Y_REGNUM;
4731 info->must_save_reg = 1;
4732 info->must_restore_reg = 1;
4734 else
4736 info->regno = HARD_D_REGNUM;
4737 info->must_save_reg = 1;
4738 info->must_restore_reg = 1;
4740 info->last = NEXT_INSN (insn);
4741 return 0;
4744 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4745 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4747 if (this_insn_uses_z)
4749 if (info->y_used == 0 && iy_clobber)
4751 info->regno = HARD_Y_REGNUM;
4752 info->must_save_reg = 0;
4753 info->must_restore_reg = 0;
4755 if (info->first != insn
4756 && ((info->y_used && ix_clobber)
4757 || (info->x_used && iy_clobber)))
4758 info->last = insn;
4759 else
4760 info->last = NEXT_INSN (insn);
4761 info->save_before_last = 1;
4763 return 0;
4765 if (this_insn_uses_ix && this_insn_uses_iy)
4767 if (this_insn_uses_z)
4769 fatal_insn ("cannot do z-register replacement", insn);
4771 return 0;
4773 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4775 if (info->y_used)
4777 return 0;
4779 info->x_used = 1;
4780 if (iy_clobber || z_clobber)
4782 info->last = NEXT_INSN (insn);
4783 info->save_before_last = 1;
4784 return 0;
4788 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4790 if (info->x_used)
4792 return 0;
4794 info->y_used = 1;
4795 if (ix_clobber || z_clobber)
4797 info->last = NEXT_INSN (insn);
4798 info->save_before_last = 1;
4799 return 0;
4802 if (z_dies_here)
4804 info->z_died = 1;
4805 info->need_save_z = 0;
4807 return 1;
4809 if (GET_CODE (body) == CLOBBER)
4812 /* IX and IY are used at the same time, we have to restore
4813 the value of the scratch register before this insn. */
4814 if (this_insn_uses_ix && this_insn_uses_iy)
4816 return 0;
4818 if (info->x_used == 0 && this_insn_uses_ix)
4820 if (info->y_used)
4822 return 0;
4824 info->x_used = 1;
4826 if (info->y_used == 0 && this_insn_uses_iy)
4828 if (info->x_used)
4830 return 0;
4832 info->y_used = 1;
4834 return 1;
4836 return 1;
4839 static void
4840 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4842 int reg;
4844 info->replace_reg = NULL_RTX;
4845 info->must_load_z = 1;
4846 info->need_save_z = 1;
4847 info->must_save_reg = 1;
4848 info->must_restore_reg = 1;
4849 info->first = insn;
4850 info->x_used = 0;
4851 info->y_used = 0;
4852 info->can_use_d = TARGET_M6811 ? 1 : 0;
4853 info->found_call = 0;
4854 info->z_died = 0;
4855 info->last = 0;
4856 info->regno = -1;
4857 info->z_set_count = 0;
4858 info->z_value = NULL_RTX;
4859 info->must_push_reg = 0;
4860 info->save_before_last = 0;
4861 info->z_loaded_with_sp = 0;
4863 /* Scan the insn forward to find an address register that is not used.
4864 Stop when:
4865 - the flow of the program changes,
4866 - when we detect that both X and Y are necessary,
4867 - when the Z register dies,
4868 - when the condition codes are set. */
4870 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4872 if (m68hc11_check_z_replacement (insn, info) == 0)
4873 break;
4876 /* May be we can use Y or X if they contain the same value as Z.
4877 This happens very often after the reload. */
4878 if (info->z_set_count == 1)
4880 rtx p = info->first;
4881 rtx v = 0;
4883 if (info->x_used)
4885 v = find_last_value (iy_reg, &p, insn, 1);
4887 else if (info->y_used)
4889 v = find_last_value (ix_reg, &p, insn, 1);
4891 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4893 if (info->x_used)
4894 info->regno = HARD_Y_REGNUM;
4895 else
4896 info->regno = HARD_X_REGNUM;
4897 info->must_load_z = 0;
4898 info->must_save_reg = 0;
4899 info->must_restore_reg = 0;
4900 info->found_call = 1;
4903 if (info->z_set_count == 0)
4904 info->need_save_z = 0;
4906 if (insn == 0)
4907 info->need_save_z = 0;
4909 if (info->last == 0)
4910 info->last = insn;
4912 if (info->regno >= 0)
4914 reg = info->regno;
4915 info->replace_reg = gen_rtx_REG (HImode, reg);
4917 else if (info->can_use_d)
4919 reg = HARD_D_REGNUM;
4920 info->replace_reg = d_reg;
4922 else if (info->x_used)
4924 reg = HARD_Y_REGNUM;
4925 info->replace_reg = iy_reg;
4927 else
4929 reg = HARD_X_REGNUM;
4930 info->replace_reg = ix_reg;
4932 info->regno = reg;
4934 if (info->must_save_reg && info->must_restore_reg)
4936 if (insn && dead_register_here (insn, info->replace_reg))
4938 info->must_save_reg = 0;
4939 info->must_restore_reg = 0;
4944 /* The insn uses the Z register. Find a replacement register for it
4945 (either X or Y) and replace it in the insn and the next ones until
4946 the flow changes or the replacement register is used. Instructions
4947 are emitted before and after the Z-block to preserve the value of
4948 Z and of the replacement register. */
4950 static void
4951 m68hc11_z_replacement (rtx insn)
4953 rtx replace_reg_qi;
4954 rtx replace_reg;
4955 struct replace_info info;
4957 /* Find trivial case where we only need to replace z with the
4958 equivalent soft register. */
4959 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4961 rtx body = PATTERN (insn);
4962 rtx src = XEXP (body, 1);
4963 rtx dst = XEXP (body, 0);
4965 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4967 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4968 return;
4970 else if (Z_REG_P (src)
4971 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4973 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4974 return;
4976 else if (D_REG_P (dst)
4977 && m68hc11_arith_operator (src, GET_MODE (src))
4978 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4980 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4981 return;
4983 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4984 && INTVAL (src) == 0)
4986 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4987 /* Force it to be re-recognized. */
4988 INSN_CODE (insn) = -1;
4989 return;
4993 m68hc11_find_z_replacement (insn, &info);
4995 replace_reg = info.replace_reg;
4996 replace_reg_qi = NULL_RTX;
4998 /* Save the X register in a .page0 location. */
4999 if (info.must_save_reg && !info.must_push_reg)
5001 rtx dst;
5003 if (info.must_push_reg && 0)
5004 dst = gen_rtx_MEM (HImode,
5005 gen_rtx_PRE_DEC (HImode,
5006 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
5007 else
5008 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
5010 emit_insn_before (gen_movhi (dst,
5011 gen_rtx_REG (HImode, info.regno)), insn);
5013 if (info.must_load_z && !info.must_push_reg)
5015 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
5016 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
5017 insn);
5021 /* Replace all occurrence of Z by replace_reg.
5022 Stop when the last instruction to replace is reached.
5023 Also stop when we detect a change in the flow (but it's not
5024 necessary; just safeguard). */
5026 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
5028 rtx body;
5030 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
5031 break;
5033 if (GET_CODE (insn) != INSN
5034 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
5035 continue;
5037 body = PATTERN (insn);
5038 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5039 || GET_CODE (body) == ASM_OPERANDS
5040 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5042 rtx note;
5044 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
5046 printf ("Reg mentioned here...:\n");
5047 fflush (stdout);
5048 debug_rtx (insn);
5051 /* Stack pointer was decremented by 2 due to the push.
5052 Correct that by adding 2 to the destination. */
5053 if (info.must_push_reg
5054 && info.z_loaded_with_sp && GET_CODE (body) == SET)
5056 rtx src, dst;
5058 src = SET_SRC (body);
5059 dst = SET_DEST (body);
5060 if (SP_REG_P (src) && Z_REG_P (dst))
5061 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
5064 /* Replace any (REG:HI Z) occurrence by either X or Y. */
5065 if (!validate_replace_rtx (z_reg, replace_reg, insn))
5067 INSN_CODE (insn) = -1;
5068 if (!validate_replace_rtx (z_reg, replace_reg, insn))
5069 fatal_insn ("cannot do z-register replacement", insn);
5072 /* Likewise for (REG:QI Z). */
5073 if (reg_mentioned_p (z_reg, insn))
5075 if (replace_reg_qi == NULL_RTX)
5076 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
5077 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
5080 /* If there is a REG_INC note on Z, replace it with a
5081 REG_INC note on the replacement register. This is necessary
5082 to make sure that the flow pass will identify the change
5083 and it will not remove a possible insn that saves Z. */
5084 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
5086 if (REG_NOTE_KIND (note) == REG_INC
5087 && GET_CODE (XEXP (note, 0)) == REG
5088 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
5090 XEXP (note, 0) = replace_reg;
5094 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5095 break;
5098 /* Save Z before restoring the old value. */
5099 if (insn && info.need_save_z && !info.must_push_reg)
5101 rtx save_pos_insn = insn;
5103 /* If Z is clobber by the last insn, we have to save its value
5104 before the last instruction. */
5105 if (info.save_before_last)
5106 save_pos_insn = PREV_INSN (save_pos_insn);
5108 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
5109 gen_rtx_REG (HImode, info.regno)),
5110 save_pos_insn);
5113 if (info.must_push_reg && info.last)
5115 rtx new_body, body;
5117 body = PATTERN (info.last);
5118 new_body = gen_rtx_PARALLEL (VOIDmode,
5119 gen_rtvec (3, body,
5120 gen_rtx_USE (VOIDmode,
5121 replace_reg),
5122 gen_rtx_USE (VOIDmode,
5123 gen_rtx_REG (HImode,
5124 SOFT_Z_REGNUM))));
5125 PATTERN (info.last) = new_body;
5127 /* Force recognition on insn since we changed it. */
5128 INSN_CODE (insn) = -1;
5130 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
5132 fatal_insn ("invalid Z register replacement for insn", insn);
5134 insn = NEXT_INSN (info.last);
5137 /* Restore replacement register unless it was died. */
5138 if (insn && info.must_restore_reg && !info.must_push_reg)
5140 rtx dst;
5142 if (info.must_push_reg && 0)
5143 dst = gen_rtx_MEM (HImode,
5144 gen_rtx_POST_INC (HImode,
5145 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
5146 else
5147 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
5149 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
5150 dst), insn);
5156 /* Scan all the insn and re-affects some registers
5157 - The Z register (if it was used), is affected to X or Y depending
5158 on the instruction. */
5160 static void
5161 m68hc11_reassign_regs (rtx first)
5163 rtx insn;
5165 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
5166 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
5167 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5168 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
5170 /* Scan all insns to replace Z by X or Y preserving the old value
5171 of X/Y and restoring it afterward. */
5173 for (insn = first; insn; insn = NEXT_INSN (insn))
5175 rtx body;
5177 if (GET_CODE (insn) == CODE_LABEL
5178 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
5179 continue;
5181 if (!INSN_P (insn))
5182 continue;
5184 body = PATTERN (insn);
5185 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
5186 continue;
5188 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5189 || GET_CODE (body) == ASM_OPERANDS
5190 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5191 continue;
5193 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5194 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5197 /* If Z appears in this insn, replace it in the current insn
5198 and the next ones until the flow changes or we have to
5199 restore back the replacement register. */
5201 if (reg_mentioned_p (z_reg, body))
5203 m68hc11_z_replacement (insn);
5206 else
5208 printf ("insn not handled by Z replacement:\n");
5209 fflush (stdout);
5210 debug_rtx (insn);
5216 /* Machine-dependent reorg pass.
5217 Specific optimizations are defined here:
5218 - this pass changes the Z register into either X or Y
5219 (it preserves X/Y previous values in a memory slot in page0).
5221 When this pass is finished, the global variable
5222 'z_replacement_completed' is set to 2. */
5224 static void
5225 m68hc11_reorg (void)
5227 int split_done = 0;
5228 rtx insn, first;
5230 z_replacement_completed = 0;
5231 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5232 first = get_insns ();
5234 /* Some RTX are shared at this point. This breaks the Z register
5235 replacement, unshare everything. */
5236 unshare_all_rtl_again (first);
5238 /* Force a split of all splitable insn. This is necessary for the
5239 Z register replacement mechanism because we end up with basic insns. */
5240 split_all_insns_noflow ();
5241 split_done = 1;
5243 z_replacement_completed = 1;
5244 m68hc11_reassign_regs (first);
5246 if (optimize)
5247 compute_bb_for_insn ();
5249 /* After some splitting, there are some opportunities for CSE pass.
5250 This happens quite often when 32-bit or above patterns are split. */
5251 if (optimize > 0 && split_done)
5253 reload_cse_regs (first);
5256 /* Re-create the REG_DEAD notes. These notes are used in the machine
5257 description to use the best assembly directives. */
5258 if (optimize)
5260 /* Before recomputing the REG_DEAD notes, remove all of them.
5261 This is necessary because the reload_cse_regs() pass can
5262 have replaced some (MEM) with a register. In that case,
5263 the REG_DEAD that could exist for that register may become
5264 wrong. */
5265 for (insn = first; insn; insn = NEXT_INSN (insn))
5267 if (INSN_P (insn))
5269 rtx *pnote;
5271 pnote = &REG_NOTES (insn);
5272 while (*pnote != 0)
5274 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5275 *pnote = XEXP (*pnote, 1);
5276 else
5277 pnote = &XEXP (*pnote, 1);
5282 life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5285 z_replacement_completed = 2;
5287 /* If optimizing, then go ahead and split insns that must be
5288 split after Z register replacement. This gives more opportunities
5289 for peephole (in particular for consecutives xgdx/xgdy). */
5290 if (optimize > 0)
5291 split_all_insns_noflow ();
5293 /* Once insns are split after the z_replacement_completed == 2,
5294 we must not re-run the life_analysis. The xgdx/xgdy patterns
5295 are not recognized and the life_analysis pass removes some
5296 insns because it thinks some (SETs) are noops or made to dead
5297 stores (which is false due to the swap).
5299 Do a simple pass to eliminate the noop set that the final
5300 split could generate (because it was easier for split definition). */
5302 rtx insn;
5304 for (insn = first; insn; insn = NEXT_INSN (insn))
5306 rtx body;
5308 if (INSN_DELETED_P (insn))
5309 continue;
5310 if (!INSN_P (insn))
5311 continue;
5313 /* Remove the (set (R) (R)) insns generated by some splits. */
5314 body = PATTERN (insn);
5315 if (GET_CODE (body) == SET
5316 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5318 PUT_CODE (insn, NOTE);
5319 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5320 NOTE_SOURCE_FILE (insn) = 0;
5321 continue;
5327 /* Override memcpy */
5329 static void
5330 m68hc11_init_libfuncs (void)
5332 memcpy_libfunc = init_one_libfunc ("__memcpy");
5333 memcmp_libfunc = init_one_libfunc ("__memcmp");
5334 memset_libfunc = init_one_libfunc ("__memset");
5339 /* Cost functions. */
5341 /* Cost of moving memory. */
5343 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class class,
5344 int in ATTRIBUTE_UNUSED)
5346 if (class <= H_REGS && class > NO_REGS)
5348 if (GET_MODE_SIZE (mode) <= 2)
5349 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5350 else
5351 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5353 else
5355 if (GET_MODE_SIZE (mode) <= 2)
5356 return COSTS_N_INSNS (3);
5357 else
5358 return COSTS_N_INSNS (4);
5363 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5364 Reload does not check the constraint of set insns when the two registers
5365 have a move cost of 2. Setting a higher cost will force reload to check
5366 the constraints. */
5368 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5369 enum reg_class to)
5371 /* All costs are symmetric, so reduce cases by putting the
5372 lower number class as the destination. */
5373 if (from < to)
5375 enum reg_class tmp = to;
5376 to = from, from = tmp;
5378 if (to >= S_REGS)
5379 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5380 else if (from <= S_REGS)
5381 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5382 else
5383 return COSTS_N_INSNS (2);
5387 /* Provide the costs of an addressing mode that contains ADDR.
5388 If ADDR is not a valid address, its cost is irrelevant. */
5390 static int
5391 m68hc11_address_cost (rtx addr)
5393 int cost = 4;
5395 switch (GET_CODE (addr))
5397 case REG:
5398 /* Make the cost of hard registers and specially SP, FP small. */
5399 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5400 cost = 0;
5401 else
5402 cost = 1;
5403 break;
5405 case SYMBOL_REF:
5406 cost = 8;
5407 break;
5409 case LABEL_REF:
5410 case CONST:
5411 cost = 0;
5412 break;
5414 case PLUS:
5416 register rtx plus0 = XEXP (addr, 0);
5417 register rtx plus1 = XEXP (addr, 1);
5419 if (GET_CODE (plus0) != REG)
5420 break;
5422 switch (GET_CODE (plus1))
5424 case CONST_INT:
5425 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5426 || INTVAL (plus1) < m68hc11_min_offset)
5427 cost = 3;
5428 else if (INTVAL (plus1) >= m68hc11_max_offset)
5429 cost = 2;
5430 else
5431 cost = 1;
5432 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5433 cost += 0;
5434 else
5435 cost += 1;
5436 break;
5438 case SYMBOL_REF:
5439 cost = 8;
5440 break;
5442 case CONST:
5443 case LABEL_REF:
5444 cost = 0;
5445 break;
5447 default:
5448 break;
5450 break;
5452 case PRE_DEC:
5453 case PRE_INC:
5454 if (SP_REG_P (XEXP (addr, 0)))
5455 cost = 1;
5456 break;
5458 default:
5459 break;
5461 if (debug_m6811)
5463 printf ("Address cost: %d for :", cost);
5464 fflush (stdout);
5465 debug_rtx (addr);
5468 return cost;
5471 static int
5472 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5474 int total;
5476 total = rtx_cost (x, SET);
5477 if (mode == QImode)
5478 total += m68hc11_cost->shiftQI_const[shift % 8];
5479 else if (mode == HImode)
5480 total += m68hc11_cost->shiftHI_const[shift % 16];
5481 else if (shift == 8 || shift == 16 || shift == 32)
5482 total += m68hc11_cost->shiftHI_const[8];
5483 else if (shift != 0 && shift != 16 && shift != 32)
5485 total += m68hc11_cost->shiftHI_const[1] * shift;
5488 /* For SI and others, the cost is higher. */
5489 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5490 total *= GET_MODE_SIZE (mode) / 2;
5492 /* When optimizing for size, make shift more costly so that
5493 multiplications are preferred. */
5494 if (optimize_size && (shift % 8) != 0)
5495 total *= 2;
5497 return total;
5500 static int
5501 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5502 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5504 enum machine_mode mode = GET_MODE (x);
5505 int extra_cost = 0;
5506 int total;
5508 switch (code)
5510 case ROTATE:
5511 case ROTATERT:
5512 case ASHIFT:
5513 case LSHIFTRT:
5514 case ASHIFTRT:
5515 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5517 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5520 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5521 total += m68hc11_cost->shift_var;
5522 return total;
5524 case AND:
5525 case XOR:
5526 case IOR:
5527 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5528 total += m68hc11_cost->logical;
5530 /* Logical instructions are byte instructions only. */
5531 total *= GET_MODE_SIZE (mode);
5532 return total;
5534 case MINUS:
5535 case PLUS:
5536 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5537 total += m68hc11_cost->add;
5538 if (GET_MODE_SIZE (mode) > 2)
5540 total *= GET_MODE_SIZE (mode) / 2;
5542 return total;
5544 case UDIV:
5545 case DIV:
5546 case MOD:
5547 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5548 switch (mode)
5550 case QImode:
5551 total += m68hc11_cost->divQI;
5552 break;
5554 case HImode:
5555 total += m68hc11_cost->divHI;
5556 break;
5558 case SImode:
5559 default:
5560 total += m68hc11_cost->divSI;
5561 break;
5563 return total;
5565 case MULT:
5566 /* mul instruction produces 16-bit result. */
5567 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5568 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5569 return m68hc11_cost->multQI
5570 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5571 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5573 /* emul instruction produces 32-bit result for 68HC12. */
5574 if (TARGET_M6812 && mode == SImode
5575 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5576 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5577 return m68hc11_cost->multHI
5578 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5579 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5581 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5582 switch (mode)
5584 case QImode:
5585 total += m68hc11_cost->multQI;
5586 break;
5588 case HImode:
5589 total += m68hc11_cost->multHI;
5590 break;
5592 case SImode:
5593 default:
5594 total += m68hc11_cost->multSI;
5595 break;
5597 return total;
5599 case NEG:
5600 case SIGN_EXTEND:
5601 extra_cost = COSTS_N_INSNS (2);
5603 /* Fall through */
5604 case NOT:
5605 case COMPARE:
5606 case ABS:
5607 case ZERO_EXTEND:
5608 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5609 if (mode == QImode)
5611 return total + COSTS_N_INSNS (1);
5613 if (mode == HImode)
5615 return total + COSTS_N_INSNS (2);
5617 if (mode == SImode)
5619 return total + COSTS_N_INSNS (4);
5621 return total + COSTS_N_INSNS (8);
5623 case IF_THEN_ELSE:
5624 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5625 return COSTS_N_INSNS (1);
5627 return COSTS_N_INSNS (1);
5629 default:
5630 return COSTS_N_INSNS (4);
5634 static bool
5635 m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total)
5637 switch (code)
5639 /* Constants are cheap. Moving them in registers must be avoided
5640 because most instructions do not handle two register operands. */
5641 case CONST_INT:
5642 case CONST:
5643 case LABEL_REF:
5644 case SYMBOL_REF:
5645 case CONST_DOUBLE:
5646 /* Logical and arithmetic operations with a constant operand are
5647 better because they are not supported with two registers. */
5648 /* 'clr' is slow */
5649 if (outer_code == SET && x == const0_rtx)
5650 /* After reload, the reload_cse pass checks the cost to change
5651 a SET into a PLUS. Make const0 cheap then. */
5652 *total = 1 - reload_completed;
5653 else
5654 *total = 0;
5655 return true;
5657 case ROTATE:
5658 case ROTATERT:
5659 case ASHIFT:
5660 case LSHIFTRT:
5661 case ASHIFTRT:
5662 case MINUS:
5663 case PLUS:
5664 case AND:
5665 case XOR:
5666 case IOR:
5667 case UDIV:
5668 case DIV:
5669 case MOD:
5670 case MULT:
5671 case NEG:
5672 case SIGN_EXTEND:
5673 case NOT:
5674 case COMPARE:
5675 case ZERO_EXTEND:
5676 case IF_THEN_ELSE:
5677 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5678 return true;
5680 default:
5681 return false;
5686 /* Worker function for TARGET_ASM_FILE_START. */
5688 static void
5689 m68hc11_file_start (void)
5691 default_file_start ();
5693 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5697 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5699 static void
5700 m68hc11_asm_out_constructor (rtx symbol, int priority)
5702 default_ctor_section_asm_out_constructor (symbol, priority);
5703 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5706 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5708 static void
5709 m68hc11_asm_out_destructor (rtx symbol, int priority)
5711 default_dtor_section_asm_out_destructor (symbol, priority);
5712 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5715 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5717 static rtx
5718 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5719 int incoming ATTRIBUTE_UNUSED)
5721 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5724 /* Return true if type TYPE should be returned in memory.
5725 Blocks and data types largers than 4 bytes cannot be returned
5726 in the register (D + X = 4). */
5728 static bool
5729 m68hc11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
5731 if (TYPE_MODE (type) == BLKmode)
5733 HOST_WIDE_INT size = int_size_in_bytes (type);
5734 return (size == -1 || size > 4);
5736 else
5737 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5740 #include "gt-m68hc11.h"