OSDN Git Service

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