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