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