OSDN Git Service

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