xref: /openbsd/gnu/gcc/gcc/config/fr30/fr30.c (revision 404b540a)
1*404b540aSrobert /* FR30 specific functions.
2*404b540aSrobert    Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005
3*404b540aSrobert    Free Software Foundation, Inc.
4*404b540aSrobert    Contributed by Cygnus Solutions.
5*404b540aSrobert 
6*404b540aSrobert    This file is part of GCC.
7*404b540aSrobert 
8*404b540aSrobert    GCC is free software; you can redistribute it and/or modify
9*404b540aSrobert    it under the terms of the GNU General Public License as published by
10*404b540aSrobert    the Free Software Foundation; either version 2, or (at your option)
11*404b540aSrobert    any later version.
12*404b540aSrobert 
13*404b540aSrobert    GCC is distributed in the hope that it will be useful,
14*404b540aSrobert    but WITHOUT ANY WARRANTY; without even the implied warranty of
15*404b540aSrobert    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16*404b540aSrobert    GNU General Public License for more details.
17*404b540aSrobert 
18*404b540aSrobert    You should have received a copy of the GNU General Public License
19*404b540aSrobert    along with GCC; see the file COPYING.  If not, write to
20*404b540aSrobert    the Free Software Foundation, 51 Franklin Street, Fifth Floor,
21*404b540aSrobert    Boston, MA 02110-1301, USA.  */
22*404b540aSrobert 
23*404b540aSrobert /*{{{  Includes */
24*404b540aSrobert 
25*404b540aSrobert #include "config.h"
26*404b540aSrobert #include "system.h"
27*404b540aSrobert #include "coretypes.h"
28*404b540aSrobert #include "tm.h"
29*404b540aSrobert #include "rtl.h"
30*404b540aSrobert #include "regs.h"
31*404b540aSrobert #include "hard-reg-set.h"
32*404b540aSrobert #include "real.h"
33*404b540aSrobert #include "insn-config.h"
34*404b540aSrobert #include "conditions.h"
35*404b540aSrobert #include "insn-attr.h"
36*404b540aSrobert #include "flags.h"
37*404b540aSrobert #include "recog.h"
38*404b540aSrobert #include "tree.h"
39*404b540aSrobert #include "output.h"
40*404b540aSrobert #include "expr.h"
41*404b540aSrobert #include "obstack.h"
42*404b540aSrobert #include "except.h"
43*404b540aSrobert #include "function.h"
44*404b540aSrobert #include "toplev.h"
45*404b540aSrobert #include "tm_p.h"
46*404b540aSrobert #include "target.h"
47*404b540aSrobert #include "target-def.h"
48*404b540aSrobert 
49*404b540aSrobert /*}}}*/
50*404b540aSrobert /*{{{  Function Prologues & Epilogues */
51*404b540aSrobert 
52*404b540aSrobert /* Define the information needed to generate branch and scc insns.  This is
53*404b540aSrobert    stored from the compare operation.  */
54*404b540aSrobert 
55*404b540aSrobert struct rtx_def * fr30_compare_op0;
56*404b540aSrobert struct rtx_def * fr30_compare_op1;
57*404b540aSrobert 
58*404b540aSrobert /* The FR30 stack looks like this:
59*404b540aSrobert 
60*404b540aSrobert              Before call                       After call
61*404b540aSrobert    FP ->|                       |       |                       |
62*404b540aSrobert         +-----------------------+       +-----------------------+       high
63*404b540aSrobert         |                       |       |                       |       memory
64*404b540aSrobert         |  local variables,     |       |  local variables,     |
65*404b540aSrobert         |  reg save area, etc.  |       |  reg save area, etc.  |
66*404b540aSrobert         |                       |       |                       |
67*404b540aSrobert         +-----------------------+       +-----------------------+
68*404b540aSrobert         |                       |       |                       |
69*404b540aSrobert         | args to the func that |       |  args to this func.   |
70*404b540aSrobert         | is being called that  |       |                       |
71*404b540aSrobert    SP ->| do not fit in regs    |       |                       |
72*404b540aSrobert         +-----------------------+       +-----------------------+
73*404b540aSrobert                                         |  args that used to be |  \
74*404b540aSrobert                                         | in regs; only created |   |  pretend_size
75*404b540aSrobert                                    AP-> |   for vararg funcs    |  /
76*404b540aSrobert                                         +-----------------------+
77*404b540aSrobert                                         |                       |  \
78*404b540aSrobert                                         |  register save area   |   |
79*404b540aSrobert                                         |                       |   |
80*404b540aSrobert 					+-----------------------+   |  reg_size
81*404b540aSrobert                                         |    return address     |   |
82*404b540aSrobert 					+-----------------------+   |
83*404b540aSrobert                                    FP ->|   previous frame ptr  |  /
84*404b540aSrobert                                         +-----------------------+
85*404b540aSrobert                                         |                       |  \
86*404b540aSrobert                                         |  local variables      |   |  var_size
87*404b540aSrobert                                         |                       |  /
88*404b540aSrobert                                         +-----------------------+
89*404b540aSrobert                                         |                       |  \
90*404b540aSrobert      low                                |  room for args to     |   |
91*404b540aSrobert      memory                             |  other funcs called   |   |  args_size
92*404b540aSrobert                                         |  from this one        |   |
93*404b540aSrobert                                    SP ->|                       |  /
94*404b540aSrobert                                         +-----------------------+
95*404b540aSrobert 
96*404b540aSrobert    Note, AP is a fake hard register.  It will be eliminated in favor of
97*404b540aSrobert    SP or FP as appropriate.
98*404b540aSrobert 
99*404b540aSrobert    Note, Some or all of the stack sections above may be omitted if they
100*404b540aSrobert    are not needed.  */
101*404b540aSrobert 
102*404b540aSrobert /* Structure to be filled in by fr30_compute_frame_size() with register
103*404b540aSrobert    save masks, and offsets for the current function.  */
104*404b540aSrobert struct fr30_frame_info
105*404b540aSrobert {
106*404b540aSrobert   unsigned int total_size;	/* # Bytes that the entire frame takes up.  */
107*404b540aSrobert   unsigned int pretend_size;	/* # Bytes we push and pretend caller did.  */
108*404b540aSrobert   unsigned int args_size;	/* # Bytes that outgoing arguments take up.  */
109*404b540aSrobert   unsigned int reg_size;	/* # Bytes needed to store regs.  */
110*404b540aSrobert   unsigned int var_size;	/* # Bytes that variables take up.  */
111*404b540aSrobert   unsigned int frame_size;      /* # Bytes in current frame.  */
112*404b540aSrobert   unsigned int gmask;		/* Mask of saved registers.  */
113*404b540aSrobert   unsigned int save_fp;		/* Nonzero if frame pointer must be saved.  */
114*404b540aSrobert   unsigned int save_rp;		/* Nonzero if return pointer must be saved.  */
115*404b540aSrobert   int          initialised;	/* Nonzero if frame size already calculated.  */
116*404b540aSrobert };
117*404b540aSrobert 
118*404b540aSrobert /* Current frame information calculated by fr30_compute_frame_size().  */
119*404b540aSrobert static struct fr30_frame_info 	current_frame_info;
120*404b540aSrobert 
121*404b540aSrobert /* Zero structure to initialize current_frame_info.  */
122*404b540aSrobert static struct fr30_frame_info 	zero_frame_info;
123*404b540aSrobert 
124*404b540aSrobert static void fr30_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
125*404b540aSrobert 					 tree, int *, int);
126*404b540aSrobert static bool fr30_must_pass_in_stack (enum machine_mode, tree);
127*404b540aSrobert static int fr30_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
128*404b540aSrobert 				   tree, bool);
129*404b540aSrobert 
130*404b540aSrobert 
131*404b540aSrobert #define FRAME_POINTER_MASK 	(1 << (FRAME_POINTER_REGNUM))
132*404b540aSrobert #define RETURN_POINTER_MASK 	(1 << (RETURN_POINTER_REGNUM))
133*404b540aSrobert 
134*404b540aSrobert /* Tell prologue and epilogue if register REGNO should be saved / restored.
135*404b540aSrobert    The return address and frame pointer are treated separately.
136*404b540aSrobert    Don't consider them here.  */
137*404b540aSrobert #define MUST_SAVE_REGISTER(regno)      \
138*404b540aSrobert   (   (regno) != RETURN_POINTER_REGNUM \
139*404b540aSrobert    && (regno) != FRAME_POINTER_REGNUM  \
140*404b540aSrobert    &&   regs_ever_live [regno]         \
141*404b540aSrobert    && ! call_used_regs [regno]         )
142*404b540aSrobert 
143*404b540aSrobert #define MUST_SAVE_FRAME_POINTER	 (regs_ever_live [FRAME_POINTER_REGNUM]  || frame_pointer_needed)
144*404b540aSrobert #define MUST_SAVE_RETURN_POINTER (regs_ever_live [RETURN_POINTER_REGNUM] || current_function_profile)
145*404b540aSrobert 
146*404b540aSrobert #if UNITS_PER_WORD == 4
147*404b540aSrobert #define WORD_ALIGN(SIZE) (((SIZE) + 3) & ~3)
148*404b540aSrobert #endif
149*404b540aSrobert 
150*404b540aSrobert /* Initialize the GCC target structure.  */
151*404b540aSrobert #undef  TARGET_ASM_ALIGNED_HI_OP
152*404b540aSrobert #define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
153*404b540aSrobert #undef  TARGET_ASM_ALIGNED_SI_OP
154*404b540aSrobert #define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
155*404b540aSrobert 
156*404b540aSrobert #undef  TARGET_PROMOTE_PROTOTYPES
157*404b540aSrobert #define TARGET_PROMOTE_PROTOTYPES hook_bool_tree_true
158*404b540aSrobert #undef  TARGET_PASS_BY_REFERENCE
159*404b540aSrobert #define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
160*404b540aSrobert #undef  TARGET_ARG_PARTIAL_BYTES
161*404b540aSrobert #define TARGET_ARG_PARTIAL_BYTES fr30_arg_partial_bytes
162*404b540aSrobert 
163*404b540aSrobert #undef  TARGET_SETUP_INCOMING_VARARGS
164*404b540aSrobert #define TARGET_SETUP_INCOMING_VARARGS fr30_setup_incoming_varargs
165*404b540aSrobert #undef  TARGET_MUST_PASS_IN_STACK
166*404b540aSrobert #define TARGET_MUST_PASS_IN_STACK fr30_must_pass_in_stack
167*404b540aSrobert 
168*404b540aSrobert struct gcc_target targetm = TARGET_INITIALIZER;
169*404b540aSrobert 
170*404b540aSrobert /* Returns the number of bytes offset between FROM_REG and TO_REG
171*404b540aSrobert    for the current function.  As a side effect it fills in the
172*404b540aSrobert    current_frame_info structure, if the data is available.  */
173*404b540aSrobert unsigned int
fr30_compute_frame_size(int from_reg,int to_reg)174*404b540aSrobert fr30_compute_frame_size (int from_reg, int to_reg)
175*404b540aSrobert {
176*404b540aSrobert   int 		regno;
177*404b540aSrobert   unsigned int 	return_value;
178*404b540aSrobert   unsigned int	var_size;
179*404b540aSrobert   unsigned int	args_size;
180*404b540aSrobert   unsigned int	pretend_size;
181*404b540aSrobert   unsigned int 	reg_size;
182*404b540aSrobert   unsigned int 	gmask;
183*404b540aSrobert 
184*404b540aSrobert   var_size	= WORD_ALIGN (get_frame_size ());
185*404b540aSrobert   args_size	= WORD_ALIGN (current_function_outgoing_args_size);
186*404b540aSrobert   pretend_size	= current_function_pretend_args_size;
187*404b540aSrobert 
188*404b540aSrobert   reg_size	= 0;
189*404b540aSrobert   gmask		= 0;
190*404b540aSrobert 
191*404b540aSrobert   /* Calculate space needed for registers.  */
192*404b540aSrobert   for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++)
193*404b540aSrobert     {
194*404b540aSrobert       if (MUST_SAVE_REGISTER (regno))
195*404b540aSrobert 	{
196*404b540aSrobert 	  reg_size += UNITS_PER_WORD;
197*404b540aSrobert 	  gmask |= 1 << regno;
198*404b540aSrobert 	}
199*404b540aSrobert     }
200*404b540aSrobert 
201*404b540aSrobert   current_frame_info.save_fp = MUST_SAVE_FRAME_POINTER;
202*404b540aSrobert   current_frame_info.save_rp = MUST_SAVE_RETURN_POINTER;
203*404b540aSrobert 
204*404b540aSrobert   reg_size += (current_frame_info.save_fp + current_frame_info.save_rp)
205*404b540aSrobert 	       * UNITS_PER_WORD;
206*404b540aSrobert 
207*404b540aSrobert   /* Save computed information.  */
208*404b540aSrobert   current_frame_info.pretend_size = pretend_size;
209*404b540aSrobert   current_frame_info.var_size     = var_size;
210*404b540aSrobert   current_frame_info.args_size    = args_size;
211*404b540aSrobert   current_frame_info.reg_size	  = reg_size;
212*404b540aSrobert   current_frame_info.frame_size   = args_size + var_size;
213*404b540aSrobert   current_frame_info.total_size   = args_size + var_size + reg_size + pretend_size;
214*404b540aSrobert   current_frame_info.gmask	  = gmask;
215*404b540aSrobert   current_frame_info.initialised  = reload_completed;
216*404b540aSrobert 
217*404b540aSrobert   /* Calculate the required distance.  */
218*404b540aSrobert   return_value = 0;
219*404b540aSrobert 
220*404b540aSrobert   if (to_reg == STACK_POINTER_REGNUM)
221*404b540aSrobert     return_value += args_size + var_size;
222*404b540aSrobert 
223*404b540aSrobert   if (from_reg == ARG_POINTER_REGNUM)
224*404b540aSrobert     return_value += reg_size;
225*404b540aSrobert 
226*404b540aSrobert   return return_value;
227*404b540aSrobert }
228*404b540aSrobert 
229*404b540aSrobert /* Called after register allocation to add any instructions needed for the
230*404b540aSrobert    prologue.  Using a prologue insn is favored compared to putting all of the
231*404b540aSrobert    instructions in output_function_prologue(), since it allows the scheduler
232*404b540aSrobert    to intermix instructions with the saves of the caller saved registers.  In
233*404b540aSrobert    some cases, it might be necessary to emit a barrier instruction as the last
234*404b540aSrobert    insn to prevent such scheduling.  */
235*404b540aSrobert 
236*404b540aSrobert void
fr30_expand_prologue(void)237*404b540aSrobert fr30_expand_prologue (void)
238*404b540aSrobert {
239*404b540aSrobert   int regno;
240*404b540aSrobert   rtx insn;
241*404b540aSrobert 
242*404b540aSrobert   if (! current_frame_info.initialised)
243*404b540aSrobert     fr30_compute_frame_size (0, 0);
244*404b540aSrobert 
245*404b540aSrobert   /* This cases shouldn't happen.  Catch it now.  */
246*404b540aSrobert   gcc_assert (current_frame_info.total_size || !current_frame_info.gmask);
247*404b540aSrobert 
248*404b540aSrobert   /* Allocate space for register arguments if this is a variadic function.  */
249*404b540aSrobert   if (current_frame_info.pretend_size)
250*404b540aSrobert     {
251*404b540aSrobert       int regs_to_save = current_frame_info.pretend_size / UNITS_PER_WORD;
252*404b540aSrobert 
253*404b540aSrobert       /* Push argument registers into the pretend arg area.  */
254*404b540aSrobert       for (regno = FIRST_ARG_REGNUM + FR30_NUM_ARG_REGS; regno --, regs_to_save --;)
255*404b540aSrobert         {
256*404b540aSrobert 	  insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
257*404b540aSrobert 	  RTX_FRAME_RELATED_P (insn) = 1;
258*404b540aSrobert 	}
259*404b540aSrobert     }
260*404b540aSrobert 
261*404b540aSrobert   if (current_frame_info.gmask)
262*404b540aSrobert     {
263*404b540aSrobert       /* Save any needed call-saved regs.  */
264*404b540aSrobert       for (regno = STACK_POINTER_REGNUM; regno--;)
265*404b540aSrobert 	{
266*404b540aSrobert 	  if ((current_frame_info.gmask & (1 << regno)) != 0)
267*404b540aSrobert 	    {
268*404b540aSrobert 	      insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
269*404b540aSrobert 	      RTX_FRAME_RELATED_P (insn) = 1;
270*404b540aSrobert 	    }
271*404b540aSrobert 	}
272*404b540aSrobert     }
273*404b540aSrobert 
274*404b540aSrobert   /* Save return address if necessary.  */
275*404b540aSrobert   if (current_frame_info.save_rp)
276*404b540aSrobert     {
277*404b540aSrobert       insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode,
278*404b540aSrobert       						     RETURN_POINTER_REGNUM)));
279*404b540aSrobert       RTX_FRAME_RELATED_P (insn) = 1;
280*404b540aSrobert     }
281*404b540aSrobert 
282*404b540aSrobert   /* Save old frame pointer and create new one, if necessary.  */
283*404b540aSrobert   if (current_frame_info.save_fp)
284*404b540aSrobert     {
285*404b540aSrobert       if (current_frame_info.frame_size < ((1 << 10) - UNITS_PER_WORD))
286*404b540aSrobert         {
287*404b540aSrobert 	  int enter_size = current_frame_info.frame_size + UNITS_PER_WORD;
288*404b540aSrobert 	  rtx pattern;
289*404b540aSrobert 
290*404b540aSrobert 	  insn = emit_insn (gen_enter_func (GEN_INT (enter_size)));
291*404b540aSrobert           RTX_FRAME_RELATED_P (insn) = 1;
292*404b540aSrobert 
293*404b540aSrobert 	  pattern = PATTERN (insn);
294*404b540aSrobert 
295*404b540aSrobert 	  /* Also mark all 3 subexpressions as RTX_FRAME_RELATED_P. */
296*404b540aSrobert           if (GET_CODE (pattern) == PARALLEL)
297*404b540aSrobert             {
298*404b540aSrobert               int x;
299*404b540aSrobert               for (x = XVECLEN (pattern, 0); x--;)
300*404b540aSrobert 		{
301*404b540aSrobert 		  rtx part = XVECEXP (pattern, 0, x);
302*404b540aSrobert 
303*404b540aSrobert 		  /* One of the insns in the ENTER pattern updates the
304*404b540aSrobert 		     frame pointer.  If we do not actually need the frame
305*404b540aSrobert 		     pointer in this function then this is a side effect
306*404b540aSrobert 		     rather than a desired effect, so we do not mark that
307*404b540aSrobert 		     insn as being related to the frame set up.  Doing this
308*404b540aSrobert 		     allows us to compile the crash66.C test file in the
309*404b540aSrobert 		     G++ testsuite.  */
310*404b540aSrobert 		  if (! frame_pointer_needed
311*404b540aSrobert 		      && GET_CODE (part) == SET
312*404b540aSrobert 		      && REGNO (SET_DEST (part)) == HARD_FRAME_POINTER_REGNUM)
313*404b540aSrobert 		    RTX_FRAME_RELATED_P (part) = 0;
314*404b540aSrobert 		  else
315*404b540aSrobert 		    RTX_FRAME_RELATED_P (part) = 1;
316*404b540aSrobert 		}
317*404b540aSrobert             }
318*404b540aSrobert 	}
319*404b540aSrobert       else
320*404b540aSrobert 	{
321*404b540aSrobert 	  insn = emit_insn (gen_movsi_push (frame_pointer_rtx));
322*404b540aSrobert           RTX_FRAME_RELATED_P (insn) = 1;
323*404b540aSrobert 
324*404b540aSrobert 	  if (frame_pointer_needed)
325*404b540aSrobert 	    {
326*404b540aSrobert 	      insn = emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
327*404b540aSrobert 	      RTX_FRAME_RELATED_P (insn) = 1;
328*404b540aSrobert 	    }
329*404b540aSrobert 	}
330*404b540aSrobert     }
331*404b540aSrobert 
332*404b540aSrobert   /* Allocate the stack frame.  */
333*404b540aSrobert   if (current_frame_info.frame_size == 0)
334*404b540aSrobert     ; /* Nothing to do.  */
335*404b540aSrobert   else if (current_frame_info.save_fp
336*404b540aSrobert 	   && current_frame_info.frame_size < ((1 << 10) - UNITS_PER_WORD))
337*404b540aSrobert     ; /* Nothing to do.  */
338*404b540aSrobert   else if (current_frame_info.frame_size <= 512)
339*404b540aSrobert     {
340*404b540aSrobert       insn = emit_insn (gen_add_to_stack (GEN_INT (- current_frame_info.frame_size)));
341*404b540aSrobert       RTX_FRAME_RELATED_P (insn) = 1;
342*404b540aSrobert     }
343*404b540aSrobert   else
344*404b540aSrobert     {
345*404b540aSrobert       rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
346*404b540aSrobert       insn = emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size)));
347*404b540aSrobert       RTX_FRAME_RELATED_P (insn) = 1;
348*404b540aSrobert       insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
349*404b540aSrobert       RTX_FRAME_RELATED_P (insn) = 1;
350*404b540aSrobert     }
351*404b540aSrobert 
352*404b540aSrobert   if (current_function_profile)
353*404b540aSrobert     emit_insn (gen_blockage ());
354*404b540aSrobert }
355*404b540aSrobert 
356*404b540aSrobert /* Called after register allocation to add any instructions needed for the
357*404b540aSrobert    epilogue.  Using an epilogue insn is favored compared to putting all of the
358*404b540aSrobert    instructions in output_function_epilogue(), since it allows the scheduler
359*404b540aSrobert    to intermix instructions with the restores of the caller saved registers.
360*404b540aSrobert    In some cases, it might be necessary to emit a barrier instruction as the
361*404b540aSrobert    first insn to prevent such scheduling.  */
362*404b540aSrobert void
fr30_expand_epilogue(void)363*404b540aSrobert fr30_expand_epilogue (void)
364*404b540aSrobert {
365*404b540aSrobert   int regno;
366*404b540aSrobert 
367*404b540aSrobert   /* Perform the inversion operations of the prologue.  */
368*404b540aSrobert   gcc_assert (current_frame_info.initialised);
369*404b540aSrobert 
370*404b540aSrobert   /* Pop local variables and arguments off the stack.
371*404b540aSrobert      If frame_pointer_needed is TRUE then the frame pointer register
372*404b540aSrobert      has actually been used as a frame pointer, and we can recover
373*404b540aSrobert      the stack pointer from it, otherwise we must unwind the stack
374*404b540aSrobert      manually.  */
375*404b540aSrobert   if (current_frame_info.frame_size > 0)
376*404b540aSrobert     {
377*404b540aSrobert       if (current_frame_info.save_fp && frame_pointer_needed)
378*404b540aSrobert 	{
379*404b540aSrobert 	  emit_insn (gen_leave_func ());
380*404b540aSrobert 	  current_frame_info.save_fp = 0;
381*404b540aSrobert 	}
382*404b540aSrobert       else if (current_frame_info.frame_size <= 508)
383*404b540aSrobert 	emit_insn (gen_add_to_stack
384*404b540aSrobert 		   (GEN_INT (current_frame_info.frame_size)));
385*404b540aSrobert       else
386*404b540aSrobert 	{
387*404b540aSrobert 	  rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
388*404b540aSrobert 	  emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size)));
389*404b540aSrobert 	  emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
390*404b540aSrobert 	}
391*404b540aSrobert     }
392*404b540aSrobert 
393*404b540aSrobert   if (current_frame_info.save_fp)
394*404b540aSrobert     emit_insn (gen_movsi_pop (frame_pointer_rtx));
395*404b540aSrobert 
396*404b540aSrobert   /* Pop all the registers that were pushed.  */
397*404b540aSrobert   if (current_frame_info.save_rp)
398*404b540aSrobert     emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, RETURN_POINTER_REGNUM)));
399*404b540aSrobert 
400*404b540aSrobert   for (regno = 0; regno < STACK_POINTER_REGNUM; regno ++)
401*404b540aSrobert     if (current_frame_info.gmask & (1 << regno))
402*404b540aSrobert       emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, regno)));
403*404b540aSrobert 
404*404b540aSrobert   if (current_frame_info.pretend_size)
405*404b540aSrobert     emit_insn (gen_add_to_stack (GEN_INT (current_frame_info.pretend_size)));
406*404b540aSrobert 
407*404b540aSrobert   /* Reset state info for each function.  */
408*404b540aSrobert   current_frame_info = zero_frame_info;
409*404b540aSrobert 
410*404b540aSrobert   emit_jump_insn (gen_return_from_func ());
411*404b540aSrobert }
412*404b540aSrobert 
413*404b540aSrobert /* Do any needed setup for a variadic function.  We must create a register
414*404b540aSrobert    parameter block, and then copy any anonymous arguments, plus the last
415*404b540aSrobert    named argument, from registers into memory.  * copying actually done in
416*404b540aSrobert    fr30_expand_prologue().
417*404b540aSrobert 
418*404b540aSrobert    ARG_REGS_USED_SO_FAR has *not* been updated for the last named argument
419*404b540aSrobert    which has type TYPE and mode MODE, and we rely on this fact.  */
420*404b540aSrobert void
fr30_setup_incoming_varargs(CUMULATIVE_ARGS * arg_regs_used_so_far,enum machine_mode mode,tree type ATTRIBUTE_UNUSED,int * pretend_size,int second_time ATTRIBUTE_UNUSED)421*404b540aSrobert fr30_setup_incoming_varargs (CUMULATIVE_ARGS *arg_regs_used_so_far,
422*404b540aSrobert 			     enum machine_mode mode,
423*404b540aSrobert 			     tree type ATTRIBUTE_UNUSED,
424*404b540aSrobert 			     int *pretend_size,
425*404b540aSrobert 			     int second_time ATTRIBUTE_UNUSED)
426*404b540aSrobert {
427*404b540aSrobert   int size;
428*404b540aSrobert 
429*404b540aSrobert   /* All BLKmode values are passed by reference.  */
430*404b540aSrobert   gcc_assert (mode != BLKmode);
431*404b540aSrobert 
432*404b540aSrobert   /* ??? This run-time test as well as the code inside the if
433*404b540aSrobert      statement is probably unnecessary.  */
434*404b540aSrobert   if (targetm.calls.strict_argument_naming (arg_regs_used_so_far))
435*404b540aSrobert     /* If TARGET_STRICT_ARGUMENT_NAMING returns true, then the last named
436*404b540aSrobert        arg must not be treated as an anonymous arg.  */
437*404b540aSrobert     arg_regs_used_so_far += fr30_num_arg_regs (mode, type);
438*404b540aSrobert 
439*404b540aSrobert   size = FR30_NUM_ARG_REGS - (* arg_regs_used_so_far);
440*404b540aSrobert 
441*404b540aSrobert   if (size <= 0)
442*404b540aSrobert     return;
443*404b540aSrobert 
444*404b540aSrobert   * pretend_size = (size * UNITS_PER_WORD);
445*404b540aSrobert }
446*404b540aSrobert 
447*404b540aSrobert /*}}}*/
448*404b540aSrobert /*{{{  Printing operands */
449*404b540aSrobert 
450*404b540aSrobert /* Print a memory address as an operand to reference that memory location.  */
451*404b540aSrobert 
452*404b540aSrobert void
fr30_print_operand_address(FILE * stream,rtx address)453*404b540aSrobert fr30_print_operand_address (FILE *stream, rtx address)
454*404b540aSrobert {
455*404b540aSrobert   switch (GET_CODE (address))
456*404b540aSrobert     {
457*404b540aSrobert     case SYMBOL_REF:
458*404b540aSrobert       output_addr_const (stream, address);
459*404b540aSrobert       break;
460*404b540aSrobert 
461*404b540aSrobert     default:
462*404b540aSrobert       fprintf (stderr, "code = %x\n", GET_CODE (address));
463*404b540aSrobert       debug_rtx (address);
464*404b540aSrobert       output_operand_lossage ("fr30_print_operand_address: unhandled address");
465*404b540aSrobert       break;
466*404b540aSrobert     }
467*404b540aSrobert }
468*404b540aSrobert 
469*404b540aSrobert /* Print an operand.  */
470*404b540aSrobert 
471*404b540aSrobert void
fr30_print_operand(FILE * file,rtx x,int code)472*404b540aSrobert fr30_print_operand (FILE *file, rtx x, int code)
473*404b540aSrobert {
474*404b540aSrobert   rtx x0;
475*404b540aSrobert 
476*404b540aSrobert   switch (code)
477*404b540aSrobert     {
478*404b540aSrobert     case '#':
479*404b540aSrobert       /* Output a :D if this instruction is delayed.  */
480*404b540aSrobert       if (dbr_sequence_length () != 0)
481*404b540aSrobert 	fputs (":D", file);
482*404b540aSrobert       return;
483*404b540aSrobert 
484*404b540aSrobert     case 'p':
485*404b540aSrobert       /* Compute the register name of the second register in a hi/lo
486*404b540aSrobert 	 register pair.  */
487*404b540aSrobert       if (GET_CODE (x) != REG)
488*404b540aSrobert 	output_operand_lossage ("fr30_print_operand: unrecognized %%p code");
489*404b540aSrobert       else
490*404b540aSrobert 	fprintf (file, "r%d", REGNO (x) + 1);
491*404b540aSrobert       return;
492*404b540aSrobert 
493*404b540aSrobert     case 'b':
494*404b540aSrobert       /* Convert GCC's comparison operators into FR30 comparison codes.  */
495*404b540aSrobert       switch (GET_CODE (x))
496*404b540aSrobert 	{
497*404b540aSrobert 	case EQ:  fprintf (file, "eq"); break;
498*404b540aSrobert 	case NE:  fprintf (file, "ne"); break;
499*404b540aSrobert 	case LT:  fprintf (file, "lt"); break;
500*404b540aSrobert 	case LE:  fprintf (file, "le"); break;
501*404b540aSrobert 	case GT:  fprintf (file, "gt"); break;
502*404b540aSrobert 	case GE:  fprintf (file, "ge"); break;
503*404b540aSrobert 	case LTU: fprintf (file, "c"); break;
504*404b540aSrobert 	case LEU: fprintf (file, "ls"); break;
505*404b540aSrobert 	case GTU: fprintf (file, "hi"); break;
506*404b540aSrobert 	case GEU: fprintf (file, "nc");  break;
507*404b540aSrobert 	default:
508*404b540aSrobert 	  output_operand_lossage ("fr30_print_operand: unrecognized %%b code");
509*404b540aSrobert 	  break;
510*404b540aSrobert 	}
511*404b540aSrobert       return;
512*404b540aSrobert 
513*404b540aSrobert     case 'B':
514*404b540aSrobert       /* Convert GCC's comparison operators into the complimentary FR30
515*404b540aSrobert 	 comparison codes.  */
516*404b540aSrobert       switch (GET_CODE (x))
517*404b540aSrobert 	{
518*404b540aSrobert 	case EQ:  fprintf (file, "ne"); break;
519*404b540aSrobert 	case NE:  fprintf (file, "eq"); break;
520*404b540aSrobert 	case LT:  fprintf (file, "ge"); break;
521*404b540aSrobert 	case LE:  fprintf (file, "gt"); break;
522*404b540aSrobert 	case GT:  fprintf (file, "le"); break;
523*404b540aSrobert 	case GE:  fprintf (file, "lt"); break;
524*404b540aSrobert 	case LTU: fprintf (file, "nc"); break;
525*404b540aSrobert 	case LEU: fprintf (file, "hi"); break;
526*404b540aSrobert 	case GTU: fprintf (file, "ls"); break;
527*404b540aSrobert 	case GEU: fprintf (file, "c"); break;
528*404b540aSrobert 	default:
529*404b540aSrobert 	  output_operand_lossage ("fr30_print_operand: unrecognized %%B code");
530*404b540aSrobert 	  break;
531*404b540aSrobert 	}
532*404b540aSrobert       return;
533*404b540aSrobert 
534*404b540aSrobert     case 'A':
535*404b540aSrobert       /* Print a signed byte value as an unsigned value.  */
536*404b540aSrobert       if (GET_CODE (x) != CONST_INT)
537*404b540aSrobert 	output_operand_lossage ("fr30_print_operand: invalid operand to %%A code");
538*404b540aSrobert       else
539*404b540aSrobert 	{
540*404b540aSrobert 	  HOST_WIDE_INT val;
541*404b540aSrobert 
542*404b540aSrobert 	  val = INTVAL (x);
543*404b540aSrobert 
544*404b540aSrobert 	  val &= 0xff;
545*404b540aSrobert 
546*404b540aSrobert 	  fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
547*404b540aSrobert 	}
548*404b540aSrobert       return;
549*404b540aSrobert 
550*404b540aSrobert     case 'x':
551*404b540aSrobert       if (GET_CODE (x) != CONST_INT
552*404b540aSrobert 	  || INTVAL (x) < 16
553*404b540aSrobert 	  || INTVAL (x) > 32)
554*404b540aSrobert 	output_operand_lossage ("fr30_print_operand: invalid %%x code");
555*404b540aSrobert       else
556*404b540aSrobert 	fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) - 16);
557*404b540aSrobert       return;
558*404b540aSrobert 
559*404b540aSrobert     case 'F':
560*404b540aSrobert       if (GET_CODE (x) != CONST_DOUBLE)
561*404b540aSrobert 	output_operand_lossage ("fr30_print_operand: invalid %%F code");
562*404b540aSrobert       else
563*404b540aSrobert 	{
564*404b540aSrobert 	  char str[30];
565*404b540aSrobert 
566*404b540aSrobert 	  real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x),
567*404b540aSrobert 			   sizeof (str), 0, 1);
568*404b540aSrobert 	  fputs (str, file);
569*404b540aSrobert 	}
570*404b540aSrobert       return;
571*404b540aSrobert 
572*404b540aSrobert     case 0:
573*404b540aSrobert       /* Handled below.  */
574*404b540aSrobert       break;
575*404b540aSrobert 
576*404b540aSrobert     default:
577*404b540aSrobert       fprintf (stderr, "unknown code = %x\n", code);
578*404b540aSrobert       output_operand_lossage ("fr30_print_operand: unknown code");
579*404b540aSrobert       return;
580*404b540aSrobert     }
581*404b540aSrobert 
582*404b540aSrobert   switch (GET_CODE (x))
583*404b540aSrobert     {
584*404b540aSrobert     case REG:
585*404b540aSrobert       fputs (reg_names [REGNO (x)], file);
586*404b540aSrobert       break;
587*404b540aSrobert 
588*404b540aSrobert     case MEM:
589*404b540aSrobert       x0 = XEXP (x,0);
590*404b540aSrobert 
591*404b540aSrobert       switch (GET_CODE (x0))
592*404b540aSrobert 	{
593*404b540aSrobert 	case REG:
594*404b540aSrobert 	  gcc_assert ((unsigned) REGNO (x0) < ARRAY_SIZE (reg_names));
595*404b540aSrobert 	  fprintf (file, "@%s", reg_names [REGNO (x0)]);
596*404b540aSrobert 	  break;
597*404b540aSrobert 
598*404b540aSrobert 	case PLUS:
599*404b540aSrobert 	  if (GET_CODE (XEXP (x0, 0)) != REG
600*404b540aSrobert 	      || REGNO (XEXP (x0, 0)) < FRAME_POINTER_REGNUM
601*404b540aSrobert 	      || REGNO (XEXP (x0, 0)) > STACK_POINTER_REGNUM
602*404b540aSrobert 	      || GET_CODE (XEXP (x0, 1)) != CONST_INT)
603*404b540aSrobert 	    {
604*404b540aSrobert 	      fprintf (stderr, "bad INDEXed address:");
605*404b540aSrobert 	      debug_rtx (x);
606*404b540aSrobert 	      output_operand_lossage ("fr30_print_operand: unhandled MEM");
607*404b540aSrobert 	    }
608*404b540aSrobert 	  else if (REGNO (XEXP (x0, 0)) == FRAME_POINTER_REGNUM)
609*404b540aSrobert 	    {
610*404b540aSrobert 	      HOST_WIDE_INT val = INTVAL (XEXP (x0, 1));
611*404b540aSrobert 	      if (val < -(1 << 9) || val > ((1 << 9) - 4))
612*404b540aSrobert 		{
613*404b540aSrobert 		  fprintf (stderr, "frame INDEX out of range:");
614*404b540aSrobert 		  debug_rtx (x);
615*404b540aSrobert 		  output_operand_lossage ("fr30_print_operand: unhandled MEM");
616*404b540aSrobert 		}
617*404b540aSrobert 	      fprintf (file, "@(r14, #" HOST_WIDE_INT_PRINT_DEC ")", val);
618*404b540aSrobert 	    }
619*404b540aSrobert 	  else
620*404b540aSrobert 	    {
621*404b540aSrobert 	      HOST_WIDE_INT val = INTVAL (XEXP (x0, 1));
622*404b540aSrobert 	      if (val < 0 || val > ((1 << 6) - 4))
623*404b540aSrobert 		{
624*404b540aSrobert 		  fprintf (stderr, "stack INDEX out of range:");
625*404b540aSrobert 		  debug_rtx (x);
626*404b540aSrobert 		  output_operand_lossage ("fr30_print_operand: unhandled MEM");
627*404b540aSrobert 		}
628*404b540aSrobert 	      fprintf (file, "@(r15, #" HOST_WIDE_INT_PRINT_DEC ")", val);
629*404b540aSrobert 	    }
630*404b540aSrobert 	  break;
631*404b540aSrobert 
632*404b540aSrobert 	case SYMBOL_REF:
633*404b540aSrobert 	  output_address (x0);
634*404b540aSrobert 	  break;
635*404b540aSrobert 
636*404b540aSrobert 	default:
637*404b540aSrobert 	  fprintf (stderr, "bad MEM code = %x\n", GET_CODE (x0));
638*404b540aSrobert 	  debug_rtx (x);
639*404b540aSrobert 	  output_operand_lossage ("fr30_print_operand: unhandled MEM");
640*404b540aSrobert 	  break;
641*404b540aSrobert 	}
642*404b540aSrobert       break;
643*404b540aSrobert 
644*404b540aSrobert     case CONST_DOUBLE :
645*404b540aSrobert       /* We handle SFmode constants here as output_addr_const doesn't.  */
646*404b540aSrobert       if (GET_MODE (x) == SFmode)
647*404b540aSrobert 	{
648*404b540aSrobert 	  REAL_VALUE_TYPE d;
649*404b540aSrobert 	  long l;
650*404b540aSrobert 
651*404b540aSrobert 	  REAL_VALUE_FROM_CONST_DOUBLE (d, x);
652*404b540aSrobert 	  REAL_VALUE_TO_TARGET_SINGLE (d, l);
653*404b540aSrobert 	  fprintf (file, "0x%08lx", l);
654*404b540aSrobert 	  break;
655*404b540aSrobert 	}
656*404b540aSrobert 
657*404b540aSrobert       /* Fall through.  Let output_addr_const deal with it.  */
658*404b540aSrobert     default:
659*404b540aSrobert       output_addr_const (file, x);
660*404b540aSrobert       break;
661*404b540aSrobert     }
662*404b540aSrobert 
663*404b540aSrobert   return;
664*404b540aSrobert }
665*404b540aSrobert 
666*404b540aSrobert /*}}}*/
667*404b540aSrobert /*{{{  Function arguments */
668*404b540aSrobert 
669*404b540aSrobert /* Return true if we should pass an argument on the stack rather than
670*404b540aSrobert    in registers.  */
671*404b540aSrobert 
672*404b540aSrobert static bool
fr30_must_pass_in_stack(enum machine_mode mode,tree type)673*404b540aSrobert fr30_must_pass_in_stack (enum machine_mode mode, tree type)
674*404b540aSrobert {
675*404b540aSrobert   if (mode == BLKmode)
676*404b540aSrobert     return true;
677*404b540aSrobert   if (type == NULL)
678*404b540aSrobert     return false;
679*404b540aSrobert   return AGGREGATE_TYPE_P (type);
680*404b540aSrobert }
681*404b540aSrobert 
682*404b540aSrobert /* Compute the number of word sized registers needed to hold a
683*404b540aSrobert    function argument of mode INT_MODE and tree type TYPE.  */
684*404b540aSrobert int
fr30_num_arg_regs(enum machine_mode mode,tree type)685*404b540aSrobert fr30_num_arg_regs (enum machine_mode mode, tree type)
686*404b540aSrobert {
687*404b540aSrobert   int size;
688*404b540aSrobert 
689*404b540aSrobert   if (targetm.calls.must_pass_in_stack (mode, type))
690*404b540aSrobert     return 0;
691*404b540aSrobert 
692*404b540aSrobert   if (type && mode == BLKmode)
693*404b540aSrobert     size = int_size_in_bytes (type);
694*404b540aSrobert   else
695*404b540aSrobert     size = GET_MODE_SIZE (mode);
696*404b540aSrobert 
697*404b540aSrobert   return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
698*404b540aSrobert }
699*404b540aSrobert 
700*404b540aSrobert /* Returns the number of bytes in which *part* of a parameter of machine
701*404b540aSrobert    mode MODE and tree type TYPE (which may be NULL if the type is not known).
702*404b540aSrobert    If the argument fits entirely in the argument registers, or entirely on
703*404b540aSrobert    the stack, then 0 is returned.
704*404b540aSrobert    CUM is the number of argument registers already used by earlier
705*404b540aSrobert    parameters to the function.  */
706*404b540aSrobert 
707*404b540aSrobert static int
fr30_arg_partial_bytes(CUMULATIVE_ARGS * cum,enum machine_mode mode,tree type,bool named)708*404b540aSrobert fr30_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
709*404b540aSrobert 			tree type, bool named)
710*404b540aSrobert {
711*404b540aSrobert   /* Unnamed arguments, i.e. those that are prototyped as ...
712*404b540aSrobert      are always passed on the stack.
713*404b540aSrobert      Also check here to see if all the argument registers are full.  */
714*404b540aSrobert   if (named == 0 || *cum >= FR30_NUM_ARG_REGS)
715*404b540aSrobert     return 0;
716*404b540aSrobert 
717*404b540aSrobert   /* Work out how many argument registers would be needed if this
718*404b540aSrobert      parameter were to be passed entirely in registers.  If there
719*404b540aSrobert      are sufficient argument registers available (or if no registers
720*404b540aSrobert      are needed because the parameter must be passed on the stack)
721*404b540aSrobert      then return zero, as this parameter does not require partial
722*404b540aSrobert      register, partial stack stack space.  */
723*404b540aSrobert   if (*cum + fr30_num_arg_regs (mode, type) <= FR30_NUM_ARG_REGS)
724*404b540aSrobert     return 0;
725*404b540aSrobert 
726*404b540aSrobert   return (FR30_NUM_ARG_REGS - *cum) * UNITS_PER_WORD;
727*404b540aSrobert }
728*404b540aSrobert 
729*404b540aSrobert /*}}}*/
730*404b540aSrobert /*{{{  Operand predicates */
731*404b540aSrobert 
732*404b540aSrobert #ifndef Mmode
733*404b540aSrobert #define Mmode enum machine_mode
734*404b540aSrobert #endif
735*404b540aSrobert 
736*404b540aSrobert /* Returns true iff all the registers in the operands array
737*404b540aSrobert    are in descending or ascending order.  */
738*404b540aSrobert int
fr30_check_multiple_regs(rtx * operands,int num_operands,int descending)739*404b540aSrobert fr30_check_multiple_regs (rtx *operands, int num_operands, int descending)
740*404b540aSrobert {
741*404b540aSrobert   if (descending)
742*404b540aSrobert     {
743*404b540aSrobert       unsigned int prev_regno = 0;
744*404b540aSrobert 
745*404b540aSrobert       while (num_operands --)
746*404b540aSrobert 	{
747*404b540aSrobert 	  if (GET_CODE (operands [num_operands]) != REG)
748*404b540aSrobert 	    return 0;
749*404b540aSrobert 
750*404b540aSrobert 	  if (REGNO (operands [num_operands]) < prev_regno)
751*404b540aSrobert 	    return 0;
752*404b540aSrobert 
753*404b540aSrobert 	  prev_regno = REGNO (operands [num_operands]);
754*404b540aSrobert 	}
755*404b540aSrobert     }
756*404b540aSrobert   else
757*404b540aSrobert     {
758*404b540aSrobert       unsigned int prev_regno = CONDITION_CODE_REGNUM;
759*404b540aSrobert 
760*404b540aSrobert       while (num_operands --)
761*404b540aSrobert 	{
762*404b540aSrobert 	  if (GET_CODE (operands [num_operands]) != REG)
763*404b540aSrobert 	    return 0;
764*404b540aSrobert 
765*404b540aSrobert 	  if (REGNO (operands [num_operands]) > prev_regno)
766*404b540aSrobert 	    return 0;
767*404b540aSrobert 
768*404b540aSrobert 	  prev_regno = REGNO (operands [num_operands]);
769*404b540aSrobert 	}
770*404b540aSrobert     }
771*404b540aSrobert 
772*404b540aSrobert   return 1;
773*404b540aSrobert }
774*404b540aSrobert 
775*404b540aSrobert int
fr30_const_double_is_zero(rtx operand)776*404b540aSrobert fr30_const_double_is_zero (rtx operand)
777*404b540aSrobert {
778*404b540aSrobert   REAL_VALUE_TYPE d;
779*404b540aSrobert 
780*404b540aSrobert   if (operand == NULL || GET_CODE (operand) != CONST_DOUBLE)
781*404b540aSrobert     return 0;
782*404b540aSrobert 
783*404b540aSrobert   REAL_VALUE_FROM_CONST_DOUBLE (d, operand);
784*404b540aSrobert 
785*404b540aSrobert   return REAL_VALUES_EQUAL (d, dconst0);
786*404b540aSrobert }
787*404b540aSrobert 
788*404b540aSrobert /*}}}*/
789*404b540aSrobert /*{{{  Instruction Output Routines  */
790*404b540aSrobert 
791*404b540aSrobert /* Output a double word move.
792*404b540aSrobert    It must be REG<-REG, REG<-MEM, MEM<-REG or REG<-CONST.
793*404b540aSrobert    On the FR30 we are constrained by the fact that it does not
794*404b540aSrobert    support offsetable addresses, and so we have to load the
795*404b540aSrobert    address of the secnd word into the second destination register
796*404b540aSrobert    before we can use it.  */
797*404b540aSrobert 
798*404b540aSrobert rtx
fr30_move_double(rtx * operands)799*404b540aSrobert fr30_move_double (rtx * operands)
800*404b540aSrobert {
801*404b540aSrobert   rtx src  = operands[1];
802*404b540aSrobert   rtx dest = operands[0];
803*404b540aSrobert   enum rtx_code src_code = GET_CODE (src);
804*404b540aSrobert   enum rtx_code dest_code = GET_CODE (dest);
805*404b540aSrobert   enum machine_mode mode = GET_MODE (dest);
806*404b540aSrobert   rtx val;
807*404b540aSrobert 
808*404b540aSrobert   start_sequence ();
809*404b540aSrobert 
810*404b540aSrobert   if (dest_code == REG)
811*404b540aSrobert     {
812*404b540aSrobert       if (src_code == REG)
813*404b540aSrobert 	{
814*404b540aSrobert 	  int reverse = (REGNO (dest) == REGNO (src) + 1);
815*404b540aSrobert 
816*404b540aSrobert 	  /* We normally copy the low-numbered register first.  However, if
817*404b540aSrobert 	     the first register of operand 0 is the same as the second register
818*404b540aSrobert 	     of operand 1, we must copy in the opposite order.  */
819*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode,
820*404b540aSrobert 				  operand_subword (dest, reverse, TRUE, mode),
821*404b540aSrobert 				  operand_subword (src,  reverse, TRUE, mode)));
822*404b540aSrobert 
823*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode,
824*404b540aSrobert 			      operand_subword (dest, !reverse, TRUE, mode),
825*404b540aSrobert 			      operand_subword (src,  !reverse, TRUE, mode)));
826*404b540aSrobert 	}
827*404b540aSrobert       else if (src_code == MEM)
828*404b540aSrobert 	{
829*404b540aSrobert 	  rtx addr = XEXP (src, 0);
830*404b540aSrobert 	  int dregno = REGNO (dest);
831*404b540aSrobert 	  rtx dest0;
832*404b540aSrobert 	  rtx dest1;
833*404b540aSrobert 	  rtx new_mem;
834*404b540aSrobert 
835*404b540aSrobert 	  /* If the high-address word is used in the address, we
836*404b540aSrobert 	     must load it last.  Otherwise, load it first.  */
837*404b540aSrobert 	  int reverse = (refers_to_regno_p (dregno, dregno + 1, addr, 0) != 0);
838*404b540aSrobert 
839*404b540aSrobert 	  gcc_assert (GET_CODE (addr) == REG);
840*404b540aSrobert 
841*404b540aSrobert 	  dest0 = operand_subword (dest, reverse, TRUE, mode);
842*404b540aSrobert 	  dest1 = operand_subword (dest, !reverse, TRUE, mode);
843*404b540aSrobert 
844*404b540aSrobert 	  if (reverse)
845*404b540aSrobert 	    {
846*404b540aSrobert 	      emit_insn (gen_rtx_SET (VOIDmode, dest1,
847*404b540aSrobert 				      adjust_address (src, SImode, 0)));
848*404b540aSrobert 	      emit_insn (gen_rtx_SET (SImode, dest0,
849*404b540aSrobert 				      gen_rtx_REG (SImode, REGNO (addr))));
850*404b540aSrobert 	      emit_insn (gen_rtx_SET (SImode, dest0,
851*404b540aSrobert 				      plus_constant (dest0, UNITS_PER_WORD)));
852*404b540aSrobert 
853*404b540aSrobert 	      new_mem = gen_rtx_MEM (SImode, dest0);
854*404b540aSrobert 	      MEM_COPY_ATTRIBUTES (new_mem, src);
855*404b540aSrobert 
856*404b540aSrobert 	      emit_insn (gen_rtx_SET (VOIDmode, dest0, new_mem));
857*404b540aSrobert 	    }
858*404b540aSrobert 	  else
859*404b540aSrobert 	    {
860*404b540aSrobert 	      emit_insn (gen_rtx_SET (VOIDmode, dest0,
861*404b540aSrobert 				      adjust_address (src, SImode, 0)));
862*404b540aSrobert 	      emit_insn (gen_rtx_SET (SImode, dest1,
863*404b540aSrobert 				      gen_rtx_REG (SImode, REGNO (addr))));
864*404b540aSrobert 	      emit_insn (gen_rtx_SET (SImode, dest1,
865*404b540aSrobert 				      plus_constant (dest1, UNITS_PER_WORD)));
866*404b540aSrobert 
867*404b540aSrobert 	      new_mem = gen_rtx_MEM (SImode, dest1);
868*404b540aSrobert 	      MEM_COPY_ATTRIBUTES (new_mem, src);
869*404b540aSrobert 
870*404b540aSrobert 	      emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
871*404b540aSrobert 	    }
872*404b540aSrobert 	}
873*404b540aSrobert       else if (src_code == CONST_INT || src_code == CONST_DOUBLE)
874*404b540aSrobert 	{
875*404b540aSrobert 	  rtx words[2];
876*404b540aSrobert 	  split_double (src, &words[0], &words[1]);
877*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode,
878*404b540aSrobert 				  operand_subword (dest, 0, TRUE, mode),
879*404b540aSrobert 				  words[0]));
880*404b540aSrobert 
881*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode,
882*404b540aSrobert 				  operand_subword (dest, 1, TRUE, mode),
883*404b540aSrobert 				  words[1]));
884*404b540aSrobert 	}
885*404b540aSrobert     }
886*404b540aSrobert   else if (src_code == REG && dest_code == MEM)
887*404b540aSrobert     {
888*404b540aSrobert       rtx addr = XEXP (dest, 0);
889*404b540aSrobert       rtx src0;
890*404b540aSrobert       rtx src1;
891*404b540aSrobert 
892*404b540aSrobert       gcc_assert (GET_CODE (addr) == REG);
893*404b540aSrobert 
894*404b540aSrobert       src0 = operand_subword (src, 0, TRUE, mode);
895*404b540aSrobert       src1 = operand_subword (src, 1, TRUE, mode);
896*404b540aSrobert 
897*404b540aSrobert       emit_insn (gen_rtx_SET (VOIDmode, adjust_address (dest, SImode, 0),
898*404b540aSrobert 			      src0));
899*404b540aSrobert 
900*404b540aSrobert       if (REGNO (addr) == STACK_POINTER_REGNUM
901*404b540aSrobert 	  || REGNO (addr) == FRAME_POINTER_REGNUM)
902*404b540aSrobert 	emit_insn (gen_rtx_SET (VOIDmode,
903*404b540aSrobert 				adjust_address (dest, SImode, UNITS_PER_WORD),
904*404b540aSrobert 				src1));
905*404b540aSrobert       else
906*404b540aSrobert 	{
907*404b540aSrobert 	  rtx new_mem;
908*404b540aSrobert 
909*404b540aSrobert 	  /* We need a scratch register to hold the value of 'address + 4'.
910*404b540aSrobert 	     We ought to allow gcc to find one for us, but for now, just
911*404b540aSrobert 	     push one of the source registers.  */
912*404b540aSrobert 	  emit_insn (gen_movsi_push (src0));
913*404b540aSrobert 	  emit_insn (gen_movsi_internal (src0, addr));
914*404b540aSrobert 	  emit_insn (gen_addsi_small_int (src0, src0, GEN_INT (UNITS_PER_WORD)));
915*404b540aSrobert 
916*404b540aSrobert 	  new_mem = gen_rtx_MEM (SImode, src0);
917*404b540aSrobert 	  MEM_COPY_ATTRIBUTES (new_mem, dest);
918*404b540aSrobert 
919*404b540aSrobert 	  emit_insn (gen_rtx_SET (VOIDmode, new_mem, src1));
920*404b540aSrobert 	  emit_insn (gen_movsi_pop (src0));
921*404b540aSrobert 	}
922*404b540aSrobert     }
923*404b540aSrobert   else
924*404b540aSrobert     /* This should have been prevented by the constraints on movdi_insn.  */
925*404b540aSrobert     gcc_unreachable ();
926*404b540aSrobert 
927*404b540aSrobert   val = get_insns ();
928*404b540aSrobert   end_sequence ();
929*404b540aSrobert 
930*404b540aSrobert   return val;
931*404b540aSrobert }
932*404b540aSrobert /*}}}*/
933*404b540aSrobert /* Local Variables: */
934*404b540aSrobert /* folded-file: t   */
935*404b540aSrobert /* End:		    */
936