OSDN Git Service

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