OSDN Git Service

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