OSDN Git Service

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