OSDN Git Service

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