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