OSDN Git Service

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