OSDN Git Service

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