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