OSDN Git Service

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