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