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