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