* config/m68hc11/m68hc11.h (target_flags, MASK_SHORT)
[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 ("-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 ("%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 ("%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 ("%<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 ("%<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 }
1933 if (mode == QImode && D_REG_P (x))
1934 return gen_rtx_REG (mode, HARD_A_REGNUM);
1935
1936 /* There is no way in GCC to represent the upper part of a word register.
1937 To obtain the 8-bit upper part of a soft register, we change the
1938 reg into a mem rtx. This is possible because they are physically
1939 located in memory. There is no offset because we are big-endian. */
1940 if (mode == QImode && S_REG_P (x))
1941 {
1942 int pos;
1943
1944 /* Avoid the '*' for direct addressing mode when this
1945 addressing mode is disabled. */
1946 pos = TARGET_NO_DIRECT_MODE ? 1 : 0;
1947 return gen_rtx_MEM (QImode,
1948 gen_rtx_SYMBOL_REF (Pmode,
1949 &reg_names[REGNO (x)][pos]));
1950 }
1951
1952 /* gen_highpart crashes when it is called with a SUBREG. */
1953 if (GET_CODE (x) == SUBREG)
1954 {
1955 return gen_rtx_SUBREG (mode, XEXP (x, 0), XEXP (x, 1));
1956 }
1957 if (GET_CODE (x) == REG)
1958 {
1959 if (REGNO (x) < FIRST_PSEUDO_REGISTER)
1960 return gen_rtx_REG (mode, REGNO (x));
1961 else
1962 return gen_rtx_SUBREG (mode, x, 0);
1963 }
1964
1965 if (GET_CODE (x) == MEM)
1966 {
1967 x = change_address (x, mode, 0);
1968
1969 /* Return a different rtx to avoid to share it in several insns
1970 (when used by a split pattern). Sharing addresses within
1971 a MEM breaks the Z register replacement (and reloading). */
1972 if (GET_CODE (x) == MEM)
1973 x = copy_rtx (x);
1974 return x;
1975 }
1976 abort ();
1977 }
1978 \f
1979
1980 /* Obscure register manipulation. */
1981
1982 /* Finds backward in the instructions to see if register 'reg' is
1983 dead. This is used when generating code to see if we can use 'reg'
1984 as a scratch register. This allows us to choose a better generation
1985 of code when we know that some register dies or can be clobbered. */
1986
1987 int
1988 dead_register_here (rtx x, rtx reg)
1989 {
1990 rtx x_reg;
1991 rtx p;
1992
1993 if (D_REG_P (reg))
1994 x_reg = gen_rtx_REG (SImode, HARD_X_REGNUM);
1995 else
1996 x_reg = 0;
1997
1998 for (p = PREV_INSN (x); p && GET_CODE (p) != CODE_LABEL; p = PREV_INSN (p))
1999 if (INSN_P (p))
2000 {
2001 rtx body;
2002
2003 body = PATTERN (p);
2004
2005 if (GET_CODE (body) == CALL_INSN)
2006 break;
2007 if (GET_CODE (body) == JUMP_INSN)
2008 break;
2009
2010 if (GET_CODE (body) == SET)
2011 {
2012 rtx dst = XEXP (body, 0);
2013
2014 if (GET_CODE (dst) == REG && REGNO (dst) == REGNO (reg))
2015 break;
2016 if (x_reg && rtx_equal_p (dst, x_reg))
2017 break;
2018
2019 if (find_regno_note (p, REG_DEAD, REGNO (reg)))
2020 return 1;
2021 }
2022 else if (reg_mentioned_p (reg, p)
2023 || (x_reg && reg_mentioned_p (x_reg, p)))
2024 break;
2025 }
2026
2027 /* Scan forward to see if the register is set in some insns and never
2028 used since then. */
2029 for (p = x /*NEXT_INSN (x) */ ; p; p = NEXT_INSN (p))
2030 {
2031 rtx body;
2032
2033 if (GET_CODE (p) == CODE_LABEL
2034 || GET_CODE (p) == JUMP_INSN
2035 || GET_CODE (p) == CALL_INSN || GET_CODE (p) == BARRIER)
2036 break;
2037
2038 if (GET_CODE (p) != INSN)
2039 continue;
2040
2041 body = PATTERN (p);
2042 if (GET_CODE (body) == SET)
2043 {
2044 rtx src = XEXP (body, 1);
2045 rtx dst = XEXP (body, 0);
2046
2047 if (GET_CODE (dst) == REG
2048 && REGNO (dst) == REGNO (reg) && !reg_mentioned_p (reg, src))
2049 return 1;
2050 }
2051
2052 /* Register is used (may be in source or in dest). */
2053 if (reg_mentioned_p (reg, p)
2054 || (x_reg != 0 && GET_MODE (p) == SImode
2055 && reg_mentioned_p (x_reg, p)))
2056 break;
2057 }
2058 return p == 0 ? 1 : 0;
2059 }
2060 \f
2061
2062 /* Code generation operations called from machine description file. */
2063
2064 /* Print the name of register 'regno' in the assembly file. */
2065 static void
2066 asm_print_register (FILE *file, int regno)
2067 {
2068 const char *name = reg_names[regno];
2069
2070 if (TARGET_NO_DIRECT_MODE && name[0] == '*')
2071 name++;
2072
2073 fprintf (file, "%s", name);
2074 }
2075
2076 /* A C compound statement to output to stdio stream STREAM the
2077 assembler syntax for an instruction operand X. X is an RTL
2078 expression.
2079
2080 CODE is a value that can be used to specify one of several ways
2081 of printing the operand. It is used when identical operands
2082 must be printed differently depending on the context. CODE
2083 comes from the `%' specification that was used to request
2084 printing of the operand. If the specification was just `%DIGIT'
2085 then CODE is 0; if the specification was `%LTR DIGIT' then CODE
2086 is the ASCII code for LTR.
2087
2088 If X is a register, this macro should print the register's name.
2089 The names can be found in an array `reg_names' whose type is
2090 `char *[]'. `reg_names' is initialized from `REGISTER_NAMES'.
2091
2092 When the machine description has a specification `%PUNCT' (a `%'
2093 followed by a punctuation character), this macro is called with
2094 a null pointer for X and the punctuation character for CODE.
2095
2096 The M68HC11 specific codes are:
2097
2098 'b' for the low part of the operand.
2099 'h' for the high part of the operand
2100 The 'b' or 'h' modifiers have no effect if the operand has
2101 the QImode and is not a S_REG_P (soft register). If the
2102 operand is a hard register, these two modifiers have no effect.
2103 't' generate the temporary scratch register. The operand is
2104 ignored.
2105 'T' generate the low-part temporary scratch register. The operand is
2106 ignored. */
2107
2108 void
2109 print_operand (FILE *file, rtx op, int letter)
2110 {
2111 if (letter == 't')
2112 {
2113 asm_print_register (file, SOFT_TMP_REGNUM);
2114 return;
2115 }
2116 else if (letter == 'T')
2117 {
2118 asm_print_register (file, SOFT_TMP_REGNUM);
2119 fprintf (file, "+1");
2120 return;
2121 }
2122 else if (letter == '#')
2123 {
2124 asm_fprintf (file, "%I");
2125 }
2126
2127 if (GET_CODE (op) == REG)
2128 {
2129 if (letter == 'b' && S_REG_P (op))
2130 {
2131 asm_print_register (file, REGNO (op));
2132 fprintf (file, "+1");
2133 }
2134 else if (letter == 'b' && D_REG_P (op))
2135 {
2136 asm_print_register (file, HARD_B_REGNUM);
2137 }
2138 else
2139 {
2140 asm_print_register (file, REGNO (op));
2141 }
2142 return;
2143 }
2144
2145 if (GET_CODE (op) == SYMBOL_REF && (letter == 'b' || letter == 'h'))
2146 {
2147 if (letter == 'b')
2148 asm_fprintf (file, "%I%%lo(");
2149 else
2150 asm_fprintf (file, "%I%%hi(");
2151
2152 output_addr_const (file, op);
2153 fprintf (file, ")");
2154 return;
2155 }
2156
2157 /* Get the low or high part of the operand when 'b' or 'h' modifiers
2158 are specified. If we already have a QImode, there is nothing to do. */
2159 if (GET_MODE (op) == HImode || GET_MODE (op) == VOIDmode)
2160 {
2161 if (letter == 'b')
2162 {
2163 op = m68hc11_gen_lowpart (QImode, op);
2164 }
2165 else if (letter == 'h')
2166 {
2167 op = m68hc11_gen_highpart (QImode, op);
2168 }
2169 }
2170
2171 if (GET_CODE (op) == MEM)
2172 {
2173 rtx base = XEXP (op, 0);
2174 switch (GET_CODE (base))
2175 {
2176 case PRE_DEC:
2177 if (TARGET_M6812)
2178 {
2179 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (op)));
2180 asm_print_register (file, REGNO (XEXP (base, 0)));
2181 }
2182 else
2183 abort ();
2184 break;
2185
2186 case POST_DEC:
2187 if (TARGET_M6812)
2188 {
2189 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2190 asm_print_register (file, REGNO (XEXP (base, 0)));
2191 fprintf (file, "-");
2192 }
2193 else
2194 abort ();
2195 break;
2196
2197 case POST_INC:
2198 if (TARGET_M6812)
2199 {
2200 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (op)));
2201 asm_print_register (file, REGNO (XEXP (base, 0)));
2202 fprintf (file, "+");
2203 }
2204 else
2205 abort ();
2206 break;
2207
2208 case PRE_INC:
2209 if (TARGET_M6812)
2210 {
2211 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (op)));
2212 asm_print_register (file, REGNO (XEXP (base, 0)));
2213 }
2214 else
2215 abort ();
2216 break;
2217
2218 case MEM:
2219 if (TARGET_M6812)
2220 {
2221 fprintf (file, "[");
2222 print_operand_address (file, XEXP (base, 0));
2223 fprintf (file, "]");
2224 }
2225 else
2226 abort ();
2227 break;
2228
2229 default:
2230 if (m68hc11_page0_symbol_p (base))
2231 fprintf (file, "*");
2232
2233 output_address (base);
2234 break;
2235 }
2236 }
2237 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == SFmode)
2238 {
2239 REAL_VALUE_TYPE r;
2240 long l;
2241
2242 REAL_VALUE_FROM_CONST_DOUBLE (r, op);
2243 REAL_VALUE_TO_TARGET_SINGLE (r, l);
2244 asm_fprintf (file, "%I0x%lx", l);
2245 }
2246 else if (GET_CODE (op) == CONST_DOUBLE && GET_MODE (op) == DFmode)
2247 {
2248 char dstr[30];
2249
2250 real_to_decimal (dstr, CONST_DOUBLE_REAL_VALUE (op),
2251 sizeof (dstr), 0, 1);
2252 asm_fprintf (file, "%I0r%s", dstr);
2253 }
2254 else
2255 {
2256 int need_parenthesize = 0;
2257
2258 if (letter != 'i')
2259 asm_fprintf (file, "%I");
2260 else
2261 need_parenthesize = must_parenthesize (op);
2262
2263 if (need_parenthesize)
2264 fprintf (file, "(");
2265
2266 output_addr_const (file, op);
2267 if (need_parenthesize)
2268 fprintf (file, ")");
2269 }
2270 }
2271
2272 /* Returns true if the operand 'op' must be printed with parenthesis
2273 around it. This must be done only if there is a symbol whose name
2274 is a processor register. */
2275 static int
2276 must_parenthesize (rtx op)
2277 {
2278 const char *name;
2279
2280 switch (GET_CODE (op))
2281 {
2282 case SYMBOL_REF:
2283 name = XSTR (op, 0);
2284 /* Avoid a conflict between symbol name and a possible
2285 register. */
2286 return (strcasecmp (name, "a") == 0
2287 || strcasecmp (name, "b") == 0
2288 || strcasecmp (name, "d") == 0
2289 || strcasecmp (name, "x") == 0
2290 || strcasecmp (name, "y") == 0
2291 || strcasecmp (name, "ix") == 0
2292 || strcasecmp (name, "iy") == 0
2293 || strcasecmp (name, "pc") == 0
2294 || strcasecmp (name, "sp") == 0
2295 || strcasecmp (name, "ccr") == 0) ? 1 : 0;
2296
2297 case PLUS:
2298 case MINUS:
2299 return must_parenthesize (XEXP (op, 0))
2300 || must_parenthesize (XEXP (op, 1));
2301
2302 case MEM:
2303 case CONST:
2304 case ZERO_EXTEND:
2305 case SIGN_EXTEND:
2306 return must_parenthesize (XEXP (op, 0));
2307
2308 case CONST_DOUBLE:
2309 case CONST_INT:
2310 case LABEL_REF:
2311 case CODE_LABEL:
2312 default:
2313 return 0;
2314 }
2315 }
2316
2317 /* A C compound statement to output to stdio stream STREAM the
2318 assembler syntax for an instruction operand that is a memory
2319 reference whose address is ADDR. ADDR is an RTL expression. */
2320
2321 void
2322 print_operand_address (FILE *file, rtx addr)
2323 {
2324 rtx base;
2325 rtx offset;
2326 int need_parenthesis = 0;
2327
2328 switch (GET_CODE (addr))
2329 {
2330 case REG:
2331 if (!REG_P (addr) || !REG_OK_FOR_BASE_STRICT_P (addr))
2332 abort ();
2333
2334 fprintf (file, "0,");
2335 asm_print_register (file, REGNO (addr));
2336 break;
2337
2338 case MEM:
2339 base = XEXP (addr, 0);
2340 switch (GET_CODE (base))
2341 {
2342 case PRE_DEC:
2343 if (TARGET_M6812)
2344 {
2345 fprintf (file, "%u,-", GET_MODE_SIZE (GET_MODE (addr)));
2346 asm_print_register (file, REGNO (XEXP (base, 0)));
2347 }
2348 else
2349 abort ();
2350 break;
2351
2352 case POST_DEC:
2353 if (TARGET_M6812)
2354 {
2355 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2356 asm_print_register (file, REGNO (XEXP (base, 0)));
2357 fprintf (file, "-");
2358 }
2359 else
2360 abort ();
2361 break;
2362
2363 case POST_INC:
2364 if (TARGET_M6812)
2365 {
2366 fprintf (file, "%u,", GET_MODE_SIZE (GET_MODE (addr)));
2367 asm_print_register (file, REGNO (XEXP (base, 0)));
2368 fprintf (file, "+");
2369 }
2370 else
2371 abort ();
2372 break;
2373
2374 case PRE_INC:
2375 if (TARGET_M6812)
2376 {
2377 fprintf (file, "%u,+", GET_MODE_SIZE (GET_MODE (addr)));
2378 asm_print_register (file, REGNO (XEXP (base, 0)));
2379 }
2380 else
2381 abort ();
2382 break;
2383
2384 default:
2385 need_parenthesis = must_parenthesize (base);
2386 if (need_parenthesis)
2387 fprintf (file, "(");
2388
2389 output_addr_const (file, base);
2390 if (need_parenthesis)
2391 fprintf (file, ")");
2392 break;
2393 }
2394 break;
2395
2396 case PLUS:
2397 base = XEXP (addr, 0);
2398 offset = XEXP (addr, 1);
2399 if (!G_REG_P (base) && G_REG_P (offset))
2400 {
2401 base = XEXP (addr, 1);
2402 offset = XEXP (addr, 0);
2403 }
2404 if ((CONSTANT_ADDRESS_P (base)) && (CONSTANT_ADDRESS_P (offset)))
2405 {
2406 need_parenthesis = must_parenthesize (addr);
2407
2408 if (need_parenthesis)
2409 fprintf (file, "(");
2410
2411 output_addr_const (file, base);
2412 fprintf (file, "+");
2413 output_addr_const (file, offset);
2414 if (need_parenthesis)
2415 fprintf (file, ")");
2416 }
2417 else if (REG_P (base) && REG_OK_FOR_BASE_STRICT_P (base))
2418 {
2419 if (REG_P (offset))
2420 {
2421 if (TARGET_M6812)
2422 {
2423 asm_print_register (file, REGNO (offset));
2424 fprintf (file, ",");
2425 asm_print_register (file, REGNO (base));
2426 }
2427 else
2428 abort ();
2429 }
2430 else
2431 {
2432 need_parenthesis = must_parenthesize (offset);
2433 if (need_parenthesis)
2434 fprintf (file, "(");
2435
2436 output_addr_const (file, offset);
2437 if (need_parenthesis)
2438 fprintf (file, ")");
2439 fprintf (file, ",");
2440 asm_print_register (file, REGNO (base));
2441 }
2442 }
2443 else
2444 {
2445 abort ();
2446 }
2447 break;
2448
2449 default:
2450 if (GET_CODE (addr) == CONST_INT
2451 && INTVAL (addr) < 0x8000 && INTVAL (addr) >= -0x8000)
2452 {
2453 fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (addr));
2454 }
2455 else
2456 {
2457 need_parenthesis = must_parenthesize (addr);
2458 if (need_parenthesis)
2459 fprintf (file, "(");
2460
2461 output_addr_const (file, addr);
2462 if (need_parenthesis)
2463 fprintf (file, ")");
2464 }
2465 break;
2466 }
2467 }
2468 \f
2469
2470 /* Splitting of some instructions. */
2471
2472 static rtx
2473 m68hc11_expand_compare (enum rtx_code code, rtx op0, rtx op1)
2474 {
2475 rtx ret = 0;
2476
2477 if (GET_MODE_CLASS (GET_MODE (op0)) == MODE_FLOAT)
2478 abort ();
2479 else
2480 {
2481 emit_insn (gen_rtx_SET (VOIDmode, cc0_rtx,
2482 gen_rtx_COMPARE (VOIDmode, op0, op1)));
2483 ret = gen_rtx_fmt_ee (code, VOIDmode, cc0_rtx, const0_rtx);
2484 }
2485
2486 return ret;
2487 }
2488
2489 rtx
2490 m68hc11_expand_compare_and_branch (enum rtx_code code, rtx op0, rtx op1,
2491 rtx label)
2492 {
2493 rtx tmp;
2494
2495 switch (GET_MODE (op0))
2496 {
2497 case QImode:
2498 case HImode:
2499 tmp = m68hc11_expand_compare (code, op0, op1);
2500 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2501 gen_rtx_LABEL_REF (VOIDmode, label),
2502 pc_rtx);
2503 emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
2504 return 0;
2505 #if 0
2506
2507 /* SCz: from i386.c */
2508 case SFmode:
2509 case DFmode:
2510 /* Don't expand the comparison early, so that we get better code
2511 when jump or whoever decides to reverse the comparison. */
2512 {
2513 rtvec vec;
2514 int use_fcomi;
2515
2516 code = m68hc11_prepare_fp_compare_args (code, &m68hc11_compare_op0,
2517 &m68hc11_compare_op1);
2518
2519 tmp = gen_rtx_fmt_ee (code, m68hc11_fp_compare_mode (code),
2520 m68hc11_compare_op0, m68hc11_compare_op1);
2521 tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
2522 gen_rtx_LABEL_REF (VOIDmode, label),
2523 pc_rtx);
2524 tmp = gen_rtx_SET (VOIDmode, pc_rtx, tmp);
2525
2526 use_fcomi = ix86_use_fcomi_compare (code);
2527 vec = rtvec_alloc (3 + !use_fcomi);
2528 RTVEC_ELT (vec, 0) = tmp;
2529 RTVEC_ELT (vec, 1)
2530 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 18));
2531 RTVEC_ELT (vec, 2)
2532 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCFPmode, 17));
2533 if (!use_fcomi)
2534 RTVEC_ELT (vec, 3)
2535 = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (HImode));
2536
2537 emit_jump_insn (gen_rtx_PARALLEL (VOIDmode, vec));
2538 return;
2539 }
2540 #endif
2541
2542 case SImode:
2543 /* Expand SImode branch into multiple compare+branch. */
2544 {
2545 rtx lo[2], hi[2], label2;
2546 enum rtx_code code1, code2, code3;
2547
2548 if (CONSTANT_P (op0) && !CONSTANT_P (op1))
2549 {
2550 tmp = op0;
2551 op0 = op1;
2552 op1 = tmp;
2553 code = swap_condition (code);
2554 }
2555 lo[0] = m68hc11_gen_lowpart (HImode, op0);
2556 lo[1] = m68hc11_gen_lowpart (HImode, op1);
2557 hi[0] = m68hc11_gen_highpart (HImode, op0);
2558 hi[1] = m68hc11_gen_highpart (HImode, op1);
2559
2560 /* Otherwise, if we are doing less-than, op1 is a constant and the
2561 low word is zero, then we can just examine the high word. */
2562
2563 if (GET_CODE (hi[1]) == CONST_INT && lo[1] == const0_rtx
2564 && (code == LT || code == LTU))
2565 {
2566 return m68hc11_expand_compare_and_branch (code, hi[0], hi[1],
2567 label);
2568 }
2569
2570 /* Otherwise, we need two or three jumps. */
2571
2572 label2 = gen_label_rtx ();
2573
2574 code1 = code;
2575 code2 = swap_condition (code);
2576 code3 = unsigned_condition (code);
2577
2578 switch (code)
2579 {
2580 case LT:
2581 case GT:
2582 case LTU:
2583 case GTU:
2584 break;
2585
2586 case LE:
2587 code1 = LT;
2588 code2 = GT;
2589 break;
2590 case GE:
2591 code1 = GT;
2592 code2 = LT;
2593 break;
2594 case LEU:
2595 code1 = LTU;
2596 code2 = GTU;
2597 break;
2598 case GEU:
2599 code1 = GTU;
2600 code2 = LTU;
2601 break;
2602
2603 case EQ:
2604 code1 = UNKNOWN;
2605 code2 = NE;
2606 break;
2607 case NE:
2608 code2 = UNKNOWN;
2609 break;
2610
2611 default:
2612 abort ();
2613 }
2614
2615 /*
2616 * a < b =>
2617 * if (hi(a) < hi(b)) goto true;
2618 * if (hi(a) > hi(b)) goto false;
2619 * if (lo(a) < lo(b)) goto true;
2620 * false:
2621 */
2622 if (code1 != UNKNOWN)
2623 m68hc11_expand_compare_and_branch (code1, hi[0], hi[1], label);
2624 if (code2 != UNKNOWN)
2625 m68hc11_expand_compare_and_branch (code2, hi[0], hi[1], label2);
2626
2627 m68hc11_expand_compare_and_branch (code3, lo[0], lo[1], label);
2628
2629 if (code2 != UNKNOWN)
2630 emit_label (label2);
2631 return 0;
2632 }
2633
2634 default:
2635 abort ();
2636 }
2637 return 0;
2638 }
2639
2640 /* Return the increment/decrement mode of a MEM if it is such.
2641 Return CONST if it is anything else. */
2642 static int
2643 autoinc_mode (rtx x)
2644 {
2645 if (GET_CODE (x) != MEM)
2646 return CONST;
2647
2648 x = XEXP (x, 0);
2649 if (GET_CODE (x) == PRE_INC
2650 || GET_CODE (x) == PRE_DEC
2651 || GET_CODE (x) == POST_INC
2652 || GET_CODE (x) == POST_DEC)
2653 return GET_CODE (x);
2654
2655 return CONST;
2656 }
2657
2658 static int
2659 m68hc11_make_autoinc_notes (rtx *x, void *data)
2660 {
2661 rtx insn;
2662
2663 switch (GET_CODE (*x))
2664 {
2665 case PRE_DEC:
2666 case PRE_INC:
2667 case POST_DEC:
2668 case POST_INC:
2669 insn = (rtx) data;
2670 REG_NOTES (insn) = alloc_EXPR_LIST (REG_INC, XEXP (*x, 0),
2671 REG_NOTES (insn));
2672 return -1;
2673
2674 default:
2675 return 0;
2676 }
2677 }
2678
2679 /* Split a DI, SI or HI move into several smaller move operations.
2680 The scratch register 'scratch' is used as a temporary to load
2681 store intermediate values. It must be a hard register. */
2682 void
2683 m68hc11_split_move (rtx to, rtx from, rtx scratch)
2684 {
2685 rtx low_to, low_from;
2686 rtx high_to, high_from;
2687 rtx insn;
2688 enum machine_mode mode;
2689 int offset = 0;
2690 int autoinc_from = autoinc_mode (from);
2691 int autoinc_to = autoinc_mode (to);
2692
2693 mode = GET_MODE (to);
2694
2695 /* If the TO and FROM contain autoinc modes that are not compatible
2696 together (one pop and the other a push), we must change one to
2697 an offsetable operand and generate an appropriate add at the end. */
2698 if (TARGET_M6812 && GET_MODE_SIZE (mode) > 2)
2699 {
2700 rtx reg;
2701 int code;
2702
2703 /* The source uses an autoinc mode which is not compatible with
2704 a split (this would result in a word swap). */
2705 if (autoinc_from == PRE_INC || autoinc_from == POST_DEC)
2706 {
2707 code = GET_CODE (XEXP (from, 0));
2708 reg = XEXP (XEXP (from, 0), 0);
2709 offset = GET_MODE_SIZE (GET_MODE (from));
2710 if (code == POST_DEC)
2711 offset = -offset;
2712
2713 if (code == PRE_INC)
2714 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2715
2716 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2717 if (code == POST_DEC)
2718 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2719 return;
2720 }
2721
2722 /* Likewise for destination. */
2723 if (autoinc_to == PRE_INC || autoinc_to == POST_DEC)
2724 {
2725 code = GET_CODE (XEXP (to, 0));
2726 reg = XEXP (XEXP (to, 0), 0);
2727 offset = GET_MODE_SIZE (GET_MODE (to));
2728 if (code == POST_DEC)
2729 offset = -offset;
2730
2731 if (code == PRE_INC)
2732 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2733
2734 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2735 if (code == POST_DEC)
2736 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2737 return;
2738 }
2739
2740 /* The source and destination auto increment modes must be compatible
2741 with each other: same direction. */
2742 if ((autoinc_to != autoinc_from
2743 && autoinc_to != CONST && autoinc_from != CONST)
2744 /* The destination address register must not be used within
2745 the source operand because the source address would change
2746 while doing the copy. */
2747 || (autoinc_to != CONST
2748 && reg_mentioned_p (XEXP (XEXP (to, 0), 0), from)
2749 && !IS_STACK_PUSH (to)))
2750 {
2751 /* Must change the destination. */
2752 code = GET_CODE (XEXP (to, 0));
2753 reg = XEXP (XEXP (to, 0), 0);
2754 offset = GET_MODE_SIZE (GET_MODE (to));
2755 if (code == PRE_DEC || code == POST_DEC)
2756 offset = -offset;
2757
2758 if (code == PRE_DEC || code == PRE_INC)
2759 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2760 m68hc11_split_move (gen_rtx_MEM (GET_MODE (to), reg), from, scratch);
2761 if (code == POST_DEC || code == POST_INC)
2762 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2763
2764 return;
2765 }
2766
2767 /* Likewise, the source address register must not be used within
2768 the destination operand. */
2769 if (autoinc_from != CONST
2770 && reg_mentioned_p (XEXP (XEXP (from, 0), 0), to)
2771 && !IS_STACK_PUSH (to))
2772 {
2773 /* Must change the source. */
2774 code = GET_CODE (XEXP (from, 0));
2775 reg = XEXP (XEXP (from, 0), 0);
2776 offset = GET_MODE_SIZE (GET_MODE (from));
2777 if (code == PRE_DEC || code == POST_DEC)
2778 offset = -offset;
2779
2780 if (code == PRE_DEC || code == PRE_INC)
2781 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2782 m68hc11_split_move (to, gen_rtx_MEM (GET_MODE (from), reg), scratch);
2783 if (code == POST_DEC || code == POST_INC)
2784 emit_insn (gen_addhi3 (reg, reg, GEN_INT (offset)));
2785
2786 return;
2787 }
2788 }
2789
2790 if (GET_MODE_SIZE (mode) == 8)
2791 mode = SImode;
2792 else if (GET_MODE_SIZE (mode) == 4)
2793 mode = HImode;
2794 else
2795 mode = QImode;
2796
2797 if (TARGET_M6812
2798 && IS_STACK_PUSH (to)
2799 && reg_mentioned_p (gen_rtx_REG (HImode, HARD_SP_REGNUM), from))
2800 {
2801 if (mode == SImode)
2802 {
2803 offset = 4;
2804 }
2805 else if (mode == HImode)
2806 {
2807 offset = 2;
2808 }
2809 else
2810 offset = 0;
2811 }
2812
2813 low_to = m68hc11_gen_lowpart (mode, to);
2814 high_to = m68hc11_gen_highpart (mode, to);
2815
2816 low_from = m68hc11_gen_lowpart (mode, from);
2817 if (mode == SImode && GET_CODE (from) == CONST_INT)
2818 {
2819 if (INTVAL (from) >= 0)
2820 high_from = const0_rtx;
2821 else
2822 high_from = constm1_rtx;
2823 }
2824 else
2825 high_from = m68hc11_gen_highpart (mode, from);
2826
2827 if (offset)
2828 {
2829 high_from = adjust_address (high_from, mode, offset);
2830 low_from = high_from;
2831 }
2832
2833 /* When copying with a POST_INC mode, we must copy the
2834 high part and then the low part to guarantee a correct
2835 32/64-bit copy. */
2836 if (TARGET_M6812
2837 && GET_MODE_SIZE (mode) >= 2
2838 && autoinc_from != autoinc_to
2839 && (autoinc_from == POST_INC || autoinc_to == POST_INC))
2840 {
2841 rtx swap;
2842
2843 swap = low_to;
2844 low_to = high_to;
2845 high_to = swap;
2846
2847 swap = low_from;
2848 low_from = high_from;
2849 high_from = swap;
2850 }
2851 if (mode == SImode)
2852 {
2853 m68hc11_split_move (low_to, low_from, scratch);
2854 m68hc11_split_move (high_to, high_from, scratch);
2855 }
2856 else if (H_REG_P (to) || H_REG_P (from)
2857 || (low_from == const0_rtx
2858 && high_from == const0_rtx
2859 && ! push_operand (to, GET_MODE (to))
2860 && ! H_REG_P (scratch))
2861 || (TARGET_M6812
2862 && (!m68hc11_register_indirect_p (from, GET_MODE (from))
2863 || m68hc11_small_indexed_indirect_p (from,
2864 GET_MODE (from)))
2865 && (!m68hc11_register_indirect_p (to, GET_MODE (to))
2866 || m68hc11_small_indexed_indirect_p (to, GET_MODE (to)))))
2867 {
2868 insn = emit_move_insn (low_to, low_from);
2869 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2870
2871 insn = emit_move_insn (high_to, high_from);
2872 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2873 }
2874 else
2875 {
2876 insn = emit_move_insn (scratch, low_from);
2877 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2878 insn = emit_move_insn (low_to, scratch);
2879 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2880
2881 insn = emit_move_insn (scratch, high_from);
2882 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2883 insn = emit_move_insn (high_to, scratch);
2884 for_each_rtx (&PATTERN (insn), m68hc11_make_autoinc_notes, insn);
2885 }
2886 }
2887
2888 static rtx
2889 simplify_logical (enum machine_mode mode, int code, rtx operand, rtx *result)
2890 {
2891 int val;
2892 int mask;
2893
2894 *result = 0;
2895 if (GET_CODE (operand) != CONST_INT)
2896 return operand;
2897
2898 if (mode == HImode)
2899 mask = 0x0ffff;
2900 else
2901 mask = 0x0ff;
2902
2903 val = INTVAL (operand);
2904 switch (code)
2905 {
2906 case IOR:
2907 if ((val & mask) == 0)
2908 return 0;
2909 if ((val & mask) == mask)
2910 *result = constm1_rtx;
2911 break;
2912
2913 case AND:
2914 if ((val & mask) == 0)
2915 *result = const0_rtx;
2916 if ((val & mask) == mask)
2917 return 0;
2918 break;
2919
2920 case XOR:
2921 if ((val & mask) == 0)
2922 return 0;
2923 break;
2924 }
2925 return operand;
2926 }
2927
2928 static void
2929 m68hc11_emit_logical (enum machine_mode mode, int code, rtx *operands)
2930 {
2931 rtx result;
2932 int need_copy;
2933
2934 need_copy = (rtx_equal_p (operands[0], operands[1])
2935 || rtx_equal_p (operands[0], operands[2])) ? 0 : 1;
2936
2937 operands[1] = simplify_logical (mode, code, operands[1], &result);
2938 operands[2] = simplify_logical (mode, code, operands[2], &result);
2939
2940 if (result && GET_CODE (result) == CONST_INT)
2941 {
2942 if (!H_REG_P (operands[0]) && operands[3]
2943 && (INTVAL (result) != 0 || IS_STACK_PUSH (operands[0])))
2944 {
2945 emit_move_insn (operands[3], result);
2946 emit_move_insn (operands[0], operands[3]);
2947 }
2948 else
2949 {
2950 emit_move_insn (operands[0], result);
2951 }
2952 }
2953 else if (operands[1] != 0 && operands[2] != 0)
2954 {
2955 rtx insn;
2956
2957 if (!H_REG_P (operands[0]) && operands[3])
2958 {
2959 emit_move_insn (operands[3], operands[1]);
2960 emit_insn (gen_rtx_SET (mode,
2961 operands[3],
2962 gen_rtx_fmt_ee (code, mode,
2963 operands[3], operands[2])));
2964 insn = emit_move_insn (operands[0], operands[3]);
2965 }
2966 else
2967 {
2968 insn = emit_insn (gen_rtx_SET (mode,
2969 operands[0],
2970 gen_rtx_fmt_ee (code, mode,
2971 operands[0],
2972 operands[2])));
2973 }
2974 }
2975
2976 /* The logical operation is similar to a copy. */
2977 else if (need_copy)
2978 {
2979 rtx src;
2980
2981 if (GET_CODE (operands[1]) == CONST_INT)
2982 src = operands[2];
2983 else
2984 src = operands[1];
2985
2986 if (!H_REG_P (operands[0]) && !H_REG_P (src))
2987 {
2988 emit_move_insn (operands[3], src);
2989 emit_move_insn (operands[0], operands[3]);
2990 }
2991 else
2992 {
2993 emit_move_insn (operands[0], src);
2994 }
2995 }
2996 }
2997
2998 void
2999 m68hc11_split_logical (enum machine_mode mode, int code, rtx *operands)
3000 {
3001 rtx low[4];
3002 rtx high[4];
3003
3004 low[0] = m68hc11_gen_lowpart (mode, operands[0]);
3005 low[1] = m68hc11_gen_lowpart (mode, operands[1]);
3006 low[2] = m68hc11_gen_lowpart (mode, operands[2]);
3007
3008 high[0] = m68hc11_gen_highpart (mode, operands[0]);
3009
3010 if (mode == SImode && GET_CODE (operands[1]) == CONST_INT)
3011 {
3012 if (INTVAL (operands[1]) >= 0)
3013 high[1] = const0_rtx;
3014 else
3015 high[1] = constm1_rtx;
3016 }
3017 else
3018 high[1] = m68hc11_gen_highpart (mode, operands[1]);
3019
3020 if (mode == SImode && GET_CODE (operands[2]) == CONST_INT)
3021 {
3022 if (INTVAL (operands[2]) >= 0)
3023 high[2] = const0_rtx;
3024 else
3025 high[2] = constm1_rtx;
3026 }
3027 else
3028 high[2] = m68hc11_gen_highpart (mode, operands[2]);
3029
3030 low[3] = operands[3];
3031 high[3] = operands[3];
3032 if (mode == SImode)
3033 {
3034 m68hc11_split_logical (HImode, code, low);
3035 m68hc11_split_logical (HImode, code, high);
3036 return;
3037 }
3038
3039 m68hc11_emit_logical (mode, code, low);
3040 m68hc11_emit_logical (mode, code, high);
3041 }
3042 \f
3043
3044 /* Code generation. */
3045
3046 void
3047 m68hc11_output_swap (rtx insn ATTRIBUTE_UNUSED, rtx operands[])
3048 {
3049 /* We have to be careful with the cc_status. An address register swap
3050 is generated for some comparison. The comparison is made with D
3051 but the branch really uses the address register. See the split
3052 pattern for compare. The xgdx/xgdy preserve the flags but after
3053 the exchange, the flags will reflect to the value of X and not D.
3054 Tell this by setting the cc_status according to the cc_prev_status. */
3055 if (X_REG_P (operands[1]) || X_REG_P (operands[0]))
3056 {
3057 if (cc_prev_status.value1 != 0
3058 && (D_REG_P (cc_prev_status.value1)
3059 || X_REG_P (cc_prev_status.value1)))
3060 {
3061 cc_status = cc_prev_status;
3062 if (D_REG_P (cc_status.value1))
3063 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3064 HARD_X_REGNUM);
3065 else
3066 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3067 HARD_D_REGNUM);
3068 }
3069 else
3070 CC_STATUS_INIT;
3071
3072 output_asm_insn ("xgdx", operands);
3073 }
3074 else
3075 {
3076 if (cc_prev_status.value1 != 0
3077 && (D_REG_P (cc_prev_status.value1)
3078 || Y_REG_P (cc_prev_status.value1)))
3079 {
3080 cc_status = cc_prev_status;
3081 if (D_REG_P (cc_status.value1))
3082 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3083 HARD_Y_REGNUM);
3084 else
3085 cc_status.value1 = gen_rtx_REG (GET_MODE (cc_status.value1),
3086 HARD_D_REGNUM);
3087 }
3088 else
3089 CC_STATUS_INIT;
3090
3091 output_asm_insn ("xgdy", operands);
3092 }
3093 }
3094
3095 /* Returns 1 if the next insn after 'insn' is a test of the register 'reg'.
3096 This is used to decide whether a move that set flags should be used
3097 instead. */
3098 int
3099 next_insn_test_reg (rtx insn, rtx reg)
3100 {
3101 rtx body;
3102
3103 insn = next_nonnote_insn (insn);
3104 if (GET_CODE (insn) != INSN)
3105 return 0;
3106
3107 body = PATTERN (insn);
3108 if (sets_cc0_p (body) != 1)
3109 return 0;
3110
3111 if (rtx_equal_p (XEXP (body, 1), reg) == 0)
3112 return 0;
3113
3114 return 1;
3115 }
3116
3117 /* Generate the code to move a 16-bit operand into another one. */
3118
3119 void
3120 m68hc11_gen_movhi (rtx insn, rtx *operands)
3121 {
3122 int reg;
3123
3124 /* Move a register or memory to the same location.
3125 This is possible because such insn can appear
3126 in a non-optimizing mode. */
3127 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3128 {
3129 cc_status = cc_prev_status;
3130 return;
3131 }
3132
3133 if (TARGET_M6812)
3134 {
3135 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3136 {
3137 cc_status = cc_prev_status;
3138 switch (REGNO (operands[1]))
3139 {
3140 case HARD_X_REGNUM:
3141 case HARD_Y_REGNUM:
3142 case HARD_D_REGNUM:
3143 output_asm_insn ("psh%1", operands);
3144 break;
3145 case HARD_SP_REGNUM:
3146 output_asm_insn ("sts\t2,-sp", operands);
3147 break;
3148 default:
3149 abort ();
3150 }
3151 return;
3152 }
3153 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3154 {
3155 cc_status = cc_prev_status;
3156 switch (REGNO (operands[0]))
3157 {
3158 case HARD_X_REGNUM:
3159 case HARD_Y_REGNUM:
3160 case HARD_D_REGNUM:
3161 output_asm_insn ("pul%0", operands);
3162 break;
3163 default:
3164 abort ();
3165 }
3166 return;
3167 }
3168 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3169 {
3170 m68hc11_notice_keep_cc (operands[0]);
3171 output_asm_insn ("tfr\t%1,%0", operands);
3172 }
3173 else if (H_REG_P (operands[0]))
3174 {
3175 if (SP_REG_P (operands[0]))
3176 output_asm_insn ("lds\t%1", operands);
3177 else
3178 output_asm_insn ("ld%0\t%1", operands);
3179 }
3180 else if (H_REG_P (operands[1]))
3181 {
3182 if (SP_REG_P (operands[1]))
3183 output_asm_insn ("sts\t%0", operands);
3184 else
3185 output_asm_insn ("st%1\t%0", operands);
3186 }
3187 else
3188 {
3189 rtx from = operands[1];
3190 rtx to = operands[0];
3191
3192 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3193 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3194 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3195 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3196 {
3197 rtx ops[3];
3198
3199 if (operands[2])
3200 {
3201 ops[0] = operands[2];
3202 ops[1] = from;
3203 ops[2] = 0;
3204 m68hc11_gen_movhi (insn, ops);
3205 ops[0] = to;
3206 ops[1] = operands[2];
3207 m68hc11_gen_movhi (insn, ops);
3208 }
3209 else
3210 {
3211 /* !!!! SCz wrong here. */
3212 fatal_insn ("move insn not handled", insn);
3213 }
3214 }
3215 else
3216 {
3217 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3218 {
3219 output_asm_insn ("clr\t%h0", operands);
3220 output_asm_insn ("clr\t%b0", operands);
3221 }
3222 else
3223 {
3224 m68hc11_notice_keep_cc (operands[0]);
3225 output_asm_insn ("movw\t%1,%0", operands);
3226 }
3227 }
3228 }
3229 return;
3230 }
3231
3232 if (IS_STACK_POP (operands[1]) && H_REG_P (operands[0]))
3233 {
3234 cc_status = cc_prev_status;
3235 switch (REGNO (operands[0]))
3236 {
3237 case HARD_X_REGNUM:
3238 case HARD_Y_REGNUM:
3239 output_asm_insn ("pul%0", operands);
3240 break;
3241 case HARD_D_REGNUM:
3242 output_asm_insn ("pula", operands);
3243 output_asm_insn ("pulb", operands);
3244 break;
3245 default:
3246 abort ();
3247 }
3248 return;
3249 }
3250 /* Some moves to a hard register are special. Not all of them
3251 are really supported and we have to use a temporary
3252 location to provide them (either the stack of a temp var). */
3253 if (H_REG_P (operands[0]))
3254 {
3255 switch (REGNO (operands[0]))
3256 {
3257 case HARD_D_REGNUM:
3258 if (X_REG_P (operands[1]))
3259 {
3260 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3261 {
3262 m68hc11_output_swap (insn, operands);
3263 }
3264 else if (next_insn_test_reg (insn, operands[0]))
3265 {
3266 output_asm_insn ("stx\t%t0\n\tldd\t%t0", operands);
3267 }
3268 else
3269 {
3270 m68hc11_notice_keep_cc (operands[0]);
3271 output_asm_insn ("pshx\n\tpula\n\tpulb", operands);
3272 }
3273 }
3274 else if (Y_REG_P (operands[1]))
3275 {
3276 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3277 {
3278 m68hc11_output_swap (insn, operands);
3279 }
3280 else
3281 {
3282 /* %t means *ZTMP scratch register. */
3283 output_asm_insn ("sty\t%t1", operands);
3284 output_asm_insn ("ldd\t%t1", operands);
3285 }
3286 }
3287 else if (SP_REG_P (operands[1]))
3288 {
3289 CC_STATUS_INIT;
3290 if (ix_reg == 0)
3291 create_regs_rtx ();
3292 if (optimize == 0 || dead_register_here (insn, ix_reg) == 0)
3293 output_asm_insn ("xgdx", operands);
3294 output_asm_insn ("tsx", operands);
3295 output_asm_insn ("xgdx", operands);
3296 }
3297 else if (IS_STACK_POP (operands[1]))
3298 {
3299 output_asm_insn ("pula\n\tpulb", operands);
3300 }
3301 else if (GET_CODE (operands[1]) == CONST_INT
3302 && INTVAL (operands[1]) == 0)
3303 {
3304 output_asm_insn ("clra\n\tclrb", operands);
3305 }
3306 else
3307 {
3308 output_asm_insn ("ldd\t%1", operands);
3309 }
3310 break;
3311
3312 case HARD_X_REGNUM:
3313 if (D_REG_P (operands[1]))
3314 {
3315 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3316 {
3317 m68hc11_output_swap (insn, operands);
3318 }
3319 else if (next_insn_test_reg (insn, operands[0]))
3320 {
3321 output_asm_insn ("std\t%t0\n\tldx\t%t0", operands);
3322 }
3323 else
3324 {
3325 m68hc11_notice_keep_cc (operands[0]);
3326 output_asm_insn ("pshb", operands);
3327 output_asm_insn ("psha", operands);
3328 output_asm_insn ("pulx", operands);
3329 }
3330 }
3331 else if (Y_REG_P (operands[1]))
3332 {
3333 /* When both D and Y are dead, use the sequence xgdy, xgdx
3334 to move Y into X. The D and Y registers are modified. */
3335 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM)
3336 && dead_register_here (insn, d_reg))
3337 {
3338 output_asm_insn ("xgdy", operands);
3339 output_asm_insn ("xgdx", operands);
3340 CC_STATUS_INIT;
3341 }
3342 else if (!optimize_size)
3343 {
3344 output_asm_insn ("sty\t%t1", operands);
3345 output_asm_insn ("ldx\t%t1", operands);
3346 }
3347 else
3348 {
3349 CC_STATUS_INIT;
3350 output_asm_insn ("pshy", operands);
3351 output_asm_insn ("pulx", operands);
3352 }
3353 }
3354 else if (SP_REG_P (operands[1]))
3355 {
3356 /* tsx, tsy preserve the flags */
3357 cc_status = cc_prev_status;
3358 output_asm_insn ("tsx", operands);
3359 }
3360 else
3361 {
3362 output_asm_insn ("ldx\t%1", operands);
3363 }
3364 break;
3365
3366 case HARD_Y_REGNUM:
3367 if (D_REG_P (operands[1]))
3368 {
3369 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3370 {
3371 m68hc11_output_swap (insn, operands);
3372 }
3373 else
3374 {
3375 output_asm_insn ("std\t%t1", operands);
3376 output_asm_insn ("ldy\t%t1", operands);
3377 }
3378 }
3379 else if (X_REG_P (operands[1]))
3380 {
3381 /* When both D and X are dead, use the sequence xgdx, xgdy
3382 to move X into Y. The D and X registers are modified. */
3383 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM)
3384 && dead_register_here (insn, d_reg))
3385 {
3386 output_asm_insn ("xgdx", operands);
3387 output_asm_insn ("xgdy", operands);
3388 CC_STATUS_INIT;
3389 }
3390 else if (!optimize_size)
3391 {
3392 output_asm_insn ("stx\t%t1", operands);
3393 output_asm_insn ("ldy\t%t1", operands);
3394 }
3395 else
3396 {
3397 CC_STATUS_INIT;
3398 output_asm_insn ("pshx", operands);
3399 output_asm_insn ("puly", operands);
3400 }
3401 }
3402 else if (SP_REG_P (operands[1]))
3403 {
3404 /* tsx, tsy preserve the flags */
3405 cc_status = cc_prev_status;
3406 output_asm_insn ("tsy", operands);
3407 }
3408 else
3409 {
3410 output_asm_insn ("ldy\t%1", operands);
3411 }
3412 break;
3413
3414 case HARD_SP_REGNUM:
3415 if (D_REG_P (operands[1]))
3416 {
3417 m68hc11_notice_keep_cc (operands[0]);
3418 output_asm_insn ("xgdx", operands);
3419 output_asm_insn ("txs", operands);
3420 output_asm_insn ("xgdx", operands);
3421 }
3422 else if (X_REG_P (operands[1]))
3423 {
3424 /* tys, txs preserve the flags */
3425 cc_status = cc_prev_status;
3426 output_asm_insn ("txs", operands);
3427 }
3428 else if (Y_REG_P (operands[1]))
3429 {
3430 /* tys, txs preserve the flags */
3431 cc_status = cc_prev_status;
3432 output_asm_insn ("tys", operands);
3433 }
3434 else
3435 {
3436 /* lds sets the flags but the des does not. */
3437 CC_STATUS_INIT;
3438 output_asm_insn ("lds\t%1", operands);
3439 output_asm_insn ("des", operands);
3440 }
3441 break;
3442
3443 default:
3444 fatal_insn ("invalid register in the move instruction", insn);
3445 break;
3446 }
3447 return;
3448 }
3449 if (SP_REG_P (operands[1]) && REG_P (operands[0])
3450 && REGNO (operands[0]) == HARD_FRAME_POINTER_REGNUM)
3451 {
3452 output_asm_insn ("sts\t%0", operands);
3453 return;
3454 }
3455
3456 if (IS_STACK_PUSH (operands[0]) && H_REG_P (operands[1]))
3457 {
3458 cc_status = cc_prev_status;
3459 switch (REGNO (operands[1]))
3460 {
3461 case HARD_X_REGNUM:
3462 case HARD_Y_REGNUM:
3463 output_asm_insn ("psh%1", operands);
3464 break;
3465 case HARD_D_REGNUM:
3466 output_asm_insn ("pshb", operands);
3467 output_asm_insn ("psha", operands);
3468 break;
3469 default:
3470 abort ();
3471 }
3472 return;
3473 }
3474
3475 /* Operand 1 must be a hard register. */
3476 if (!H_REG_P (operands[1]))
3477 {
3478 fatal_insn ("invalid operand in the instruction", insn);
3479 }
3480
3481 reg = REGNO (operands[1]);
3482 switch (reg)
3483 {
3484 case HARD_D_REGNUM:
3485 output_asm_insn ("std\t%0", operands);
3486 break;
3487
3488 case HARD_X_REGNUM:
3489 output_asm_insn ("stx\t%0", operands);
3490 break;
3491
3492 case HARD_Y_REGNUM:
3493 output_asm_insn ("sty\t%0", operands);
3494 break;
3495
3496 case HARD_SP_REGNUM:
3497 if (ix_reg == 0)
3498 create_regs_rtx ();
3499
3500 if (REG_P (operands[0]) && REGNO (operands[0]) == SOFT_TMP_REGNUM)
3501 {
3502 output_asm_insn ("pshx", operands);
3503 output_asm_insn ("tsx", operands);
3504 output_asm_insn ("inx", operands);
3505 output_asm_insn ("inx", operands);
3506 output_asm_insn ("stx\t%0", operands);
3507 output_asm_insn ("pulx", operands);
3508 }
3509
3510 else if (reg_mentioned_p (ix_reg, operands[0]))
3511 {
3512 output_asm_insn ("sty\t%t0", operands);
3513 output_asm_insn ("tsy", operands);
3514 output_asm_insn ("sty\t%0", operands);
3515 output_asm_insn ("ldy\t%t0", operands);
3516 }
3517 else
3518 {
3519 output_asm_insn ("stx\t%t0", operands);
3520 output_asm_insn ("tsx", operands);
3521 output_asm_insn ("stx\t%0", operands);
3522 output_asm_insn ("ldx\t%t0", operands);
3523 }
3524 CC_STATUS_INIT;
3525 break;
3526
3527 default:
3528 fatal_insn ("invalid register in the move instruction", insn);
3529 break;
3530 }
3531 }
3532
3533 void
3534 m68hc11_gen_movqi (rtx insn, rtx *operands)
3535 {
3536 /* Move a register or memory to the same location.
3537 This is possible because such insn can appear
3538 in a non-optimizing mode. */
3539 if (operands[0] == operands[1] || rtx_equal_p (operands[0], operands[1]))
3540 {
3541 cc_status = cc_prev_status;
3542 return;
3543 }
3544
3545 if (TARGET_M6812)
3546 {
3547
3548 if (H_REG_P (operands[0]) && H_REG_P (operands[1]))
3549 {
3550 m68hc11_notice_keep_cc (operands[0]);
3551 output_asm_insn ("tfr\t%1,%0", operands);
3552 }
3553 else if (H_REG_P (operands[0]))
3554 {
3555 if (Q_REG_P (operands[0]))
3556 output_asm_insn ("lda%0\t%b1", operands);
3557 else if (D_REG_P (operands[0]))
3558 output_asm_insn ("ldab\t%b1", operands);
3559 else
3560 goto m6811_move;
3561 }
3562 else if (H_REG_P (operands[1]))
3563 {
3564 if (Q_REG_P (operands[1]))
3565 output_asm_insn ("sta%1\t%b0", operands);
3566 else if (D_REG_P (operands[1]))
3567 output_asm_insn ("stab\t%b0", operands);
3568 else
3569 goto m6811_move;
3570 }
3571 else
3572 {
3573 rtx from = operands[1];
3574 rtx to = operands[0];
3575
3576 if ((m68hc11_register_indirect_p (from, GET_MODE (from))
3577 && !m68hc11_small_indexed_indirect_p (from, GET_MODE (from)))
3578 || (m68hc11_register_indirect_p (to, GET_MODE (to))
3579 && !m68hc11_small_indexed_indirect_p (to, GET_MODE (to))))
3580 {
3581 rtx ops[3];
3582
3583 if (operands[2])
3584 {
3585 ops[0] = operands[2];
3586 ops[1] = from;
3587 ops[2] = 0;
3588 m68hc11_gen_movqi (insn, ops);
3589 ops[0] = to;
3590 ops[1] = operands[2];
3591 m68hc11_gen_movqi (insn, ops);
3592 }
3593 else
3594 {
3595 /* !!!! SCz wrong here. */
3596 fatal_insn ("move insn not handled", insn);
3597 }
3598 }
3599 else
3600 {
3601 if (GET_CODE (from) == CONST_INT && INTVAL (from) == 0)
3602 {
3603 output_asm_insn ("clr\t%b0", operands);
3604 }
3605 else
3606 {
3607 m68hc11_notice_keep_cc (operands[0]);
3608 output_asm_insn ("movb\t%b1,%b0", operands);
3609 }
3610 }
3611 }
3612 return;
3613 }
3614
3615 m6811_move:
3616 if (H_REG_P (operands[0]))
3617 {
3618 switch (REGNO (operands[0]))
3619 {
3620 case HARD_B_REGNUM:
3621 case HARD_D_REGNUM:
3622 if (X_REG_P (operands[1]))
3623 {
3624 if (optimize && find_regno_note (insn, REG_DEAD, HARD_X_REGNUM))
3625 {
3626 m68hc11_output_swap (insn, operands);
3627 }
3628 else
3629 {
3630 output_asm_insn ("stx\t%t1", operands);
3631 output_asm_insn ("ldab\t%T0", operands);
3632 }
3633 }
3634 else if (Y_REG_P (operands[1]))
3635 {
3636 if (optimize && find_regno_note (insn, REG_DEAD, HARD_Y_REGNUM))
3637 {
3638 m68hc11_output_swap (insn, operands);
3639 }
3640 else
3641 {
3642 output_asm_insn ("sty\t%t1", operands);
3643 output_asm_insn ("ldab\t%T0", operands);
3644 }
3645 }
3646 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3647 && !DA_REG_P (operands[1]))
3648 {
3649 output_asm_insn ("ldab\t%b1", operands);
3650 }
3651 else if (DA_REG_P (operands[1]))
3652 {
3653 output_asm_insn ("tab", operands);
3654 }
3655 else
3656 {
3657 cc_status = cc_prev_status;
3658 return;
3659 }
3660 break;
3661
3662 case HARD_A_REGNUM:
3663 if (X_REG_P (operands[1]))
3664 {
3665 output_asm_insn ("stx\t%t1", operands);
3666 output_asm_insn ("ldaa\t%T0", operands);
3667 }
3668 else if (Y_REG_P (operands[1]))
3669 {
3670 output_asm_insn ("sty\t%t1", operands);
3671 output_asm_insn ("ldaa\t%T0", operands);
3672 }
3673 else if (!DB_REG_P (operands[1]) && !D_REG_P (operands[1])
3674 && !DA_REG_P (operands[1]))
3675 {
3676 output_asm_insn ("ldaa\t%b1", operands);
3677 }
3678 else if (!DA_REG_P (operands[1]))
3679 {
3680 output_asm_insn ("tba", operands);
3681 }
3682 else
3683 {
3684 cc_status = cc_prev_status;
3685 }
3686 break;
3687
3688 case HARD_X_REGNUM:
3689 if (D_REG_P (operands[1]))
3690 {
3691 if (optimize && find_regno_note (insn, REG_DEAD, HARD_D_REGNUM))
3692 {
3693 m68hc11_output_swap (insn, operands);
3694 }
3695 else
3696 {
3697 output_asm_insn ("stab\t%T1", operands);
3698 output_asm_insn ("ldx\t%t1", operands);
3699 }
3700 CC_STATUS_INIT;
3701 }
3702 else if (Y_REG_P (operands[1]))
3703 {
3704 output_asm_insn ("sty\t%t0", operands);
3705 output_asm_insn ("ldx\t%t0", operands);
3706 }
3707 else if (GET_CODE (operands[1]) == CONST_INT)
3708 {
3709 output_asm_insn ("ldx\t%1", operands);
3710 }
3711 else if (dead_register_here (insn, d_reg))
3712 {
3713 output_asm_insn ("ldab\t%b1", operands);
3714 output_asm_insn ("xgdx", operands);
3715 }
3716 else if (!reg_mentioned_p (operands[0], operands[1]))
3717 {
3718 output_asm_insn ("xgdx", operands);
3719 output_asm_insn ("ldab\t%b1", operands);
3720 output_asm_insn ("xgdx", operands);
3721 }
3722 else
3723 {
3724 output_asm_insn ("pshb", operands);
3725 output_asm_insn ("ldab\t%b1", operands);
3726 output_asm_insn ("stab\t%T1", operands);
3727 output_asm_insn ("ldx\t%t1", operands);
3728 output_asm_insn ("pulb", operands);
3729 CC_STATUS_INIT;
3730 }
3731 break;
3732
3733 case HARD_Y_REGNUM:
3734 if (D_REG_P (operands[1]))
3735 {
3736 output_asm_insn ("stab\t%T1", operands);
3737 output_asm_insn ("ldy\t%t1", operands);
3738 CC_STATUS_INIT;
3739 }
3740 else if (X_REG_P (operands[1]))
3741 {
3742 output_asm_insn ("stx\t%t1", operands);
3743 output_asm_insn ("ldy\t%t1", operands);
3744 CC_STATUS_INIT;
3745 }
3746 else if (GET_CODE (operands[1]) == CONST_INT)
3747 {
3748 output_asm_insn ("ldy\t%1", operands);
3749 }
3750 else if (dead_register_here (insn, d_reg))
3751 {
3752 output_asm_insn ("ldab\t%b1", operands);
3753 output_asm_insn ("xgdy", operands);
3754 }
3755 else if (!reg_mentioned_p (operands[0], operands[1]))
3756 {
3757 output_asm_insn ("xgdy", operands);
3758 output_asm_insn ("ldab\t%b1", operands);
3759 output_asm_insn ("xgdy", operands);
3760 }
3761 else
3762 {
3763 output_asm_insn ("pshb", operands);
3764 output_asm_insn ("ldab\t%b1", operands);
3765 output_asm_insn ("stab\t%T1", operands);
3766 output_asm_insn ("ldy\t%t1", operands);
3767 output_asm_insn ("pulb", operands);
3768 CC_STATUS_INIT;
3769 }
3770 break;
3771
3772 default:
3773 fatal_insn ("invalid register in the instruction", insn);
3774 break;
3775 }
3776 }
3777 else if (H_REG_P (operands[1]))
3778 {
3779 switch (REGNO (operands[1]))
3780 {
3781 case HARD_D_REGNUM:
3782 case HARD_B_REGNUM:
3783 output_asm_insn ("stab\t%b0", operands);
3784 break;
3785
3786 case HARD_A_REGNUM:
3787 output_asm_insn ("staa\t%b0", operands);
3788 break;
3789
3790 case HARD_X_REGNUM:
3791 output_asm_insn ("xgdx\n\tstab\t%b0\n\txgdx", operands);
3792 break;
3793
3794 case HARD_Y_REGNUM:
3795 output_asm_insn ("xgdy\n\tstab\t%b0\n\txgdy", operands);
3796 break;
3797
3798 default:
3799 fatal_insn ("invalid register in the move instruction", insn);
3800 break;
3801 }
3802 return;
3803 }
3804 else
3805 {
3806 fatal_insn ("operand 1 must be a hard register", insn);
3807 }
3808 }
3809
3810 /* Generate the code for a ROTATE or ROTATERT on a QI or HI mode.
3811 The source and destination must be D or A and the shift must
3812 be a constant. */
3813 void
3814 m68hc11_gen_rotate (enum rtx_code code, rtx insn, rtx operands[])
3815 {
3816 int val;
3817
3818 if (GET_CODE (operands[2]) != CONST_INT
3819 || (!D_REG_P (operands[0]) && !DA_REG_P (operands[0])))
3820 fatal_insn ("invalid rotate insn", insn);
3821
3822 val = INTVAL (operands[2]);
3823 if (code == ROTATERT)
3824 val = GET_MODE_SIZE (GET_MODE (operands[0])) * BITS_PER_UNIT - val;
3825
3826 if (GET_MODE (operands[0]) != QImode)
3827 CC_STATUS_INIT;
3828
3829 /* Rotate by 8-bits if the shift is within [5..11]. */
3830 if (val >= 5 && val <= 11)
3831 {
3832 if (TARGET_M6812)
3833 output_asm_insn ("exg\ta,b", operands);
3834 else
3835 {
3836 output_asm_insn ("psha", operands);
3837 output_asm_insn ("tba", operands);
3838 output_asm_insn ("pulb", operands);
3839 }
3840 val -= 8;
3841 }
3842
3843 /* If the shift is big, invert the rotation. */
3844 else if (val >= 12)
3845 {
3846 val = val - 16;
3847 }
3848
3849 if (val > 0)
3850 {
3851 while (--val >= 0)
3852 {
3853 /* Set the carry to bit-15, but don't change D yet. */
3854 if (GET_MODE (operands[0]) != QImode)
3855 {
3856 output_asm_insn ("asra", operands);
3857 output_asm_insn ("rola", operands);
3858 }
3859
3860 /* Rotate B first to move the carry to bit-0. */
3861 if (D_REG_P (operands[0]))
3862 output_asm_insn ("rolb", operands);
3863
3864 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3865 output_asm_insn ("rola", operands);
3866 }
3867 }
3868 else
3869 {
3870 while (++val <= 0)
3871 {
3872 /* Set the carry to bit-8 of D. */
3873 if (GET_MODE (operands[0]) != QImode)
3874 output_asm_insn ("tap", operands);
3875
3876 /* Rotate B first to move the carry to bit-7. */
3877 if (D_REG_P (operands[0]))
3878 output_asm_insn ("rorb", operands);
3879
3880 if (GET_MODE (operands[0]) != QImode || DA_REG_P (operands[0]))
3881 output_asm_insn ("rora", operands);
3882 }
3883 }
3884 }
3885
3886 \f
3887
3888 /* Store in cc_status the expressions that the condition codes will
3889 describe after execution of an instruction whose pattern is EXP.
3890 Do not alter them if the instruction would not alter the cc's. */
3891
3892 void
3893 m68hc11_notice_update_cc (rtx exp, rtx insn ATTRIBUTE_UNUSED)
3894 {
3895 /* recognize SET insn's. */
3896 if (GET_CODE (exp) == SET)
3897 {
3898 /* Jumps do not alter the cc's. */
3899 if (SET_DEST (exp) == pc_rtx)
3900 ;
3901
3902 /* NOTE: most instructions don't affect the carry bit, but the
3903 bhi/bls/bhs/blo instructions use it. This isn't mentioned in
3904 the conditions.h header. */
3905
3906 /* Function calls clobber the cc's. */
3907 else if (GET_CODE (SET_SRC (exp)) == CALL)
3908 {
3909 CC_STATUS_INIT;
3910 }
3911
3912 /* Tests and compares set the cc's in predictable ways. */
3913 else if (SET_DEST (exp) == cc0_rtx)
3914 {
3915 cc_status.flags = 0;
3916 cc_status.value1 = XEXP (exp, 0);
3917 cc_status.value2 = XEXP (exp, 1);
3918 }
3919 else
3920 {
3921 /* All other instructions affect the condition codes. */
3922 cc_status.flags = 0;
3923 cc_status.value1 = XEXP (exp, 0);
3924 cc_status.value2 = XEXP (exp, 1);
3925 }
3926 }
3927 else
3928 {
3929 /* Default action if we haven't recognized something
3930 and returned earlier. */
3931 CC_STATUS_INIT;
3932 }
3933
3934 if (cc_status.value2 != 0)
3935 switch (GET_CODE (cc_status.value2))
3936 {
3937 /* These logical operations can generate several insns.
3938 The flags are setup according to what is generated. */
3939 case IOR:
3940 case XOR:
3941 case AND:
3942 break;
3943
3944 /* The (not ...) generates several 'com' instructions for
3945 non QImode. We have to invalidate the flags. */
3946 case NOT:
3947 if (GET_MODE (cc_status.value2) != QImode)
3948 CC_STATUS_INIT;
3949 break;
3950
3951 case PLUS:
3952 case MINUS:
3953 case MULT:
3954 case DIV:
3955 case UDIV:
3956 case MOD:
3957 case UMOD:
3958 case NEG:
3959 if (GET_MODE (cc_status.value2) != VOIDmode)
3960 cc_status.flags |= CC_NO_OVERFLOW;
3961 break;
3962
3963 /* The asl sets the overflow bit in such a way that this
3964 makes the flags unusable for a next compare insn. */
3965 case ASHIFT:
3966 case ROTATE:
3967 case ROTATERT:
3968 if (GET_MODE (cc_status.value2) != VOIDmode)
3969 cc_status.flags |= CC_NO_OVERFLOW;
3970 break;
3971
3972 /* A load/store instruction does not affect the carry. */
3973 case MEM:
3974 case SYMBOL_REF:
3975 case REG:
3976 case CONST_INT:
3977 cc_status.flags |= CC_NO_OVERFLOW;
3978 break;
3979
3980 default:
3981 break;
3982 }
3983 if (cc_status.value1 && GET_CODE (cc_status.value1) == REG
3984 && cc_status.value2
3985 && reg_overlap_mentioned_p (cc_status.value1, cc_status.value2))
3986 cc_status.value2 = 0;
3987
3988 else if (cc_status.value1 && side_effects_p (cc_status.value1))
3989 cc_status.value1 = 0;
3990
3991 else if (cc_status.value2 && side_effects_p (cc_status.value2))
3992 cc_status.value2 = 0;
3993 }
3994
3995 /* The current instruction does not affect the flags but changes
3996 the register 'reg'. See if the previous flags can be kept for the
3997 next instruction to avoid a comparison. */
3998 void
3999 m68hc11_notice_keep_cc (rtx reg)
4000 {
4001 if (reg == 0
4002 || cc_prev_status.value1 == 0
4003 || rtx_equal_p (reg, cc_prev_status.value1)
4004 || (cc_prev_status.value2
4005 && reg_mentioned_p (reg, cc_prev_status.value2)))
4006 CC_STATUS_INIT;
4007 else
4008 cc_status = cc_prev_status;
4009 }
4010
4011 \f
4012
4013 /* Machine Specific Reorg. */
4014
4015 /* Z register replacement:
4016
4017 GCC treats the Z register as an index base address register like
4018 X or Y. In general, it uses it during reload to compute the address
4019 of some operand. This helps the reload pass to avoid to fall into the
4020 register spill failure.
4021
4022 The Z register is in the A_REGS class. In the machine description,
4023 the 'A' constraint matches it. The 'x' or 'y' constraints do not.
4024
4025 It can appear everywhere an X or Y register can appear, except for
4026 some templates in the clobber section (when a clobber of X or Y is asked).
4027 For a given instruction, the template must ensure that no more than
4028 2 'A' registers are used. Otherwise, the register replacement is not
4029 possible.
4030
4031 To replace the Z register, the algorithm is not terrific:
4032 1. Insns that do not use the Z register are not changed
4033 2. When a Z register is used, we scan forward the insns to see
4034 a potential register to use: either X or Y and sometimes D.
4035 We stop when a call, a label or a branch is seen, or when we
4036 detect that both X and Y are used (probably at different times, but it does
4037 not matter).
4038 3. The register that will be used for the replacement of Z is saved
4039 in a .page0 register or on the stack. If the first instruction that
4040 used Z, uses Z as an input, the value is loaded from another .page0
4041 register. The replacement register is pushed on the stack in the
4042 rare cases where a compare insn uses Z and we couldn't find if X/Y
4043 are dead.
4044 4. The Z register is replaced in all instructions until we reach
4045 the end of the Z-block, as detected by step 2.
4046 5. If we detect that Z is still alive, its value is saved.
4047 If the replacement register is alive, its old value is loaded.
4048
4049 The Z register can be disabled with -ffixed-z.
4050 */
4051
4052 struct replace_info
4053 {
4054 rtx first;
4055 rtx replace_reg;
4056 int need_save_z;
4057 int must_load_z;
4058 int must_save_reg;
4059 int must_restore_reg;
4060 rtx last;
4061 int regno;
4062 int x_used;
4063 int y_used;
4064 int can_use_d;
4065 int found_call;
4066 int z_died;
4067 int z_set_count;
4068 rtx z_value;
4069 int must_push_reg;
4070 int save_before_last;
4071 int z_loaded_with_sp;
4072 };
4073
4074 static int m68hc11_check_z_replacement (rtx, struct replace_info *);
4075 static void m68hc11_find_z_replacement (rtx, struct replace_info *);
4076 static void m68hc11_z_replacement (rtx);
4077 static void m68hc11_reassign_regs (rtx);
4078
4079 int z_replacement_completed = 0;
4080
4081 /* Analyze the insn to find out which replacement register to use and
4082 the boundaries of the replacement.
4083 Returns 0 if we reached the last insn to be replaced, 1 if we can
4084 continue replacement in next insns. */
4085
4086 static int
4087 m68hc11_check_z_replacement (rtx insn, struct replace_info *info)
4088 {
4089 int this_insn_uses_ix;
4090 int this_insn_uses_iy;
4091 int this_insn_uses_z;
4092 int this_insn_uses_z_in_dst;
4093 int this_insn_uses_d;
4094 rtx body;
4095 int z_dies_here;
4096
4097 /* A call is said to clobber the Z register, we don't need
4098 to save the value of Z. We also don't need to restore
4099 the replacement register (unless it is used by the call). */
4100 if (GET_CODE (insn) == CALL_INSN)
4101 {
4102 body = PATTERN (insn);
4103
4104 info->can_use_d = 0;
4105
4106 /* If the call is an indirect call with Z, we have to use the
4107 Y register because X can be used as an input (D+X).
4108 We also must not save Z nor restore Y. */
4109 if (reg_mentioned_p (z_reg, body))
4110 {
4111 insn = NEXT_INSN (insn);
4112 info->x_used = 1;
4113 info->y_used = 0;
4114 info->found_call = 1;
4115 info->must_restore_reg = 0;
4116 info->last = NEXT_INSN (insn);
4117 }
4118 info->need_save_z = 0;
4119 return 0;
4120 }
4121 if (GET_CODE (insn) == CODE_LABEL
4122 || GET_CODE (insn) == BARRIER || GET_CODE (insn) == ASM_INPUT)
4123 return 0;
4124
4125 if (GET_CODE (insn) == JUMP_INSN)
4126 {
4127 if (reg_mentioned_p (z_reg, insn) == 0)
4128 return 0;
4129
4130 info->can_use_d = 0;
4131 info->must_save_reg = 0;
4132 info->must_restore_reg = 0;
4133 info->need_save_z = 0;
4134 info->last = NEXT_INSN (insn);
4135 return 0;
4136 }
4137 if (GET_CODE (insn) != INSN && GET_CODE (insn) != JUMP_INSN)
4138 {
4139 return 1;
4140 }
4141
4142 /* Z register dies here. */
4143 z_dies_here = find_regno_note (insn, REG_DEAD, HARD_Z_REGNUM) != NULL;
4144
4145 body = PATTERN (insn);
4146 if (GET_CODE (body) == SET)
4147 {
4148 rtx src = XEXP (body, 1);
4149 rtx dst = XEXP (body, 0);
4150
4151 /* Condition code is set here. We have to restore the X/Y and
4152 save into Z before any test/compare insn because once we save/restore
4153 we can change the condition codes. When the compare insn uses Z and
4154 we can't use X/Y, the comparison is made with the *ZREG soft register
4155 (this is supported by cmphi, cmpqi, tsthi, tstqi patterns). */
4156 if (dst == cc0_rtx)
4157 {
4158 if ((GET_CODE (src) == REG && REGNO (src) == HARD_Z_REGNUM)
4159 || (GET_CODE (src) == COMPARE &&
4160 ((rtx_equal_p (XEXP (src, 0), z_reg)
4161 && H_REG_P (XEXP (src, 1)))
4162 || (rtx_equal_p (XEXP (src, 1), z_reg)
4163 && H_REG_P (XEXP (src, 0))))))
4164 {
4165 if (insn == info->first)
4166 {
4167 info->must_load_z = 0;
4168 info->must_save_reg = 0;
4169 info->must_restore_reg = 0;
4170 info->need_save_z = 0;
4171 info->found_call = 1;
4172 info->regno = SOFT_Z_REGNUM;
4173 info->last = NEXT_INSN (insn);
4174 }
4175 return 0;
4176 }
4177 if (reg_mentioned_p (z_reg, src) == 0)
4178 {
4179 info->can_use_d = 0;
4180 return 0;
4181 }
4182
4183 if (insn != info->first)
4184 return 0;
4185
4186 /* Compare insn which uses Z. We have to save/restore the X/Y
4187 register without modifying the condition codes. For this
4188 we have to use a push/pop insn. */
4189 info->must_push_reg = 1;
4190 info->last = insn;
4191 }
4192
4193 /* Z reg is set to something new. We don't need to load it. */
4194 if (Z_REG_P (dst))
4195 {
4196 if (!reg_mentioned_p (z_reg, src))
4197 {
4198 /* Z reg is used before being set. Treat this as
4199 a new sequence of Z register replacement. */
4200 if (insn != info->first)
4201 {
4202 return 0;
4203 }
4204 info->must_load_z = 0;
4205 }
4206 info->z_set_count++;
4207 info->z_value = src;
4208 if (SP_REG_P (src))
4209 info->z_loaded_with_sp = 1;
4210 }
4211 else if (reg_mentioned_p (z_reg, dst))
4212 info->can_use_d = 0;
4213
4214 this_insn_uses_d = reg_mentioned_p (d_reg, src)
4215 | reg_mentioned_p (d_reg, dst);
4216 this_insn_uses_ix = reg_mentioned_p (ix_reg, src)
4217 | reg_mentioned_p (ix_reg, dst);
4218 this_insn_uses_iy = reg_mentioned_p (iy_reg, src)
4219 | reg_mentioned_p (iy_reg, dst);
4220 this_insn_uses_z = reg_mentioned_p (z_reg, src);
4221
4222 /* If z is used as an address operand (like (MEM (reg z))),
4223 we can't replace it with d. */
4224 if (this_insn_uses_z && !Z_REG_P (src)
4225 && !(m68hc11_arith_operator (src, GET_MODE (src))
4226 && Z_REG_P (XEXP (src, 0))
4227 && !reg_mentioned_p (z_reg, XEXP (src, 1))
4228 && insn == info->first
4229 && dead_register_here (insn, d_reg)))
4230 info->can_use_d = 0;
4231
4232 this_insn_uses_z_in_dst = reg_mentioned_p (z_reg, dst);
4233 if (TARGET_M6812 && !z_dies_here
4234 && ((this_insn_uses_z && side_effects_p (src))
4235 || (this_insn_uses_z_in_dst && side_effects_p (dst))))
4236 {
4237 info->need_save_z = 1;
4238 info->z_set_count++;
4239 }
4240 this_insn_uses_z |= this_insn_uses_z_in_dst;
4241
4242 if (this_insn_uses_z && this_insn_uses_ix && this_insn_uses_iy)
4243 {
4244 fatal_insn ("registers IX, IY and Z used in the same INSN", insn);
4245 }
4246
4247 if (this_insn_uses_d)
4248 info->can_use_d = 0;
4249
4250 /* IX and IY are used at the same time, we have to restore
4251 the value of the scratch register before this insn. */
4252 if (this_insn_uses_ix && this_insn_uses_iy)
4253 {
4254 return 0;
4255 }
4256
4257 if (this_insn_uses_ix && X_REG_P (dst) && GET_MODE (dst) == SImode)
4258 info->can_use_d = 0;
4259
4260 if (info->x_used == 0 && this_insn_uses_ix)
4261 {
4262 if (info->y_used)
4263 {
4264 /* We have a (set (REG:HI X) (REG:HI Z)).
4265 Since we use Z as the replacement register, this insn
4266 is no longer necessary. We turn it into a note. We must
4267 not reload the old value of X. */
4268 if (X_REG_P (dst) && rtx_equal_p (src, z_reg))
4269 {
4270 if (z_dies_here)
4271 {
4272 info->need_save_z = 0;
4273 info->z_died = 1;
4274 }
4275 info->must_save_reg = 0;
4276 info->must_restore_reg = 0;
4277 info->found_call = 1;
4278 info->can_use_d = 0;
4279 PUT_CODE (insn, NOTE);
4280 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4281 NOTE_SOURCE_FILE (insn) = 0;
4282 info->last = NEXT_INSN (insn);
4283 return 0;
4284 }
4285
4286 if (X_REG_P (dst)
4287 && (rtx_equal_p (src, z_reg)
4288 || (z_dies_here && !reg_mentioned_p (ix_reg, src))))
4289 {
4290 if (z_dies_here)
4291 {
4292 info->need_save_z = 0;
4293 info->z_died = 1;
4294 }
4295 info->last = NEXT_INSN (insn);
4296 info->must_save_reg = 0;
4297 info->must_restore_reg = 0;
4298 }
4299 else if (X_REG_P (dst) && reg_mentioned_p (z_reg, src)
4300 && !reg_mentioned_p (ix_reg, src))
4301 {
4302 if (z_dies_here)
4303 {
4304 info->z_died = 1;
4305 info->need_save_z = 0;
4306 }
4307 else if (TARGET_M6812 && side_effects_p (src))
4308 {
4309 info->last = 0;
4310 info->must_restore_reg = 0;
4311 return 0;
4312 }
4313 else
4314 {
4315 info->save_before_last = 1;
4316 }
4317 info->must_restore_reg = 0;
4318 info->last = NEXT_INSN (insn);
4319 }
4320 else if (info->can_use_d)
4321 {
4322 info->last = NEXT_INSN (insn);
4323 info->x_used = 1;
4324 }
4325 return 0;
4326 }
4327 info->x_used = 1;
4328 if (z_dies_here && !reg_mentioned_p (ix_reg, src)
4329 && GET_CODE (dst) == REG && REGNO (dst) == HARD_X_REGNUM)
4330 {
4331 info->need_save_z = 0;
4332 info->z_died = 1;
4333 info->last = NEXT_INSN (insn);
4334 info->regno = HARD_X_REGNUM;
4335 info->must_save_reg = 0;
4336 info->must_restore_reg = 0;
4337 return 0;
4338 }
4339 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, ix_reg))
4340 {
4341 info->regno = HARD_X_REGNUM;
4342 info->must_restore_reg = 0;
4343 info->must_save_reg = 0;
4344 return 0;
4345 }
4346 }
4347 if (info->y_used == 0 && this_insn_uses_iy)
4348 {
4349 if (info->x_used)
4350 {
4351 if (Y_REG_P (dst) && rtx_equal_p (src, z_reg))
4352 {
4353 if (z_dies_here)
4354 {
4355 info->need_save_z = 0;
4356 info->z_died = 1;
4357 }
4358 info->must_save_reg = 0;
4359 info->must_restore_reg = 0;
4360 info->found_call = 1;
4361 info->can_use_d = 0;
4362 PUT_CODE (insn, NOTE);
4363 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
4364 NOTE_SOURCE_FILE (insn) = 0;
4365 info->last = NEXT_INSN (insn);
4366 return 0;
4367 }
4368
4369 if (Y_REG_P (dst)
4370 && (rtx_equal_p (src, z_reg)
4371 || (z_dies_here && !reg_mentioned_p (iy_reg, src))))
4372 {
4373 if (z_dies_here)
4374 {
4375 info->z_died = 1;
4376 info->need_save_z = 0;
4377 }
4378 info->last = NEXT_INSN (insn);
4379 info->must_save_reg = 0;
4380 info->must_restore_reg = 0;
4381 }
4382 else if (Y_REG_P (dst) && reg_mentioned_p (z_reg, src)
4383 && !reg_mentioned_p (iy_reg, src))
4384 {
4385 if (z_dies_here)
4386 {
4387 info->z_died = 1;
4388 info->need_save_z = 0;
4389 }
4390 else if (TARGET_M6812 && side_effects_p (src))
4391 {
4392 info->last = 0;
4393 info->must_restore_reg = 0;
4394 return 0;
4395 }
4396 else
4397 {
4398 info->save_before_last = 1;
4399 }
4400 info->must_restore_reg = 0;
4401 info->last = NEXT_INSN (insn);
4402 }
4403 else if (info->can_use_d)
4404 {
4405 info->last = NEXT_INSN (insn);
4406 info->y_used = 1;
4407 }
4408
4409 return 0;
4410 }
4411 info->y_used = 1;
4412 if (z_dies_here && !reg_mentioned_p (iy_reg, src)
4413 && GET_CODE (dst) == REG && REGNO (dst) == HARD_Y_REGNUM)
4414 {
4415 info->need_save_z = 0;
4416 info->z_died = 1;
4417 info->last = NEXT_INSN (insn);
4418 info->regno = HARD_Y_REGNUM;
4419 info->must_save_reg = 0;
4420 info->must_restore_reg = 0;
4421 return 0;
4422 }
4423 if (rtx_equal_p (src, z_reg) && rtx_equal_p (dst, iy_reg))
4424 {
4425 info->regno = HARD_Y_REGNUM;
4426 info->must_restore_reg = 0;
4427 info->must_save_reg = 0;
4428 return 0;
4429 }
4430 }
4431 if (z_dies_here)
4432 {
4433 info->need_save_z = 0;
4434 info->z_died = 1;
4435 if (info->last == 0)
4436 info->last = NEXT_INSN (insn);
4437 return 0;
4438 }
4439 return info->last != NULL_RTX ? 0 : 1;
4440 }
4441 if (GET_CODE (body) == PARALLEL)
4442 {
4443 int i;
4444 char ix_clobber = 0;
4445 char iy_clobber = 0;
4446 char z_clobber = 0;
4447 this_insn_uses_iy = 0;
4448 this_insn_uses_ix = 0;
4449 this_insn_uses_z = 0;
4450
4451 for (i = XVECLEN (body, 0) - 1; i >= 0; i--)
4452 {
4453 rtx x;
4454 int uses_ix, uses_iy, uses_z;
4455
4456 x = XVECEXP (body, 0, i);
4457
4458 if (info->can_use_d && reg_mentioned_p (d_reg, x))
4459 info->can_use_d = 0;
4460
4461 uses_ix = reg_mentioned_p (ix_reg, x);
4462 uses_iy = reg_mentioned_p (iy_reg, x);
4463 uses_z = reg_mentioned_p (z_reg, x);
4464 if (GET_CODE (x) == CLOBBER)
4465 {
4466 ix_clobber |= uses_ix;
4467 iy_clobber |= uses_iy;
4468 z_clobber |= uses_z;
4469 }
4470 else
4471 {
4472 this_insn_uses_ix |= uses_ix;
4473 this_insn_uses_iy |= uses_iy;
4474 this_insn_uses_z |= uses_z;
4475 }
4476 if (uses_z && GET_CODE (x) == SET)
4477 {
4478 rtx dst = XEXP (x, 0);
4479
4480 if (Z_REG_P (dst))
4481 info->z_set_count++;
4482 }
4483 if (TARGET_M6812 && uses_z && side_effects_p (x))
4484 info->need_save_z = 1;
4485
4486 if (z_clobber)
4487 info->need_save_z = 0;
4488 }
4489 if (debug_m6811)
4490 {
4491 printf ("Uses X:%d Y:%d Z:%d CX:%d CY:%d CZ:%d\n",
4492 this_insn_uses_ix, this_insn_uses_iy,
4493 this_insn_uses_z, ix_clobber, iy_clobber, z_clobber);
4494 debug_rtx (insn);
4495 }
4496 if (this_insn_uses_z)
4497 info->can_use_d = 0;
4498
4499 if (z_clobber && info->first != insn)
4500 {
4501 info->need_save_z = 0;
4502 info->last = insn;
4503 return 0;
4504 }
4505 if (z_clobber && info->x_used == 0 && info->y_used == 0)
4506 {
4507 if (this_insn_uses_z == 0 && insn == info->first)
4508 {
4509 info->must_load_z = 0;
4510 }
4511 if (dead_register_here (insn, d_reg))
4512 {
4513 info->regno = HARD_D_REGNUM;
4514 info->must_save_reg = 0;
4515 info->must_restore_reg = 0;
4516 }
4517 else if (dead_register_here (insn, ix_reg))
4518 {
4519 info->regno = HARD_X_REGNUM;
4520 info->must_save_reg = 0;
4521 info->must_restore_reg = 0;
4522 }
4523 else if (dead_register_here (insn, iy_reg))
4524 {
4525 info->regno = HARD_Y_REGNUM;
4526 info->must_save_reg = 0;
4527 info->must_restore_reg = 0;
4528 }
4529 if (info->regno >= 0)
4530 {
4531 info->last = NEXT_INSN (insn);
4532 return 0;
4533 }
4534 if (this_insn_uses_ix == 0)
4535 {
4536 info->regno = HARD_X_REGNUM;
4537 info->must_save_reg = 1;
4538 info->must_restore_reg = 1;
4539 }
4540 else if (this_insn_uses_iy == 0)
4541 {
4542 info->regno = HARD_Y_REGNUM;
4543 info->must_save_reg = 1;
4544 info->must_restore_reg = 1;
4545 }
4546 else
4547 {
4548 info->regno = HARD_D_REGNUM;
4549 info->must_save_reg = 1;
4550 info->must_restore_reg = 1;
4551 }
4552 info->last = NEXT_INSN (insn);
4553 return 0;
4554 }
4555
4556 if (((info->x_used || this_insn_uses_ix) && iy_clobber)
4557 || ((info->y_used || this_insn_uses_iy) && ix_clobber))
4558 {
4559 if (this_insn_uses_z)
4560 {
4561 if (info->y_used == 0 && iy_clobber)
4562 {
4563 info->regno = HARD_Y_REGNUM;
4564 info->must_save_reg = 0;
4565 info->must_restore_reg = 0;
4566 }
4567 if (info->first != insn
4568 && ((info->y_used && ix_clobber)
4569 || (info->x_used && iy_clobber)))
4570 info->last = insn;
4571 else
4572 info->last = NEXT_INSN (insn);
4573 info->save_before_last = 1;
4574 }
4575 return 0;
4576 }
4577 if (this_insn_uses_ix && this_insn_uses_iy)
4578 {
4579 if (this_insn_uses_z)
4580 {
4581 fatal_insn ("cannot do z-register replacement", insn);
4582 }
4583 return 0;
4584 }
4585 if (info->x_used == 0 && (this_insn_uses_ix || ix_clobber))
4586 {
4587 if (info->y_used)
4588 {
4589 return 0;
4590 }
4591 info->x_used = 1;
4592 if (iy_clobber || z_clobber)
4593 {
4594 info->last = NEXT_INSN (insn);
4595 info->save_before_last = 1;
4596 return 0;
4597 }
4598 }
4599
4600 if (info->y_used == 0 && (this_insn_uses_iy || iy_clobber))
4601 {
4602 if (info->x_used)
4603 {
4604 return 0;
4605 }
4606 info->y_used = 1;
4607 if (ix_clobber || z_clobber)
4608 {
4609 info->last = NEXT_INSN (insn);
4610 info->save_before_last = 1;
4611 return 0;
4612 }
4613 }
4614 if (z_dies_here)
4615 {
4616 info->z_died = 1;
4617 info->need_save_z = 0;
4618 }
4619 return 1;
4620 }
4621 if (GET_CODE (body) == CLOBBER)
4622 {
4623
4624 /* IX and IY are used at the same time, we have to restore
4625 the value of the scratch register before this insn. */
4626 if (this_insn_uses_ix && this_insn_uses_iy)
4627 {
4628 return 0;
4629 }
4630 if (info->x_used == 0 && this_insn_uses_ix)
4631 {
4632 if (info->y_used)
4633 {
4634 return 0;
4635 }
4636 info->x_used = 1;
4637 }
4638 if (info->y_used == 0 && this_insn_uses_iy)
4639 {
4640 if (info->x_used)
4641 {
4642 return 0;
4643 }
4644 info->y_used = 1;
4645 }
4646 return 1;
4647 }
4648 return 1;
4649 }
4650
4651 static void
4652 m68hc11_find_z_replacement (rtx insn, struct replace_info *info)
4653 {
4654 int reg;
4655
4656 info->replace_reg = NULL_RTX;
4657 info->must_load_z = 1;
4658 info->need_save_z = 1;
4659 info->must_save_reg = 1;
4660 info->must_restore_reg = 1;
4661 info->first = insn;
4662 info->x_used = 0;
4663 info->y_used = 0;
4664 info->can_use_d = TARGET_M6811 ? 1 : 0;
4665 info->found_call = 0;
4666 info->z_died = 0;
4667 info->last = 0;
4668 info->regno = -1;
4669 info->z_set_count = 0;
4670 info->z_value = NULL_RTX;
4671 info->must_push_reg = 0;
4672 info->save_before_last = 0;
4673 info->z_loaded_with_sp = 0;
4674
4675 /* Scan the insn forward to find an address register that is not used.
4676 Stop when:
4677 - the flow of the program changes,
4678 - when we detect that both X and Y are necessary,
4679 - when the Z register dies,
4680 - when the condition codes are set. */
4681
4682 for (; insn && info->z_died == 0; insn = NEXT_INSN (insn))
4683 {
4684 if (m68hc11_check_z_replacement (insn, info) == 0)
4685 break;
4686 }
4687
4688 /* May be we can use Y or X if they contain the same value as Z.
4689 This happens very often after the reload. */
4690 if (info->z_set_count == 1)
4691 {
4692 rtx p = info->first;
4693 rtx v = 0;
4694
4695 if (info->x_used)
4696 {
4697 v = find_last_value (iy_reg, &p, insn, 1);
4698 }
4699 else if (info->y_used)
4700 {
4701 v = find_last_value (ix_reg, &p, insn, 1);
4702 }
4703 if (v && (v != iy_reg && v != ix_reg) && rtx_equal_p (v, info->z_value))
4704 {
4705 if (info->x_used)
4706 info->regno = HARD_Y_REGNUM;
4707 else
4708 info->regno = HARD_X_REGNUM;
4709 info->must_load_z = 0;
4710 info->must_save_reg = 0;
4711 info->must_restore_reg = 0;
4712 info->found_call = 1;
4713 }
4714 }
4715 if (info->z_set_count == 0)
4716 info->need_save_z = 0;
4717
4718 if (insn == 0)
4719 info->need_save_z = 0;
4720
4721 if (info->last == 0)
4722 info->last = insn;
4723
4724 if (info->regno >= 0)
4725 {
4726 reg = info->regno;
4727 info->replace_reg = gen_rtx_REG (HImode, reg);
4728 }
4729 else if (info->can_use_d)
4730 {
4731 reg = HARD_D_REGNUM;
4732 info->replace_reg = d_reg;
4733 }
4734 else if (info->x_used)
4735 {
4736 reg = HARD_Y_REGNUM;
4737 info->replace_reg = iy_reg;
4738 }
4739 else
4740 {
4741 reg = HARD_X_REGNUM;
4742 info->replace_reg = ix_reg;
4743 }
4744 info->regno = reg;
4745
4746 if (info->must_save_reg && info->must_restore_reg)
4747 {
4748 if (insn && dead_register_here (insn, info->replace_reg))
4749 {
4750 info->must_save_reg = 0;
4751 info->must_restore_reg = 0;
4752 }
4753 }
4754 }
4755
4756 /* The insn uses the Z register. Find a replacement register for it
4757 (either X or Y) and replace it in the insn and the next ones until
4758 the flow changes or the replacement register is used. Instructions
4759 are emitted before and after the Z-block to preserve the value of
4760 Z and of the replacement register. */
4761
4762 static void
4763 m68hc11_z_replacement (rtx insn)
4764 {
4765 rtx replace_reg_qi;
4766 rtx replace_reg;
4767 struct replace_info info;
4768
4769 /* Find trivial case where we only need to replace z with the
4770 equivalent soft register. */
4771 if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET)
4772 {
4773 rtx body = PATTERN (insn);
4774 rtx src = XEXP (body, 1);
4775 rtx dst = XEXP (body, 0);
4776
4777 if (Z_REG_P (dst) && (H_REG_P (src) && !SP_REG_P (src)))
4778 {
4779 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4780 return;
4781 }
4782 else if (Z_REG_P (src)
4783 && ((H_REG_P (dst) && !SP_REG_P (src)) || dst == cc0_rtx))
4784 {
4785 XEXP (body, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4786 return;
4787 }
4788 else if (D_REG_P (dst)
4789 && m68hc11_arith_operator (src, GET_MODE (src))
4790 && D_REG_P (XEXP (src, 0)) && Z_REG_P (XEXP (src, 1)))
4791 {
4792 XEXP (src, 1) = gen_rtx_REG (GET_MODE (src), SOFT_Z_REGNUM);
4793 return;
4794 }
4795 else if (Z_REG_P (dst) && GET_CODE (src) == CONST_INT
4796 && INTVAL (src) == 0)
4797 {
4798 XEXP (body, 0) = gen_rtx_REG (GET_MODE (dst), SOFT_Z_REGNUM);
4799 /* Force it to be re-recognized. */
4800 INSN_CODE (insn) = -1;
4801 return;
4802 }
4803 }
4804
4805 m68hc11_find_z_replacement (insn, &info);
4806
4807 replace_reg = info.replace_reg;
4808 replace_reg_qi = NULL_RTX;
4809
4810 /* Save the X register in a .page0 location. */
4811 if (info.must_save_reg && !info.must_push_reg)
4812 {
4813 rtx dst;
4814
4815 if (info.must_push_reg && 0)
4816 dst = gen_rtx_MEM (HImode,
4817 gen_rtx_PRE_DEC (HImode,
4818 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4819 else
4820 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4821
4822 emit_insn_before (gen_movhi (dst,
4823 gen_rtx_REG (HImode, info.regno)), insn);
4824 }
4825 if (info.must_load_z && !info.must_push_reg)
4826 {
4827 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4828 gen_rtx_REG (HImode, SOFT_Z_REGNUM)),
4829 insn);
4830 }
4831
4832
4833 /* Replace all occurrence of Z by replace_reg.
4834 Stop when the last instruction to replace is reached.
4835 Also stop when we detect a change in the flow (but it's not
4836 necessary; just safeguard). */
4837
4838 for (; insn && insn != info.last; insn = NEXT_INSN (insn))
4839 {
4840 rtx body;
4841
4842 if (GET_CODE (insn) == CODE_LABEL || GET_CODE (insn) == BARRIER)
4843 break;
4844
4845 if (GET_CODE (insn) != INSN
4846 && GET_CODE (insn) != CALL_INSN && GET_CODE (insn) != JUMP_INSN)
4847 continue;
4848
4849 body = PATTERN (insn);
4850 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
4851 || GET_CODE (body) == ASM_OPERANDS
4852 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4853 {
4854 rtx note;
4855
4856 if (debug_m6811 && reg_mentioned_p (replace_reg, body))
4857 {
4858 printf ("Reg mentioned here...:\n");
4859 fflush (stdout);
4860 debug_rtx (insn);
4861 }
4862
4863 /* Stack pointer was decremented by 2 due to the push.
4864 Correct that by adding 2 to the destination. */
4865 if (info.must_push_reg
4866 && info.z_loaded_with_sp && GET_CODE (body) == SET)
4867 {
4868 rtx src, dst;
4869
4870 src = SET_SRC (body);
4871 dst = SET_DEST (body);
4872 if (SP_REG_P (src) && Z_REG_P (dst))
4873 emit_insn_after (gen_addhi3 (dst, dst, const2_rtx), insn);
4874 }
4875
4876 /* Replace any (REG:HI Z) occurrence by either X or Y. */
4877 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4878 {
4879 INSN_CODE (insn) = -1;
4880 if (!validate_replace_rtx (z_reg, replace_reg, insn))
4881 fatal_insn ("cannot do z-register replacement", insn);
4882 }
4883
4884 /* Likewise for (REG:QI Z). */
4885 if (reg_mentioned_p (z_reg, insn))
4886 {
4887 if (replace_reg_qi == NULL_RTX)
4888 replace_reg_qi = gen_rtx_REG (QImode, REGNO (replace_reg));
4889 validate_replace_rtx (z_reg_qi, replace_reg_qi, insn);
4890 }
4891
4892 /* If there is a REG_INC note on Z, replace it with a
4893 REG_INC note on the replacement register. This is necessary
4894 to make sure that the flow pass will identify the change
4895 and it will not remove a possible insn that saves Z. */
4896 for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
4897 {
4898 if (REG_NOTE_KIND (note) == REG_INC
4899 && GET_CODE (XEXP (note, 0)) == REG
4900 && REGNO (XEXP (note, 0)) == REGNO (z_reg))
4901 {
4902 XEXP (note, 0) = replace_reg;
4903 }
4904 }
4905 }
4906 if (GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
4907 break;
4908 }
4909
4910 /* Save Z before restoring the old value. */
4911 if (insn && info.need_save_z && !info.must_push_reg)
4912 {
4913 rtx save_pos_insn = insn;
4914
4915 /* If Z is clobber by the last insn, we have to save its value
4916 before the last instruction. */
4917 if (info.save_before_last)
4918 save_pos_insn = PREV_INSN (save_pos_insn);
4919
4920 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, SOFT_Z_REGNUM),
4921 gen_rtx_REG (HImode, info.regno)),
4922 save_pos_insn);
4923 }
4924
4925 if (info.must_push_reg && info.last)
4926 {
4927 rtx new_body, body;
4928
4929 body = PATTERN (info.last);
4930 new_body = gen_rtx_PARALLEL (VOIDmode,
4931 gen_rtvec (3, body,
4932 gen_rtx_USE (VOIDmode,
4933 replace_reg),
4934 gen_rtx_USE (VOIDmode,
4935 gen_rtx_REG (HImode,
4936 SOFT_Z_REGNUM))));
4937 PATTERN (info.last) = new_body;
4938
4939 /* Force recognition on insn since we changed it. */
4940 INSN_CODE (insn) = -1;
4941
4942 if (!validate_replace_rtx (z_reg, replace_reg, info.last))
4943 {
4944 fatal_insn ("invalid Z register replacement for insn", insn);
4945 }
4946 insn = NEXT_INSN (info.last);
4947 }
4948
4949 /* Restore replacement register unless it was died. */
4950 if (insn && info.must_restore_reg && !info.must_push_reg)
4951 {
4952 rtx dst;
4953
4954 if (info.must_push_reg && 0)
4955 dst = gen_rtx_MEM (HImode,
4956 gen_rtx_POST_INC (HImode,
4957 gen_rtx_REG (HImode, HARD_SP_REGNUM)));
4958 else
4959 dst = gen_rtx_REG (HImode, SOFT_SAVED_XY_REGNUM);
4960
4961 emit_insn_before (gen_movhi (gen_rtx_REG (HImode, info.regno),
4962 dst), insn);
4963 }
4964
4965 }
4966
4967
4968 /* Scan all the insn and re-affects some registers
4969 - The Z register (if it was used), is affected to X or Y depending
4970 on the instruction. */
4971
4972 static void
4973 m68hc11_reassign_regs (rtx first)
4974 {
4975 rtx insn;
4976
4977 ix_reg = gen_rtx_REG (HImode, HARD_X_REGNUM);
4978 iy_reg = gen_rtx_REG (HImode, HARD_Y_REGNUM);
4979 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
4980 z_reg_qi = gen_rtx_REG (QImode, HARD_Z_REGNUM);
4981
4982 /* Scan all insns to replace Z by X or Y preserving the old value
4983 of X/Y and restoring it afterward. */
4984
4985 for (insn = first; insn; insn = NEXT_INSN (insn))
4986 {
4987 rtx body;
4988
4989 if (GET_CODE (insn) == CODE_LABEL
4990 || GET_CODE (insn) == NOTE || GET_CODE (insn) == BARRIER)
4991 continue;
4992
4993 if (!INSN_P (insn))
4994 continue;
4995
4996 body = PATTERN (insn);
4997 if (GET_CODE (body) == CLOBBER || GET_CODE (body) == USE)
4998 continue;
4999
5000 if (GET_CODE (body) == CONST_INT || GET_CODE (body) == ASM_INPUT
5001 || GET_CODE (body) == ASM_OPERANDS
5002 || GET_CODE (body) == UNSPEC || GET_CODE (body) == UNSPEC_VOLATILE)
5003 continue;
5004
5005 if (GET_CODE (body) == SET || GET_CODE (body) == PARALLEL
5006 || GET_CODE (insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
5007 {
5008
5009 /* If Z appears in this insn, replace it in the current insn
5010 and the next ones until the flow changes or we have to
5011 restore back the replacement register. */
5012
5013 if (reg_mentioned_p (z_reg, body))
5014 {
5015 m68hc11_z_replacement (insn);
5016 }
5017 }
5018 else
5019 {
5020 printf ("insn not handled by Z replacement:\n");
5021 fflush (stdout);
5022 debug_rtx (insn);
5023 }
5024 }
5025 }
5026
5027
5028 /* Machine-dependent reorg pass.
5029 Specific optimizations are defined here:
5030 - this pass changes the Z register into either X or Y
5031 (it preserves X/Y previous values in a memory slot in page0).
5032
5033 When this pass is finished, the global variable
5034 'z_replacement_completed' is set to 2. */
5035
5036 static void
5037 m68hc11_reorg (void)
5038 {
5039 int split_done = 0;
5040 rtx insn, first;
5041
5042 z_replacement_completed = 0;
5043 z_reg = gen_rtx_REG (HImode, HARD_Z_REGNUM);
5044 first = get_insns ();
5045
5046 /* Some RTX are shared at this point. This breaks the Z register
5047 replacement, unshare everything. */
5048 unshare_all_rtl_again (first);
5049
5050 /* Force a split of all splitable insn. This is necessary for the
5051 Z register replacement mechanism because we end up with basic insns. */
5052 split_all_insns_noflow ();
5053 split_done = 1;
5054
5055 z_replacement_completed = 1;
5056 m68hc11_reassign_regs (first);
5057
5058 if (optimize)
5059 compute_bb_for_insn ();
5060
5061 /* After some splitting, there are some opportunities for CSE pass.
5062 This happens quite often when 32-bit or above patterns are split. */
5063 if (optimize > 0 && split_done)
5064 {
5065 reload_cse_regs (first);
5066 }
5067
5068 /* Re-create the REG_DEAD notes. These notes are used in the machine
5069 description to use the best assembly directives. */
5070 if (optimize)
5071 {
5072 /* Before recomputing the REG_DEAD notes, remove all of them.
5073 This is necessary because the reload_cse_regs() pass can
5074 have replaced some (MEM) with a register. In that case,
5075 the REG_DEAD that could exist for that register may become
5076 wrong. */
5077 for (insn = first; insn; insn = NEXT_INSN (insn))
5078 {
5079 if (INSN_P (insn))
5080 {
5081 rtx *pnote;
5082
5083 pnote = &REG_NOTES (insn);
5084 while (*pnote != 0)
5085 {
5086 if (REG_NOTE_KIND (*pnote) == REG_DEAD)
5087 *pnote = XEXP (*pnote, 1);
5088 else
5089 pnote = &XEXP (*pnote, 1);
5090 }
5091 }
5092 }
5093
5094 life_analysis (0, PROP_REG_INFO | PROP_DEATH_NOTES);
5095 }
5096
5097 z_replacement_completed = 2;
5098
5099 /* If optimizing, then go ahead and split insns that must be
5100 split after Z register replacement. This gives more opportunities
5101 for peephole (in particular for consecutives xgdx/xgdy). */
5102 if (optimize > 0)
5103 split_all_insns_noflow ();
5104
5105 /* Once insns are split after the z_replacement_completed == 2,
5106 we must not re-run the life_analysis. The xgdx/xgdy patterns
5107 are not recognized and the life_analysis pass removes some
5108 insns because it thinks some (SETs) are noops or made to dead
5109 stores (which is false due to the swap).
5110
5111 Do a simple pass to eliminate the noop set that the final
5112 split could generate (because it was easier for split definition). */
5113 {
5114 rtx insn;
5115
5116 for (insn = first; insn; insn = NEXT_INSN (insn))
5117 {
5118 rtx body;
5119
5120 if (INSN_DELETED_P (insn))
5121 continue;
5122 if (!INSN_P (insn))
5123 continue;
5124
5125 /* Remove the (set (R) (R)) insns generated by some splits. */
5126 body = PATTERN (insn);
5127 if (GET_CODE (body) == SET
5128 && rtx_equal_p (SET_SRC (body), SET_DEST (body)))
5129 {
5130 PUT_CODE (insn, NOTE);
5131 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
5132 NOTE_SOURCE_FILE (insn) = 0;
5133 continue;
5134 }
5135 }
5136 }
5137 }
5138 \f
5139 /* Override memcpy */
5140
5141 static void
5142 m68hc11_init_libfuncs (void)
5143 {
5144 memcpy_libfunc = init_one_libfunc ("__memcpy");
5145 memcmp_libfunc = init_one_libfunc ("__memcmp");
5146 memset_libfunc = init_one_libfunc ("__memset");
5147 }
5148
5149 \f
5150
5151 /* Cost functions. */
5152
5153 /* Cost of moving memory. */
5154 int
5155 m68hc11_memory_move_cost (enum machine_mode mode, enum reg_class class,
5156 int in ATTRIBUTE_UNUSED)
5157 {
5158 if (class <= H_REGS && class > NO_REGS)
5159 {
5160 if (GET_MODE_SIZE (mode) <= 2)
5161 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5162 else
5163 return COSTS_N_INSNS (2) + (reload_completed | reload_in_progress);
5164 }
5165 else
5166 {
5167 if (GET_MODE_SIZE (mode) <= 2)
5168 return COSTS_N_INSNS (3);
5169 else
5170 return COSTS_N_INSNS (4);
5171 }
5172 }
5173
5174
5175 /* Cost of moving data from a register of class 'from' to on in class 'to'.
5176 Reload does not check the constraint of set insns when the two registers
5177 have a move cost of 2. Setting a higher cost will force reload to check
5178 the constraints. */
5179 int
5180 m68hc11_register_move_cost (enum machine_mode mode, enum reg_class from,
5181 enum reg_class to)
5182 {
5183 /* All costs are symmetric, so reduce cases by putting the
5184 lower number class as the destination. */
5185 if (from < to)
5186 {
5187 enum reg_class tmp = to;
5188 to = from, from = tmp;
5189 }
5190 if (to >= S_REGS)
5191 return m68hc11_memory_move_cost (mode, S_REGS, 0);
5192 else if (from <= S_REGS)
5193 return COSTS_N_INSNS (1) + (reload_completed | reload_in_progress);
5194 else
5195 return COSTS_N_INSNS (2);
5196 }
5197
5198
5199 /* Provide the costs of an addressing mode that contains ADDR.
5200 If ADDR is not a valid address, its cost is irrelevant. */
5201
5202 static int
5203 m68hc11_address_cost (rtx addr)
5204 {
5205 int cost = 4;
5206
5207 switch (GET_CODE (addr))
5208 {
5209 case REG:
5210 /* Make the cost of hard registers and specially SP, FP small. */
5211 if (REGNO (addr) < FIRST_PSEUDO_REGISTER)
5212 cost = 0;
5213 else
5214 cost = 1;
5215 break;
5216
5217 case SYMBOL_REF:
5218 cost = 8;
5219 break;
5220
5221 case LABEL_REF:
5222 case CONST:
5223 cost = 0;
5224 break;
5225
5226 case PLUS:
5227 {
5228 register rtx plus0 = XEXP (addr, 0);
5229 register rtx plus1 = XEXP (addr, 1);
5230
5231 if (GET_CODE (plus0) != REG)
5232 break;
5233
5234 switch (GET_CODE (plus1))
5235 {
5236 case CONST_INT:
5237 if (INTVAL (plus1) >= 2 * m68hc11_max_offset
5238 || INTVAL (plus1) < m68hc11_min_offset)
5239 cost = 3;
5240 else if (INTVAL (plus1) >= m68hc11_max_offset)
5241 cost = 2;
5242 else
5243 cost = 1;
5244 if (REGNO (plus0) < FIRST_PSEUDO_REGISTER)
5245 cost += 0;
5246 else
5247 cost += 1;
5248 break;
5249
5250 case SYMBOL_REF:
5251 cost = 8;
5252 break;
5253
5254 case CONST:
5255 case LABEL_REF:
5256 cost = 0;
5257 break;
5258
5259 default:
5260 break;
5261 }
5262 break;
5263 }
5264 case PRE_DEC:
5265 case PRE_INC:
5266 if (SP_REG_P (XEXP (addr, 0)))
5267 cost = 1;
5268 break;
5269
5270 default:
5271 break;
5272 }
5273 if (debug_m6811)
5274 {
5275 printf ("Address cost: %d for :", cost);
5276 fflush (stdout);
5277 debug_rtx (addr);
5278 }
5279
5280 return cost;
5281 }
5282
5283 static int
5284 m68hc11_shift_cost (enum machine_mode mode, rtx x, int shift)
5285 {
5286 int total;
5287
5288 total = rtx_cost (x, SET);
5289 if (mode == QImode)
5290 total += m68hc11_cost->shiftQI_const[shift % 8];
5291 else if (mode == HImode)
5292 total += m68hc11_cost->shiftHI_const[shift % 16];
5293 else if (shift == 8 || shift == 16 || shift == 32)
5294 total += m68hc11_cost->shiftHI_const[8];
5295 else if (shift != 0 && shift != 16 && shift != 32)
5296 {
5297 total += m68hc11_cost->shiftHI_const[1] * shift;
5298 }
5299
5300 /* For SI and others, the cost is higher. */
5301 if (GET_MODE_SIZE (mode) > 2 && (shift % 16) != 0)
5302 total *= GET_MODE_SIZE (mode) / 2;
5303
5304 /* When optimizing for size, make shift more costly so that
5305 multiplications are preferred. */
5306 if (optimize_size && (shift % 8) != 0)
5307 total *= 2;
5308
5309 return total;
5310 }
5311
5312 static int
5313 m68hc11_rtx_costs_1 (rtx x, enum rtx_code code,
5314 enum rtx_code outer_code ATTRIBUTE_UNUSED)
5315 {
5316 enum machine_mode mode = GET_MODE (x);
5317 int extra_cost = 0;
5318 int total;
5319
5320 switch (code)
5321 {
5322 case ROTATE:
5323 case ROTATERT:
5324 case ASHIFT:
5325 case LSHIFTRT:
5326 case ASHIFTRT:
5327 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
5328 {
5329 return m68hc11_shift_cost (mode, XEXP (x, 0), INTVAL (XEXP (x, 1)));
5330 }
5331
5332 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5333 total += m68hc11_cost->shift_var;
5334 return total;
5335
5336 case AND:
5337 case XOR:
5338 case IOR:
5339 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5340 total += m68hc11_cost->logical;
5341
5342 /* Logical instructions are byte instructions only. */
5343 total *= GET_MODE_SIZE (mode);
5344 return total;
5345
5346 case MINUS:
5347 case PLUS:
5348 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5349 total += m68hc11_cost->add;
5350 if (GET_MODE_SIZE (mode) > 2)
5351 {
5352 total *= GET_MODE_SIZE (mode) / 2;
5353 }
5354 return total;
5355
5356 case UDIV:
5357 case DIV:
5358 case MOD:
5359 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5360 switch (mode)
5361 {
5362 case QImode:
5363 total += m68hc11_cost->divQI;
5364 break;
5365
5366 case HImode:
5367 total += m68hc11_cost->divHI;
5368 break;
5369
5370 case SImode:
5371 default:
5372 total += m68hc11_cost->divSI;
5373 break;
5374 }
5375 return total;
5376
5377 case MULT:
5378 /* mul instruction produces 16-bit result. */
5379 if (mode == HImode && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5380 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5381 return m68hc11_cost->multQI
5382 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5383 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5384
5385 /* emul instruction produces 32-bit result for 68HC12. */
5386 if (TARGET_M6812 && mode == SImode
5387 && GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
5388 && GET_CODE (XEXP (x, 1)) == ZERO_EXTEND)
5389 return m68hc11_cost->multHI
5390 + rtx_cost (XEXP (XEXP (x, 0), 0), code)
5391 + rtx_cost (XEXP (XEXP (x, 1), 0), code);
5392
5393 total = rtx_cost (XEXP (x, 0), code) + rtx_cost (XEXP (x, 1), code);
5394 switch (mode)
5395 {
5396 case QImode:
5397 total += m68hc11_cost->multQI;
5398 break;
5399
5400 case HImode:
5401 total += m68hc11_cost->multHI;
5402 break;
5403
5404 case SImode:
5405 default:
5406 total += m68hc11_cost->multSI;
5407 break;
5408 }
5409 return total;
5410
5411 case NEG:
5412 case SIGN_EXTEND:
5413 extra_cost = COSTS_N_INSNS (2);
5414
5415 /* Fall through */
5416 case NOT:
5417 case COMPARE:
5418 case ABS:
5419 case ZERO_EXTEND:
5420 total = extra_cost + rtx_cost (XEXP (x, 0), code);
5421 if (mode == QImode)
5422 {
5423 return total + COSTS_N_INSNS (1);
5424 }
5425 if (mode == HImode)
5426 {
5427 return total + COSTS_N_INSNS (2);
5428 }
5429 if (mode == SImode)
5430 {
5431 return total + COSTS_N_INSNS (4);
5432 }
5433 return total + COSTS_N_INSNS (8);
5434
5435 case IF_THEN_ELSE:
5436 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
5437 return COSTS_N_INSNS (1);
5438
5439 return COSTS_N_INSNS (1);
5440
5441 default:
5442 return COSTS_N_INSNS (4);
5443 }
5444 }
5445
5446 static bool
5447 m68hc11_rtx_costs (rtx x, int code, int outer_code, int *total)
5448 {
5449 switch (code)
5450 {
5451 /* Constants are cheap. Moving them in registers must be avoided
5452 because most instructions do not handle two register operands. */
5453 case CONST_INT:
5454 case CONST:
5455 case LABEL_REF:
5456 case SYMBOL_REF:
5457 case CONST_DOUBLE:
5458 /* Logical and arithmetic operations with a constant operand are
5459 better because they are not supported with two registers. */
5460 /* 'clr' is slow */
5461 if (outer_code == SET && x == const0_rtx)
5462 /* After reload, the reload_cse pass checks the cost to change
5463 a SET into a PLUS. Make const0 cheap then. */
5464 *total = 1 - reload_completed;
5465 else
5466 *total = 0;
5467 return true;
5468
5469 case ROTATE:
5470 case ROTATERT:
5471 case ASHIFT:
5472 case LSHIFTRT:
5473 case ASHIFTRT:
5474 case MINUS:
5475 case PLUS:
5476 case AND:
5477 case XOR:
5478 case IOR:
5479 case UDIV:
5480 case DIV:
5481 case MOD:
5482 case MULT:
5483 case NEG:
5484 case SIGN_EXTEND:
5485 case NOT:
5486 case COMPARE:
5487 case ZERO_EXTEND:
5488 case IF_THEN_ELSE:
5489 *total = m68hc11_rtx_costs_1 (x, code, outer_code);
5490 return true;
5491
5492 default:
5493 return false;
5494 }
5495 }
5496 \f
5497
5498 /* Worker function for TARGET_ASM_FILE_START. */
5499
5500 static void
5501 m68hc11_file_start (void)
5502 {
5503 default_file_start ();
5504
5505 fprintf (asm_out_file, "\t.mode %s\n", TARGET_SHORT ? "mshort" : "mlong");
5506 }
5507
5508
5509 /* Worker function for TARGET_ASM_CONSTRUCTOR. */
5510
5511 static void
5512 m68hc11_asm_out_constructor (rtx symbol, int priority)
5513 {
5514 default_ctor_section_asm_out_constructor (symbol, priority);
5515 fprintf (asm_out_file, "\t.globl\t__do_global_ctors\n");
5516 }
5517
5518 /* Worker function for TARGET_ASM_DESTRUCTOR. */
5519
5520 static void
5521 m68hc11_asm_out_destructor (rtx symbol, int priority)
5522 {
5523 default_dtor_section_asm_out_destructor (symbol, priority);
5524 fprintf (asm_out_file, "\t.globl\t__do_global_dtors\n");
5525 }
5526
5527 /* Worker function for TARGET_STRUCT_VALUE_RTX. */
5528
5529 static rtx
5530 m68hc11_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
5531 int incoming ATTRIBUTE_UNUSED)
5532 {
5533 return gen_rtx_REG (Pmode, HARD_D_REGNUM);
5534 }
5535
5536 /* Return true if type TYPE should be returned in memory.
5537 Blocks and data types largers than 4 bytes cannot be returned
5538 in the register (D + X = 4). */
5539
5540 static bool
5541 m68hc11_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
5542 {
5543 if (TYPE_MODE (type) == BLKmode)
5544 {
5545 HOST_WIDE_INT size = int_size_in_bytes (type);
5546 return (size == -1 || size > 4);
5547 }
5548 else
5549 return GET_MODE_SIZE (TYPE_MODE (type)) > 4;
5550 }
5551
5552 #include "gt-m68hc11.h"