OSDN Git Service

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