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