OSDN Git Service

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