OSDN Git Service

* calls.c, function.c: Always define PREFERRED_STACK_BOUNDARY
[pf3gnuchains/gcc-fork.git] / gcc / config / we32k / we32k.c
1 /* Subroutines for insn-output.c for AT&T we32000 Family.
2    Copyright (C) 1991, 1992, 1997, 1998, 1999, 2000, 2001
3    Free Software Foundation, Inc.
4    Contributed by John Wehle (john@feith1.uucp)
5
6 This file is part of GNU CC.
7
8 GNU CC is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2, or (at your option)
11 any later version.
12
13 GNU CC is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU CC; see the file COPYING.  If not, write to
20 the Free Software Foundation, 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA.  */
22
23
24 #include "config.h"
25 #include "system.h"
26 #include "insn-config.h"
27 #include "rtl.h"
28 #include "function.h"
29 #include "real.h"
30 #include "recog.h"
31 #include "output.h"
32 #include "regs.h"
33 #include "tree.h"
34 #include "expr.h"
35 #include "tm_p.h"
36 #include "target.h"
37 #include "target-def.h"
38
39 static void we32k_output_function_prologue PARAMS ((FILE *, HOST_WIDE_INT));
40 static void we32k_output_function_epilogue PARAMS ((FILE *, HOST_WIDE_INT));
41 \f
42 /* Initialize the GCC target structure.  */
43 #undef TARGET_ASM_FUNCTION_PROLOGUE
44 #define TARGET_ASM_FUNCTION_PROLOGUE we32k_output_function_prologue
45 #undef TARGET_ASM_FUNCTION_EPILOGUE
46 #define TARGET_ASM_FUNCTION_EPILOGUE we32k_output_function_epilogue
47
48 struct gcc_target targetm = TARGET_INITIALIZER;
49 \f
50 /* Generate the assembly code for function entry.  FILE is a stdio
51    stream to output the code to.  SIZE is an int: how many units of
52    temporary storage to allocate.
53
54    Refer to the array `regs_ever_live' to determine which registers to
55    save; `regs_ever_live[I]' is nonzero if register number I is ever
56    used in the function.  This function is responsible for knowing
57    which registers should not be saved even if used.  */
58
59 static void
60 we32k_output_function_prologue (file, size)
61      FILE *file;
62      HOST_WIDE_INT size;
63 {
64   register int nregs_to_save;
65   register int regno;
66   extern char call_used_regs[];
67
68   nregs_to_save = 0;
69   for (regno = 8; regno > 2; regno--)
70     if (regs_ever_live[regno] && ! call_used_regs[regno])
71       nregs_to_save = (9 - regno);
72
73   fprintf (file, "\tsave &%d\n", nregs_to_save);
74   if (size)
75     fprintf (file, "\taddw2 &%d,%%sp\n", (size + 3) & ~3);
76 }
77
78 /* This function generates the assembly code for function exit.
79    Args are as for output_function_prologue ().
80
81    The function epilogue should not depend on the current stack
82    pointer!  It should use the frame pointer only.  This is mandatory
83    because of alloca; we also take advantage of it to omit stack
84    adjustments before returning. */
85
86 static void
87 we32k_output_function_epilogue (file, size)
88      FILE *file;
89      HOST_WIDE_INT size ATTRIBUTE_UNUSED;
90 {
91   register int nregs_to_restore;
92   register int regno;
93   extern char call_used_regs[];
94
95   nregs_to_restore = 0;
96   for (regno = 8; regno > 2; regno--)
97     if (regs_ever_live[regno] && ! call_used_regs[regno])
98       nregs_to_restore = (9 - regno);
99
100   fprintf (file, "\tret &%d\n", nregs_to_restore);
101 }
102
103 void
104 output_move_double (operands)
105      rtx *operands;
106 {
107   rtx lsw_operands[2];
108   rtx lsw_sreg = NULL;
109   rtx msw_dreg = NULL;
110
111   if (GET_CODE (operands[0]) == REG) 
112     {
113       lsw_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
114       msw_dreg = operands[0];
115     }
116   else if (GET_CODE (operands[0]) == MEM && offsettable_memref_p (operands[0]))
117     lsw_operands[0] = adjust_address (operands[0], SImode, 4);
118   else
119     abort ();
120
121   if (GET_CODE (operands[1]) == REG) 
122     {
123       lsw_operands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
124       lsw_sreg = lsw_operands[1];
125     }
126   else if (GET_CODE (operands[1]) == MEM && offsettable_memref_p (operands[1])) 
127     {
128       lsw_operands[1] = adjust_address (operands[1], SImode, 4);
129       lsw_sreg = operands[1];
130       for ( ; ; ) 
131         {
132           if (REG_P (lsw_sreg))
133             break;
134           if (CONSTANT_ADDRESS_P (lsw_sreg)) 
135             {
136               lsw_sreg = NULL;
137               break;
138             }
139           if (GET_CODE (lsw_sreg) == MEM) 
140             {
141               lsw_sreg = XEXP (lsw_sreg, 0);
142               continue;
143             }
144           if (GET_CODE (lsw_sreg) == PLUS)
145             {
146               if (CONSTANT_ADDRESS_P (XEXP (lsw_sreg, 1))) 
147                 {
148                   lsw_sreg = XEXP (lsw_sreg, 0);
149                   continue;
150                 }
151               else if (CONSTANT_ADDRESS_P (XEXP (lsw_sreg, 0))) 
152                 {
153                   lsw_sreg = XEXP (lsw_sreg, 1);
154                   continue;
155                 }
156             }
157           abort ();
158         }
159     }
160   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
161     {
162       lsw_operands[1] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
163       operands[1] = GEN_INT (CONST_DOUBLE_LOW (operands[1]));
164     }
165   else if (GET_CODE (operands[1]) == CONST_INT)
166     {
167       lsw_operands[1] = operands[1];
168       operands[1] = const0_rtx;
169     }
170   else
171     abort ();
172
173   if (!msw_dreg || !lsw_sreg || REGNO (msw_dreg) != REGNO (lsw_sreg)) 
174     {
175       output_asm_insn ("movw %1, %0", operands);
176       output_asm_insn ("movw %1, %0", lsw_operands);
177     }
178   else 
179     {
180       output_asm_insn ("movw %1, %0", lsw_operands);
181       output_asm_insn ("movw %1, %0", operands);
182     }
183 }
184
185 void
186 output_push_double (operands)
187      rtx *operands;
188 {
189   rtx lsw_operands[1];
190
191   if (GET_CODE (operands[0]) == REG)
192     lsw_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
193   else if (GET_CODE (operands[0]) == MEM && offsettable_memref_p (operands[0]))
194     lsw_operands[0] = adjust_address (operands[0], SImode, 4);
195   else if (GET_CODE (operands[0]) == CONST_DOUBLE)
196     {
197       lsw_operands[0] = GEN_INT (CONST_DOUBLE_HIGH (operands[0]));
198       operands[0] = GEN_INT (CONST_DOUBLE_LOW (operands[0]));
199     }
200   else if (GET_CODE (operands[0]) == CONST_INT)
201     { 
202       lsw_operands[0] = operands[0];
203       operands[0] = const0_rtx;
204     }
205   else
206     abort ();
207
208   output_asm_insn ("pushw %0", operands);
209   output_asm_insn ("pushw %0", lsw_operands);
210 }