OSDN Git Service

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