OSDN Git Service

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