OSDN Git Service

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