1 |
709 |
jeremybenn |
/* Subroutines for insn-output.c for SPARC.
|
2 |
|
|
Copyright (C) 1987, 1988, 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998,
|
3 |
|
|
1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
|
4 |
|
|
2011
|
5 |
|
|
Free Software Foundation, Inc.
|
6 |
|
|
Contributed by Michael Tiemann (tiemann@cygnus.com)
|
7 |
|
|
64-bit SPARC-V9 support by Michael Tiemann, Jim Wilson, and Doug Evans,
|
8 |
|
|
at Cygnus Support.
|
9 |
|
|
|
10 |
|
|
This file is part of GCC.
|
11 |
|
|
|
12 |
|
|
GCC is free software; you can redistribute it and/or modify
|
13 |
|
|
it under the terms of the GNU General Public License as published by
|
14 |
|
|
the Free Software Foundation; either version 3, or (at your option)
|
15 |
|
|
any later version.
|
16 |
|
|
|
17 |
|
|
GCC is distributed in the hope that it will be useful,
|
18 |
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19 |
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20 |
|
|
GNU General Public License for more details.
|
21 |
|
|
|
22 |
|
|
You should have received a copy of the GNU General Public License
|
23 |
|
|
along with GCC; see the file COPYING3. If not see
|
24 |
|
|
<http://www.gnu.org/licenses/>. */
|
25 |
|
|
|
26 |
|
|
#include "config.h"
|
27 |
|
|
#include "system.h"
|
28 |
|
|
#include "coretypes.h"
|
29 |
|
|
#include "tm.h"
|
30 |
|
|
#include "tree.h"
|
31 |
|
|
#include "rtl.h"
|
32 |
|
|
#include "regs.h"
|
33 |
|
|
#include "hard-reg-set.h"
|
34 |
|
|
#include "insn-config.h"
|
35 |
|
|
#include "insn-codes.h"
|
36 |
|
|
#include "conditions.h"
|
37 |
|
|
#include "output.h"
|
38 |
|
|
#include "insn-attr.h"
|
39 |
|
|
#include "flags.h"
|
40 |
|
|
#include "function.h"
|
41 |
|
|
#include "except.h"
|
42 |
|
|
#include "expr.h"
|
43 |
|
|
#include "optabs.h"
|
44 |
|
|
#include "recog.h"
|
45 |
|
|
#include "diagnostic-core.h"
|
46 |
|
|
#include "ggc.h"
|
47 |
|
|
#include "tm_p.h"
|
48 |
|
|
#include "debug.h"
|
49 |
|
|
#include "target.h"
|
50 |
|
|
#include "target-def.h"
|
51 |
|
|
#include "common/common-target.h"
|
52 |
|
|
#include "cfglayout.h"
|
53 |
|
|
#include "gimple.h"
|
54 |
|
|
#include "langhooks.h"
|
55 |
|
|
#include "reload.h"
|
56 |
|
|
#include "params.h"
|
57 |
|
|
#include "df.h"
|
58 |
|
|
#include "dwarf2out.h"
|
59 |
|
|
#include "opts.h"
|
60 |
|
|
|
61 |
|
|
/* Processor costs */
|
62 |
|
|
|
63 |
|
|
struct processor_costs {
|
64 |
|
|
/* Integer load */
|
65 |
|
|
const int int_load;
|
66 |
|
|
|
67 |
|
|
/* Integer signed load */
|
68 |
|
|
const int int_sload;
|
69 |
|
|
|
70 |
|
|
/* Integer zeroed load */
|
71 |
|
|
const int int_zload;
|
72 |
|
|
|
73 |
|
|
/* Float load */
|
74 |
|
|
const int float_load;
|
75 |
|
|
|
76 |
|
|
/* fmov, fneg, fabs */
|
77 |
|
|
const int float_move;
|
78 |
|
|
|
79 |
|
|
/* fadd, fsub */
|
80 |
|
|
const int float_plusminus;
|
81 |
|
|
|
82 |
|
|
/* fcmp */
|
83 |
|
|
const int float_cmp;
|
84 |
|
|
|
85 |
|
|
/* fmov, fmovr */
|
86 |
|
|
const int float_cmove;
|
87 |
|
|
|
88 |
|
|
/* fmul */
|
89 |
|
|
const int float_mul;
|
90 |
|
|
|
91 |
|
|
/* fdivs */
|
92 |
|
|
const int float_div_sf;
|
93 |
|
|
|
94 |
|
|
/* fdivd */
|
95 |
|
|
const int float_div_df;
|
96 |
|
|
|
97 |
|
|
/* fsqrts */
|
98 |
|
|
const int float_sqrt_sf;
|
99 |
|
|
|
100 |
|
|
/* fsqrtd */
|
101 |
|
|
const int float_sqrt_df;
|
102 |
|
|
|
103 |
|
|
/* umul/smul */
|
104 |
|
|
const int int_mul;
|
105 |
|
|
|
106 |
|
|
/* mulX */
|
107 |
|
|
const int int_mulX;
|
108 |
|
|
|
109 |
|
|
/* integer multiply cost for each bit set past the most
|
110 |
|
|
significant 3, so the formula for multiply cost becomes:
|
111 |
|
|
|
112 |
|
|
if (rs1 < 0)
|
113 |
|
|
highest_bit = highest_clear_bit(rs1);
|
114 |
|
|
else
|
115 |
|
|
highest_bit = highest_set_bit(rs1);
|
116 |
|
|
if (highest_bit < 3)
|
117 |
|
|
highest_bit = 3;
|
118 |
|
|
cost = int_mul{,X} + ((highest_bit - 3) / int_mul_bit_factor);
|
119 |
|
|
|
120 |
|
|
A value of zero indicates that the multiply costs is fixed,
|
121 |
|
|
and not variable. */
|
122 |
|
|
const int int_mul_bit_factor;
|
123 |
|
|
|
124 |
|
|
/* udiv/sdiv */
|
125 |
|
|
const int int_div;
|
126 |
|
|
|
127 |
|
|
/* divX */
|
128 |
|
|
const int int_divX;
|
129 |
|
|
|
130 |
|
|
/* movcc, movr */
|
131 |
|
|
const int int_cmove;
|
132 |
|
|
|
133 |
|
|
/* penalty for shifts, due to scheduling rules etc. */
|
134 |
|
|
const int shift_penalty;
|
135 |
|
|
};
|
136 |
|
|
|
137 |
|
|
static const
|
138 |
|
|
struct processor_costs cypress_costs = {
|
139 |
|
|
COSTS_N_INSNS (2), /* int load */
|
140 |
|
|
COSTS_N_INSNS (2), /* int signed load */
|
141 |
|
|
COSTS_N_INSNS (2), /* int zeroed load */
|
142 |
|
|
COSTS_N_INSNS (2), /* float load */
|
143 |
|
|
COSTS_N_INSNS (5), /* fmov, fneg, fabs */
|
144 |
|
|
COSTS_N_INSNS (5), /* fadd, fsub */
|
145 |
|
|
COSTS_N_INSNS (1), /* fcmp */
|
146 |
|
|
COSTS_N_INSNS (1), /* fmov, fmovr */
|
147 |
|
|
COSTS_N_INSNS (7), /* fmul */
|
148 |
|
|
COSTS_N_INSNS (37), /* fdivs */
|
149 |
|
|
COSTS_N_INSNS (37), /* fdivd */
|
150 |
|
|
COSTS_N_INSNS (63), /* fsqrts */
|
151 |
|
|
COSTS_N_INSNS (63), /* fsqrtd */
|
152 |
|
|
COSTS_N_INSNS (1), /* imul */
|
153 |
|
|
COSTS_N_INSNS (1), /* imulX */
|
154 |
|
|
0, /* imul bit factor */
|
155 |
|
|
COSTS_N_INSNS (1), /* idiv */
|
156 |
|
|
COSTS_N_INSNS (1), /* idivX */
|
157 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
158 |
|
|
0, /* shift penalty */
|
159 |
|
|
};
|
160 |
|
|
|
161 |
|
|
static const
|
162 |
|
|
struct processor_costs supersparc_costs = {
|
163 |
|
|
COSTS_N_INSNS (1), /* int load */
|
164 |
|
|
COSTS_N_INSNS (1), /* int signed load */
|
165 |
|
|
COSTS_N_INSNS (1), /* int zeroed load */
|
166 |
|
|
COSTS_N_INSNS (0), /* float load */
|
167 |
|
|
COSTS_N_INSNS (3), /* fmov, fneg, fabs */
|
168 |
|
|
COSTS_N_INSNS (3), /* fadd, fsub */
|
169 |
|
|
COSTS_N_INSNS (3), /* fcmp */
|
170 |
|
|
COSTS_N_INSNS (1), /* fmov, fmovr */
|
171 |
|
|
COSTS_N_INSNS (3), /* fmul */
|
172 |
|
|
COSTS_N_INSNS (6), /* fdivs */
|
173 |
|
|
COSTS_N_INSNS (9), /* fdivd */
|
174 |
|
|
COSTS_N_INSNS (12), /* fsqrts */
|
175 |
|
|
COSTS_N_INSNS (12), /* fsqrtd */
|
176 |
|
|
COSTS_N_INSNS (4), /* imul */
|
177 |
|
|
COSTS_N_INSNS (4), /* imulX */
|
178 |
|
|
0, /* imul bit factor */
|
179 |
|
|
COSTS_N_INSNS (4), /* idiv */
|
180 |
|
|
COSTS_N_INSNS (4), /* idivX */
|
181 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
182 |
|
|
1, /* shift penalty */
|
183 |
|
|
};
|
184 |
|
|
|
185 |
|
|
static const
|
186 |
|
|
struct processor_costs hypersparc_costs = {
|
187 |
|
|
COSTS_N_INSNS (1), /* int load */
|
188 |
|
|
COSTS_N_INSNS (1), /* int signed load */
|
189 |
|
|
COSTS_N_INSNS (1), /* int zeroed load */
|
190 |
|
|
COSTS_N_INSNS (1), /* float load */
|
191 |
|
|
COSTS_N_INSNS (1), /* fmov, fneg, fabs */
|
192 |
|
|
COSTS_N_INSNS (1), /* fadd, fsub */
|
193 |
|
|
COSTS_N_INSNS (1), /* fcmp */
|
194 |
|
|
COSTS_N_INSNS (1), /* fmov, fmovr */
|
195 |
|
|
COSTS_N_INSNS (1), /* fmul */
|
196 |
|
|
COSTS_N_INSNS (8), /* fdivs */
|
197 |
|
|
COSTS_N_INSNS (12), /* fdivd */
|
198 |
|
|
COSTS_N_INSNS (17), /* fsqrts */
|
199 |
|
|
COSTS_N_INSNS (17), /* fsqrtd */
|
200 |
|
|
COSTS_N_INSNS (17), /* imul */
|
201 |
|
|
COSTS_N_INSNS (17), /* imulX */
|
202 |
|
|
0, /* imul bit factor */
|
203 |
|
|
COSTS_N_INSNS (17), /* idiv */
|
204 |
|
|
COSTS_N_INSNS (17), /* idivX */
|
205 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
206 |
|
|
0, /* shift penalty */
|
207 |
|
|
};
|
208 |
|
|
|
209 |
|
|
static const
|
210 |
|
|
struct processor_costs leon_costs = {
|
211 |
|
|
COSTS_N_INSNS (1), /* int load */
|
212 |
|
|
COSTS_N_INSNS (1), /* int signed load */
|
213 |
|
|
COSTS_N_INSNS (1), /* int zeroed load */
|
214 |
|
|
COSTS_N_INSNS (1), /* float load */
|
215 |
|
|
COSTS_N_INSNS (1), /* fmov, fneg, fabs */
|
216 |
|
|
COSTS_N_INSNS (1), /* fadd, fsub */
|
217 |
|
|
COSTS_N_INSNS (1), /* fcmp */
|
218 |
|
|
COSTS_N_INSNS (1), /* fmov, fmovr */
|
219 |
|
|
COSTS_N_INSNS (1), /* fmul */
|
220 |
|
|
COSTS_N_INSNS (15), /* fdivs */
|
221 |
|
|
COSTS_N_INSNS (15), /* fdivd */
|
222 |
|
|
COSTS_N_INSNS (23), /* fsqrts */
|
223 |
|
|
COSTS_N_INSNS (23), /* fsqrtd */
|
224 |
|
|
COSTS_N_INSNS (5), /* imul */
|
225 |
|
|
COSTS_N_INSNS (5), /* imulX */
|
226 |
|
|
0, /* imul bit factor */
|
227 |
|
|
COSTS_N_INSNS (5), /* idiv */
|
228 |
|
|
COSTS_N_INSNS (5), /* idivX */
|
229 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
230 |
|
|
0, /* shift penalty */
|
231 |
|
|
};
|
232 |
|
|
|
233 |
|
|
static const
|
234 |
|
|
struct processor_costs sparclet_costs = {
|
235 |
|
|
COSTS_N_INSNS (3), /* int load */
|
236 |
|
|
COSTS_N_INSNS (3), /* int signed load */
|
237 |
|
|
COSTS_N_INSNS (1), /* int zeroed load */
|
238 |
|
|
COSTS_N_INSNS (1), /* float load */
|
239 |
|
|
COSTS_N_INSNS (1), /* fmov, fneg, fabs */
|
240 |
|
|
COSTS_N_INSNS (1), /* fadd, fsub */
|
241 |
|
|
COSTS_N_INSNS (1), /* fcmp */
|
242 |
|
|
COSTS_N_INSNS (1), /* fmov, fmovr */
|
243 |
|
|
COSTS_N_INSNS (1), /* fmul */
|
244 |
|
|
COSTS_N_INSNS (1), /* fdivs */
|
245 |
|
|
COSTS_N_INSNS (1), /* fdivd */
|
246 |
|
|
COSTS_N_INSNS (1), /* fsqrts */
|
247 |
|
|
COSTS_N_INSNS (1), /* fsqrtd */
|
248 |
|
|
COSTS_N_INSNS (5), /* imul */
|
249 |
|
|
COSTS_N_INSNS (5), /* imulX */
|
250 |
|
|
0, /* imul bit factor */
|
251 |
|
|
COSTS_N_INSNS (5), /* idiv */
|
252 |
|
|
COSTS_N_INSNS (5), /* idivX */
|
253 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
254 |
|
|
0, /* shift penalty */
|
255 |
|
|
};
|
256 |
|
|
|
257 |
|
|
static const
|
258 |
|
|
struct processor_costs ultrasparc_costs = {
|
259 |
|
|
COSTS_N_INSNS (2), /* int load */
|
260 |
|
|
COSTS_N_INSNS (3), /* int signed load */
|
261 |
|
|
COSTS_N_INSNS (2), /* int zeroed load */
|
262 |
|
|
COSTS_N_INSNS (2), /* float load */
|
263 |
|
|
COSTS_N_INSNS (1), /* fmov, fneg, fabs */
|
264 |
|
|
COSTS_N_INSNS (4), /* fadd, fsub */
|
265 |
|
|
COSTS_N_INSNS (1), /* fcmp */
|
266 |
|
|
COSTS_N_INSNS (2), /* fmov, fmovr */
|
267 |
|
|
COSTS_N_INSNS (4), /* fmul */
|
268 |
|
|
COSTS_N_INSNS (13), /* fdivs */
|
269 |
|
|
COSTS_N_INSNS (23), /* fdivd */
|
270 |
|
|
COSTS_N_INSNS (13), /* fsqrts */
|
271 |
|
|
COSTS_N_INSNS (23), /* fsqrtd */
|
272 |
|
|
COSTS_N_INSNS (4), /* imul */
|
273 |
|
|
COSTS_N_INSNS (4), /* imulX */
|
274 |
|
|
2, /* imul bit factor */
|
275 |
|
|
COSTS_N_INSNS (37), /* idiv */
|
276 |
|
|
COSTS_N_INSNS (68), /* idivX */
|
277 |
|
|
COSTS_N_INSNS (2), /* movcc/movr */
|
278 |
|
|
2, /* shift penalty */
|
279 |
|
|
};
|
280 |
|
|
|
281 |
|
|
static const
|
282 |
|
|
struct processor_costs ultrasparc3_costs = {
|
283 |
|
|
COSTS_N_INSNS (2), /* int load */
|
284 |
|
|
COSTS_N_INSNS (3), /* int signed load */
|
285 |
|
|
COSTS_N_INSNS (3), /* int zeroed load */
|
286 |
|
|
COSTS_N_INSNS (2), /* float load */
|
287 |
|
|
COSTS_N_INSNS (3), /* fmov, fneg, fabs */
|
288 |
|
|
COSTS_N_INSNS (4), /* fadd, fsub */
|
289 |
|
|
COSTS_N_INSNS (5), /* fcmp */
|
290 |
|
|
COSTS_N_INSNS (3), /* fmov, fmovr */
|
291 |
|
|
COSTS_N_INSNS (4), /* fmul */
|
292 |
|
|
COSTS_N_INSNS (17), /* fdivs */
|
293 |
|
|
COSTS_N_INSNS (20), /* fdivd */
|
294 |
|
|
COSTS_N_INSNS (20), /* fsqrts */
|
295 |
|
|
COSTS_N_INSNS (29), /* fsqrtd */
|
296 |
|
|
COSTS_N_INSNS (6), /* imul */
|
297 |
|
|
COSTS_N_INSNS (6), /* imulX */
|
298 |
|
|
0, /* imul bit factor */
|
299 |
|
|
COSTS_N_INSNS (40), /* idiv */
|
300 |
|
|
COSTS_N_INSNS (71), /* idivX */
|
301 |
|
|
COSTS_N_INSNS (2), /* movcc/movr */
|
302 |
|
|
0, /* shift penalty */
|
303 |
|
|
};
|
304 |
|
|
|
305 |
|
|
static const
|
306 |
|
|
struct processor_costs niagara_costs = {
|
307 |
|
|
COSTS_N_INSNS (3), /* int load */
|
308 |
|
|
COSTS_N_INSNS (3), /* int signed load */
|
309 |
|
|
COSTS_N_INSNS (3), /* int zeroed load */
|
310 |
|
|
COSTS_N_INSNS (9), /* float load */
|
311 |
|
|
COSTS_N_INSNS (8), /* fmov, fneg, fabs */
|
312 |
|
|
COSTS_N_INSNS (8), /* fadd, fsub */
|
313 |
|
|
COSTS_N_INSNS (26), /* fcmp */
|
314 |
|
|
COSTS_N_INSNS (8), /* fmov, fmovr */
|
315 |
|
|
COSTS_N_INSNS (29), /* fmul */
|
316 |
|
|
COSTS_N_INSNS (54), /* fdivs */
|
317 |
|
|
COSTS_N_INSNS (83), /* fdivd */
|
318 |
|
|
COSTS_N_INSNS (100), /* fsqrts - not implemented in hardware */
|
319 |
|
|
COSTS_N_INSNS (100), /* fsqrtd - not implemented in hardware */
|
320 |
|
|
COSTS_N_INSNS (11), /* imul */
|
321 |
|
|
COSTS_N_INSNS (11), /* imulX */
|
322 |
|
|
0, /* imul bit factor */
|
323 |
|
|
COSTS_N_INSNS (72), /* idiv */
|
324 |
|
|
COSTS_N_INSNS (72), /* idivX */
|
325 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
326 |
|
|
0, /* shift penalty */
|
327 |
|
|
};
|
328 |
|
|
|
329 |
|
|
static const
|
330 |
|
|
struct processor_costs niagara2_costs = {
|
331 |
|
|
COSTS_N_INSNS (3), /* int load */
|
332 |
|
|
COSTS_N_INSNS (3), /* int signed load */
|
333 |
|
|
COSTS_N_INSNS (3), /* int zeroed load */
|
334 |
|
|
COSTS_N_INSNS (3), /* float load */
|
335 |
|
|
COSTS_N_INSNS (6), /* fmov, fneg, fabs */
|
336 |
|
|
COSTS_N_INSNS (6), /* fadd, fsub */
|
337 |
|
|
COSTS_N_INSNS (6), /* fcmp */
|
338 |
|
|
COSTS_N_INSNS (6), /* fmov, fmovr */
|
339 |
|
|
COSTS_N_INSNS (6), /* fmul */
|
340 |
|
|
COSTS_N_INSNS (19), /* fdivs */
|
341 |
|
|
COSTS_N_INSNS (33), /* fdivd */
|
342 |
|
|
COSTS_N_INSNS (19), /* fsqrts */
|
343 |
|
|
COSTS_N_INSNS (33), /* fsqrtd */
|
344 |
|
|
COSTS_N_INSNS (5), /* imul */
|
345 |
|
|
COSTS_N_INSNS (5), /* imulX */
|
346 |
|
|
0, /* imul bit factor */
|
347 |
|
|
COSTS_N_INSNS (26), /* idiv, average of 12 - 41 cycle range */
|
348 |
|
|
COSTS_N_INSNS (26), /* idivX, average of 12 - 41 cycle range */
|
349 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
350 |
|
|
0, /* shift penalty */
|
351 |
|
|
};
|
352 |
|
|
|
353 |
|
|
static const
|
354 |
|
|
struct processor_costs niagara3_costs = {
|
355 |
|
|
COSTS_N_INSNS (3), /* int load */
|
356 |
|
|
COSTS_N_INSNS (3), /* int signed load */
|
357 |
|
|
COSTS_N_INSNS (3), /* int zeroed load */
|
358 |
|
|
COSTS_N_INSNS (3), /* float load */
|
359 |
|
|
COSTS_N_INSNS (9), /* fmov, fneg, fabs */
|
360 |
|
|
COSTS_N_INSNS (9), /* fadd, fsub */
|
361 |
|
|
COSTS_N_INSNS (9), /* fcmp */
|
362 |
|
|
COSTS_N_INSNS (9), /* fmov, fmovr */
|
363 |
|
|
COSTS_N_INSNS (9), /* fmul */
|
364 |
|
|
COSTS_N_INSNS (23), /* fdivs */
|
365 |
|
|
COSTS_N_INSNS (37), /* fdivd */
|
366 |
|
|
COSTS_N_INSNS (23), /* fsqrts */
|
367 |
|
|
COSTS_N_INSNS (37), /* fsqrtd */
|
368 |
|
|
COSTS_N_INSNS (9), /* imul */
|
369 |
|
|
COSTS_N_INSNS (9), /* imulX */
|
370 |
|
|
0, /* imul bit factor */
|
371 |
|
|
COSTS_N_INSNS (31), /* idiv, average of 17 - 45 cycle range */
|
372 |
|
|
COSTS_N_INSNS (30), /* idivX, average of 16 - 44 cycle range */
|
373 |
|
|
COSTS_N_INSNS (1), /* movcc/movr */
|
374 |
|
|
0, /* shift penalty */
|
375 |
|
|
};
|
376 |
|
|
|
377 |
|
|
static const struct processor_costs *sparc_costs = &cypress_costs;
|
378 |
|
|
|
379 |
|
|
#ifdef HAVE_AS_RELAX_OPTION
|
380 |
|
|
/* If 'as' and 'ld' are relaxing tail call insns into branch always, use
|
381 |
|
|
"or %o7,%g0,X; call Y; or X,%g0,%o7" always, so that it can be optimized.
|
382 |
|
|
With sethi/jmp, neither 'as' nor 'ld' has an easy way how to find out if
|
383 |
|
|
somebody does not branch between the sethi and jmp. */
|
384 |
|
|
#define LEAF_SIBCALL_SLOT_RESERVED_P 1
|
385 |
|
|
#else
|
386 |
|
|
#define LEAF_SIBCALL_SLOT_RESERVED_P \
|
387 |
|
|
((TARGET_ARCH64 && !TARGET_CM_MEDLOW) || flag_pic)
|
388 |
|
|
#endif
|
389 |
|
|
|
390 |
|
|
/* Vector to say how input registers are mapped to output registers.
|
391 |
|
|
HARD_FRAME_POINTER_REGNUM cannot be remapped by this function to
|
392 |
|
|
eliminate it. You must use -fomit-frame-pointer to get that. */
|
393 |
|
|
char leaf_reg_remap[] =
|
394 |
|
|
{ 0, 1, 2, 3, 4, 5, 6, 7,
|
395 |
|
|
-1, -1, -1, -1, -1, -1, 14, -1,
|
396 |
|
|
-1, -1, -1, -1, -1, -1, -1, -1,
|
397 |
|
|
8, 9, 10, 11, 12, 13, -1, 15,
|
398 |
|
|
|
399 |
|
|
32, 33, 34, 35, 36, 37, 38, 39,
|
400 |
|
|
40, 41, 42, 43, 44, 45, 46, 47,
|
401 |
|
|
48, 49, 50, 51, 52, 53, 54, 55,
|
402 |
|
|
56, 57, 58, 59, 60, 61, 62, 63,
|
403 |
|
|
64, 65, 66, 67, 68, 69, 70, 71,
|
404 |
|
|
72, 73, 74, 75, 76, 77, 78, 79,
|
405 |
|
|
80, 81, 82, 83, 84, 85, 86, 87,
|
406 |
|
|
88, 89, 90, 91, 92, 93, 94, 95,
|
407 |
|
|
96, 97, 98, 99, 100, 101, 102};
|
408 |
|
|
|
409 |
|
|
/* Vector, indexed by hard register number, which contains 1
|
410 |
|
|
for a register that is allowable in a candidate for leaf
|
411 |
|
|
function treatment. */
|
412 |
|
|
char sparc_leaf_regs[] =
|
413 |
|
|
{ 1, 1, 1, 1, 1, 1, 1, 1,
|
414 |
|
|
0, 0, 0, 0, 0, 0, 1, 0,
|
415 |
|
|
0, 0, 0, 0, 0, 0, 0, 0,
|
416 |
|
|
1, 1, 1, 1, 1, 1, 0, 1,
|
417 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
418 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
419 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
420 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
421 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
422 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
423 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
424 |
|
|
1, 1, 1, 1, 1, 1, 1, 1,
|
425 |
|
|
1, 1, 1, 1, 1, 1, 1};
|
426 |
|
|
|
427 |
|
|
struct GTY(()) machine_function
|
428 |
|
|
{
|
429 |
|
|
/* Size of the frame of the function. */
|
430 |
|
|
HOST_WIDE_INT frame_size;
|
431 |
|
|
|
432 |
|
|
/* Size of the frame of the function minus the register window save area
|
433 |
|
|
and the outgoing argument area. */
|
434 |
|
|
HOST_WIDE_INT apparent_frame_size;
|
435 |
|
|
|
436 |
|
|
/* Register we pretend the frame pointer is allocated to. Normally, this
|
437 |
|
|
is %fp, but if we are in a leaf procedure, this is (%sp + offset). We
|
438 |
|
|
record "offset" separately as it may be too big for (reg + disp). */
|
439 |
|
|
rtx frame_base_reg;
|
440 |
|
|
HOST_WIDE_INT frame_base_offset;
|
441 |
|
|
|
442 |
|
|
/* Some local-dynamic TLS symbol name. */
|
443 |
|
|
const char *some_ld_name;
|
444 |
|
|
|
445 |
|
|
/* Number of global or FP registers to be saved (as 4-byte quantities). */
|
446 |
|
|
int n_global_fp_regs;
|
447 |
|
|
|
448 |
|
|
/* True if the current function is leaf and uses only leaf regs,
|
449 |
|
|
so that the SPARC leaf function optimization can be applied.
|
450 |
|
|
Private version of current_function_uses_only_leaf_regs, see
|
451 |
|
|
sparc_expand_prologue for the rationale. */
|
452 |
|
|
int leaf_function_p;
|
453 |
|
|
|
454 |
|
|
/* True if the prologue saves local or in registers. */
|
455 |
|
|
bool save_local_in_regs_p;
|
456 |
|
|
|
457 |
|
|
/* True if the data calculated by sparc_expand_prologue are valid. */
|
458 |
|
|
bool prologue_data_valid_p;
|
459 |
|
|
};
|
460 |
|
|
|
461 |
|
|
#define sparc_frame_size cfun->machine->frame_size
|
462 |
|
|
#define sparc_apparent_frame_size cfun->machine->apparent_frame_size
|
463 |
|
|
#define sparc_frame_base_reg cfun->machine->frame_base_reg
|
464 |
|
|
#define sparc_frame_base_offset cfun->machine->frame_base_offset
|
465 |
|
|
#define sparc_n_global_fp_regs cfun->machine->n_global_fp_regs
|
466 |
|
|
#define sparc_leaf_function_p cfun->machine->leaf_function_p
|
467 |
|
|
#define sparc_save_local_in_regs_p cfun->machine->save_local_in_regs_p
|
468 |
|
|
#define sparc_prologue_data_valid_p cfun->machine->prologue_data_valid_p
|
469 |
|
|
|
470 |
|
|
/* 1 if the next opcode is to be specially indented. */
|
471 |
|
|
int sparc_indent_opcode = 0;
|
472 |
|
|
|
473 |
|
|
static void sparc_option_override (void);
|
474 |
|
|
static void sparc_init_modes (void);
|
475 |
|
|
static void scan_record_type (const_tree, int *, int *, int *);
|
476 |
|
|
static int function_arg_slotno (const CUMULATIVE_ARGS *, enum machine_mode,
|
477 |
|
|
const_tree, bool, bool, int *, int *);
|
478 |
|
|
|
479 |
|
|
static int supersparc_adjust_cost (rtx, rtx, rtx, int);
|
480 |
|
|
static int hypersparc_adjust_cost (rtx, rtx, rtx, int);
|
481 |
|
|
|
482 |
|
|
static void sparc_emit_set_const32 (rtx, rtx);
|
483 |
|
|
static void sparc_emit_set_const64 (rtx, rtx);
|
484 |
|
|
static void sparc_output_addr_vec (rtx);
|
485 |
|
|
static void sparc_output_addr_diff_vec (rtx);
|
486 |
|
|
static void sparc_output_deferred_case_vectors (void);
|
487 |
|
|
static bool sparc_legitimate_address_p (enum machine_mode, rtx, bool);
|
488 |
|
|
static bool sparc_legitimate_constant_p (enum machine_mode, rtx);
|
489 |
|
|
static rtx sparc_builtin_saveregs (void);
|
490 |
|
|
static int epilogue_renumber (rtx *, int);
|
491 |
|
|
static bool sparc_assemble_integer (rtx, unsigned int, int);
|
492 |
|
|
static int set_extends (rtx);
|
493 |
|
|
static void sparc_asm_function_prologue (FILE *, HOST_WIDE_INT);
|
494 |
|
|
static void sparc_asm_function_epilogue (FILE *, HOST_WIDE_INT);
|
495 |
|
|
#ifdef TARGET_SOLARIS
|
496 |
|
|
static void sparc_solaris_elf_asm_named_section (const char *, unsigned int,
|
497 |
|
|
tree) ATTRIBUTE_UNUSED;
|
498 |
|
|
#endif
|
499 |
|
|
static int sparc_adjust_cost (rtx, rtx, rtx, int);
|
500 |
|
|
static int sparc_issue_rate (void);
|
501 |
|
|
static void sparc_sched_init (FILE *, int, int);
|
502 |
|
|
static int sparc_use_sched_lookahead (void);
|
503 |
|
|
|
504 |
|
|
static void emit_soft_tfmode_libcall (const char *, int, rtx *);
|
505 |
|
|
static void emit_soft_tfmode_binop (enum rtx_code, rtx *);
|
506 |
|
|
static void emit_soft_tfmode_unop (enum rtx_code, rtx *);
|
507 |
|
|
static void emit_soft_tfmode_cvt (enum rtx_code, rtx *);
|
508 |
|
|
static void emit_hard_tfmode_operation (enum rtx_code, rtx *);
|
509 |
|
|
|
510 |
|
|
static bool sparc_function_ok_for_sibcall (tree, tree);
|
511 |
|
|
static void sparc_init_libfuncs (void);
|
512 |
|
|
static void sparc_init_builtins (void);
|
513 |
|
|
static void sparc_vis_init_builtins (void);
|
514 |
|
|
static rtx sparc_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
|
515 |
|
|
static tree sparc_fold_builtin (tree, int, tree *, bool);
|
516 |
|
|
static int sparc_vis_mul8x16 (int, int);
|
517 |
|
|
static tree sparc_handle_vis_mul8x16 (int, tree, tree, tree);
|
518 |
|
|
static void sparc_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
|
519 |
|
|
HOST_WIDE_INT, tree);
|
520 |
|
|
static bool sparc_can_output_mi_thunk (const_tree, HOST_WIDE_INT,
|
521 |
|
|
HOST_WIDE_INT, const_tree);
|
522 |
|
|
static void sparc_reorg (void);
|
523 |
|
|
static struct machine_function * sparc_init_machine_status (void);
|
524 |
|
|
static bool sparc_cannot_force_const_mem (enum machine_mode, rtx);
|
525 |
|
|
static rtx sparc_tls_get_addr (void);
|
526 |
|
|
static rtx sparc_tls_got (void);
|
527 |
|
|
static const char *get_some_local_dynamic_name (void);
|
528 |
|
|
static int get_some_local_dynamic_name_1 (rtx *, void *);
|
529 |
|
|
static int sparc_register_move_cost (enum machine_mode,
|
530 |
|
|
reg_class_t, reg_class_t);
|
531 |
|
|
static bool sparc_rtx_costs (rtx, int, int, int, int *, bool);
|
532 |
|
|
static rtx sparc_function_value (const_tree, const_tree, bool);
|
533 |
|
|
static rtx sparc_libcall_value (enum machine_mode, const_rtx);
|
534 |
|
|
static bool sparc_function_value_regno_p (const unsigned int);
|
535 |
|
|
static rtx sparc_struct_value_rtx (tree, int);
|
536 |
|
|
static enum machine_mode sparc_promote_function_mode (const_tree, enum machine_mode,
|
537 |
|
|
int *, const_tree, int);
|
538 |
|
|
static bool sparc_return_in_memory (const_tree, const_tree);
|
539 |
|
|
static bool sparc_strict_argument_naming (cumulative_args_t);
|
540 |
|
|
static void sparc_va_start (tree, rtx);
|
541 |
|
|
static tree sparc_gimplify_va_arg (tree, tree, gimple_seq *, gimple_seq *);
|
542 |
|
|
static bool sparc_vector_mode_supported_p (enum machine_mode);
|
543 |
|
|
static bool sparc_tls_referenced_p (rtx);
|
544 |
|
|
static rtx sparc_legitimize_tls_address (rtx);
|
545 |
|
|
static rtx sparc_legitimize_pic_address (rtx, rtx);
|
546 |
|
|
static rtx sparc_legitimize_address (rtx, rtx, enum machine_mode);
|
547 |
|
|
static rtx sparc_delegitimize_address (rtx);
|
548 |
|
|
static bool sparc_mode_dependent_address_p (const_rtx);
|
549 |
|
|
static bool sparc_pass_by_reference (cumulative_args_t,
|
550 |
|
|
enum machine_mode, const_tree, bool);
|
551 |
|
|
static void sparc_function_arg_advance (cumulative_args_t,
|
552 |
|
|
enum machine_mode, const_tree, bool);
|
553 |
|
|
static rtx sparc_function_arg_1 (cumulative_args_t,
|
554 |
|
|
enum machine_mode, const_tree, bool, bool);
|
555 |
|
|
static rtx sparc_function_arg (cumulative_args_t,
|
556 |
|
|
enum machine_mode, const_tree, bool);
|
557 |
|
|
static rtx sparc_function_incoming_arg (cumulative_args_t,
|
558 |
|
|
enum machine_mode, const_tree, bool);
|
559 |
|
|
static unsigned int sparc_function_arg_boundary (enum machine_mode,
|
560 |
|
|
const_tree);
|
561 |
|
|
static int sparc_arg_partial_bytes (cumulative_args_t,
|
562 |
|
|
enum machine_mode, tree, bool);
|
563 |
|
|
static void sparc_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED;
|
564 |
|
|
static void sparc_file_end (void);
|
565 |
|
|
static bool sparc_frame_pointer_required (void);
|
566 |
|
|
static bool sparc_can_eliminate (const int, const int);
|
567 |
|
|
static rtx sparc_builtin_setjmp_frame_value (void);
|
568 |
|
|
static void sparc_conditional_register_usage (void);
|
569 |
|
|
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
|
570 |
|
|
static const char *sparc_mangle_type (const_tree);
|
571 |
|
|
#endif
|
572 |
|
|
static void sparc_trampoline_init (rtx, tree, rtx);
|
573 |
|
|
static enum machine_mode sparc_preferred_simd_mode (enum machine_mode);
|
574 |
|
|
static reg_class_t sparc_preferred_reload_class (rtx x, reg_class_t rclass);
|
575 |
|
|
static bool sparc_print_operand_punct_valid_p (unsigned char);
|
576 |
|
|
static void sparc_print_operand (FILE *, rtx, int);
|
577 |
|
|
static void sparc_print_operand_address (FILE *, rtx);
|
578 |
|
|
static reg_class_t sparc_secondary_reload (bool, rtx, reg_class_t,
|
579 |
|
|
enum machine_mode,
|
580 |
|
|
secondary_reload_info *);
|
581 |
|
|
|
582 |
|
|
#ifdef SUBTARGET_ATTRIBUTE_TABLE
|
583 |
|
|
/* Table of valid machine attributes. */
|
584 |
|
|
static const struct attribute_spec sparc_attribute_table[] =
|
585 |
|
|
{
|
586 |
|
|
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
|
587 |
|
|
do_diagnostic } */
|
588 |
|
|
SUBTARGET_ATTRIBUTE_TABLE,
|
589 |
|
|
{ NULL, 0, 0, false, false, false, NULL, false }
|
590 |
|
|
};
|
591 |
|
|
#endif
|
592 |
|
|
|
593 |
|
|
/* Option handling. */
|
594 |
|
|
|
595 |
|
|
/* Parsed value. */
|
596 |
|
|
enum cmodel sparc_cmodel;
|
597 |
|
|
|
598 |
|
|
char sparc_hard_reg_printed[8];
|
599 |
|
|
|
600 |
|
|
/* Initialize the GCC target structure. */
|
601 |
|
|
|
602 |
|
|
/* The default is to use .half rather than .short for aligned HI objects. */
|
603 |
|
|
#undef TARGET_ASM_ALIGNED_HI_OP
|
604 |
|
|
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
|
605 |
|
|
|
606 |
|
|
#undef TARGET_ASM_UNALIGNED_HI_OP
|
607 |
|
|
#define TARGET_ASM_UNALIGNED_HI_OP "\t.uahalf\t"
|
608 |
|
|
#undef TARGET_ASM_UNALIGNED_SI_OP
|
609 |
|
|
#define TARGET_ASM_UNALIGNED_SI_OP "\t.uaword\t"
|
610 |
|
|
#undef TARGET_ASM_UNALIGNED_DI_OP
|
611 |
|
|
#define TARGET_ASM_UNALIGNED_DI_OP "\t.uaxword\t"
|
612 |
|
|
|
613 |
|
|
/* The target hook has to handle DI-mode values. */
|
614 |
|
|
#undef TARGET_ASM_INTEGER
|
615 |
|
|
#define TARGET_ASM_INTEGER sparc_assemble_integer
|
616 |
|
|
|
617 |
|
|
#undef TARGET_ASM_FUNCTION_PROLOGUE
|
618 |
|
|
#define TARGET_ASM_FUNCTION_PROLOGUE sparc_asm_function_prologue
|
619 |
|
|
#undef TARGET_ASM_FUNCTION_EPILOGUE
|
620 |
|
|
#define TARGET_ASM_FUNCTION_EPILOGUE sparc_asm_function_epilogue
|
621 |
|
|
|
622 |
|
|
#undef TARGET_SCHED_ADJUST_COST
|
623 |
|
|
#define TARGET_SCHED_ADJUST_COST sparc_adjust_cost
|
624 |
|
|
#undef TARGET_SCHED_ISSUE_RATE
|
625 |
|
|
#define TARGET_SCHED_ISSUE_RATE sparc_issue_rate
|
626 |
|
|
#undef TARGET_SCHED_INIT
|
627 |
|
|
#define TARGET_SCHED_INIT sparc_sched_init
|
628 |
|
|
#undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD
|
629 |
|
|
#define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD sparc_use_sched_lookahead
|
630 |
|
|
|
631 |
|
|
#undef TARGET_FUNCTION_OK_FOR_SIBCALL
|
632 |
|
|
#define TARGET_FUNCTION_OK_FOR_SIBCALL sparc_function_ok_for_sibcall
|
633 |
|
|
|
634 |
|
|
#undef TARGET_INIT_LIBFUNCS
|
635 |
|
|
#define TARGET_INIT_LIBFUNCS sparc_init_libfuncs
|
636 |
|
|
#undef TARGET_INIT_BUILTINS
|
637 |
|
|
#define TARGET_INIT_BUILTINS sparc_init_builtins
|
638 |
|
|
|
639 |
|
|
#undef TARGET_LEGITIMIZE_ADDRESS
|
640 |
|
|
#define TARGET_LEGITIMIZE_ADDRESS sparc_legitimize_address
|
641 |
|
|
#undef TARGET_DELEGITIMIZE_ADDRESS
|
642 |
|
|
#define TARGET_DELEGITIMIZE_ADDRESS sparc_delegitimize_address
|
643 |
|
|
#undef TARGET_MODE_DEPENDENT_ADDRESS_P
|
644 |
|
|
#define TARGET_MODE_DEPENDENT_ADDRESS_P sparc_mode_dependent_address_p
|
645 |
|
|
|
646 |
|
|
#undef TARGET_EXPAND_BUILTIN
|
647 |
|
|
#define TARGET_EXPAND_BUILTIN sparc_expand_builtin
|
648 |
|
|
#undef TARGET_FOLD_BUILTIN
|
649 |
|
|
#define TARGET_FOLD_BUILTIN sparc_fold_builtin
|
650 |
|
|
|
651 |
|
|
#if TARGET_TLS
|
652 |
|
|
#undef TARGET_HAVE_TLS
|
653 |
|
|
#define TARGET_HAVE_TLS true
|
654 |
|
|
#endif
|
655 |
|
|
|
656 |
|
|
#undef TARGET_CANNOT_FORCE_CONST_MEM
|
657 |
|
|
#define TARGET_CANNOT_FORCE_CONST_MEM sparc_cannot_force_const_mem
|
658 |
|
|
|
659 |
|
|
#undef TARGET_ASM_OUTPUT_MI_THUNK
|
660 |
|
|
#define TARGET_ASM_OUTPUT_MI_THUNK sparc_output_mi_thunk
|
661 |
|
|
#undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
|
662 |
|
|
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK sparc_can_output_mi_thunk
|
663 |
|
|
|
664 |
|
|
#undef TARGET_MACHINE_DEPENDENT_REORG
|
665 |
|
|
#define TARGET_MACHINE_DEPENDENT_REORG sparc_reorg
|
666 |
|
|
|
667 |
|
|
#undef TARGET_RTX_COSTS
|
668 |
|
|
#define TARGET_RTX_COSTS sparc_rtx_costs
|
669 |
|
|
#undef TARGET_ADDRESS_COST
|
670 |
|
|
#define TARGET_ADDRESS_COST hook_int_rtx_bool_0
|
671 |
|
|
#undef TARGET_REGISTER_MOVE_COST
|
672 |
|
|
#define TARGET_REGISTER_MOVE_COST sparc_register_move_cost
|
673 |
|
|
|
674 |
|
|
#undef TARGET_PROMOTE_FUNCTION_MODE
|
675 |
|
|
#define TARGET_PROMOTE_FUNCTION_MODE sparc_promote_function_mode
|
676 |
|
|
|
677 |
|
|
#undef TARGET_FUNCTION_VALUE
|
678 |
|
|
#define TARGET_FUNCTION_VALUE sparc_function_value
|
679 |
|
|
#undef TARGET_LIBCALL_VALUE
|
680 |
|
|
#define TARGET_LIBCALL_VALUE sparc_libcall_value
|
681 |
|
|
#undef TARGET_FUNCTION_VALUE_REGNO_P
|
682 |
|
|
#define TARGET_FUNCTION_VALUE_REGNO_P sparc_function_value_regno_p
|
683 |
|
|
|
684 |
|
|
#undef TARGET_STRUCT_VALUE_RTX
|
685 |
|
|
#define TARGET_STRUCT_VALUE_RTX sparc_struct_value_rtx
|
686 |
|
|
#undef TARGET_RETURN_IN_MEMORY
|
687 |
|
|
#define TARGET_RETURN_IN_MEMORY sparc_return_in_memory
|
688 |
|
|
#undef TARGET_MUST_PASS_IN_STACK
|
689 |
|
|
#define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
|
690 |
|
|
#undef TARGET_PASS_BY_REFERENCE
|
691 |
|
|
#define TARGET_PASS_BY_REFERENCE sparc_pass_by_reference
|
692 |
|
|
#undef TARGET_ARG_PARTIAL_BYTES
|
693 |
|
|
#define TARGET_ARG_PARTIAL_BYTES sparc_arg_partial_bytes
|
694 |
|
|
#undef TARGET_FUNCTION_ARG_ADVANCE
|
695 |
|
|
#define TARGET_FUNCTION_ARG_ADVANCE sparc_function_arg_advance
|
696 |
|
|
#undef TARGET_FUNCTION_ARG
|
697 |
|
|
#define TARGET_FUNCTION_ARG sparc_function_arg
|
698 |
|
|
#undef TARGET_FUNCTION_INCOMING_ARG
|
699 |
|
|
#define TARGET_FUNCTION_INCOMING_ARG sparc_function_incoming_arg
|
700 |
|
|
#undef TARGET_FUNCTION_ARG_BOUNDARY
|
701 |
|
|
#define TARGET_FUNCTION_ARG_BOUNDARY sparc_function_arg_boundary
|
702 |
|
|
|
703 |
|
|
#undef TARGET_EXPAND_BUILTIN_SAVEREGS
|
704 |
|
|
#define TARGET_EXPAND_BUILTIN_SAVEREGS sparc_builtin_saveregs
|
705 |
|
|
#undef TARGET_STRICT_ARGUMENT_NAMING
|
706 |
|
|
#define TARGET_STRICT_ARGUMENT_NAMING sparc_strict_argument_naming
|
707 |
|
|
|
708 |
|
|
#undef TARGET_EXPAND_BUILTIN_VA_START
|
709 |
|
|
#define TARGET_EXPAND_BUILTIN_VA_START sparc_va_start
|
710 |
|
|
#undef TARGET_GIMPLIFY_VA_ARG_EXPR
|
711 |
|
|
#define TARGET_GIMPLIFY_VA_ARG_EXPR sparc_gimplify_va_arg
|
712 |
|
|
|
713 |
|
|
#undef TARGET_VECTOR_MODE_SUPPORTED_P
|
714 |
|
|
#define TARGET_VECTOR_MODE_SUPPORTED_P sparc_vector_mode_supported_p
|
715 |
|
|
|
716 |
|
|
#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE
|
717 |
|
|
#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE sparc_preferred_simd_mode
|
718 |
|
|
|
719 |
|
|
#ifdef SUBTARGET_INSERT_ATTRIBUTES
|
720 |
|
|
#undef TARGET_INSERT_ATTRIBUTES
|
721 |
|
|
#define TARGET_INSERT_ATTRIBUTES SUBTARGET_INSERT_ATTRIBUTES
|
722 |
|
|
#endif
|
723 |
|
|
|
724 |
|
|
#ifdef SUBTARGET_ATTRIBUTE_TABLE
|
725 |
|
|
#undef TARGET_ATTRIBUTE_TABLE
|
726 |
|
|
#define TARGET_ATTRIBUTE_TABLE sparc_attribute_table
|
727 |
|
|
#endif
|
728 |
|
|
|
729 |
|
|
#undef TARGET_RELAXED_ORDERING
|
730 |
|
|
#define TARGET_RELAXED_ORDERING SPARC_RELAXED_ORDERING
|
731 |
|
|
|
732 |
|
|
#undef TARGET_OPTION_OVERRIDE
|
733 |
|
|
#define TARGET_OPTION_OVERRIDE sparc_option_override
|
734 |
|
|
|
735 |
|
|
#if TARGET_GNU_TLS && defined(HAVE_AS_SPARC_UA_PCREL)
|
736 |
|
|
#undef TARGET_ASM_OUTPUT_DWARF_DTPREL
|
737 |
|
|
#define TARGET_ASM_OUTPUT_DWARF_DTPREL sparc_output_dwarf_dtprel
|
738 |
|
|
#endif
|
739 |
|
|
|
740 |
|
|
#undef TARGET_ASM_FILE_END
|
741 |
|
|
#define TARGET_ASM_FILE_END sparc_file_end
|
742 |
|
|
|
743 |
|
|
#undef TARGET_FRAME_POINTER_REQUIRED
|
744 |
|
|
#define TARGET_FRAME_POINTER_REQUIRED sparc_frame_pointer_required
|
745 |
|
|
|
746 |
|
|
#undef TARGET_BUILTIN_SETJMP_FRAME_VALUE
|
747 |
|
|
#define TARGET_BUILTIN_SETJMP_FRAME_VALUE sparc_builtin_setjmp_frame_value
|
748 |
|
|
|
749 |
|
|
#undef TARGET_CAN_ELIMINATE
|
750 |
|
|
#define TARGET_CAN_ELIMINATE sparc_can_eliminate
|
751 |
|
|
|
752 |
|
|
#undef TARGET_PREFERRED_RELOAD_CLASS
|
753 |
|
|
#define TARGET_PREFERRED_RELOAD_CLASS sparc_preferred_reload_class
|
754 |
|
|
|
755 |
|
|
#undef TARGET_SECONDARY_RELOAD
|
756 |
|
|
#define TARGET_SECONDARY_RELOAD sparc_secondary_reload
|
757 |
|
|
|
758 |
|
|
#undef TARGET_CONDITIONAL_REGISTER_USAGE
|
759 |
|
|
#define TARGET_CONDITIONAL_REGISTER_USAGE sparc_conditional_register_usage
|
760 |
|
|
|
761 |
|
|
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
|
762 |
|
|
#undef TARGET_MANGLE_TYPE
|
763 |
|
|
#define TARGET_MANGLE_TYPE sparc_mangle_type
|
764 |
|
|
#endif
|
765 |
|
|
|
766 |
|
|
#undef TARGET_LEGITIMATE_ADDRESS_P
|
767 |
|
|
#define TARGET_LEGITIMATE_ADDRESS_P sparc_legitimate_address_p
|
768 |
|
|
|
769 |
|
|
#undef TARGET_LEGITIMATE_CONSTANT_P
|
770 |
|
|
#define TARGET_LEGITIMATE_CONSTANT_P sparc_legitimate_constant_p
|
771 |
|
|
|
772 |
|
|
#undef TARGET_TRAMPOLINE_INIT
|
773 |
|
|
#define TARGET_TRAMPOLINE_INIT sparc_trampoline_init
|
774 |
|
|
|
775 |
|
|
#undef TARGET_PRINT_OPERAND_PUNCT_VALID_P
|
776 |
|
|
#define TARGET_PRINT_OPERAND_PUNCT_VALID_P sparc_print_operand_punct_valid_p
|
777 |
|
|
#undef TARGET_PRINT_OPERAND
|
778 |
|
|
#define TARGET_PRINT_OPERAND sparc_print_operand
|
779 |
|
|
#undef TARGET_PRINT_OPERAND_ADDRESS
|
780 |
|
|
#define TARGET_PRINT_OPERAND_ADDRESS sparc_print_operand_address
|
781 |
|
|
|
782 |
|
|
/* The value stored by LDSTUB. */
|
783 |
|
|
#undef TARGET_ATOMIC_TEST_AND_SET_TRUEVAL
|
784 |
|
|
#define TARGET_ATOMIC_TEST_AND_SET_TRUEVAL 0xff
|
785 |
|
|
|
786 |
|
|
struct gcc_target targetm = TARGET_INITIALIZER;
|
787 |
|
|
|
788 |
|
|
static void
|
789 |
|
|
dump_target_flag_bits (const int flags)
|
790 |
|
|
{
|
791 |
|
|
if (flags & MASK_64BIT)
|
792 |
|
|
fprintf (stderr, "64BIT ");
|
793 |
|
|
if (flags & MASK_APP_REGS)
|
794 |
|
|
fprintf (stderr, "APP_REGS ");
|
795 |
|
|
if (flags & MASK_FASTER_STRUCTS)
|
796 |
|
|
fprintf (stderr, "FASTER_STRUCTS ");
|
797 |
|
|
if (flags & MASK_FLAT)
|
798 |
|
|
fprintf (stderr, "FLAT ");
|
799 |
|
|
if (flags & MASK_FMAF)
|
800 |
|
|
fprintf (stderr, "FMAF ");
|
801 |
|
|
if (flags & MASK_FPU)
|
802 |
|
|
fprintf (stderr, "FPU ");
|
803 |
|
|
if (flags & MASK_HARD_QUAD)
|
804 |
|
|
fprintf (stderr, "HARD_QUAD ");
|
805 |
|
|
if (flags & MASK_POPC)
|
806 |
|
|
fprintf (stderr, "POPC ");
|
807 |
|
|
if (flags & MASK_PTR64)
|
808 |
|
|
fprintf (stderr, "PTR64 ");
|
809 |
|
|
if (flags & MASK_STACK_BIAS)
|
810 |
|
|
fprintf (stderr, "STACK_BIAS ");
|
811 |
|
|
if (flags & MASK_UNALIGNED_DOUBLES)
|
812 |
|
|
fprintf (stderr, "UNALIGNED_DOUBLES ");
|
813 |
|
|
if (flags & MASK_V8PLUS)
|
814 |
|
|
fprintf (stderr, "V8PLUS ");
|
815 |
|
|
if (flags & MASK_VIS)
|
816 |
|
|
fprintf (stderr, "VIS ");
|
817 |
|
|
if (flags & MASK_VIS2)
|
818 |
|
|
fprintf (stderr, "VIS2 ");
|
819 |
|
|
if (flags & MASK_VIS3)
|
820 |
|
|
fprintf (stderr, "VIS3 ");
|
821 |
|
|
if (flags & MASK_DEPRECATED_V8_INSNS)
|
822 |
|
|
fprintf (stderr, "DEPRECATED_V8_INSNS ");
|
823 |
|
|
if (flags & MASK_SPARCLET)
|
824 |
|
|
fprintf (stderr, "SPARCLET ");
|
825 |
|
|
if (flags & MASK_SPARCLITE)
|
826 |
|
|
fprintf (stderr, "SPARCLITE ");
|
827 |
|
|
if (flags & MASK_V8)
|
828 |
|
|
fprintf (stderr, "V8 ");
|
829 |
|
|
if (flags & MASK_V9)
|
830 |
|
|
fprintf (stderr, "V9 ");
|
831 |
|
|
}
|
832 |
|
|
|
833 |
|
|
static void
|
834 |
|
|
dump_target_flags (const char *prefix, const int flags)
|
835 |
|
|
{
|
836 |
|
|
fprintf (stderr, "%s: (%08x) [ ", prefix, flags);
|
837 |
|
|
dump_target_flag_bits (flags);
|
838 |
|
|
fprintf(stderr, "]\n");
|
839 |
|
|
}
|
840 |
|
|
|
841 |
|
|
/* Validate and override various options, and do some machine dependent
|
842 |
|
|
initialization. */
|
843 |
|
|
|
844 |
|
|
static void
|
845 |
|
|
sparc_option_override (void)
|
846 |
|
|
{
|
847 |
|
|
static struct code_model {
|
848 |
|
|
const char *const name;
|
849 |
|
|
const enum cmodel value;
|
850 |
|
|
} const cmodels[] = {
|
851 |
|
|
{ "32", CM_32 },
|
852 |
|
|
{ "medlow", CM_MEDLOW },
|
853 |
|
|
{ "medmid", CM_MEDMID },
|
854 |
|
|
{ "medany", CM_MEDANY },
|
855 |
|
|
{ "embmedany", CM_EMBMEDANY },
|
856 |
|
|
{ NULL, (enum cmodel) 0 }
|
857 |
|
|
};
|
858 |
|
|
const struct code_model *cmodel;
|
859 |
|
|
/* Map TARGET_CPU_DEFAULT to value for -m{cpu,tune}=. */
|
860 |
|
|
static struct cpu_default {
|
861 |
|
|
const int cpu;
|
862 |
|
|
const enum processor_type processor;
|
863 |
|
|
} const cpu_default[] = {
|
864 |
|
|
/* There must be one entry here for each TARGET_CPU value. */
|
865 |
|
|
{ TARGET_CPU_sparc, PROCESSOR_CYPRESS },
|
866 |
|
|
{ TARGET_CPU_v8, PROCESSOR_V8 },
|
867 |
|
|
{ TARGET_CPU_supersparc, PROCESSOR_SUPERSPARC },
|
868 |
|
|
{ TARGET_CPU_hypersparc, PROCESSOR_HYPERSPARC },
|
869 |
|
|
{ TARGET_CPU_leon, PROCESSOR_LEON },
|
870 |
|
|
{ TARGET_CPU_sparclite, PROCESSOR_F930 },
|
871 |
|
|
{ TARGET_CPU_sparclite86x, PROCESSOR_SPARCLITE86X },
|
872 |
|
|
{ TARGET_CPU_sparclet, PROCESSOR_TSC701 },
|
873 |
|
|
{ TARGET_CPU_v9, PROCESSOR_V9 },
|
874 |
|
|
{ TARGET_CPU_ultrasparc, PROCESSOR_ULTRASPARC },
|
875 |
|
|
{ TARGET_CPU_ultrasparc3, PROCESSOR_ULTRASPARC3 },
|
876 |
|
|
{ TARGET_CPU_niagara, PROCESSOR_NIAGARA },
|
877 |
|
|
{ TARGET_CPU_niagara2, PROCESSOR_NIAGARA2 },
|
878 |
|
|
{ TARGET_CPU_niagara3, PROCESSOR_NIAGARA3 },
|
879 |
|
|
{ TARGET_CPU_niagara4, PROCESSOR_NIAGARA4 },
|
880 |
|
|
{ -1, PROCESSOR_V7 }
|
881 |
|
|
};
|
882 |
|
|
const struct cpu_default *def;
|
883 |
|
|
/* Table of values for -m{cpu,tune}=. This must match the order of
|
884 |
|
|
the PROCESSOR_* enumeration. */
|
885 |
|
|
static struct cpu_table {
|
886 |
|
|
const char *const name;
|
887 |
|
|
const int disable;
|
888 |
|
|
const int enable;
|
889 |
|
|
} const cpu_table[] = {
|
890 |
|
|
{ "v7", MASK_ISA, 0 },
|
891 |
|
|
{ "cypress", MASK_ISA, 0 },
|
892 |
|
|
{ "v8", MASK_ISA, MASK_V8 },
|
893 |
|
|
/* TI TMS390Z55 supersparc */
|
894 |
|
|
{ "supersparc", MASK_ISA, MASK_V8 },
|
895 |
|
|
{ "hypersparc", MASK_ISA, MASK_V8|MASK_FPU },
|
896 |
|
|
/* LEON */
|
897 |
|
|
{ "leon", MASK_ISA, MASK_V8|MASK_FPU },
|
898 |
|
|
{ "sparclite", MASK_ISA, MASK_SPARCLITE },
|
899 |
|
|
/* The Fujitsu MB86930 is the original sparclite chip, with no FPU. */
|
900 |
|
|
{ "f930", MASK_ISA|MASK_FPU, MASK_SPARCLITE },
|
901 |
|
|
/* The Fujitsu MB86934 is the recent sparclite chip, with an FPU. */
|
902 |
|
|
{ "f934", MASK_ISA, MASK_SPARCLITE|MASK_FPU },
|
903 |
|
|
{ "sparclite86x", MASK_ISA|MASK_FPU, MASK_SPARCLITE },
|
904 |
|
|
{ "sparclet", MASK_ISA, MASK_SPARCLET },
|
905 |
|
|
/* TEMIC sparclet */
|
906 |
|
|
{ "tsc701", MASK_ISA, MASK_SPARCLET },
|
907 |
|
|
{ "v9", MASK_ISA, MASK_V9 },
|
908 |
|
|
/* UltraSPARC I, II, IIi */
|
909 |
|
|
{ "ultrasparc", MASK_ISA,
|
910 |
|
|
/* Although insns using %y are deprecated, it is a clear win. */
|
911 |
|
|
MASK_V9|MASK_DEPRECATED_V8_INSNS },
|
912 |
|
|
/* UltraSPARC III */
|
913 |
|
|
/* ??? Check if %y issue still holds true. */
|
914 |
|
|
{ "ultrasparc3", MASK_ISA,
|
915 |
|
|
MASK_V9|MASK_DEPRECATED_V8_INSNS|MASK_VIS2 },
|
916 |
|
|
/* UltraSPARC T1 */
|
917 |
|
|
{ "niagara", MASK_ISA,
|
918 |
|
|
MASK_V9|MASK_DEPRECATED_V8_INSNS },
|
919 |
|
|
/* UltraSPARC T2 */
|
920 |
|
|
{ "niagara2", MASK_ISA,
|
921 |
|
|
MASK_V9|MASK_POPC|MASK_VIS2 },
|
922 |
|
|
/* UltraSPARC T3 */
|
923 |
|
|
{ "niagara3", MASK_ISA,
|
924 |
|
|
MASK_V9|MASK_POPC|MASK_VIS2|MASK_VIS3|MASK_FMAF },
|
925 |
|
|
/* UltraSPARC T4 */
|
926 |
|
|
{ "niagara4", MASK_ISA,
|
927 |
|
|
MASK_V9|MASK_POPC|MASK_VIS2|MASK_VIS3|MASK_FMAF },
|
928 |
|
|
};
|
929 |
|
|
const struct cpu_table *cpu;
|
930 |
|
|
unsigned int i;
|
931 |
|
|
int fpu;
|
932 |
|
|
|
933 |
|
|
if (sparc_debug_string != NULL)
|
934 |
|
|
{
|
935 |
|
|
const char *q;
|
936 |
|
|
char *p;
|
937 |
|
|
|
938 |
|
|
p = ASTRDUP (sparc_debug_string);
|
939 |
|
|
while ((q = strtok (p, ",")) != NULL)
|
940 |
|
|
{
|
941 |
|
|
bool invert;
|
942 |
|
|
int mask;
|
943 |
|
|
|
944 |
|
|
p = NULL;
|
945 |
|
|
if (*q == '!')
|
946 |
|
|
{
|
947 |
|
|
invert = true;
|
948 |
|
|
q++;
|
949 |
|
|
}
|
950 |
|
|
else
|
951 |
|
|
invert = false;
|
952 |
|
|
|
953 |
|
|
if (! strcmp (q, "all"))
|
954 |
|
|
mask = MASK_DEBUG_ALL;
|
955 |
|
|
else if (! strcmp (q, "options"))
|
956 |
|
|
mask = MASK_DEBUG_OPTIONS;
|
957 |
|
|
else
|
958 |
|
|
error ("unknown -mdebug-%s switch", q);
|
959 |
|
|
|
960 |
|
|
if (invert)
|
961 |
|
|
sparc_debug &= ~mask;
|
962 |
|
|
else
|
963 |
|
|
sparc_debug |= mask;
|
964 |
|
|
}
|
965 |
|
|
}
|
966 |
|
|
|
967 |
|
|
if (TARGET_DEBUG_OPTIONS)
|
968 |
|
|
{
|
969 |
|
|
dump_target_flags("Initial target_flags", target_flags);
|
970 |
|
|
dump_target_flags("target_flags_explicit", target_flags_explicit);
|
971 |
|
|
}
|
972 |
|
|
|
973 |
|
|
#ifdef SUBTARGET_OVERRIDE_OPTIONS
|
974 |
|
|
SUBTARGET_OVERRIDE_OPTIONS;
|
975 |
|
|
#endif
|
976 |
|
|
|
977 |
|
|
#ifndef SPARC_BI_ARCH
|
978 |
|
|
/* Check for unsupported architecture size. */
|
979 |
|
|
if (! TARGET_64BIT != DEFAULT_ARCH32_P)
|
980 |
|
|
error ("%s is not supported by this configuration",
|
981 |
|
|
DEFAULT_ARCH32_P ? "-m64" : "-m32");
|
982 |
|
|
#endif
|
983 |
|
|
|
984 |
|
|
/* We force all 64bit archs to use 128 bit long double */
|
985 |
|
|
if (TARGET_64BIT && ! TARGET_LONG_DOUBLE_128)
|
986 |
|
|
{
|
987 |
|
|
error ("-mlong-double-64 not allowed with -m64");
|
988 |
|
|
target_flags |= MASK_LONG_DOUBLE_128;
|
989 |
|
|
}
|
990 |
|
|
|
991 |
|
|
/* Code model selection. */
|
992 |
|
|
sparc_cmodel = SPARC_DEFAULT_CMODEL;
|
993 |
|
|
|
994 |
|
|
#ifdef SPARC_BI_ARCH
|
995 |
|
|
if (TARGET_ARCH32)
|
996 |
|
|
sparc_cmodel = CM_32;
|
997 |
|
|
#endif
|
998 |
|
|
|
999 |
|
|
if (sparc_cmodel_string != NULL)
|
1000 |
|
|
{
|
1001 |
|
|
if (TARGET_ARCH64)
|
1002 |
|
|
{
|
1003 |
|
|
for (cmodel = &cmodels[0]; cmodel->name; cmodel++)
|
1004 |
|
|
if (strcmp (sparc_cmodel_string, cmodel->name) == 0)
|
1005 |
|
|
break;
|
1006 |
|
|
if (cmodel->name == NULL)
|
1007 |
|
|
error ("bad value (%s) for -mcmodel= switch", sparc_cmodel_string);
|
1008 |
|
|
else
|
1009 |
|
|
sparc_cmodel = cmodel->value;
|
1010 |
|
|
}
|
1011 |
|
|
else
|
1012 |
|
|
error ("-mcmodel= is not supported on 32 bit systems");
|
1013 |
|
|
}
|
1014 |
|
|
|
1015 |
|
|
/* Check that -fcall-saved-REG wasn't specified for out registers. */
|
1016 |
|
|
for (i = 8; i < 16; i++)
|
1017 |
|
|
if (!call_used_regs [i])
|
1018 |
|
|
{
|
1019 |
|
|
error ("-fcall-saved-REG is not supported for out registers");
|
1020 |
|
|
call_used_regs [i] = 1;
|
1021 |
|
|
}
|
1022 |
|
|
|
1023 |
|
|
fpu = target_flags & MASK_FPU; /* save current -mfpu status */
|
1024 |
|
|
|
1025 |
|
|
/* Set the default CPU. */
|
1026 |
|
|
if (!global_options_set.x_sparc_cpu_and_features)
|
1027 |
|
|
{
|
1028 |
|
|
for (def = &cpu_default[0]; def->cpu != -1; ++def)
|
1029 |
|
|
if (def->cpu == TARGET_CPU_DEFAULT)
|
1030 |
|
|
break;
|
1031 |
|
|
gcc_assert (def->cpu != -1);
|
1032 |
|
|
sparc_cpu_and_features = def->processor;
|
1033 |
|
|
}
|
1034 |
|
|
|
1035 |
|
|
if (!global_options_set.x_sparc_cpu)
|
1036 |
|
|
sparc_cpu = sparc_cpu_and_features;
|
1037 |
|
|
|
1038 |
|
|
cpu = &cpu_table[(int) sparc_cpu_and_features];
|
1039 |
|
|
|
1040 |
|
|
if (TARGET_DEBUG_OPTIONS)
|
1041 |
|
|
{
|
1042 |
|
|
fprintf (stderr, "sparc_cpu_and_features: %s\n", cpu->name);
|
1043 |
|
|
fprintf (stderr, "sparc_cpu: %s\n",
|
1044 |
|
|
cpu_table[(int) sparc_cpu].name);
|
1045 |
|
|
dump_target_flags ("cpu->disable", cpu->disable);
|
1046 |
|
|
dump_target_flags ("cpu->enable", cpu->enable);
|
1047 |
|
|
}
|
1048 |
|
|
|
1049 |
|
|
target_flags &= ~cpu->disable;
|
1050 |
|
|
target_flags |= (cpu->enable
|
1051 |
|
|
#ifndef HAVE_AS_FMAF_HPC_VIS3
|
1052 |
|
|
& ~(MASK_FMAF | MASK_VIS3)
|
1053 |
|
|
#endif
|
1054 |
|
|
);
|
1055 |
|
|
|
1056 |
|
|
/* If -mfpu or -mno-fpu was explicitly used, don't override with
|
1057 |
|
|
the processor default. */
|
1058 |
|
|
if (target_flags_explicit & MASK_FPU)
|
1059 |
|
|
target_flags = (target_flags & ~MASK_FPU) | fpu;
|
1060 |
|
|
|
1061 |
|
|
/* -mvis2 implies -mvis */
|
1062 |
|
|
if (TARGET_VIS2)
|
1063 |
|
|
target_flags |= MASK_VIS;
|
1064 |
|
|
|
1065 |
|
|
/* -mvis3 implies -mvis2 and -mvis */
|
1066 |
|
|
if (TARGET_VIS3)
|
1067 |
|
|
target_flags |= MASK_VIS2 | MASK_VIS;
|
1068 |
|
|
|
1069 |
|
|
/* Don't allow -mvis, -mvis2, -mvis3, or -mfmaf if FPU is disabled. */
|
1070 |
|
|
if (! TARGET_FPU)
|
1071 |
|
|
target_flags &= ~(MASK_VIS | MASK_VIS2 | MASK_VIS3 | MASK_FMAF);
|
1072 |
|
|
|
1073 |
|
|
/* -mvis assumes UltraSPARC+, so we are sure v9 instructions
|
1074 |
|
|
are available.
|
1075 |
|
|
-m64 also implies v9. */
|
1076 |
|
|
if (TARGET_VIS || TARGET_ARCH64)
|
1077 |
|
|
{
|
1078 |
|
|
target_flags |= MASK_V9;
|
1079 |
|
|
target_flags &= ~(MASK_V8 | MASK_SPARCLET | MASK_SPARCLITE);
|
1080 |
|
|
}
|
1081 |
|
|
|
1082 |
|
|
/* -mvis also implies -mv8plus on 32-bit */
|
1083 |
|
|
if (TARGET_VIS && ! TARGET_ARCH64)
|
1084 |
|
|
target_flags |= MASK_V8PLUS;
|
1085 |
|
|
|
1086 |
|
|
/* Use the deprecated v8 insns for sparc64 in 32 bit mode. */
|
1087 |
|
|
if (TARGET_V9 && TARGET_ARCH32)
|
1088 |
|
|
target_flags |= MASK_DEPRECATED_V8_INSNS;
|
1089 |
|
|
|
1090 |
|
|
/* V8PLUS requires V9, makes no sense in 64 bit mode. */
|
1091 |
|
|
if (! TARGET_V9 || TARGET_ARCH64)
|
1092 |
|
|
target_flags &= ~MASK_V8PLUS;
|
1093 |
|
|
|
1094 |
|
|
/* Don't use stack biasing in 32 bit mode. */
|
1095 |
|
|
if (TARGET_ARCH32)
|
1096 |
|
|
target_flags &= ~MASK_STACK_BIAS;
|
1097 |
|
|
|
1098 |
|
|
/* Supply a default value for align_functions. */
|
1099 |
|
|
if (align_functions == 0
|
1100 |
|
|
&& (sparc_cpu == PROCESSOR_ULTRASPARC
|
1101 |
|
|
|| sparc_cpu == PROCESSOR_ULTRASPARC3
|
1102 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA
|
1103 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA2
|
1104 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA3
|
1105 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA4))
|
1106 |
|
|
align_functions = 32;
|
1107 |
|
|
|
1108 |
|
|
/* Validate PCC_STRUCT_RETURN. */
|
1109 |
|
|
if (flag_pcc_struct_return == DEFAULT_PCC_STRUCT_RETURN)
|
1110 |
|
|
flag_pcc_struct_return = (TARGET_ARCH64 ? 0 : 1);
|
1111 |
|
|
|
1112 |
|
|
/* Only use .uaxword when compiling for a 64-bit target. */
|
1113 |
|
|
if (!TARGET_ARCH64)
|
1114 |
|
|
targetm.asm_out.unaligned_op.di = NULL;
|
1115 |
|
|
|
1116 |
|
|
/* Do various machine dependent initializations. */
|
1117 |
|
|
sparc_init_modes ();
|
1118 |
|
|
|
1119 |
|
|
/* Set up function hooks. */
|
1120 |
|
|
init_machine_status = sparc_init_machine_status;
|
1121 |
|
|
|
1122 |
|
|
switch (sparc_cpu)
|
1123 |
|
|
{
|
1124 |
|
|
case PROCESSOR_V7:
|
1125 |
|
|
case PROCESSOR_CYPRESS:
|
1126 |
|
|
sparc_costs = &cypress_costs;
|
1127 |
|
|
break;
|
1128 |
|
|
case PROCESSOR_V8:
|
1129 |
|
|
case PROCESSOR_SPARCLITE:
|
1130 |
|
|
case PROCESSOR_SUPERSPARC:
|
1131 |
|
|
sparc_costs = &supersparc_costs;
|
1132 |
|
|
break;
|
1133 |
|
|
case PROCESSOR_F930:
|
1134 |
|
|
case PROCESSOR_F934:
|
1135 |
|
|
case PROCESSOR_HYPERSPARC:
|
1136 |
|
|
case PROCESSOR_SPARCLITE86X:
|
1137 |
|
|
sparc_costs = &hypersparc_costs;
|
1138 |
|
|
break;
|
1139 |
|
|
case PROCESSOR_LEON:
|
1140 |
|
|
sparc_costs = &leon_costs;
|
1141 |
|
|
break;
|
1142 |
|
|
case PROCESSOR_SPARCLET:
|
1143 |
|
|
case PROCESSOR_TSC701:
|
1144 |
|
|
sparc_costs = &sparclet_costs;
|
1145 |
|
|
break;
|
1146 |
|
|
case PROCESSOR_V9:
|
1147 |
|
|
case PROCESSOR_ULTRASPARC:
|
1148 |
|
|
sparc_costs = &ultrasparc_costs;
|
1149 |
|
|
break;
|
1150 |
|
|
case PROCESSOR_ULTRASPARC3:
|
1151 |
|
|
sparc_costs = &ultrasparc3_costs;
|
1152 |
|
|
break;
|
1153 |
|
|
case PROCESSOR_NIAGARA:
|
1154 |
|
|
sparc_costs = &niagara_costs;
|
1155 |
|
|
break;
|
1156 |
|
|
case PROCESSOR_NIAGARA2:
|
1157 |
|
|
sparc_costs = &niagara2_costs;
|
1158 |
|
|
break;
|
1159 |
|
|
case PROCESSOR_NIAGARA3:
|
1160 |
|
|
case PROCESSOR_NIAGARA4:
|
1161 |
|
|
sparc_costs = &niagara3_costs;
|
1162 |
|
|
break;
|
1163 |
|
|
case PROCESSOR_NATIVE:
|
1164 |
|
|
gcc_unreachable ();
|
1165 |
|
|
};
|
1166 |
|
|
|
1167 |
|
|
if (sparc_memory_model == SMM_DEFAULT)
|
1168 |
|
|
{
|
1169 |
|
|
/* Choose the memory model for the operating system. */
|
1170 |
|
|
enum sparc_memory_model_type os_default = SUBTARGET_DEFAULT_MEMORY_MODEL;
|
1171 |
|
|
if (os_default != SMM_DEFAULT)
|
1172 |
|
|
sparc_memory_model = os_default;
|
1173 |
|
|
/* Choose the most relaxed model for the processor. */
|
1174 |
|
|
else if (TARGET_V9)
|
1175 |
|
|
sparc_memory_model = SMM_RMO;
|
1176 |
|
|
else if (TARGET_V8)
|
1177 |
|
|
sparc_memory_model = SMM_PSO;
|
1178 |
|
|
else
|
1179 |
|
|
sparc_memory_model = SMM_SC;
|
1180 |
|
|
}
|
1181 |
|
|
|
1182 |
|
|
#ifdef TARGET_DEFAULT_LONG_DOUBLE_128
|
1183 |
|
|
if (!(target_flags_explicit & MASK_LONG_DOUBLE_128))
|
1184 |
|
|
target_flags |= MASK_LONG_DOUBLE_128;
|
1185 |
|
|
#endif
|
1186 |
|
|
|
1187 |
|
|
if (TARGET_DEBUG_OPTIONS)
|
1188 |
|
|
dump_target_flags ("Final target_flags", target_flags);
|
1189 |
|
|
|
1190 |
|
|
maybe_set_param_value (PARAM_SIMULTANEOUS_PREFETCHES,
|
1191 |
|
|
((sparc_cpu == PROCESSOR_ULTRASPARC
|
1192 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA
|
1193 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA2
|
1194 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA3
|
1195 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA4)
|
1196 |
|
|
? 2
|
1197 |
|
|
: (sparc_cpu == PROCESSOR_ULTRASPARC3
|
1198 |
|
|
? 8 : 3)),
|
1199 |
|
|
global_options.x_param_values,
|
1200 |
|
|
global_options_set.x_param_values);
|
1201 |
|
|
maybe_set_param_value (PARAM_L1_CACHE_LINE_SIZE,
|
1202 |
|
|
((sparc_cpu == PROCESSOR_ULTRASPARC
|
1203 |
|
|
|| sparc_cpu == PROCESSOR_ULTRASPARC3
|
1204 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA
|
1205 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA2
|
1206 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA3
|
1207 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA4)
|
1208 |
|
|
? 64 : 32),
|
1209 |
|
|
global_options.x_param_values,
|
1210 |
|
|
global_options_set.x_param_values);
|
1211 |
|
|
|
1212 |
|
|
/* Disable save slot sharing for call-clobbered registers by default.
|
1213 |
|
|
The IRA sharing algorithm works on single registers only and this
|
1214 |
|
|
pessimizes for double floating-point registers. */
|
1215 |
|
|
if (!global_options_set.x_flag_ira_share_save_slots)
|
1216 |
|
|
flag_ira_share_save_slots = 0;
|
1217 |
|
|
}
|
1218 |
|
|
|
1219 |
|
|
/* Miscellaneous utilities. */
|
1220 |
|
|
|
1221 |
|
|
/* Nonzero if CODE, a comparison, is suitable for use in v9 conditional move
|
1222 |
|
|
or branch on register contents instructions. */
|
1223 |
|
|
|
1224 |
|
|
int
|
1225 |
|
|
v9_regcmp_p (enum rtx_code code)
|
1226 |
|
|
{
|
1227 |
|
|
return (code == EQ || code == NE || code == GE || code == LT
|
1228 |
|
|
|| code == LE || code == GT);
|
1229 |
|
|
}
|
1230 |
|
|
|
1231 |
|
|
/* Nonzero if OP is a floating point constant which can
|
1232 |
|
|
be loaded into an integer register using a single
|
1233 |
|
|
sethi instruction. */
|
1234 |
|
|
|
1235 |
|
|
int
|
1236 |
|
|
fp_sethi_p (rtx op)
|
1237 |
|
|
{
|
1238 |
|
|
if (GET_CODE (op) == CONST_DOUBLE)
|
1239 |
|
|
{
|
1240 |
|
|
REAL_VALUE_TYPE r;
|
1241 |
|
|
long i;
|
1242 |
|
|
|
1243 |
|
|
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
|
1244 |
|
|
REAL_VALUE_TO_TARGET_SINGLE (r, i);
|
1245 |
|
|
return !SPARC_SIMM13_P (i) && SPARC_SETHI_P (i);
|
1246 |
|
|
}
|
1247 |
|
|
|
1248 |
|
|
return 0;
|
1249 |
|
|
}
|
1250 |
|
|
|
1251 |
|
|
/* Nonzero if OP is a floating point constant which can
|
1252 |
|
|
be loaded into an integer register using a single
|
1253 |
|
|
mov instruction. */
|
1254 |
|
|
|
1255 |
|
|
int
|
1256 |
|
|
fp_mov_p (rtx op)
|
1257 |
|
|
{
|
1258 |
|
|
if (GET_CODE (op) == CONST_DOUBLE)
|
1259 |
|
|
{
|
1260 |
|
|
REAL_VALUE_TYPE r;
|
1261 |
|
|
long i;
|
1262 |
|
|
|
1263 |
|
|
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
|
1264 |
|
|
REAL_VALUE_TO_TARGET_SINGLE (r, i);
|
1265 |
|
|
return SPARC_SIMM13_P (i);
|
1266 |
|
|
}
|
1267 |
|
|
|
1268 |
|
|
return 0;
|
1269 |
|
|
}
|
1270 |
|
|
|
1271 |
|
|
/* Nonzero if OP is a floating point constant which can
|
1272 |
|
|
be loaded into an integer register using a high/losum
|
1273 |
|
|
instruction sequence. */
|
1274 |
|
|
|
1275 |
|
|
int
|
1276 |
|
|
fp_high_losum_p (rtx op)
|
1277 |
|
|
{
|
1278 |
|
|
/* The constraints calling this should only be in
|
1279 |
|
|
SFmode move insns, so any constant which cannot
|
1280 |
|
|
be moved using a single insn will do. */
|
1281 |
|
|
if (GET_CODE (op) == CONST_DOUBLE)
|
1282 |
|
|
{
|
1283 |
|
|
REAL_VALUE_TYPE r;
|
1284 |
|
|
long i;
|
1285 |
|
|
|
1286 |
|
|
REAL_VALUE_FROM_CONST_DOUBLE (r, op);
|
1287 |
|
|
REAL_VALUE_TO_TARGET_SINGLE (r, i);
|
1288 |
|
|
return !SPARC_SIMM13_P (i) && !SPARC_SETHI_P (i);
|
1289 |
|
|
}
|
1290 |
|
|
|
1291 |
|
|
return 0;
|
1292 |
|
|
}
|
1293 |
|
|
|
1294 |
|
|
/* Return true if the address of LABEL can be loaded by means of the
|
1295 |
|
|
mov{si,di}_pic_label_ref patterns in PIC mode. */
|
1296 |
|
|
|
1297 |
|
|
static bool
|
1298 |
|
|
can_use_mov_pic_label_ref (rtx label)
|
1299 |
|
|
{
|
1300 |
|
|
/* VxWorks does not impose a fixed gap between segments; the run-time
|
1301 |
|
|
gap can be different from the object-file gap. We therefore can't
|
1302 |
|
|
assume X - _GLOBAL_OFFSET_TABLE_ is a link-time constant unless we
|
1303 |
|
|
are absolutely sure that X is in the same segment as the GOT.
|
1304 |
|
|
Unfortunately, the flexibility of linker scripts means that we
|
1305 |
|
|
can't be sure of that in general, so assume that GOT-relative
|
1306 |
|
|
accesses are never valid on VxWorks. */
|
1307 |
|
|
if (TARGET_VXWORKS_RTP)
|
1308 |
|
|
return false;
|
1309 |
|
|
|
1310 |
|
|
/* Similarly, if the label is non-local, it might end up being placed
|
1311 |
|
|
in a different section than the current one; now mov_pic_label_ref
|
1312 |
|
|
requires the label and the code to be in the same section. */
|
1313 |
|
|
if (LABEL_REF_NONLOCAL_P (label))
|
1314 |
|
|
return false;
|
1315 |
|
|
|
1316 |
|
|
/* Finally, if we are reordering basic blocks and partition into hot
|
1317 |
|
|
and cold sections, this might happen for any label. */
|
1318 |
|
|
if (flag_reorder_blocks_and_partition)
|
1319 |
|
|
return false;
|
1320 |
|
|
|
1321 |
|
|
return true;
|
1322 |
|
|
}
|
1323 |
|
|
|
1324 |
|
|
/* Expand a move instruction. Return true if all work is done. */
|
1325 |
|
|
|
1326 |
|
|
bool
|
1327 |
|
|
sparc_expand_move (enum machine_mode mode, rtx *operands)
|
1328 |
|
|
{
|
1329 |
|
|
/* Handle sets of MEM first. */
|
1330 |
|
|
if (GET_CODE (operands[0]) == MEM)
|
1331 |
|
|
{
|
1332 |
|
|
/* 0 is a register (or a pair of registers) on SPARC. */
|
1333 |
|
|
if (register_or_zero_operand (operands[1], mode))
|
1334 |
|
|
return false;
|
1335 |
|
|
|
1336 |
|
|
if (!reload_in_progress)
|
1337 |
|
|
{
|
1338 |
|
|
operands[0] = validize_mem (operands[0]);
|
1339 |
|
|
operands[1] = force_reg (mode, operands[1]);
|
1340 |
|
|
}
|
1341 |
|
|
}
|
1342 |
|
|
|
1343 |
|
|
/* Fixup TLS cases. */
|
1344 |
|
|
if (TARGET_HAVE_TLS
|
1345 |
|
|
&& CONSTANT_P (operands[1])
|
1346 |
|
|
&& sparc_tls_referenced_p (operands [1]))
|
1347 |
|
|
{
|
1348 |
|
|
operands[1] = sparc_legitimize_tls_address (operands[1]);
|
1349 |
|
|
return false;
|
1350 |
|
|
}
|
1351 |
|
|
|
1352 |
|
|
/* Fixup PIC cases. */
|
1353 |
|
|
if (flag_pic && CONSTANT_P (operands[1]))
|
1354 |
|
|
{
|
1355 |
|
|
if (pic_address_needs_scratch (operands[1]))
|
1356 |
|
|
operands[1] = sparc_legitimize_pic_address (operands[1], NULL_RTX);
|
1357 |
|
|
|
1358 |
|
|
/* We cannot use the mov{si,di}_pic_label_ref patterns in all cases. */
|
1359 |
|
|
if (GET_CODE (operands[1]) == LABEL_REF
|
1360 |
|
|
&& can_use_mov_pic_label_ref (operands[1]))
|
1361 |
|
|
{
|
1362 |
|
|
if (mode == SImode)
|
1363 |
|
|
{
|
1364 |
|
|
emit_insn (gen_movsi_pic_label_ref (operands[0], operands[1]));
|
1365 |
|
|
return true;
|
1366 |
|
|
}
|
1367 |
|
|
|
1368 |
|
|
if (mode == DImode)
|
1369 |
|
|
{
|
1370 |
|
|
gcc_assert (TARGET_ARCH64);
|
1371 |
|
|
emit_insn (gen_movdi_pic_label_ref (operands[0], operands[1]));
|
1372 |
|
|
return true;
|
1373 |
|
|
}
|
1374 |
|
|
}
|
1375 |
|
|
|
1376 |
|
|
if (symbolic_operand (operands[1], mode))
|
1377 |
|
|
{
|
1378 |
|
|
operands[1]
|
1379 |
|
|
= sparc_legitimize_pic_address (operands[1],
|
1380 |
|
|
reload_in_progress
|
1381 |
|
|
? operands[0] : NULL_RTX);
|
1382 |
|
|
return false;
|
1383 |
|
|
}
|
1384 |
|
|
}
|
1385 |
|
|
|
1386 |
|
|
/* If we are trying to toss an integer constant into FP registers,
|
1387 |
|
|
or loading a FP or vector constant, force it into memory. */
|
1388 |
|
|
if (CONSTANT_P (operands[1])
|
1389 |
|
|
&& REG_P (operands[0])
|
1390 |
|
|
&& (SPARC_FP_REG_P (REGNO (operands[0]))
|
1391 |
|
|
|| SCALAR_FLOAT_MODE_P (mode)
|
1392 |
|
|
|| VECTOR_MODE_P (mode)))
|
1393 |
|
|
{
|
1394 |
|
|
/* emit_group_store will send such bogosity to us when it is
|
1395 |
|
|
not storing directly into memory. So fix this up to avoid
|
1396 |
|
|
crashes in output_constant_pool. */
|
1397 |
|
|
if (operands [1] == const0_rtx)
|
1398 |
|
|
operands[1] = CONST0_RTX (mode);
|
1399 |
|
|
|
1400 |
|
|
/* We can clear or set to all-ones FP registers if TARGET_VIS, and
|
1401 |
|
|
always other regs. */
|
1402 |
|
|
if ((TARGET_VIS || REGNO (operands[0]) < SPARC_FIRST_FP_REG)
|
1403 |
|
|
&& (const_zero_operand (operands[1], mode)
|
1404 |
|
|
|| const_all_ones_operand (operands[1], mode)))
|
1405 |
|
|
return false;
|
1406 |
|
|
|
1407 |
|
|
if (REGNO (operands[0]) < SPARC_FIRST_FP_REG
|
1408 |
|
|
/* We are able to build any SF constant in integer registers
|
1409 |
|
|
with at most 2 instructions. */
|
1410 |
|
|
&& (mode == SFmode
|
1411 |
|
|
/* And any DF constant in integer registers. */
|
1412 |
|
|
|| (mode == DFmode
|
1413 |
|
|
&& ! can_create_pseudo_p ())))
|
1414 |
|
|
return false;
|
1415 |
|
|
|
1416 |
|
|
operands[1] = force_const_mem (mode, operands[1]);
|
1417 |
|
|
if (!reload_in_progress)
|
1418 |
|
|
operands[1] = validize_mem (operands[1]);
|
1419 |
|
|
return false;
|
1420 |
|
|
}
|
1421 |
|
|
|
1422 |
|
|
/* Accept non-constants and valid constants unmodified. */
|
1423 |
|
|
if (!CONSTANT_P (operands[1])
|
1424 |
|
|
|| GET_CODE (operands[1]) == HIGH
|
1425 |
|
|
|| input_operand (operands[1], mode))
|
1426 |
|
|
return false;
|
1427 |
|
|
|
1428 |
|
|
switch (mode)
|
1429 |
|
|
{
|
1430 |
|
|
case QImode:
|
1431 |
|
|
/* All QImode constants require only one insn, so proceed. */
|
1432 |
|
|
break;
|
1433 |
|
|
|
1434 |
|
|
case HImode:
|
1435 |
|
|
case SImode:
|
1436 |
|
|
sparc_emit_set_const32 (operands[0], operands[1]);
|
1437 |
|
|
return true;
|
1438 |
|
|
|
1439 |
|
|
case DImode:
|
1440 |
|
|
/* input_operand should have filtered out 32-bit mode. */
|
1441 |
|
|
sparc_emit_set_const64 (operands[0], operands[1]);
|
1442 |
|
|
return true;
|
1443 |
|
|
|
1444 |
|
|
default:
|
1445 |
|
|
gcc_unreachable ();
|
1446 |
|
|
}
|
1447 |
|
|
|
1448 |
|
|
return false;
|
1449 |
|
|
}
|
1450 |
|
|
|
1451 |
|
|
/* Load OP1, a 32-bit constant, into OP0, a register.
|
1452 |
|
|
We know it can't be done in one insn when we get
|
1453 |
|
|
here, the move expander guarantees this. */
|
1454 |
|
|
|
1455 |
|
|
static void
|
1456 |
|
|
sparc_emit_set_const32 (rtx op0, rtx op1)
|
1457 |
|
|
{
|
1458 |
|
|
enum machine_mode mode = GET_MODE (op0);
|
1459 |
|
|
rtx temp = op0;
|
1460 |
|
|
|
1461 |
|
|
if (can_create_pseudo_p ())
|
1462 |
|
|
temp = gen_reg_rtx (mode);
|
1463 |
|
|
|
1464 |
|
|
if (GET_CODE (op1) == CONST_INT)
|
1465 |
|
|
{
|
1466 |
|
|
gcc_assert (!small_int_operand (op1, mode)
|
1467 |
|
|
&& !const_high_operand (op1, mode));
|
1468 |
|
|
|
1469 |
|
|
/* Emit them as real moves instead of a HIGH/LO_SUM,
|
1470 |
|
|
this way CSE can see everything and reuse intermediate
|
1471 |
|
|
values if it wants. */
|
1472 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp,
|
1473 |
|
|
GEN_INT (INTVAL (op1)
|
1474 |
|
|
& ~(HOST_WIDE_INT)0x3ff)));
|
1475 |
|
|
|
1476 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
1477 |
|
|
op0,
|
1478 |
|
|
gen_rtx_IOR (mode, temp,
|
1479 |
|
|
GEN_INT (INTVAL (op1) & 0x3ff))));
|
1480 |
|
|
}
|
1481 |
|
|
else
|
1482 |
|
|
{
|
1483 |
|
|
/* A symbol, emit in the traditional way. */
|
1484 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp,
|
1485 |
|
|
gen_rtx_HIGH (mode, op1)));
|
1486 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
1487 |
|
|
op0, gen_rtx_LO_SUM (mode, temp, op1)));
|
1488 |
|
|
}
|
1489 |
|
|
}
|
1490 |
|
|
|
1491 |
|
|
/* Load OP1, a symbolic 64-bit constant, into OP0, a DImode register.
|
1492 |
|
|
If TEMP is nonzero, we are forbidden to use any other scratch
|
1493 |
|
|
registers. Otherwise, we are allowed to generate them as needed.
|
1494 |
|
|
|
1495 |
|
|
Note that TEMP may have TImode if the code model is TARGET_CM_MEDANY
|
1496 |
|
|
or TARGET_CM_EMBMEDANY (see the reload_indi and reload_outdi patterns). */
|
1497 |
|
|
|
1498 |
|
|
void
|
1499 |
|
|
sparc_emit_set_symbolic_const64 (rtx op0, rtx op1, rtx temp)
|
1500 |
|
|
{
|
1501 |
|
|
rtx temp1, temp2, temp3, temp4, temp5;
|
1502 |
|
|
rtx ti_temp = 0;
|
1503 |
|
|
|
1504 |
|
|
if (temp && GET_MODE (temp) == TImode)
|
1505 |
|
|
{
|
1506 |
|
|
ti_temp = temp;
|
1507 |
|
|
temp = gen_rtx_REG (DImode, REGNO (temp));
|
1508 |
|
|
}
|
1509 |
|
|
|
1510 |
|
|
/* SPARC-V9 code-model support. */
|
1511 |
|
|
switch (sparc_cmodel)
|
1512 |
|
|
{
|
1513 |
|
|
case CM_MEDLOW:
|
1514 |
|
|
/* The range spanned by all instructions in the object is less
|
1515 |
|
|
than 2^31 bytes (2GB) and the distance from any instruction
|
1516 |
|
|
to the location of the label _GLOBAL_OFFSET_TABLE_ is less
|
1517 |
|
|
than 2^31 bytes (2GB).
|
1518 |
|
|
|
1519 |
|
|
The executable must be in the low 4TB of the virtual address
|
1520 |
|
|
space.
|
1521 |
|
|
|
1522 |
|
|
sethi %hi(symbol), %temp1
|
1523 |
|
|
or %temp1, %lo(symbol), %reg */
|
1524 |
|
|
if (temp)
|
1525 |
|
|
temp1 = temp; /* op0 is allowed. */
|
1526 |
|
|
else
|
1527 |
|
|
temp1 = gen_reg_rtx (DImode);
|
1528 |
|
|
|
1529 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp1, gen_rtx_HIGH (DImode, op1)));
|
1530 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0, gen_rtx_LO_SUM (DImode, temp1, op1)));
|
1531 |
|
|
break;
|
1532 |
|
|
|
1533 |
|
|
case CM_MEDMID:
|
1534 |
|
|
/* The range spanned by all instructions in the object is less
|
1535 |
|
|
than 2^31 bytes (2GB) and the distance from any instruction
|
1536 |
|
|
to the location of the label _GLOBAL_OFFSET_TABLE_ is less
|
1537 |
|
|
than 2^31 bytes (2GB).
|
1538 |
|
|
|
1539 |
|
|
The executable must be in the low 16TB of the virtual address
|
1540 |
|
|
space.
|
1541 |
|
|
|
1542 |
|
|
sethi %h44(symbol), %temp1
|
1543 |
|
|
or %temp1, %m44(symbol), %temp2
|
1544 |
|
|
sllx %temp2, 12, %temp3
|
1545 |
|
|
or %temp3, %l44(symbol), %reg */
|
1546 |
|
|
if (temp)
|
1547 |
|
|
{
|
1548 |
|
|
temp1 = op0;
|
1549 |
|
|
temp2 = op0;
|
1550 |
|
|
temp3 = temp; /* op0 is allowed. */
|
1551 |
|
|
}
|
1552 |
|
|
else
|
1553 |
|
|
{
|
1554 |
|
|
temp1 = gen_reg_rtx (DImode);
|
1555 |
|
|
temp2 = gen_reg_rtx (DImode);
|
1556 |
|
|
temp3 = gen_reg_rtx (DImode);
|
1557 |
|
|
}
|
1558 |
|
|
|
1559 |
|
|
emit_insn (gen_seth44 (temp1, op1));
|
1560 |
|
|
emit_insn (gen_setm44 (temp2, temp1, op1));
|
1561 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp3,
|
1562 |
|
|
gen_rtx_ASHIFT (DImode, temp2, GEN_INT (12))));
|
1563 |
|
|
emit_insn (gen_setl44 (op0, temp3, op1));
|
1564 |
|
|
break;
|
1565 |
|
|
|
1566 |
|
|
case CM_MEDANY:
|
1567 |
|
|
/* The range spanned by all instructions in the object is less
|
1568 |
|
|
than 2^31 bytes (2GB) and the distance from any instruction
|
1569 |
|
|
to the location of the label _GLOBAL_OFFSET_TABLE_ is less
|
1570 |
|
|
than 2^31 bytes (2GB).
|
1571 |
|
|
|
1572 |
|
|
The executable can be placed anywhere in the virtual address
|
1573 |
|
|
space.
|
1574 |
|
|
|
1575 |
|
|
sethi %hh(symbol), %temp1
|
1576 |
|
|
sethi %lm(symbol), %temp2
|
1577 |
|
|
or %temp1, %hm(symbol), %temp3
|
1578 |
|
|
sllx %temp3, 32, %temp4
|
1579 |
|
|
or %temp4, %temp2, %temp5
|
1580 |
|
|
or %temp5, %lo(symbol), %reg */
|
1581 |
|
|
if (temp)
|
1582 |
|
|
{
|
1583 |
|
|
/* It is possible that one of the registers we got for operands[2]
|
1584 |
|
|
might coincide with that of operands[0] (which is why we made
|
1585 |
|
|
it TImode). Pick the other one to use as our scratch. */
|
1586 |
|
|
if (rtx_equal_p (temp, op0))
|
1587 |
|
|
{
|
1588 |
|
|
gcc_assert (ti_temp);
|
1589 |
|
|
temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
|
1590 |
|
|
}
|
1591 |
|
|
temp1 = op0;
|
1592 |
|
|
temp2 = temp; /* op0 is _not_ allowed, see above. */
|
1593 |
|
|
temp3 = op0;
|
1594 |
|
|
temp4 = op0;
|
1595 |
|
|
temp5 = op0;
|
1596 |
|
|
}
|
1597 |
|
|
else
|
1598 |
|
|
{
|
1599 |
|
|
temp1 = gen_reg_rtx (DImode);
|
1600 |
|
|
temp2 = gen_reg_rtx (DImode);
|
1601 |
|
|
temp3 = gen_reg_rtx (DImode);
|
1602 |
|
|
temp4 = gen_reg_rtx (DImode);
|
1603 |
|
|
temp5 = gen_reg_rtx (DImode);
|
1604 |
|
|
}
|
1605 |
|
|
|
1606 |
|
|
emit_insn (gen_sethh (temp1, op1));
|
1607 |
|
|
emit_insn (gen_setlm (temp2, op1));
|
1608 |
|
|
emit_insn (gen_sethm (temp3, temp1, op1));
|
1609 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp4,
|
1610 |
|
|
gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32))));
|
1611 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp5,
|
1612 |
|
|
gen_rtx_PLUS (DImode, temp4, temp2)));
|
1613 |
|
|
emit_insn (gen_setlo (op0, temp5, op1));
|
1614 |
|
|
break;
|
1615 |
|
|
|
1616 |
|
|
case CM_EMBMEDANY:
|
1617 |
|
|
/* Old old old backwards compatibility kruft here.
|
1618 |
|
|
Essentially it is MEDLOW with a fixed 64-bit
|
1619 |
|
|
virtual base added to all data segment addresses.
|
1620 |
|
|
Text-segment stuff is computed like MEDANY, we can't
|
1621 |
|
|
reuse the code above because the relocation knobs
|
1622 |
|
|
look different.
|
1623 |
|
|
|
1624 |
|
|
Data segment: sethi %hi(symbol), %temp1
|
1625 |
|
|
add %temp1, EMBMEDANY_BASE_REG, %temp2
|
1626 |
|
|
or %temp2, %lo(symbol), %reg */
|
1627 |
|
|
if (data_segment_operand (op1, GET_MODE (op1)))
|
1628 |
|
|
{
|
1629 |
|
|
if (temp)
|
1630 |
|
|
{
|
1631 |
|
|
temp1 = temp; /* op0 is allowed. */
|
1632 |
|
|
temp2 = op0;
|
1633 |
|
|
}
|
1634 |
|
|
else
|
1635 |
|
|
{
|
1636 |
|
|
temp1 = gen_reg_rtx (DImode);
|
1637 |
|
|
temp2 = gen_reg_rtx (DImode);
|
1638 |
|
|
}
|
1639 |
|
|
|
1640 |
|
|
emit_insn (gen_embmedany_sethi (temp1, op1));
|
1641 |
|
|
emit_insn (gen_embmedany_brsum (temp2, temp1));
|
1642 |
|
|
emit_insn (gen_embmedany_losum (op0, temp2, op1));
|
1643 |
|
|
}
|
1644 |
|
|
|
1645 |
|
|
/* Text segment: sethi %uhi(symbol), %temp1
|
1646 |
|
|
sethi %hi(symbol), %temp2
|
1647 |
|
|
or %temp1, %ulo(symbol), %temp3
|
1648 |
|
|
sllx %temp3, 32, %temp4
|
1649 |
|
|
or %temp4, %temp2, %temp5
|
1650 |
|
|
or %temp5, %lo(symbol), %reg */
|
1651 |
|
|
else
|
1652 |
|
|
{
|
1653 |
|
|
if (temp)
|
1654 |
|
|
{
|
1655 |
|
|
/* It is possible that one of the registers we got for operands[2]
|
1656 |
|
|
might coincide with that of operands[0] (which is why we made
|
1657 |
|
|
it TImode). Pick the other one to use as our scratch. */
|
1658 |
|
|
if (rtx_equal_p (temp, op0))
|
1659 |
|
|
{
|
1660 |
|
|
gcc_assert (ti_temp);
|
1661 |
|
|
temp = gen_rtx_REG (DImode, REGNO (temp) + 1);
|
1662 |
|
|
}
|
1663 |
|
|
temp1 = op0;
|
1664 |
|
|
temp2 = temp; /* op0 is _not_ allowed, see above. */
|
1665 |
|
|
temp3 = op0;
|
1666 |
|
|
temp4 = op0;
|
1667 |
|
|
temp5 = op0;
|
1668 |
|
|
}
|
1669 |
|
|
else
|
1670 |
|
|
{
|
1671 |
|
|
temp1 = gen_reg_rtx (DImode);
|
1672 |
|
|
temp2 = gen_reg_rtx (DImode);
|
1673 |
|
|
temp3 = gen_reg_rtx (DImode);
|
1674 |
|
|
temp4 = gen_reg_rtx (DImode);
|
1675 |
|
|
temp5 = gen_reg_rtx (DImode);
|
1676 |
|
|
}
|
1677 |
|
|
|
1678 |
|
|
emit_insn (gen_embmedany_textuhi (temp1, op1));
|
1679 |
|
|
emit_insn (gen_embmedany_texthi (temp2, op1));
|
1680 |
|
|
emit_insn (gen_embmedany_textulo (temp3, temp1, op1));
|
1681 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp4,
|
1682 |
|
|
gen_rtx_ASHIFT (DImode, temp3, GEN_INT (32))));
|
1683 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp5,
|
1684 |
|
|
gen_rtx_PLUS (DImode, temp4, temp2)));
|
1685 |
|
|
emit_insn (gen_embmedany_textlo (op0, temp5, op1));
|
1686 |
|
|
}
|
1687 |
|
|
break;
|
1688 |
|
|
|
1689 |
|
|
default:
|
1690 |
|
|
gcc_unreachable ();
|
1691 |
|
|
}
|
1692 |
|
|
}
|
1693 |
|
|
|
1694 |
|
|
#if HOST_BITS_PER_WIDE_INT == 32
|
1695 |
|
|
static void
|
1696 |
|
|
sparc_emit_set_const64 (rtx op0 ATTRIBUTE_UNUSED, rtx op1 ATTRIBUTE_UNUSED)
|
1697 |
|
|
{
|
1698 |
|
|
gcc_unreachable ();
|
1699 |
|
|
}
|
1700 |
|
|
#else
|
1701 |
|
|
/* These avoid problems when cross compiling. If we do not
|
1702 |
|
|
go through all this hair then the optimizer will see
|
1703 |
|
|
invalid REG_EQUAL notes or in some cases none at all. */
|
1704 |
|
|
static rtx gen_safe_HIGH64 (rtx, HOST_WIDE_INT);
|
1705 |
|
|
static rtx gen_safe_SET64 (rtx, HOST_WIDE_INT);
|
1706 |
|
|
static rtx gen_safe_OR64 (rtx, HOST_WIDE_INT);
|
1707 |
|
|
static rtx gen_safe_XOR64 (rtx, HOST_WIDE_INT);
|
1708 |
|
|
|
1709 |
|
|
/* The optimizer is not to assume anything about exactly
|
1710 |
|
|
which bits are set for a HIGH, they are unspecified.
|
1711 |
|
|
Unfortunately this leads to many missed optimizations
|
1712 |
|
|
during CSE. We mask out the non-HIGH bits, and matches
|
1713 |
|
|
a plain movdi, to alleviate this problem. */
|
1714 |
|
|
static rtx
|
1715 |
|
|
gen_safe_HIGH64 (rtx dest, HOST_WIDE_INT val)
|
1716 |
|
|
{
|
1717 |
|
|
return gen_rtx_SET (VOIDmode, dest, GEN_INT (val & ~(HOST_WIDE_INT)0x3ff));
|
1718 |
|
|
}
|
1719 |
|
|
|
1720 |
|
|
static rtx
|
1721 |
|
|
gen_safe_SET64 (rtx dest, HOST_WIDE_INT val)
|
1722 |
|
|
{
|
1723 |
|
|
return gen_rtx_SET (VOIDmode, dest, GEN_INT (val));
|
1724 |
|
|
}
|
1725 |
|
|
|
1726 |
|
|
static rtx
|
1727 |
|
|
gen_safe_OR64 (rtx src, HOST_WIDE_INT val)
|
1728 |
|
|
{
|
1729 |
|
|
return gen_rtx_IOR (DImode, src, GEN_INT (val));
|
1730 |
|
|
}
|
1731 |
|
|
|
1732 |
|
|
static rtx
|
1733 |
|
|
gen_safe_XOR64 (rtx src, HOST_WIDE_INT val)
|
1734 |
|
|
{
|
1735 |
|
|
return gen_rtx_XOR (DImode, src, GEN_INT (val));
|
1736 |
|
|
}
|
1737 |
|
|
|
1738 |
|
|
/* Worker routines for 64-bit constant formation on arch64.
|
1739 |
|
|
One of the key things to be doing in these emissions is
|
1740 |
|
|
to create as many temp REGs as possible. This makes it
|
1741 |
|
|
possible for half-built constants to be used later when
|
1742 |
|
|
such values are similar to something required later on.
|
1743 |
|
|
Without doing this, the optimizer cannot see such
|
1744 |
|
|
opportunities. */
|
1745 |
|
|
|
1746 |
|
|
static void sparc_emit_set_const64_quick1 (rtx, rtx,
|
1747 |
|
|
unsigned HOST_WIDE_INT, int);
|
1748 |
|
|
|
1749 |
|
|
static void
|
1750 |
|
|
sparc_emit_set_const64_quick1 (rtx op0, rtx temp,
|
1751 |
|
|
unsigned HOST_WIDE_INT low_bits, int is_neg)
|
1752 |
|
|
{
|
1753 |
|
|
unsigned HOST_WIDE_INT high_bits;
|
1754 |
|
|
|
1755 |
|
|
if (is_neg)
|
1756 |
|
|
high_bits = (~low_bits) & 0xffffffff;
|
1757 |
|
|
else
|
1758 |
|
|
high_bits = low_bits;
|
1759 |
|
|
|
1760 |
|
|
emit_insn (gen_safe_HIGH64 (temp, high_bits));
|
1761 |
|
|
if (!is_neg)
|
1762 |
|
|
{
|
1763 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1764 |
|
|
gen_safe_OR64 (temp, (high_bits & 0x3ff))));
|
1765 |
|
|
}
|
1766 |
|
|
else
|
1767 |
|
|
{
|
1768 |
|
|
/* If we are XOR'ing with -1, then we should emit a one's complement
|
1769 |
|
|
instead. This way the combiner will notice logical operations
|
1770 |
|
|
such as ANDN later on and substitute. */
|
1771 |
|
|
if ((low_bits & 0x3ff) == 0x3ff)
|
1772 |
|
|
{
|
1773 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1774 |
|
|
gen_rtx_NOT (DImode, temp)));
|
1775 |
|
|
}
|
1776 |
|
|
else
|
1777 |
|
|
{
|
1778 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1779 |
|
|
gen_safe_XOR64 (temp,
|
1780 |
|
|
(-(HOST_WIDE_INT)0x400
|
1781 |
|
|
| (low_bits & 0x3ff)))));
|
1782 |
|
|
}
|
1783 |
|
|
}
|
1784 |
|
|
}
|
1785 |
|
|
|
1786 |
|
|
static void sparc_emit_set_const64_quick2 (rtx, rtx, unsigned HOST_WIDE_INT,
|
1787 |
|
|
unsigned HOST_WIDE_INT, int);
|
1788 |
|
|
|
1789 |
|
|
static void
|
1790 |
|
|
sparc_emit_set_const64_quick2 (rtx op0, rtx temp,
|
1791 |
|
|
unsigned HOST_WIDE_INT high_bits,
|
1792 |
|
|
unsigned HOST_WIDE_INT low_immediate,
|
1793 |
|
|
int shift_count)
|
1794 |
|
|
{
|
1795 |
|
|
rtx temp2 = op0;
|
1796 |
|
|
|
1797 |
|
|
if ((high_bits & 0xfffffc00) != 0)
|
1798 |
|
|
{
|
1799 |
|
|
emit_insn (gen_safe_HIGH64 (temp, high_bits));
|
1800 |
|
|
if ((high_bits & ~0xfffffc00) != 0)
|
1801 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1802 |
|
|
gen_safe_OR64 (temp, (high_bits & 0x3ff))));
|
1803 |
|
|
else
|
1804 |
|
|
temp2 = temp;
|
1805 |
|
|
}
|
1806 |
|
|
else
|
1807 |
|
|
{
|
1808 |
|
|
emit_insn (gen_safe_SET64 (temp, high_bits));
|
1809 |
|
|
temp2 = temp;
|
1810 |
|
|
}
|
1811 |
|
|
|
1812 |
|
|
/* Now shift it up into place. */
|
1813 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1814 |
|
|
gen_rtx_ASHIFT (DImode, temp2,
|
1815 |
|
|
GEN_INT (shift_count))));
|
1816 |
|
|
|
1817 |
|
|
/* If there is a low immediate part piece, finish up by
|
1818 |
|
|
putting that in as well. */
|
1819 |
|
|
if (low_immediate != 0)
|
1820 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1821 |
|
|
gen_safe_OR64 (op0, low_immediate)));
|
1822 |
|
|
}
|
1823 |
|
|
|
1824 |
|
|
static void sparc_emit_set_const64_longway (rtx, rtx, unsigned HOST_WIDE_INT,
|
1825 |
|
|
unsigned HOST_WIDE_INT);
|
1826 |
|
|
|
1827 |
|
|
/* Full 64-bit constant decomposition. Even though this is the
|
1828 |
|
|
'worst' case, we still optimize a few things away. */
|
1829 |
|
|
static void
|
1830 |
|
|
sparc_emit_set_const64_longway (rtx op0, rtx temp,
|
1831 |
|
|
unsigned HOST_WIDE_INT high_bits,
|
1832 |
|
|
unsigned HOST_WIDE_INT low_bits)
|
1833 |
|
|
{
|
1834 |
|
|
rtx sub_temp = op0;
|
1835 |
|
|
|
1836 |
|
|
if (can_create_pseudo_p ())
|
1837 |
|
|
sub_temp = gen_reg_rtx (DImode);
|
1838 |
|
|
|
1839 |
|
|
if ((high_bits & 0xfffffc00) != 0)
|
1840 |
|
|
{
|
1841 |
|
|
emit_insn (gen_safe_HIGH64 (temp, high_bits));
|
1842 |
|
|
if ((high_bits & ~0xfffffc00) != 0)
|
1843 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
1844 |
|
|
sub_temp,
|
1845 |
|
|
gen_safe_OR64 (temp, (high_bits & 0x3ff))));
|
1846 |
|
|
else
|
1847 |
|
|
sub_temp = temp;
|
1848 |
|
|
}
|
1849 |
|
|
else
|
1850 |
|
|
{
|
1851 |
|
|
emit_insn (gen_safe_SET64 (temp, high_bits));
|
1852 |
|
|
sub_temp = temp;
|
1853 |
|
|
}
|
1854 |
|
|
|
1855 |
|
|
if (can_create_pseudo_p ())
|
1856 |
|
|
{
|
1857 |
|
|
rtx temp2 = gen_reg_rtx (DImode);
|
1858 |
|
|
rtx temp3 = gen_reg_rtx (DImode);
|
1859 |
|
|
rtx temp4 = gen_reg_rtx (DImode);
|
1860 |
|
|
|
1861 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp4,
|
1862 |
|
|
gen_rtx_ASHIFT (DImode, sub_temp,
|
1863 |
|
|
GEN_INT (32))));
|
1864 |
|
|
|
1865 |
|
|
emit_insn (gen_safe_HIGH64 (temp2, low_bits));
|
1866 |
|
|
if ((low_bits & ~0xfffffc00) != 0)
|
1867 |
|
|
{
|
1868 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, temp3,
|
1869 |
|
|
gen_safe_OR64 (temp2, (low_bits & 0x3ff))));
|
1870 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1871 |
|
|
gen_rtx_PLUS (DImode, temp4, temp3)));
|
1872 |
|
|
}
|
1873 |
|
|
else
|
1874 |
|
|
{
|
1875 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1876 |
|
|
gen_rtx_PLUS (DImode, temp4, temp2)));
|
1877 |
|
|
}
|
1878 |
|
|
}
|
1879 |
|
|
else
|
1880 |
|
|
{
|
1881 |
|
|
rtx low1 = GEN_INT ((low_bits >> (32 - 12)) & 0xfff);
|
1882 |
|
|
rtx low2 = GEN_INT ((low_bits >> (32 - 12 - 12)) & 0xfff);
|
1883 |
|
|
rtx low3 = GEN_INT ((low_bits >> (32 - 12 - 12 - 8)) & 0x0ff);
|
1884 |
|
|
int to_shift = 12;
|
1885 |
|
|
|
1886 |
|
|
/* We are in the middle of reload, so this is really
|
1887 |
|
|
painful. However we do still make an attempt to
|
1888 |
|
|
avoid emitting truly stupid code. */
|
1889 |
|
|
if (low1 != const0_rtx)
|
1890 |
|
|
{
|
1891 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1892 |
|
|
gen_rtx_ASHIFT (DImode, sub_temp,
|
1893 |
|
|
GEN_INT (to_shift))));
|
1894 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1895 |
|
|
gen_rtx_IOR (DImode, op0, low1)));
|
1896 |
|
|
sub_temp = op0;
|
1897 |
|
|
to_shift = 12;
|
1898 |
|
|
}
|
1899 |
|
|
else
|
1900 |
|
|
{
|
1901 |
|
|
to_shift += 12;
|
1902 |
|
|
}
|
1903 |
|
|
if (low2 != const0_rtx)
|
1904 |
|
|
{
|
1905 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1906 |
|
|
gen_rtx_ASHIFT (DImode, sub_temp,
|
1907 |
|
|
GEN_INT (to_shift))));
|
1908 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1909 |
|
|
gen_rtx_IOR (DImode, op0, low2)));
|
1910 |
|
|
sub_temp = op0;
|
1911 |
|
|
to_shift = 8;
|
1912 |
|
|
}
|
1913 |
|
|
else
|
1914 |
|
|
{
|
1915 |
|
|
to_shift += 8;
|
1916 |
|
|
}
|
1917 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1918 |
|
|
gen_rtx_ASHIFT (DImode, sub_temp,
|
1919 |
|
|
GEN_INT (to_shift))));
|
1920 |
|
|
if (low3 != const0_rtx)
|
1921 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
1922 |
|
|
gen_rtx_IOR (DImode, op0, low3)));
|
1923 |
|
|
/* phew... */
|
1924 |
|
|
}
|
1925 |
|
|
}
|
1926 |
|
|
|
1927 |
|
|
/* Analyze a 64-bit constant for certain properties. */
|
1928 |
|
|
static void analyze_64bit_constant (unsigned HOST_WIDE_INT,
|
1929 |
|
|
unsigned HOST_WIDE_INT,
|
1930 |
|
|
int *, int *, int *);
|
1931 |
|
|
|
1932 |
|
|
static void
|
1933 |
|
|
analyze_64bit_constant (unsigned HOST_WIDE_INT high_bits,
|
1934 |
|
|
unsigned HOST_WIDE_INT low_bits,
|
1935 |
|
|
int *hbsp, int *lbsp, int *abbasp)
|
1936 |
|
|
{
|
1937 |
|
|
int lowest_bit_set, highest_bit_set, all_bits_between_are_set;
|
1938 |
|
|
int i;
|
1939 |
|
|
|
1940 |
|
|
lowest_bit_set = highest_bit_set = -1;
|
1941 |
|
|
i = 0;
|
1942 |
|
|
do
|
1943 |
|
|
{
|
1944 |
|
|
if ((lowest_bit_set == -1)
|
1945 |
|
|
&& ((low_bits >> i) & 1))
|
1946 |
|
|
lowest_bit_set = i;
|
1947 |
|
|
if ((highest_bit_set == -1)
|
1948 |
|
|
&& ((high_bits >> (32 - i - 1)) & 1))
|
1949 |
|
|
highest_bit_set = (64 - i - 1);
|
1950 |
|
|
}
|
1951 |
|
|
while (++i < 32
|
1952 |
|
|
&& ((highest_bit_set == -1)
|
1953 |
|
|
|| (lowest_bit_set == -1)));
|
1954 |
|
|
if (i == 32)
|
1955 |
|
|
{
|
1956 |
|
|
i = 0;
|
1957 |
|
|
do
|
1958 |
|
|
{
|
1959 |
|
|
if ((lowest_bit_set == -1)
|
1960 |
|
|
&& ((high_bits >> i) & 1))
|
1961 |
|
|
lowest_bit_set = i + 32;
|
1962 |
|
|
if ((highest_bit_set == -1)
|
1963 |
|
|
&& ((low_bits >> (32 - i - 1)) & 1))
|
1964 |
|
|
highest_bit_set = 32 - i - 1;
|
1965 |
|
|
}
|
1966 |
|
|
while (++i < 32
|
1967 |
|
|
&& ((highest_bit_set == -1)
|
1968 |
|
|
|| (lowest_bit_set == -1)));
|
1969 |
|
|
}
|
1970 |
|
|
/* If there are no bits set this should have gone out
|
1971 |
|
|
as one instruction! */
|
1972 |
|
|
gcc_assert (lowest_bit_set != -1 && highest_bit_set != -1);
|
1973 |
|
|
all_bits_between_are_set = 1;
|
1974 |
|
|
for (i = lowest_bit_set; i <= highest_bit_set; i++)
|
1975 |
|
|
{
|
1976 |
|
|
if (i < 32)
|
1977 |
|
|
{
|
1978 |
|
|
if ((low_bits & (1 << i)) != 0)
|
1979 |
|
|
continue;
|
1980 |
|
|
}
|
1981 |
|
|
else
|
1982 |
|
|
{
|
1983 |
|
|
if ((high_bits & (1 << (i - 32))) != 0)
|
1984 |
|
|
continue;
|
1985 |
|
|
}
|
1986 |
|
|
all_bits_between_are_set = 0;
|
1987 |
|
|
break;
|
1988 |
|
|
}
|
1989 |
|
|
*hbsp = highest_bit_set;
|
1990 |
|
|
*lbsp = lowest_bit_set;
|
1991 |
|
|
*abbasp = all_bits_between_are_set;
|
1992 |
|
|
}
|
1993 |
|
|
|
1994 |
|
|
static int const64_is_2insns (unsigned HOST_WIDE_INT, unsigned HOST_WIDE_INT);
|
1995 |
|
|
|
1996 |
|
|
static int
|
1997 |
|
|
const64_is_2insns (unsigned HOST_WIDE_INT high_bits,
|
1998 |
|
|
unsigned HOST_WIDE_INT low_bits)
|
1999 |
|
|
{
|
2000 |
|
|
int highest_bit_set, lowest_bit_set, all_bits_between_are_set;
|
2001 |
|
|
|
2002 |
|
|
if (high_bits == 0
|
2003 |
|
|
|| high_bits == 0xffffffff)
|
2004 |
|
|
return 1;
|
2005 |
|
|
|
2006 |
|
|
analyze_64bit_constant (high_bits, low_bits,
|
2007 |
|
|
&highest_bit_set, &lowest_bit_set,
|
2008 |
|
|
&all_bits_between_are_set);
|
2009 |
|
|
|
2010 |
|
|
if ((highest_bit_set == 63
|
2011 |
|
|
|| lowest_bit_set == 0)
|
2012 |
|
|
&& all_bits_between_are_set != 0)
|
2013 |
|
|
return 1;
|
2014 |
|
|
|
2015 |
|
|
if ((highest_bit_set - lowest_bit_set) < 21)
|
2016 |
|
|
return 1;
|
2017 |
|
|
|
2018 |
|
|
return 0;
|
2019 |
|
|
}
|
2020 |
|
|
|
2021 |
|
|
static unsigned HOST_WIDE_INT create_simple_focus_bits (unsigned HOST_WIDE_INT,
|
2022 |
|
|
unsigned HOST_WIDE_INT,
|
2023 |
|
|
int, int);
|
2024 |
|
|
|
2025 |
|
|
static unsigned HOST_WIDE_INT
|
2026 |
|
|
create_simple_focus_bits (unsigned HOST_WIDE_INT high_bits,
|
2027 |
|
|
unsigned HOST_WIDE_INT low_bits,
|
2028 |
|
|
int lowest_bit_set, int shift)
|
2029 |
|
|
{
|
2030 |
|
|
HOST_WIDE_INT hi, lo;
|
2031 |
|
|
|
2032 |
|
|
if (lowest_bit_set < 32)
|
2033 |
|
|
{
|
2034 |
|
|
lo = (low_bits >> lowest_bit_set) << shift;
|
2035 |
|
|
hi = ((high_bits << (32 - lowest_bit_set)) << shift);
|
2036 |
|
|
}
|
2037 |
|
|
else
|
2038 |
|
|
{
|
2039 |
|
|
lo = 0;
|
2040 |
|
|
hi = ((high_bits >> (lowest_bit_set - 32)) << shift);
|
2041 |
|
|
}
|
2042 |
|
|
gcc_assert (! (hi & lo));
|
2043 |
|
|
return (hi | lo);
|
2044 |
|
|
}
|
2045 |
|
|
|
2046 |
|
|
/* Here we are sure to be arch64 and this is an integer constant
|
2047 |
|
|
being loaded into a register. Emit the most efficient
|
2048 |
|
|
insn sequence possible. Detection of all the 1-insn cases
|
2049 |
|
|
has been done already. */
|
2050 |
|
|
static void
|
2051 |
|
|
sparc_emit_set_const64 (rtx op0, rtx op1)
|
2052 |
|
|
{
|
2053 |
|
|
unsigned HOST_WIDE_INT high_bits, low_bits;
|
2054 |
|
|
int lowest_bit_set, highest_bit_set;
|
2055 |
|
|
int all_bits_between_are_set;
|
2056 |
|
|
rtx temp = 0;
|
2057 |
|
|
|
2058 |
|
|
/* Sanity check that we know what we are working with. */
|
2059 |
|
|
gcc_assert (TARGET_ARCH64
|
2060 |
|
|
&& (GET_CODE (op0) == SUBREG
|
2061 |
|
|
|| (REG_P (op0) && ! SPARC_FP_REG_P (REGNO (op0)))));
|
2062 |
|
|
|
2063 |
|
|
if (! can_create_pseudo_p ())
|
2064 |
|
|
temp = op0;
|
2065 |
|
|
|
2066 |
|
|
if (GET_CODE (op1) != CONST_INT)
|
2067 |
|
|
{
|
2068 |
|
|
sparc_emit_set_symbolic_const64 (op0, op1, temp);
|
2069 |
|
|
return;
|
2070 |
|
|
}
|
2071 |
|
|
|
2072 |
|
|
if (! temp)
|
2073 |
|
|
temp = gen_reg_rtx (DImode);
|
2074 |
|
|
|
2075 |
|
|
high_bits = ((INTVAL (op1) >> 32) & 0xffffffff);
|
2076 |
|
|
low_bits = (INTVAL (op1) & 0xffffffff);
|
2077 |
|
|
|
2078 |
|
|
/* low_bits bits 0 --> 31
|
2079 |
|
|
high_bits bits 32 --> 63 */
|
2080 |
|
|
|
2081 |
|
|
analyze_64bit_constant (high_bits, low_bits,
|
2082 |
|
|
&highest_bit_set, &lowest_bit_set,
|
2083 |
|
|
&all_bits_between_are_set);
|
2084 |
|
|
|
2085 |
|
|
/* First try for a 2-insn sequence. */
|
2086 |
|
|
|
2087 |
|
|
/* These situations are preferred because the optimizer can
|
2088 |
|
|
* do more things with them:
|
2089 |
|
|
* 1) mov -1, %reg
|
2090 |
|
|
* sllx %reg, shift, %reg
|
2091 |
|
|
* 2) mov -1, %reg
|
2092 |
|
|
* srlx %reg, shift, %reg
|
2093 |
|
|
* 3) mov some_small_const, %reg
|
2094 |
|
|
* sllx %reg, shift, %reg
|
2095 |
|
|
*/
|
2096 |
|
|
if (((highest_bit_set == 63
|
2097 |
|
|
|| lowest_bit_set == 0)
|
2098 |
|
|
&& all_bits_between_are_set != 0)
|
2099 |
|
|
|| ((highest_bit_set - lowest_bit_set) < 12))
|
2100 |
|
|
{
|
2101 |
|
|
HOST_WIDE_INT the_const = -1;
|
2102 |
|
|
int shift = lowest_bit_set;
|
2103 |
|
|
|
2104 |
|
|
if ((highest_bit_set != 63
|
2105 |
|
|
&& lowest_bit_set != 0)
|
2106 |
|
|
|| all_bits_between_are_set == 0)
|
2107 |
|
|
{
|
2108 |
|
|
the_const =
|
2109 |
|
|
create_simple_focus_bits (high_bits, low_bits,
|
2110 |
|
|
lowest_bit_set, 0);
|
2111 |
|
|
}
|
2112 |
|
|
else if (lowest_bit_set == 0)
|
2113 |
|
|
shift = -(63 - highest_bit_set);
|
2114 |
|
|
|
2115 |
|
|
gcc_assert (SPARC_SIMM13_P (the_const));
|
2116 |
|
|
gcc_assert (shift != 0);
|
2117 |
|
|
|
2118 |
|
|
emit_insn (gen_safe_SET64 (temp, the_const));
|
2119 |
|
|
if (shift > 0)
|
2120 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
2121 |
|
|
op0,
|
2122 |
|
|
gen_rtx_ASHIFT (DImode,
|
2123 |
|
|
temp,
|
2124 |
|
|
GEN_INT (shift))));
|
2125 |
|
|
else if (shift < 0)
|
2126 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
2127 |
|
|
op0,
|
2128 |
|
|
gen_rtx_LSHIFTRT (DImode,
|
2129 |
|
|
temp,
|
2130 |
|
|
GEN_INT (-shift))));
|
2131 |
|
|
return;
|
2132 |
|
|
}
|
2133 |
|
|
|
2134 |
|
|
/* Now a range of 22 or less bits set somewhere.
|
2135 |
|
|
* 1) sethi %hi(focus_bits), %reg
|
2136 |
|
|
* sllx %reg, shift, %reg
|
2137 |
|
|
* 2) sethi %hi(focus_bits), %reg
|
2138 |
|
|
* srlx %reg, shift, %reg
|
2139 |
|
|
*/
|
2140 |
|
|
if ((highest_bit_set - lowest_bit_set) < 21)
|
2141 |
|
|
{
|
2142 |
|
|
unsigned HOST_WIDE_INT focus_bits =
|
2143 |
|
|
create_simple_focus_bits (high_bits, low_bits,
|
2144 |
|
|
lowest_bit_set, 10);
|
2145 |
|
|
|
2146 |
|
|
gcc_assert (SPARC_SETHI_P (focus_bits));
|
2147 |
|
|
gcc_assert (lowest_bit_set != 10);
|
2148 |
|
|
|
2149 |
|
|
emit_insn (gen_safe_HIGH64 (temp, focus_bits));
|
2150 |
|
|
|
2151 |
|
|
/* If lowest_bit_set == 10 then a sethi alone could have done it. */
|
2152 |
|
|
if (lowest_bit_set < 10)
|
2153 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
2154 |
|
|
op0,
|
2155 |
|
|
gen_rtx_LSHIFTRT (DImode, temp,
|
2156 |
|
|
GEN_INT (10 - lowest_bit_set))));
|
2157 |
|
|
else if (lowest_bit_set > 10)
|
2158 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
2159 |
|
|
op0,
|
2160 |
|
|
gen_rtx_ASHIFT (DImode, temp,
|
2161 |
|
|
GEN_INT (lowest_bit_set - 10))));
|
2162 |
|
|
return;
|
2163 |
|
|
}
|
2164 |
|
|
|
2165 |
|
|
/* 1) sethi %hi(low_bits), %reg
|
2166 |
|
|
* or %reg, %lo(low_bits), %reg
|
2167 |
|
|
* 2) sethi %hi(~low_bits), %reg
|
2168 |
|
|
* xor %reg, %lo(-0x400 | (low_bits & 0x3ff)), %reg
|
2169 |
|
|
*/
|
2170 |
|
|
if (high_bits == 0
|
2171 |
|
|
|| high_bits == 0xffffffff)
|
2172 |
|
|
{
|
2173 |
|
|
sparc_emit_set_const64_quick1 (op0, temp, low_bits,
|
2174 |
|
|
(high_bits == 0xffffffff));
|
2175 |
|
|
return;
|
2176 |
|
|
}
|
2177 |
|
|
|
2178 |
|
|
/* Now, try 3-insn sequences. */
|
2179 |
|
|
|
2180 |
|
|
/* 1) sethi %hi(high_bits), %reg
|
2181 |
|
|
* or %reg, %lo(high_bits), %reg
|
2182 |
|
|
* sllx %reg, 32, %reg
|
2183 |
|
|
*/
|
2184 |
|
|
if (low_bits == 0)
|
2185 |
|
|
{
|
2186 |
|
|
sparc_emit_set_const64_quick2 (op0, temp, high_bits, 0, 32);
|
2187 |
|
|
return;
|
2188 |
|
|
}
|
2189 |
|
|
|
2190 |
|
|
/* We may be able to do something quick
|
2191 |
|
|
when the constant is negated, so try that. */
|
2192 |
|
|
if (const64_is_2insns ((~high_bits) & 0xffffffff,
|
2193 |
|
|
(~low_bits) & 0xfffffc00))
|
2194 |
|
|
{
|
2195 |
|
|
/* NOTE: The trailing bits get XOR'd so we need the
|
2196 |
|
|
non-negated bits, not the negated ones. */
|
2197 |
|
|
unsigned HOST_WIDE_INT trailing_bits = low_bits & 0x3ff;
|
2198 |
|
|
|
2199 |
|
|
if ((((~high_bits) & 0xffffffff) == 0
|
2200 |
|
|
&& ((~low_bits) & 0x80000000) == 0)
|
2201 |
|
|
|| (((~high_bits) & 0xffffffff) == 0xffffffff
|
2202 |
|
|
&& ((~low_bits) & 0x80000000) != 0))
|
2203 |
|
|
{
|
2204 |
|
|
unsigned HOST_WIDE_INT fast_int = (~low_bits & 0xffffffff);
|
2205 |
|
|
|
2206 |
|
|
if ((SPARC_SETHI_P (fast_int)
|
2207 |
|
|
&& (~high_bits & 0xffffffff) == 0)
|
2208 |
|
|
|| SPARC_SIMM13_P (fast_int))
|
2209 |
|
|
emit_insn (gen_safe_SET64 (temp, fast_int));
|
2210 |
|
|
else
|
2211 |
|
|
sparc_emit_set_const64 (temp, GEN_INT (fast_int));
|
2212 |
|
|
}
|
2213 |
|
|
else
|
2214 |
|
|
{
|
2215 |
|
|
rtx negated_const;
|
2216 |
|
|
negated_const = GEN_INT (((~low_bits) & 0xfffffc00) |
|
2217 |
|
|
(((HOST_WIDE_INT)((~high_bits) & 0xffffffff))<<32));
|
2218 |
|
|
sparc_emit_set_const64 (temp, negated_const);
|
2219 |
|
|
}
|
2220 |
|
|
|
2221 |
|
|
/* If we are XOR'ing with -1, then we should emit a one's complement
|
2222 |
|
|
instead. This way the combiner will notice logical operations
|
2223 |
|
|
such as ANDN later on and substitute. */
|
2224 |
|
|
if (trailing_bits == 0x3ff)
|
2225 |
|
|
{
|
2226 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, op0,
|
2227 |
|
|
gen_rtx_NOT (DImode, temp)));
|
2228 |
|
|
}
|
2229 |
|
|
else
|
2230 |
|
|
{
|
2231 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
2232 |
|
|
op0,
|
2233 |
|
|
gen_safe_XOR64 (temp,
|
2234 |
|
|
(-0x400 | trailing_bits))));
|
2235 |
|
|
}
|
2236 |
|
|
return;
|
2237 |
|
|
}
|
2238 |
|
|
|
2239 |
|
|
/* 1) sethi %hi(xxx), %reg
|
2240 |
|
|
* or %reg, %lo(xxx), %reg
|
2241 |
|
|
* sllx %reg, yyy, %reg
|
2242 |
|
|
*
|
2243 |
|
|
* ??? This is just a generalized version of the low_bits==0
|
2244 |
|
|
* thing above, FIXME...
|
2245 |
|
|
*/
|
2246 |
|
|
if ((highest_bit_set - lowest_bit_set) < 32)
|
2247 |
|
|
{
|
2248 |
|
|
unsigned HOST_WIDE_INT focus_bits =
|
2249 |
|
|
create_simple_focus_bits (high_bits, low_bits,
|
2250 |
|
|
lowest_bit_set, 0);
|
2251 |
|
|
|
2252 |
|
|
/* We can't get here in this state. */
|
2253 |
|
|
gcc_assert (highest_bit_set >= 32 && lowest_bit_set < 32);
|
2254 |
|
|
|
2255 |
|
|
/* So what we know is that the set bits straddle the
|
2256 |
|
|
middle of the 64-bit word. */
|
2257 |
|
|
sparc_emit_set_const64_quick2 (op0, temp,
|
2258 |
|
|
focus_bits, 0,
|
2259 |
|
|
lowest_bit_set);
|
2260 |
|
|
return;
|
2261 |
|
|
}
|
2262 |
|
|
|
2263 |
|
|
/* 1) sethi %hi(high_bits), %reg
|
2264 |
|
|
* or %reg, %lo(high_bits), %reg
|
2265 |
|
|
* sllx %reg, 32, %reg
|
2266 |
|
|
* or %reg, low_bits, %reg
|
2267 |
|
|
*/
|
2268 |
|
|
if (SPARC_SIMM13_P(low_bits)
|
2269 |
|
|
&& ((int)low_bits > 0))
|
2270 |
|
|
{
|
2271 |
|
|
sparc_emit_set_const64_quick2 (op0, temp, high_bits, low_bits, 32);
|
2272 |
|
|
return;
|
2273 |
|
|
}
|
2274 |
|
|
|
2275 |
|
|
/* The easiest way when all else fails, is full decomposition. */
|
2276 |
|
|
sparc_emit_set_const64_longway (op0, temp, high_bits, low_bits);
|
2277 |
|
|
}
|
2278 |
|
|
#endif /* HOST_BITS_PER_WIDE_INT == 32 */
|
2279 |
|
|
|
2280 |
|
|
/* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE,
|
2281 |
|
|
return the mode to be used for the comparison. For floating-point,
|
2282 |
|
|
CCFP[E]mode is used. CC_NOOVmode should be used when the first operand
|
2283 |
|
|
is a PLUS, MINUS, NEG, or ASHIFT. CCmode should be used when no special
|
2284 |
|
|
processing is needed. */
|
2285 |
|
|
|
2286 |
|
|
enum machine_mode
|
2287 |
|
|
select_cc_mode (enum rtx_code op, rtx x, rtx y ATTRIBUTE_UNUSED)
|
2288 |
|
|
{
|
2289 |
|
|
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
|
2290 |
|
|
{
|
2291 |
|
|
switch (op)
|
2292 |
|
|
{
|
2293 |
|
|
case EQ:
|
2294 |
|
|
case NE:
|
2295 |
|
|
case UNORDERED:
|
2296 |
|
|
case ORDERED:
|
2297 |
|
|
case UNLT:
|
2298 |
|
|
case UNLE:
|
2299 |
|
|
case UNGT:
|
2300 |
|
|
case UNGE:
|
2301 |
|
|
case UNEQ:
|
2302 |
|
|
case LTGT:
|
2303 |
|
|
return CCFPmode;
|
2304 |
|
|
|
2305 |
|
|
case LT:
|
2306 |
|
|
case LE:
|
2307 |
|
|
case GT:
|
2308 |
|
|
case GE:
|
2309 |
|
|
return CCFPEmode;
|
2310 |
|
|
|
2311 |
|
|
default:
|
2312 |
|
|
gcc_unreachable ();
|
2313 |
|
|
}
|
2314 |
|
|
}
|
2315 |
|
|
else if (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
|
2316 |
|
|
|| GET_CODE (x) == NEG || GET_CODE (x) == ASHIFT)
|
2317 |
|
|
{
|
2318 |
|
|
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
|
2319 |
|
|
return CCX_NOOVmode;
|
2320 |
|
|
else
|
2321 |
|
|
return CC_NOOVmode;
|
2322 |
|
|
}
|
2323 |
|
|
else
|
2324 |
|
|
{
|
2325 |
|
|
if (TARGET_ARCH64 && GET_MODE (x) == DImode)
|
2326 |
|
|
return CCXmode;
|
2327 |
|
|
else
|
2328 |
|
|
return CCmode;
|
2329 |
|
|
}
|
2330 |
|
|
}
|
2331 |
|
|
|
2332 |
|
|
/* Emit the compare insn and return the CC reg for a CODE comparison
|
2333 |
|
|
with operands X and Y. */
|
2334 |
|
|
|
2335 |
|
|
static rtx
|
2336 |
|
|
gen_compare_reg_1 (enum rtx_code code, rtx x, rtx y)
|
2337 |
|
|
{
|
2338 |
|
|
enum machine_mode mode;
|
2339 |
|
|
rtx cc_reg;
|
2340 |
|
|
|
2341 |
|
|
if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
|
2342 |
|
|
return x;
|
2343 |
|
|
|
2344 |
|
|
mode = SELECT_CC_MODE (code, x, y);
|
2345 |
|
|
|
2346 |
|
|
/* ??? We don't have movcc patterns so we cannot generate pseudo regs for the
|
2347 |
|
|
fcc regs (cse can't tell they're really call clobbered regs and will
|
2348 |
|
|
remove a duplicate comparison even if there is an intervening function
|
2349 |
|
|
call - it will then try to reload the cc reg via an int reg which is why
|
2350 |
|
|
we need the movcc patterns). It is possible to provide the movcc
|
2351 |
|
|
patterns by using the ldxfsr/stxfsr v9 insns. I tried it: you need two
|
2352 |
|
|
registers (say %g1,%g5) and it takes about 6 insns. A better fix would be
|
2353 |
|
|
to tell cse that CCFPE mode registers (even pseudos) are call
|
2354 |
|
|
clobbered. */
|
2355 |
|
|
|
2356 |
|
|
/* ??? This is an experiment. Rather than making changes to cse which may
|
2357 |
|
|
or may not be easy/clean, we do our own cse. This is possible because
|
2358 |
|
|
we will generate hard registers. Cse knows they're call clobbered (it
|
2359 |
|
|
doesn't know the same thing about pseudos). If we guess wrong, no big
|
2360 |
|
|
deal, but if we win, great! */
|
2361 |
|
|
|
2362 |
|
|
if (TARGET_V9 && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
|
2363 |
|
|
#if 1 /* experiment */
|
2364 |
|
|
{
|
2365 |
|
|
int reg;
|
2366 |
|
|
/* We cycle through the registers to ensure they're all exercised. */
|
2367 |
|
|
static int next_fcc_reg = 0;
|
2368 |
|
|
/* Previous x,y for each fcc reg. */
|
2369 |
|
|
static rtx prev_args[4][2];
|
2370 |
|
|
|
2371 |
|
|
/* Scan prev_args for x,y. */
|
2372 |
|
|
for (reg = 0; reg < 4; reg++)
|
2373 |
|
|
if (prev_args[reg][0] == x && prev_args[reg][1] == y)
|
2374 |
|
|
break;
|
2375 |
|
|
if (reg == 4)
|
2376 |
|
|
{
|
2377 |
|
|
reg = next_fcc_reg;
|
2378 |
|
|
prev_args[reg][0] = x;
|
2379 |
|
|
prev_args[reg][1] = y;
|
2380 |
|
|
next_fcc_reg = (next_fcc_reg + 1) & 3;
|
2381 |
|
|
}
|
2382 |
|
|
cc_reg = gen_rtx_REG (mode, reg + SPARC_FIRST_V9_FCC_REG);
|
2383 |
|
|
}
|
2384 |
|
|
#else
|
2385 |
|
|
cc_reg = gen_reg_rtx (mode);
|
2386 |
|
|
#endif /* ! experiment */
|
2387 |
|
|
else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
|
2388 |
|
|
cc_reg = gen_rtx_REG (mode, SPARC_FCC_REG);
|
2389 |
|
|
else
|
2390 |
|
|
cc_reg = gen_rtx_REG (mode, SPARC_ICC_REG);
|
2391 |
|
|
|
2392 |
|
|
/* We shouldn't get there for TFmode if !TARGET_HARD_QUAD. If we do, this
|
2393 |
|
|
will only result in an unrecognizable insn so no point in asserting. */
|
2394 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, cc_reg, gen_rtx_COMPARE (mode, x, y)));
|
2395 |
|
|
|
2396 |
|
|
return cc_reg;
|
2397 |
|
|
}
|
2398 |
|
|
|
2399 |
|
|
|
2400 |
|
|
/* Emit the compare insn and return the CC reg for the comparison in CMP. */
|
2401 |
|
|
|
2402 |
|
|
rtx
|
2403 |
|
|
gen_compare_reg (rtx cmp)
|
2404 |
|
|
{
|
2405 |
|
|
return gen_compare_reg_1 (GET_CODE (cmp), XEXP (cmp, 0), XEXP (cmp, 1));
|
2406 |
|
|
}
|
2407 |
|
|
|
2408 |
|
|
/* This function is used for v9 only.
|
2409 |
|
|
DEST is the target of the Scc insn.
|
2410 |
|
|
CODE is the code for an Scc's comparison.
|
2411 |
|
|
X and Y are the values we compare.
|
2412 |
|
|
|
2413 |
|
|
This function is needed to turn
|
2414 |
|
|
|
2415 |
|
|
(set (reg:SI 110)
|
2416 |
|
|
(gt (reg:CCX 100 %icc)
|
2417 |
|
|
(const_int 0)))
|
2418 |
|
|
into
|
2419 |
|
|
(set (reg:SI 110)
|
2420 |
|
|
(gt:DI (reg:CCX 100 %icc)
|
2421 |
|
|
(const_int 0)))
|
2422 |
|
|
|
2423 |
|
|
IE: The instruction recognizer needs to see the mode of the comparison to
|
2424 |
|
|
find the right instruction. We could use "gt:DI" right in the
|
2425 |
|
|
define_expand, but leaving it out allows us to handle DI, SI, etc. */
|
2426 |
|
|
|
2427 |
|
|
static int
|
2428 |
|
|
gen_v9_scc (rtx dest, enum rtx_code compare_code, rtx x, rtx y)
|
2429 |
|
|
{
|
2430 |
|
|
if (! TARGET_ARCH64
|
2431 |
|
|
&& (GET_MODE (x) == DImode
|
2432 |
|
|
|| GET_MODE (dest) == DImode))
|
2433 |
|
|
return 0;
|
2434 |
|
|
|
2435 |
|
|
/* Try to use the movrCC insns. */
|
2436 |
|
|
if (TARGET_ARCH64
|
2437 |
|
|
&& GET_MODE_CLASS (GET_MODE (x)) == MODE_INT
|
2438 |
|
|
&& y == const0_rtx
|
2439 |
|
|
&& v9_regcmp_p (compare_code))
|
2440 |
|
|
{
|
2441 |
|
|
rtx op0 = x;
|
2442 |
|
|
rtx temp;
|
2443 |
|
|
|
2444 |
|
|
/* Special case for op0 != 0. This can be done with one instruction if
|
2445 |
|
|
dest == x. */
|
2446 |
|
|
|
2447 |
|
|
if (compare_code == NE
|
2448 |
|
|
&& GET_MODE (dest) == DImode
|
2449 |
|
|
&& rtx_equal_p (op0, dest))
|
2450 |
|
|
{
|
2451 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, dest,
|
2452 |
|
|
gen_rtx_IF_THEN_ELSE (DImode,
|
2453 |
|
|
gen_rtx_fmt_ee (compare_code, DImode,
|
2454 |
|
|
op0, const0_rtx),
|
2455 |
|
|
const1_rtx,
|
2456 |
|
|
dest)));
|
2457 |
|
|
return 1;
|
2458 |
|
|
}
|
2459 |
|
|
|
2460 |
|
|
if (reg_overlap_mentioned_p (dest, op0))
|
2461 |
|
|
{
|
2462 |
|
|
/* Handle the case where dest == x.
|
2463 |
|
|
We "early clobber" the result. */
|
2464 |
|
|
op0 = gen_reg_rtx (GET_MODE (x));
|
2465 |
|
|
emit_move_insn (op0, x);
|
2466 |
|
|
}
|
2467 |
|
|
|
2468 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, dest, const0_rtx));
|
2469 |
|
|
if (GET_MODE (op0) != DImode)
|
2470 |
|
|
{
|
2471 |
|
|
temp = gen_reg_rtx (DImode);
|
2472 |
|
|
convert_move (temp, op0, 0);
|
2473 |
|
|
}
|
2474 |
|
|
else
|
2475 |
|
|
temp = op0;
|
2476 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, dest,
|
2477 |
|
|
gen_rtx_IF_THEN_ELSE (GET_MODE (dest),
|
2478 |
|
|
gen_rtx_fmt_ee (compare_code, DImode,
|
2479 |
|
|
temp, const0_rtx),
|
2480 |
|
|
const1_rtx,
|
2481 |
|
|
dest)));
|
2482 |
|
|
return 1;
|
2483 |
|
|
}
|
2484 |
|
|
else
|
2485 |
|
|
{
|
2486 |
|
|
x = gen_compare_reg_1 (compare_code, x, y);
|
2487 |
|
|
y = const0_rtx;
|
2488 |
|
|
|
2489 |
|
|
gcc_assert (GET_MODE (x) != CC_NOOVmode
|
2490 |
|
|
&& GET_MODE (x) != CCX_NOOVmode);
|
2491 |
|
|
|
2492 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, dest, const0_rtx));
|
2493 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, dest,
|
2494 |
|
|
gen_rtx_IF_THEN_ELSE (GET_MODE (dest),
|
2495 |
|
|
gen_rtx_fmt_ee (compare_code,
|
2496 |
|
|
GET_MODE (x), x, y),
|
2497 |
|
|
const1_rtx, dest)));
|
2498 |
|
|
return 1;
|
2499 |
|
|
}
|
2500 |
|
|
}
|
2501 |
|
|
|
2502 |
|
|
|
2503 |
|
|
/* Emit an scc insn. For seq, sne, sgeu, and sltu, we can do this
|
2504 |
|
|
without jumps using the addx/subx instructions. */
|
2505 |
|
|
|
2506 |
|
|
bool
|
2507 |
|
|
emit_scc_insn (rtx operands[])
|
2508 |
|
|
{
|
2509 |
|
|
rtx tem;
|
2510 |
|
|
rtx x;
|
2511 |
|
|
rtx y;
|
2512 |
|
|
enum rtx_code code;
|
2513 |
|
|
|
2514 |
|
|
/* The quad-word fp compare library routines all return nonzero to indicate
|
2515 |
|
|
true, which is different from the equivalent libgcc routines, so we must
|
2516 |
|
|
handle them specially here. */
|
2517 |
|
|
if (GET_MODE (operands[2]) == TFmode && ! TARGET_HARD_QUAD)
|
2518 |
|
|
{
|
2519 |
|
|
operands[1] = sparc_emit_float_lib_cmp (operands[2], operands[3],
|
2520 |
|
|
GET_CODE (operands[1]));
|
2521 |
|
|
operands[2] = XEXP (operands[1], 0);
|
2522 |
|
|
operands[3] = XEXP (operands[1], 1);
|
2523 |
|
|
}
|
2524 |
|
|
|
2525 |
|
|
code = GET_CODE (operands[1]);
|
2526 |
|
|
x = operands[2];
|
2527 |
|
|
y = operands[3];
|
2528 |
|
|
|
2529 |
|
|
/* For seq/sne on v9 we use the same code as v8 (the addx/subx method has
|
2530 |
|
|
more applications). The exception to this is "reg != 0" which can
|
2531 |
|
|
be done in one instruction on v9 (so we do it). */
|
2532 |
|
|
if (code == EQ)
|
2533 |
|
|
{
|
2534 |
|
|
if (GET_MODE (x) == SImode)
|
2535 |
|
|
{
|
2536 |
|
|
rtx pat = gen_seqsi_special (operands[0], x, y);
|
2537 |
|
|
emit_insn (pat);
|
2538 |
|
|
return true;
|
2539 |
|
|
}
|
2540 |
|
|
else if (GET_MODE (x) == DImode)
|
2541 |
|
|
{
|
2542 |
|
|
rtx pat = gen_seqdi_special (operands[0], x, y);
|
2543 |
|
|
emit_insn (pat);
|
2544 |
|
|
return true;
|
2545 |
|
|
}
|
2546 |
|
|
}
|
2547 |
|
|
|
2548 |
|
|
if (code == NE)
|
2549 |
|
|
{
|
2550 |
|
|
if (GET_MODE (x) == SImode)
|
2551 |
|
|
{
|
2552 |
|
|
rtx pat = gen_snesi_special (operands[0], x, y);
|
2553 |
|
|
emit_insn (pat);
|
2554 |
|
|
return true;
|
2555 |
|
|
}
|
2556 |
|
|
else if (GET_MODE (x) == DImode)
|
2557 |
|
|
{
|
2558 |
|
|
rtx pat;
|
2559 |
|
|
if (TARGET_VIS3)
|
2560 |
|
|
pat = gen_snedi_special_vis3 (operands[0], x, y);
|
2561 |
|
|
else
|
2562 |
|
|
pat = gen_snedi_special (operands[0], x, y);
|
2563 |
|
|
emit_insn (pat);
|
2564 |
|
|
return true;
|
2565 |
|
|
}
|
2566 |
|
|
}
|
2567 |
|
|
|
2568 |
|
|
if (TARGET_V9
|
2569 |
|
|
&& TARGET_ARCH64
|
2570 |
|
|
&& GET_MODE (x) == DImode
|
2571 |
|
|
&& !(TARGET_VIS3
|
2572 |
|
|
&& (code == GTU || code == LTU))
|
2573 |
|
|
&& gen_v9_scc (operands[0], code, x, y))
|
2574 |
|
|
return true;
|
2575 |
|
|
|
2576 |
|
|
/* We can do LTU and GEU using the addx/subx instructions too. And
|
2577 |
|
|
for GTU/LEU, if both operands are registers swap them and fall
|
2578 |
|
|
back to the easy case. */
|
2579 |
|
|
if (code == GTU || code == LEU)
|
2580 |
|
|
{
|
2581 |
|
|
if ((GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
|
2582 |
|
|
&& (GET_CODE (y) == REG || GET_CODE (y) == SUBREG))
|
2583 |
|
|
{
|
2584 |
|
|
tem = x;
|
2585 |
|
|
x = y;
|
2586 |
|
|
y = tem;
|
2587 |
|
|
code = swap_condition (code);
|
2588 |
|
|
}
|
2589 |
|
|
}
|
2590 |
|
|
|
2591 |
|
|
if (code == LTU
|
2592 |
|
|
|| (!TARGET_VIS3 && code == GEU))
|
2593 |
|
|
{
|
2594 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, operands[0],
|
2595 |
|
|
gen_rtx_fmt_ee (code, SImode,
|
2596 |
|
|
gen_compare_reg_1 (code, x, y),
|
2597 |
|
|
const0_rtx)));
|
2598 |
|
|
return true;
|
2599 |
|
|
}
|
2600 |
|
|
|
2601 |
|
|
/* All the posibilities to use addx/subx based sequences has been
|
2602 |
|
|
exhausted, try for a 3 instruction sequence using v9 conditional
|
2603 |
|
|
moves. */
|
2604 |
|
|
if (TARGET_V9 && gen_v9_scc (operands[0], code, x, y))
|
2605 |
|
|
return true;
|
2606 |
|
|
|
2607 |
|
|
/* Nope, do branches. */
|
2608 |
|
|
return false;
|
2609 |
|
|
}
|
2610 |
|
|
|
2611 |
|
|
/* Emit a conditional jump insn for the v9 architecture using comparison code
|
2612 |
|
|
CODE and jump target LABEL.
|
2613 |
|
|
This function exists to take advantage of the v9 brxx insns. */
|
2614 |
|
|
|
2615 |
|
|
static void
|
2616 |
|
|
emit_v9_brxx_insn (enum rtx_code code, rtx op0, rtx label)
|
2617 |
|
|
{
|
2618 |
|
|
emit_jump_insn (gen_rtx_SET (VOIDmode,
|
2619 |
|
|
pc_rtx,
|
2620 |
|
|
gen_rtx_IF_THEN_ELSE (VOIDmode,
|
2621 |
|
|
gen_rtx_fmt_ee (code, GET_MODE (op0),
|
2622 |
|
|
op0, const0_rtx),
|
2623 |
|
|
gen_rtx_LABEL_REF (VOIDmode, label),
|
2624 |
|
|
pc_rtx)));
|
2625 |
|
|
}
|
2626 |
|
|
|
2627 |
|
|
void
|
2628 |
|
|
emit_conditional_branch_insn (rtx operands[])
|
2629 |
|
|
{
|
2630 |
|
|
/* The quad-word fp compare library routines all return nonzero to indicate
|
2631 |
|
|
true, which is different from the equivalent libgcc routines, so we must
|
2632 |
|
|
handle them specially here. */
|
2633 |
|
|
if (GET_MODE (operands[1]) == TFmode && ! TARGET_HARD_QUAD)
|
2634 |
|
|
{
|
2635 |
|
|
operands[0] = sparc_emit_float_lib_cmp (operands[1], operands[2],
|
2636 |
|
|
GET_CODE (operands[0]));
|
2637 |
|
|
operands[1] = XEXP (operands[0], 0);
|
2638 |
|
|
operands[2] = XEXP (operands[0], 1);
|
2639 |
|
|
}
|
2640 |
|
|
|
2641 |
|
|
if (TARGET_ARCH64 && operands[2] == const0_rtx
|
2642 |
|
|
&& GET_CODE (operands[1]) == REG
|
2643 |
|
|
&& GET_MODE (operands[1]) == DImode)
|
2644 |
|
|
{
|
2645 |
|
|
emit_v9_brxx_insn (GET_CODE (operands[0]), operands[1], operands[3]);
|
2646 |
|
|
return;
|
2647 |
|
|
}
|
2648 |
|
|
|
2649 |
|
|
operands[1] = gen_compare_reg (operands[0]);
|
2650 |
|
|
operands[2] = const0_rtx;
|
2651 |
|
|
operands[0] = gen_rtx_fmt_ee (GET_CODE (operands[0]), VOIDmode,
|
2652 |
|
|
operands[1], operands[2]);
|
2653 |
|
|
emit_jump_insn (gen_cbranchcc4 (operands[0], operands[1], operands[2],
|
2654 |
|
|
operands[3]));
|
2655 |
|
|
}
|
2656 |
|
|
|
2657 |
|
|
|
2658 |
|
|
/* Generate a DFmode part of a hard TFmode register.
|
2659 |
|
|
REG is the TFmode hard register, LOW is 1 for the
|
2660 |
|
|
low 64bit of the register and 0 otherwise.
|
2661 |
|
|
*/
|
2662 |
|
|
rtx
|
2663 |
|
|
gen_df_reg (rtx reg, int low)
|
2664 |
|
|
{
|
2665 |
|
|
int regno = REGNO (reg);
|
2666 |
|
|
|
2667 |
|
|
if ((WORDS_BIG_ENDIAN == 0) ^ (low != 0))
|
2668 |
|
|
regno += (TARGET_ARCH64 && SPARC_INT_REG_P (regno)) ? 1 : 2;
|
2669 |
|
|
return gen_rtx_REG (DFmode, regno);
|
2670 |
|
|
}
|
2671 |
|
|
|
2672 |
|
|
/* Generate a call to FUNC with OPERANDS. Operand 0 is the return value.
|
2673 |
|
|
Unlike normal calls, TFmode operands are passed by reference. It is
|
2674 |
|
|
assumed that no more than 3 operands are required. */
|
2675 |
|
|
|
2676 |
|
|
static void
|
2677 |
|
|
emit_soft_tfmode_libcall (const char *func_name, int nargs, rtx *operands)
|
2678 |
|
|
{
|
2679 |
|
|
rtx ret_slot = NULL, arg[3], func_sym;
|
2680 |
|
|
int i;
|
2681 |
|
|
|
2682 |
|
|
/* We only expect to be called for conversions, unary, and binary ops. */
|
2683 |
|
|
gcc_assert (nargs == 2 || nargs == 3);
|
2684 |
|
|
|
2685 |
|
|
for (i = 0; i < nargs; ++i)
|
2686 |
|
|
{
|
2687 |
|
|
rtx this_arg = operands[i];
|
2688 |
|
|
rtx this_slot;
|
2689 |
|
|
|
2690 |
|
|
/* TFmode arguments and return values are passed by reference. */
|
2691 |
|
|
if (GET_MODE (this_arg) == TFmode)
|
2692 |
|
|
{
|
2693 |
|
|
int force_stack_temp;
|
2694 |
|
|
|
2695 |
|
|
force_stack_temp = 0;
|
2696 |
|
|
if (TARGET_BUGGY_QP_LIB && i == 0)
|
2697 |
|
|
force_stack_temp = 1;
|
2698 |
|
|
|
2699 |
|
|
if (GET_CODE (this_arg) == MEM
|
2700 |
|
|
&& ! force_stack_temp)
|
2701 |
|
|
this_arg = XEXP (this_arg, 0);
|
2702 |
|
|
else if (CONSTANT_P (this_arg)
|
2703 |
|
|
&& ! force_stack_temp)
|
2704 |
|
|
{
|
2705 |
|
|
this_slot = force_const_mem (TFmode, this_arg);
|
2706 |
|
|
this_arg = XEXP (this_slot, 0);
|
2707 |
|
|
}
|
2708 |
|
|
else
|
2709 |
|
|
{
|
2710 |
|
|
this_slot = assign_stack_temp (TFmode, GET_MODE_SIZE (TFmode), 0);
|
2711 |
|
|
|
2712 |
|
|
/* Operand 0 is the return value. We'll copy it out later. */
|
2713 |
|
|
if (i > 0)
|
2714 |
|
|
emit_move_insn (this_slot, this_arg);
|
2715 |
|
|
else
|
2716 |
|
|
ret_slot = this_slot;
|
2717 |
|
|
|
2718 |
|
|
this_arg = XEXP (this_slot, 0);
|
2719 |
|
|
}
|
2720 |
|
|
}
|
2721 |
|
|
|
2722 |
|
|
arg[i] = this_arg;
|
2723 |
|
|
}
|
2724 |
|
|
|
2725 |
|
|
func_sym = gen_rtx_SYMBOL_REF (Pmode, func_name);
|
2726 |
|
|
|
2727 |
|
|
if (GET_MODE (operands[0]) == TFmode)
|
2728 |
|
|
{
|
2729 |
|
|
if (nargs == 2)
|
2730 |
|
|
emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 2,
|
2731 |
|
|
arg[0], GET_MODE (arg[0]),
|
2732 |
|
|
arg[1], GET_MODE (arg[1]));
|
2733 |
|
|
else
|
2734 |
|
|
emit_library_call (func_sym, LCT_NORMAL, VOIDmode, 3,
|
2735 |
|
|
arg[0], GET_MODE (arg[0]),
|
2736 |
|
|
arg[1], GET_MODE (arg[1]),
|
2737 |
|
|
arg[2], GET_MODE (arg[2]));
|
2738 |
|
|
|
2739 |
|
|
if (ret_slot)
|
2740 |
|
|
emit_move_insn (operands[0], ret_slot);
|
2741 |
|
|
}
|
2742 |
|
|
else
|
2743 |
|
|
{
|
2744 |
|
|
rtx ret;
|
2745 |
|
|
|
2746 |
|
|
gcc_assert (nargs == 2);
|
2747 |
|
|
|
2748 |
|
|
ret = emit_library_call_value (func_sym, operands[0], LCT_NORMAL,
|
2749 |
|
|
GET_MODE (operands[0]), 1,
|
2750 |
|
|
arg[1], GET_MODE (arg[1]));
|
2751 |
|
|
|
2752 |
|
|
if (ret != operands[0])
|
2753 |
|
|
emit_move_insn (operands[0], ret);
|
2754 |
|
|
}
|
2755 |
|
|
}
|
2756 |
|
|
|
2757 |
|
|
/* Expand soft-float TFmode calls to sparc abi routines. */
|
2758 |
|
|
|
2759 |
|
|
static void
|
2760 |
|
|
emit_soft_tfmode_binop (enum rtx_code code, rtx *operands)
|
2761 |
|
|
{
|
2762 |
|
|
const char *func;
|
2763 |
|
|
|
2764 |
|
|
switch (code)
|
2765 |
|
|
{
|
2766 |
|
|
case PLUS:
|
2767 |
|
|
func = "_Qp_add";
|
2768 |
|
|
break;
|
2769 |
|
|
case MINUS:
|
2770 |
|
|
func = "_Qp_sub";
|
2771 |
|
|
break;
|
2772 |
|
|
case MULT:
|
2773 |
|
|
func = "_Qp_mul";
|
2774 |
|
|
break;
|
2775 |
|
|
case DIV:
|
2776 |
|
|
func = "_Qp_div";
|
2777 |
|
|
break;
|
2778 |
|
|
default:
|
2779 |
|
|
gcc_unreachable ();
|
2780 |
|
|
}
|
2781 |
|
|
|
2782 |
|
|
emit_soft_tfmode_libcall (func, 3, operands);
|
2783 |
|
|
}
|
2784 |
|
|
|
2785 |
|
|
static void
|
2786 |
|
|
emit_soft_tfmode_unop (enum rtx_code code, rtx *operands)
|
2787 |
|
|
{
|
2788 |
|
|
const char *func;
|
2789 |
|
|
|
2790 |
|
|
gcc_assert (code == SQRT);
|
2791 |
|
|
func = "_Qp_sqrt";
|
2792 |
|
|
|
2793 |
|
|
emit_soft_tfmode_libcall (func, 2, operands);
|
2794 |
|
|
}
|
2795 |
|
|
|
2796 |
|
|
static void
|
2797 |
|
|
emit_soft_tfmode_cvt (enum rtx_code code, rtx *operands)
|
2798 |
|
|
{
|
2799 |
|
|
const char *func;
|
2800 |
|
|
|
2801 |
|
|
switch (code)
|
2802 |
|
|
{
|
2803 |
|
|
case FLOAT_EXTEND:
|
2804 |
|
|
switch (GET_MODE (operands[1]))
|
2805 |
|
|
{
|
2806 |
|
|
case SFmode:
|
2807 |
|
|
func = "_Qp_stoq";
|
2808 |
|
|
break;
|
2809 |
|
|
case DFmode:
|
2810 |
|
|
func = "_Qp_dtoq";
|
2811 |
|
|
break;
|
2812 |
|
|
default:
|
2813 |
|
|
gcc_unreachable ();
|
2814 |
|
|
}
|
2815 |
|
|
break;
|
2816 |
|
|
|
2817 |
|
|
case FLOAT_TRUNCATE:
|
2818 |
|
|
switch (GET_MODE (operands[0]))
|
2819 |
|
|
{
|
2820 |
|
|
case SFmode:
|
2821 |
|
|
func = "_Qp_qtos";
|
2822 |
|
|
break;
|
2823 |
|
|
case DFmode:
|
2824 |
|
|
func = "_Qp_qtod";
|
2825 |
|
|
break;
|
2826 |
|
|
default:
|
2827 |
|
|
gcc_unreachable ();
|
2828 |
|
|
}
|
2829 |
|
|
break;
|
2830 |
|
|
|
2831 |
|
|
case FLOAT:
|
2832 |
|
|
switch (GET_MODE (operands[1]))
|
2833 |
|
|
{
|
2834 |
|
|
case SImode:
|
2835 |
|
|
func = "_Qp_itoq";
|
2836 |
|
|
if (TARGET_ARCH64)
|
2837 |
|
|
operands[1] = gen_rtx_SIGN_EXTEND (DImode, operands[1]);
|
2838 |
|
|
break;
|
2839 |
|
|
case DImode:
|
2840 |
|
|
func = "_Qp_xtoq";
|
2841 |
|
|
break;
|
2842 |
|
|
default:
|
2843 |
|
|
gcc_unreachable ();
|
2844 |
|
|
}
|
2845 |
|
|
break;
|
2846 |
|
|
|
2847 |
|
|
case UNSIGNED_FLOAT:
|
2848 |
|
|
switch (GET_MODE (operands[1]))
|
2849 |
|
|
{
|
2850 |
|
|
case SImode:
|
2851 |
|
|
func = "_Qp_uitoq";
|
2852 |
|
|
if (TARGET_ARCH64)
|
2853 |
|
|
operands[1] = gen_rtx_ZERO_EXTEND (DImode, operands[1]);
|
2854 |
|
|
break;
|
2855 |
|
|
case DImode:
|
2856 |
|
|
func = "_Qp_uxtoq";
|
2857 |
|
|
break;
|
2858 |
|
|
default:
|
2859 |
|
|
gcc_unreachable ();
|
2860 |
|
|
}
|
2861 |
|
|
break;
|
2862 |
|
|
|
2863 |
|
|
case FIX:
|
2864 |
|
|
switch (GET_MODE (operands[0]))
|
2865 |
|
|
{
|
2866 |
|
|
case SImode:
|
2867 |
|
|
func = "_Qp_qtoi";
|
2868 |
|
|
break;
|
2869 |
|
|
case DImode:
|
2870 |
|
|
func = "_Qp_qtox";
|
2871 |
|
|
break;
|
2872 |
|
|
default:
|
2873 |
|
|
gcc_unreachable ();
|
2874 |
|
|
}
|
2875 |
|
|
break;
|
2876 |
|
|
|
2877 |
|
|
case UNSIGNED_FIX:
|
2878 |
|
|
switch (GET_MODE (operands[0]))
|
2879 |
|
|
{
|
2880 |
|
|
case SImode:
|
2881 |
|
|
func = "_Qp_qtoui";
|
2882 |
|
|
break;
|
2883 |
|
|
case DImode:
|
2884 |
|
|
func = "_Qp_qtoux";
|
2885 |
|
|
break;
|
2886 |
|
|
default:
|
2887 |
|
|
gcc_unreachable ();
|
2888 |
|
|
}
|
2889 |
|
|
break;
|
2890 |
|
|
|
2891 |
|
|
default:
|
2892 |
|
|
gcc_unreachable ();
|
2893 |
|
|
}
|
2894 |
|
|
|
2895 |
|
|
emit_soft_tfmode_libcall (func, 2, operands);
|
2896 |
|
|
}
|
2897 |
|
|
|
2898 |
|
|
/* Expand a hard-float tfmode operation. All arguments must be in
|
2899 |
|
|
registers. */
|
2900 |
|
|
|
2901 |
|
|
static void
|
2902 |
|
|
emit_hard_tfmode_operation (enum rtx_code code, rtx *operands)
|
2903 |
|
|
{
|
2904 |
|
|
rtx op, dest;
|
2905 |
|
|
|
2906 |
|
|
if (GET_RTX_CLASS (code) == RTX_UNARY)
|
2907 |
|
|
{
|
2908 |
|
|
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
|
2909 |
|
|
op = gen_rtx_fmt_e (code, GET_MODE (operands[0]), operands[1]);
|
2910 |
|
|
}
|
2911 |
|
|
else
|
2912 |
|
|
{
|
2913 |
|
|
operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
|
2914 |
|
|
operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
|
2915 |
|
|
op = gen_rtx_fmt_ee (code, GET_MODE (operands[0]),
|
2916 |
|
|
operands[1], operands[2]);
|
2917 |
|
|
}
|
2918 |
|
|
|
2919 |
|
|
if (register_operand (operands[0], VOIDmode))
|
2920 |
|
|
dest = operands[0];
|
2921 |
|
|
else
|
2922 |
|
|
dest = gen_reg_rtx (GET_MODE (operands[0]));
|
2923 |
|
|
|
2924 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, dest, op));
|
2925 |
|
|
|
2926 |
|
|
if (dest != operands[0])
|
2927 |
|
|
emit_move_insn (operands[0], dest);
|
2928 |
|
|
}
|
2929 |
|
|
|
2930 |
|
|
void
|
2931 |
|
|
emit_tfmode_binop (enum rtx_code code, rtx *operands)
|
2932 |
|
|
{
|
2933 |
|
|
if (TARGET_HARD_QUAD)
|
2934 |
|
|
emit_hard_tfmode_operation (code, operands);
|
2935 |
|
|
else
|
2936 |
|
|
emit_soft_tfmode_binop (code, operands);
|
2937 |
|
|
}
|
2938 |
|
|
|
2939 |
|
|
void
|
2940 |
|
|
emit_tfmode_unop (enum rtx_code code, rtx *operands)
|
2941 |
|
|
{
|
2942 |
|
|
if (TARGET_HARD_QUAD)
|
2943 |
|
|
emit_hard_tfmode_operation (code, operands);
|
2944 |
|
|
else
|
2945 |
|
|
emit_soft_tfmode_unop (code, operands);
|
2946 |
|
|
}
|
2947 |
|
|
|
2948 |
|
|
void
|
2949 |
|
|
emit_tfmode_cvt (enum rtx_code code, rtx *operands)
|
2950 |
|
|
{
|
2951 |
|
|
if (TARGET_HARD_QUAD)
|
2952 |
|
|
emit_hard_tfmode_operation (code, operands);
|
2953 |
|
|
else
|
2954 |
|
|
emit_soft_tfmode_cvt (code, operands);
|
2955 |
|
|
}
|
2956 |
|
|
|
2957 |
|
|
/* Return nonzero if a branch/jump/call instruction will be emitting
|
2958 |
|
|
nop into its delay slot. */
|
2959 |
|
|
|
2960 |
|
|
int
|
2961 |
|
|
empty_delay_slot (rtx insn)
|
2962 |
|
|
{
|
2963 |
|
|
rtx seq;
|
2964 |
|
|
|
2965 |
|
|
/* If no previous instruction (should not happen), return true. */
|
2966 |
|
|
if (PREV_INSN (insn) == NULL)
|
2967 |
|
|
return 1;
|
2968 |
|
|
|
2969 |
|
|
seq = NEXT_INSN (PREV_INSN (insn));
|
2970 |
|
|
if (GET_CODE (PATTERN (seq)) == SEQUENCE)
|
2971 |
|
|
return 0;
|
2972 |
|
|
|
2973 |
|
|
return 1;
|
2974 |
|
|
}
|
2975 |
|
|
|
2976 |
|
|
/* Return nonzero if TRIAL can go into the call delay slot. */
|
2977 |
|
|
|
2978 |
|
|
int
|
2979 |
|
|
tls_call_delay (rtx trial)
|
2980 |
|
|
{
|
2981 |
|
|
rtx pat;
|
2982 |
|
|
|
2983 |
|
|
/* Binutils allows
|
2984 |
|
|
call __tls_get_addr, %tgd_call (foo)
|
2985 |
|
|
add %l7, %o0, %o0, %tgd_add (foo)
|
2986 |
|
|
while Sun as/ld does not. */
|
2987 |
|
|
if (TARGET_GNU_TLS || !TARGET_TLS)
|
2988 |
|
|
return 1;
|
2989 |
|
|
|
2990 |
|
|
pat = PATTERN (trial);
|
2991 |
|
|
|
2992 |
|
|
/* We must reject tgd_add{32|64}, i.e.
|
2993 |
|
|
(set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSGD)))
|
2994 |
|
|
and tldm_add{32|64}, i.e.
|
2995 |
|
|
(set (reg) (plus (reg) (unspec [(reg) (symbol_ref)] UNSPEC_TLSLDM)))
|
2996 |
|
|
for Sun as/ld. */
|
2997 |
|
|
if (GET_CODE (pat) == SET
|
2998 |
|
|
&& GET_CODE (SET_SRC (pat)) == PLUS)
|
2999 |
|
|
{
|
3000 |
|
|
rtx unspec = XEXP (SET_SRC (pat), 1);
|
3001 |
|
|
|
3002 |
|
|
if (GET_CODE (unspec) == UNSPEC
|
3003 |
|
|
&& (XINT (unspec, 1) == UNSPEC_TLSGD
|
3004 |
|
|
|| XINT (unspec, 1) == UNSPEC_TLSLDM))
|
3005 |
|
|
return 0;
|
3006 |
|
|
}
|
3007 |
|
|
|
3008 |
|
|
return 1;
|
3009 |
|
|
}
|
3010 |
|
|
|
3011 |
|
|
/* Return nonzero if TRIAL, an insn, can be combined with a 'restore'
|
3012 |
|
|
instruction. RETURN_P is true if the v9 variant 'return' is to be
|
3013 |
|
|
considered in the test too.
|
3014 |
|
|
|
3015 |
|
|
TRIAL must be a SET whose destination is a REG appropriate for the
|
3016 |
|
|
'restore' instruction or, if RETURN_P is true, for the 'return'
|
3017 |
|
|
instruction. */
|
3018 |
|
|
|
3019 |
|
|
static int
|
3020 |
|
|
eligible_for_restore_insn (rtx trial, bool return_p)
|
3021 |
|
|
{
|
3022 |
|
|
rtx pat = PATTERN (trial);
|
3023 |
|
|
rtx src = SET_SRC (pat);
|
3024 |
|
|
bool src_is_freg = false;
|
3025 |
|
|
rtx src_reg;
|
3026 |
|
|
|
3027 |
|
|
/* Since we now can do moves between float and integer registers when
|
3028 |
|
|
VIS3 is enabled, we have to catch this case. We can allow such
|
3029 |
|
|
moves when doing a 'return' however. */
|
3030 |
|
|
src_reg = src;
|
3031 |
|
|
if (GET_CODE (src_reg) == SUBREG)
|
3032 |
|
|
src_reg = SUBREG_REG (src_reg);
|
3033 |
|
|
if (GET_CODE (src_reg) == REG
|
3034 |
|
|
&& SPARC_FP_REG_P (REGNO (src_reg)))
|
3035 |
|
|
src_is_freg = true;
|
3036 |
|
|
|
3037 |
|
|
/* The 'restore src,%g0,dest' pattern for word mode and below. */
|
3038 |
|
|
if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
|
3039 |
|
|
&& arith_operand (src, GET_MODE (src))
|
3040 |
|
|
&& ! src_is_freg)
|
3041 |
|
|
{
|
3042 |
|
|
if (TARGET_ARCH64)
|
3043 |
|
|
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
|
3044 |
|
|
else
|
3045 |
|
|
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (SImode);
|
3046 |
|
|
}
|
3047 |
|
|
|
3048 |
|
|
/* The 'restore src,%g0,dest' pattern for double-word mode. */
|
3049 |
|
|
else if (GET_MODE_CLASS (GET_MODE (src)) != MODE_FLOAT
|
3050 |
|
|
&& arith_double_operand (src, GET_MODE (src))
|
3051 |
|
|
&& ! src_is_freg)
|
3052 |
|
|
return GET_MODE_SIZE (GET_MODE (src)) <= GET_MODE_SIZE (DImode);
|
3053 |
|
|
|
3054 |
|
|
/* The 'restore src,%g0,dest' pattern for float if no FPU. */
|
3055 |
|
|
else if (! TARGET_FPU && register_operand (src, SFmode))
|
3056 |
|
|
return 1;
|
3057 |
|
|
|
3058 |
|
|
/* The 'restore src,%g0,dest' pattern for double if no FPU. */
|
3059 |
|
|
else if (! TARGET_FPU && TARGET_ARCH64 && register_operand (src, DFmode))
|
3060 |
|
|
return 1;
|
3061 |
|
|
|
3062 |
|
|
/* If we have the 'return' instruction, anything that does not use
|
3063 |
|
|
local or output registers and can go into a delay slot wins. */
|
3064 |
|
|
else if (return_p
|
3065 |
|
|
&& TARGET_V9
|
3066 |
|
|
&& !epilogue_renumber (&pat, 1)
|
3067 |
|
|
&& get_attr_in_uncond_branch_delay (trial)
|
3068 |
|
|
== IN_UNCOND_BRANCH_DELAY_TRUE)
|
3069 |
|
|
return 1;
|
3070 |
|
|
|
3071 |
|
|
/* The 'restore src1,src2,dest' pattern for SImode. */
|
3072 |
|
|
else if (GET_CODE (src) == PLUS
|
3073 |
|
|
&& register_operand (XEXP (src, 0), SImode)
|
3074 |
|
|
&& arith_operand (XEXP (src, 1), SImode))
|
3075 |
|
|
return 1;
|
3076 |
|
|
|
3077 |
|
|
/* The 'restore src1,src2,dest' pattern for DImode. */
|
3078 |
|
|
else if (GET_CODE (src) == PLUS
|
3079 |
|
|
&& register_operand (XEXP (src, 0), DImode)
|
3080 |
|
|
&& arith_double_operand (XEXP (src, 1), DImode))
|
3081 |
|
|
return 1;
|
3082 |
|
|
|
3083 |
|
|
/* The 'restore src1,%lo(src2),dest' pattern. */
|
3084 |
|
|
else if (GET_CODE (src) == LO_SUM
|
3085 |
|
|
&& ! TARGET_CM_MEDMID
|
3086 |
|
|
&& ((register_operand (XEXP (src, 0), SImode)
|
3087 |
|
|
&& immediate_operand (XEXP (src, 1), SImode))
|
3088 |
|
|
|| (TARGET_ARCH64
|
3089 |
|
|
&& register_operand (XEXP (src, 0), DImode)
|
3090 |
|
|
&& immediate_operand (XEXP (src, 1), DImode))))
|
3091 |
|
|
return 1;
|
3092 |
|
|
|
3093 |
|
|
/* The 'restore src,src,dest' pattern. */
|
3094 |
|
|
else if (GET_CODE (src) == ASHIFT
|
3095 |
|
|
&& (register_operand (XEXP (src, 0), SImode)
|
3096 |
|
|
|| register_operand (XEXP (src, 0), DImode))
|
3097 |
|
|
&& XEXP (src, 1) == const1_rtx)
|
3098 |
|
|
return 1;
|
3099 |
|
|
|
3100 |
|
|
return 0;
|
3101 |
|
|
}
|
3102 |
|
|
|
3103 |
|
|
/* Return nonzero if TRIAL can go into the function return's delay slot. */
|
3104 |
|
|
|
3105 |
|
|
int
|
3106 |
|
|
eligible_for_return_delay (rtx trial)
|
3107 |
|
|
{
|
3108 |
|
|
int regno;
|
3109 |
|
|
rtx pat;
|
3110 |
|
|
|
3111 |
|
|
if (GET_CODE (trial) != INSN)
|
3112 |
|
|
return 0;
|
3113 |
|
|
|
3114 |
|
|
if (get_attr_length (trial) != 1)
|
3115 |
|
|
return 0;
|
3116 |
|
|
|
3117 |
|
|
/* If the function uses __builtin_eh_return, the eh_return machinery
|
3118 |
|
|
occupies the delay slot. */
|
3119 |
|
|
if (crtl->calls_eh_return)
|
3120 |
|
|
return 0;
|
3121 |
|
|
|
3122 |
|
|
/* In the case of a leaf or flat function, anything can go into the slot. */
|
3123 |
|
|
if (sparc_leaf_function_p || TARGET_FLAT)
|
3124 |
|
|
return
|
3125 |
|
|
get_attr_in_uncond_branch_delay (trial) == IN_UNCOND_BRANCH_DELAY_TRUE;
|
3126 |
|
|
|
3127 |
|
|
pat = PATTERN (trial);
|
3128 |
|
|
if (GET_CODE (pat) == PARALLEL)
|
3129 |
|
|
{
|
3130 |
|
|
int i;
|
3131 |
|
|
|
3132 |
|
|
if (! TARGET_V9)
|
3133 |
|
|
return 0;
|
3134 |
|
|
for (i = XVECLEN (pat, 0) - 1; i >= 0; i--)
|
3135 |
|
|
{
|
3136 |
|
|
rtx expr = XVECEXP (pat, 0, i);
|
3137 |
|
|
if (GET_CODE (expr) != SET)
|
3138 |
|
|
return 0;
|
3139 |
|
|
if (GET_CODE (SET_DEST (expr)) != REG)
|
3140 |
|
|
return 0;
|
3141 |
|
|
regno = REGNO (SET_DEST (expr));
|
3142 |
|
|
if (regno >= 8 && regno < 24)
|
3143 |
|
|
return 0;
|
3144 |
|
|
}
|
3145 |
|
|
return !epilogue_renumber (&pat, 1)
|
3146 |
|
|
&& (get_attr_in_uncond_branch_delay (trial)
|
3147 |
|
|
== IN_UNCOND_BRANCH_DELAY_TRUE);
|
3148 |
|
|
}
|
3149 |
|
|
|
3150 |
|
|
if (GET_CODE (pat) != SET)
|
3151 |
|
|
return 0;
|
3152 |
|
|
|
3153 |
|
|
if (GET_CODE (SET_DEST (pat)) != REG)
|
3154 |
|
|
return 0;
|
3155 |
|
|
|
3156 |
|
|
regno = REGNO (SET_DEST (pat));
|
3157 |
|
|
|
3158 |
|
|
/* Otherwise, only operations which can be done in tandem with
|
3159 |
|
|
a `restore' or `return' insn can go into the delay slot. */
|
3160 |
|
|
if (regno >= 8 && regno < 24)
|
3161 |
|
|
return 0;
|
3162 |
|
|
|
3163 |
|
|
/* If this instruction sets up floating point register and we have a return
|
3164 |
|
|
instruction, it can probably go in. But restore will not work
|
3165 |
|
|
with FP_REGS. */
|
3166 |
|
|
if (! SPARC_INT_REG_P (regno))
|
3167 |
|
|
return (TARGET_V9
|
3168 |
|
|
&& !epilogue_renumber (&pat, 1)
|
3169 |
|
|
&& get_attr_in_uncond_branch_delay (trial)
|
3170 |
|
|
== IN_UNCOND_BRANCH_DELAY_TRUE);
|
3171 |
|
|
|
3172 |
|
|
return eligible_for_restore_insn (trial, true);
|
3173 |
|
|
}
|
3174 |
|
|
|
3175 |
|
|
/* Return nonzero if TRIAL can go into the sibling call's delay slot. */
|
3176 |
|
|
|
3177 |
|
|
int
|
3178 |
|
|
eligible_for_sibcall_delay (rtx trial)
|
3179 |
|
|
{
|
3180 |
|
|
rtx pat;
|
3181 |
|
|
|
3182 |
|
|
if (GET_CODE (trial) != INSN || GET_CODE (PATTERN (trial)) != SET)
|
3183 |
|
|
return 0;
|
3184 |
|
|
|
3185 |
|
|
if (get_attr_length (trial) != 1)
|
3186 |
|
|
return 0;
|
3187 |
|
|
|
3188 |
|
|
pat = PATTERN (trial);
|
3189 |
|
|
|
3190 |
|
|
if (sparc_leaf_function_p || TARGET_FLAT)
|
3191 |
|
|
{
|
3192 |
|
|
/* If the tail call is done using the call instruction,
|
3193 |
|
|
we have to restore %o7 in the delay slot. */
|
3194 |
|
|
if (LEAF_SIBCALL_SLOT_RESERVED_P)
|
3195 |
|
|
return 0;
|
3196 |
|
|
|
3197 |
|
|
/* %g1 is used to build the function address */
|
3198 |
|
|
if (reg_mentioned_p (gen_rtx_REG (Pmode, 1), pat))
|
3199 |
|
|
return 0;
|
3200 |
|
|
|
3201 |
|
|
return 1;
|
3202 |
|
|
}
|
3203 |
|
|
|
3204 |
|
|
/* Otherwise, only operations which can be done in tandem with
|
3205 |
|
|
a `restore' insn can go into the delay slot. */
|
3206 |
|
|
if (GET_CODE (SET_DEST (pat)) != REG
|
3207 |
|
|
|| (REGNO (SET_DEST (pat)) >= 8 && REGNO (SET_DEST (pat)) < 24)
|
3208 |
|
|
|| ! SPARC_INT_REG_P (REGNO (SET_DEST (pat))))
|
3209 |
|
|
return 0;
|
3210 |
|
|
|
3211 |
|
|
/* If it mentions %o7, it can't go in, because sibcall will clobber it
|
3212 |
|
|
in most cases. */
|
3213 |
|
|
if (reg_mentioned_p (gen_rtx_REG (Pmode, 15), pat))
|
3214 |
|
|
return 0;
|
3215 |
|
|
|
3216 |
|
|
return eligible_for_restore_insn (trial, false);
|
3217 |
|
|
}
|
3218 |
|
|
|
3219 |
|
|
/* Determine if it's legal to put X into the constant pool. This
|
3220 |
|
|
is not possible if X contains the address of a symbol that is
|
3221 |
|
|
not constant (TLS) or not known at final link time (PIC). */
|
3222 |
|
|
|
3223 |
|
|
static bool
|
3224 |
|
|
sparc_cannot_force_const_mem (enum machine_mode mode, rtx x)
|
3225 |
|
|
{
|
3226 |
|
|
switch (GET_CODE (x))
|
3227 |
|
|
{
|
3228 |
|
|
case CONST_INT:
|
3229 |
|
|
case CONST_DOUBLE:
|
3230 |
|
|
case CONST_VECTOR:
|
3231 |
|
|
/* Accept all non-symbolic constants. */
|
3232 |
|
|
return false;
|
3233 |
|
|
|
3234 |
|
|
case LABEL_REF:
|
3235 |
|
|
/* Labels are OK iff we are non-PIC. */
|
3236 |
|
|
return flag_pic != 0;
|
3237 |
|
|
|
3238 |
|
|
case SYMBOL_REF:
|
3239 |
|
|
/* 'Naked' TLS symbol references are never OK,
|
3240 |
|
|
non-TLS symbols are OK iff we are non-PIC. */
|
3241 |
|
|
if (SYMBOL_REF_TLS_MODEL (x))
|
3242 |
|
|
return true;
|
3243 |
|
|
else
|
3244 |
|
|
return flag_pic != 0;
|
3245 |
|
|
|
3246 |
|
|
case CONST:
|
3247 |
|
|
return sparc_cannot_force_const_mem (mode, XEXP (x, 0));
|
3248 |
|
|
case PLUS:
|
3249 |
|
|
case MINUS:
|
3250 |
|
|
return sparc_cannot_force_const_mem (mode, XEXP (x, 0))
|
3251 |
|
|
|| sparc_cannot_force_const_mem (mode, XEXP (x, 1));
|
3252 |
|
|
case UNSPEC:
|
3253 |
|
|
return true;
|
3254 |
|
|
default:
|
3255 |
|
|
gcc_unreachable ();
|
3256 |
|
|
}
|
3257 |
|
|
}
|
3258 |
|
|
|
3259 |
|
|
/* Global Offset Table support. */
|
3260 |
|
|
static GTY(()) rtx got_helper_rtx = NULL_RTX;
|
3261 |
|
|
static GTY(()) rtx global_offset_table_rtx = NULL_RTX;
|
3262 |
|
|
|
3263 |
|
|
/* Return the SYMBOL_REF for the Global Offset Table. */
|
3264 |
|
|
|
3265 |
|
|
static GTY(()) rtx sparc_got_symbol = NULL_RTX;
|
3266 |
|
|
|
3267 |
|
|
static rtx
|
3268 |
|
|
sparc_got (void)
|
3269 |
|
|
{
|
3270 |
|
|
if (!sparc_got_symbol)
|
3271 |
|
|
sparc_got_symbol = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
|
3272 |
|
|
|
3273 |
|
|
return sparc_got_symbol;
|
3274 |
|
|
}
|
3275 |
|
|
|
3276 |
|
|
/* Ensure that we are not using patterns that are not OK with PIC. */
|
3277 |
|
|
|
3278 |
|
|
int
|
3279 |
|
|
check_pic (int i)
|
3280 |
|
|
{
|
3281 |
|
|
rtx op;
|
3282 |
|
|
|
3283 |
|
|
switch (flag_pic)
|
3284 |
|
|
{
|
3285 |
|
|
case 1:
|
3286 |
|
|
op = recog_data.operand[i];
|
3287 |
|
|
gcc_assert (GET_CODE (op) != SYMBOL_REF
|
3288 |
|
|
&& (GET_CODE (op) != CONST
|
3289 |
|
|
|| (GET_CODE (XEXP (op, 0)) == MINUS
|
3290 |
|
|
&& XEXP (XEXP (op, 0), 0) == sparc_got ()
|
3291 |
|
|
&& GET_CODE (XEXP (XEXP (op, 0), 1)) == CONST)));
|
3292 |
|
|
case 2:
|
3293 |
|
|
default:
|
3294 |
|
|
return 1;
|
3295 |
|
|
}
|
3296 |
|
|
}
|
3297 |
|
|
|
3298 |
|
|
/* Return true if X is an address which needs a temporary register when
|
3299 |
|
|
reloaded while generating PIC code. */
|
3300 |
|
|
|
3301 |
|
|
int
|
3302 |
|
|
pic_address_needs_scratch (rtx x)
|
3303 |
|
|
{
|
3304 |
|
|
/* An address which is a symbolic plus a non SMALL_INT needs a temp reg. */
|
3305 |
|
|
if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS
|
3306 |
|
|
&& GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
|
3307 |
|
|
&& GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
|
3308 |
|
|
&& ! SMALL_INT (XEXP (XEXP (x, 0), 1)))
|
3309 |
|
|
return 1;
|
3310 |
|
|
|
3311 |
|
|
return 0;
|
3312 |
|
|
}
|
3313 |
|
|
|
3314 |
|
|
/* Determine if a given RTX is a valid constant. We already know this
|
3315 |
|
|
satisfies CONSTANT_P. */
|
3316 |
|
|
|
3317 |
|
|
static bool
|
3318 |
|
|
sparc_legitimate_constant_p (enum machine_mode mode, rtx x)
|
3319 |
|
|
{
|
3320 |
|
|
switch (GET_CODE (x))
|
3321 |
|
|
{
|
3322 |
|
|
case CONST:
|
3323 |
|
|
case SYMBOL_REF:
|
3324 |
|
|
if (sparc_tls_referenced_p (x))
|
3325 |
|
|
return false;
|
3326 |
|
|
break;
|
3327 |
|
|
|
3328 |
|
|
case CONST_DOUBLE:
|
3329 |
|
|
if (GET_MODE (x) == VOIDmode)
|
3330 |
|
|
return true;
|
3331 |
|
|
|
3332 |
|
|
/* Floating point constants are generally not ok.
|
3333 |
|
|
The only exception is 0.0 and all-ones in VIS. */
|
3334 |
|
|
if (TARGET_VIS
|
3335 |
|
|
&& SCALAR_FLOAT_MODE_P (mode)
|
3336 |
|
|
&& (const_zero_operand (x, mode)
|
3337 |
|
|
|| const_all_ones_operand (x, mode)))
|
3338 |
|
|
return true;
|
3339 |
|
|
|
3340 |
|
|
return false;
|
3341 |
|
|
|
3342 |
|
|
case CONST_VECTOR:
|
3343 |
|
|
/* Vector constants are generally not ok.
|
3344 |
|
|
The only exception is 0 or -1 in VIS. */
|
3345 |
|
|
if (TARGET_VIS
|
3346 |
|
|
&& (const_zero_operand (x, mode)
|
3347 |
|
|
|| const_all_ones_operand (x, mode)))
|
3348 |
|
|
return true;
|
3349 |
|
|
|
3350 |
|
|
return false;
|
3351 |
|
|
|
3352 |
|
|
default:
|
3353 |
|
|
break;
|
3354 |
|
|
}
|
3355 |
|
|
|
3356 |
|
|
return true;
|
3357 |
|
|
}
|
3358 |
|
|
|
3359 |
|
|
/* Determine if a given RTX is a valid constant address. */
|
3360 |
|
|
|
3361 |
|
|
bool
|
3362 |
|
|
constant_address_p (rtx x)
|
3363 |
|
|
{
|
3364 |
|
|
switch (GET_CODE (x))
|
3365 |
|
|
{
|
3366 |
|
|
case LABEL_REF:
|
3367 |
|
|
case CONST_INT:
|
3368 |
|
|
case HIGH:
|
3369 |
|
|
return true;
|
3370 |
|
|
|
3371 |
|
|
case CONST:
|
3372 |
|
|
if (flag_pic && pic_address_needs_scratch (x))
|
3373 |
|
|
return false;
|
3374 |
|
|
return sparc_legitimate_constant_p (Pmode, x);
|
3375 |
|
|
|
3376 |
|
|
case SYMBOL_REF:
|
3377 |
|
|
return !flag_pic && sparc_legitimate_constant_p (Pmode, x);
|
3378 |
|
|
|
3379 |
|
|
default:
|
3380 |
|
|
return false;
|
3381 |
|
|
}
|
3382 |
|
|
}
|
3383 |
|
|
|
3384 |
|
|
/* Nonzero if the constant value X is a legitimate general operand
|
3385 |
|
|
when generating PIC code. It is given that flag_pic is on and
|
3386 |
|
|
that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
|
3387 |
|
|
|
3388 |
|
|
bool
|
3389 |
|
|
legitimate_pic_operand_p (rtx x)
|
3390 |
|
|
{
|
3391 |
|
|
if (pic_address_needs_scratch (x))
|
3392 |
|
|
return false;
|
3393 |
|
|
if (sparc_tls_referenced_p (x))
|
3394 |
|
|
return false;
|
3395 |
|
|
return true;
|
3396 |
|
|
}
|
3397 |
|
|
|
3398 |
|
|
#define RTX_OK_FOR_OFFSET_P(X, MODE) \
|
3399 |
|
|
(CONST_INT_P (X) \
|
3400 |
|
|
&& INTVAL (X) >= -0x1000 \
|
3401 |
|
|
&& INTVAL (X) < (0x1000 - GET_MODE_SIZE (MODE)))
|
3402 |
|
|
|
3403 |
|
|
#define RTX_OK_FOR_OLO10_P(X, MODE) \
|
3404 |
|
|
(CONST_INT_P (X) \
|
3405 |
|
|
&& INTVAL (X) >= -0x1000 \
|
3406 |
|
|
&& INTVAL (X) < (0xc00 - GET_MODE_SIZE (MODE)))
|
3407 |
|
|
|
3408 |
|
|
/* Handle the TARGET_LEGITIMATE_ADDRESS_P target hook.
|
3409 |
|
|
|
3410 |
|
|
On SPARC, the actual legitimate addresses must be REG+REG or REG+SMALLINT
|
3411 |
|
|
ordinarily. This changes a bit when generating PIC. */
|
3412 |
|
|
|
3413 |
|
|
static bool
|
3414 |
|
|
sparc_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
|
3415 |
|
|
{
|
3416 |
|
|
rtx rs1 = NULL, rs2 = NULL, imm1 = NULL;
|
3417 |
|
|
|
3418 |
|
|
if (REG_P (addr) || GET_CODE (addr) == SUBREG)
|
3419 |
|
|
rs1 = addr;
|
3420 |
|
|
else if (GET_CODE (addr) == PLUS)
|
3421 |
|
|
{
|
3422 |
|
|
rs1 = XEXP (addr, 0);
|
3423 |
|
|
rs2 = XEXP (addr, 1);
|
3424 |
|
|
|
3425 |
|
|
/* Canonicalize. REG comes first, if there are no regs,
|
3426 |
|
|
LO_SUM comes first. */
|
3427 |
|
|
if (!REG_P (rs1)
|
3428 |
|
|
&& GET_CODE (rs1) != SUBREG
|
3429 |
|
|
&& (REG_P (rs2)
|
3430 |
|
|
|| GET_CODE (rs2) == SUBREG
|
3431 |
|
|
|| (GET_CODE (rs2) == LO_SUM && GET_CODE (rs1) != LO_SUM)))
|
3432 |
|
|
{
|
3433 |
|
|
rs1 = XEXP (addr, 1);
|
3434 |
|
|
rs2 = XEXP (addr, 0);
|
3435 |
|
|
}
|
3436 |
|
|
|
3437 |
|
|
if ((flag_pic == 1
|
3438 |
|
|
&& rs1 == pic_offset_table_rtx
|
3439 |
|
|
&& !REG_P (rs2)
|
3440 |
|
|
&& GET_CODE (rs2) != SUBREG
|
3441 |
|
|
&& GET_CODE (rs2) != LO_SUM
|
3442 |
|
|
&& GET_CODE (rs2) != MEM
|
3443 |
|
|
&& !(GET_CODE (rs2) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs2))
|
3444 |
|
|
&& (! symbolic_operand (rs2, VOIDmode) || mode == Pmode)
|
3445 |
|
|
&& (GET_CODE (rs2) != CONST_INT || SMALL_INT (rs2)))
|
3446 |
|
|
|| ((REG_P (rs1)
|
3447 |
|
|
|| GET_CODE (rs1) == SUBREG)
|
3448 |
|
|
&& RTX_OK_FOR_OFFSET_P (rs2, mode)))
|
3449 |
|
|
{
|
3450 |
|
|
imm1 = rs2;
|
3451 |
|
|
rs2 = NULL;
|
3452 |
|
|
}
|
3453 |
|
|
else if ((REG_P (rs1) || GET_CODE (rs1) == SUBREG)
|
3454 |
|
|
&& (REG_P (rs2) || GET_CODE (rs2) == SUBREG))
|
3455 |
|
|
{
|
3456 |
|
|
/* We prohibit REG + REG for TFmode when there are no quad move insns
|
3457 |
|
|
and we consequently need to split. We do this because REG+REG
|
3458 |
|
|
is not an offsettable address. If we get the situation in reload
|
3459 |
|
|
where source and destination of a movtf pattern are both MEMs with
|
3460 |
|
|
REG+REG address, then only one of them gets converted to an
|
3461 |
|
|
offsettable address. */
|
3462 |
|
|
if (mode == TFmode
|
3463 |
|
|
&& ! (TARGET_ARCH64 && TARGET_HARD_QUAD))
|
3464 |
|
|
return 0;
|
3465 |
|
|
|
3466 |
|
|
/* We prohibit REG + REG on ARCH32 if not optimizing for
|
3467 |
|
|
DFmode/DImode because then mem_min_alignment is likely to be zero
|
3468 |
|
|
after reload and the forced split would lack a matching splitter
|
3469 |
|
|
pattern. */
|
3470 |
|
|
if (TARGET_ARCH32 && !optimize
|
3471 |
|
|
&& (mode == DFmode || mode == DImode))
|
3472 |
|
|
return 0;
|
3473 |
|
|
}
|
3474 |
|
|
else if (USE_AS_OFFSETABLE_LO10
|
3475 |
|
|
&& GET_CODE (rs1) == LO_SUM
|
3476 |
|
|
&& TARGET_ARCH64
|
3477 |
|
|
&& ! TARGET_CM_MEDMID
|
3478 |
|
|
&& RTX_OK_FOR_OLO10_P (rs2, mode))
|
3479 |
|
|
{
|
3480 |
|
|
rs2 = NULL;
|
3481 |
|
|
imm1 = XEXP (rs1, 1);
|
3482 |
|
|
rs1 = XEXP (rs1, 0);
|
3483 |
|
|
if (!CONSTANT_P (imm1)
|
3484 |
|
|
|| (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
|
3485 |
|
|
return 0;
|
3486 |
|
|
}
|
3487 |
|
|
}
|
3488 |
|
|
else if (GET_CODE (addr) == LO_SUM)
|
3489 |
|
|
{
|
3490 |
|
|
rs1 = XEXP (addr, 0);
|
3491 |
|
|
imm1 = XEXP (addr, 1);
|
3492 |
|
|
|
3493 |
|
|
if (!CONSTANT_P (imm1)
|
3494 |
|
|
|| (GET_CODE (rs1) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (rs1)))
|
3495 |
|
|
return 0;
|
3496 |
|
|
|
3497 |
|
|
/* We can't allow TFmode in 32-bit mode, because an offset greater
|
3498 |
|
|
than the alignment (8) may cause the LO_SUM to overflow. */
|
3499 |
|
|
if (mode == TFmode && TARGET_ARCH32)
|
3500 |
|
|
return 0;
|
3501 |
|
|
}
|
3502 |
|
|
else if (GET_CODE (addr) == CONST_INT && SMALL_INT (addr))
|
3503 |
|
|
return 1;
|
3504 |
|
|
else
|
3505 |
|
|
return 0;
|
3506 |
|
|
|
3507 |
|
|
if (GET_CODE (rs1) == SUBREG)
|
3508 |
|
|
rs1 = SUBREG_REG (rs1);
|
3509 |
|
|
if (!REG_P (rs1))
|
3510 |
|
|
return 0;
|
3511 |
|
|
|
3512 |
|
|
if (rs2)
|
3513 |
|
|
{
|
3514 |
|
|
if (GET_CODE (rs2) == SUBREG)
|
3515 |
|
|
rs2 = SUBREG_REG (rs2);
|
3516 |
|
|
if (!REG_P (rs2))
|
3517 |
|
|
return 0;
|
3518 |
|
|
}
|
3519 |
|
|
|
3520 |
|
|
if (strict)
|
3521 |
|
|
{
|
3522 |
|
|
if (!REGNO_OK_FOR_BASE_P (REGNO (rs1))
|
3523 |
|
|
|| (rs2 && !REGNO_OK_FOR_BASE_P (REGNO (rs2))))
|
3524 |
|
|
return 0;
|
3525 |
|
|
}
|
3526 |
|
|
else
|
3527 |
|
|
{
|
3528 |
|
|
if ((! SPARC_INT_REG_P (REGNO (rs1))
|
3529 |
|
|
&& REGNO (rs1) != FRAME_POINTER_REGNUM
|
3530 |
|
|
&& REGNO (rs1) < FIRST_PSEUDO_REGISTER)
|
3531 |
|
|
|| (rs2
|
3532 |
|
|
&& (! SPARC_INT_REG_P (REGNO (rs2))
|
3533 |
|
|
&& REGNO (rs2) != FRAME_POINTER_REGNUM
|
3534 |
|
|
&& REGNO (rs2) < FIRST_PSEUDO_REGISTER)))
|
3535 |
|
|
return 0;
|
3536 |
|
|
}
|
3537 |
|
|
return 1;
|
3538 |
|
|
}
|
3539 |
|
|
|
3540 |
|
|
/* Return the SYMBOL_REF for the tls_get_addr function. */
|
3541 |
|
|
|
3542 |
|
|
static GTY(()) rtx sparc_tls_symbol = NULL_RTX;
|
3543 |
|
|
|
3544 |
|
|
static rtx
|
3545 |
|
|
sparc_tls_get_addr (void)
|
3546 |
|
|
{
|
3547 |
|
|
if (!sparc_tls_symbol)
|
3548 |
|
|
sparc_tls_symbol = gen_rtx_SYMBOL_REF (Pmode, "__tls_get_addr");
|
3549 |
|
|
|
3550 |
|
|
return sparc_tls_symbol;
|
3551 |
|
|
}
|
3552 |
|
|
|
3553 |
|
|
/* Return the Global Offset Table to be used in TLS mode. */
|
3554 |
|
|
|
3555 |
|
|
static rtx
|
3556 |
|
|
sparc_tls_got (void)
|
3557 |
|
|
{
|
3558 |
|
|
/* In PIC mode, this is just the PIC offset table. */
|
3559 |
|
|
if (flag_pic)
|
3560 |
|
|
{
|
3561 |
|
|
crtl->uses_pic_offset_table = 1;
|
3562 |
|
|
return pic_offset_table_rtx;
|
3563 |
|
|
}
|
3564 |
|
|
|
3565 |
|
|
/* In non-PIC mode, Sun as (unlike GNU as) emits PC-relative relocations for
|
3566 |
|
|
the GOT symbol with the 32-bit ABI, so we reload the GOT register. */
|
3567 |
|
|
if (TARGET_SUN_TLS && TARGET_ARCH32)
|
3568 |
|
|
{
|
3569 |
|
|
load_got_register ();
|
3570 |
|
|
return global_offset_table_rtx;
|
3571 |
|
|
}
|
3572 |
|
|
|
3573 |
|
|
/* In all other cases, we load a new pseudo with the GOT symbol. */
|
3574 |
|
|
return copy_to_reg (sparc_got ());
|
3575 |
|
|
}
|
3576 |
|
|
|
3577 |
|
|
/* Return true if X contains a thread-local symbol. */
|
3578 |
|
|
|
3579 |
|
|
static bool
|
3580 |
|
|
sparc_tls_referenced_p (rtx x)
|
3581 |
|
|
{
|
3582 |
|
|
if (!TARGET_HAVE_TLS)
|
3583 |
|
|
return false;
|
3584 |
|
|
|
3585 |
|
|
if (GET_CODE (x) == CONST && GET_CODE (XEXP (x, 0)) == PLUS)
|
3586 |
|
|
x = XEXP (XEXP (x, 0), 0);
|
3587 |
|
|
|
3588 |
|
|
if (GET_CODE (x) == SYMBOL_REF && SYMBOL_REF_TLS_MODEL (x))
|
3589 |
|
|
return true;
|
3590 |
|
|
|
3591 |
|
|
/* That's all we handle in sparc_legitimize_tls_address for now. */
|
3592 |
|
|
return false;
|
3593 |
|
|
}
|
3594 |
|
|
|
3595 |
|
|
/* ADDR contains a thread-local SYMBOL_REF. Generate code to compute
|
3596 |
|
|
this (thread-local) address. */
|
3597 |
|
|
|
3598 |
|
|
static rtx
|
3599 |
|
|
sparc_legitimize_tls_address (rtx addr)
|
3600 |
|
|
{
|
3601 |
|
|
rtx temp1, temp2, temp3, ret, o0, got, insn;
|
3602 |
|
|
|
3603 |
|
|
gcc_assert (can_create_pseudo_p ());
|
3604 |
|
|
|
3605 |
|
|
if (GET_CODE (addr) == SYMBOL_REF)
|
3606 |
|
|
switch (SYMBOL_REF_TLS_MODEL (addr))
|
3607 |
|
|
{
|
3608 |
|
|
case TLS_MODEL_GLOBAL_DYNAMIC:
|
3609 |
|
|
start_sequence ();
|
3610 |
|
|
temp1 = gen_reg_rtx (SImode);
|
3611 |
|
|
temp2 = gen_reg_rtx (SImode);
|
3612 |
|
|
ret = gen_reg_rtx (Pmode);
|
3613 |
|
|
o0 = gen_rtx_REG (Pmode, 8);
|
3614 |
|
|
got = sparc_tls_got ();
|
3615 |
|
|
emit_insn (gen_tgd_hi22 (temp1, addr));
|
3616 |
|
|
emit_insn (gen_tgd_lo10 (temp2, temp1, addr));
|
3617 |
|
|
if (TARGET_ARCH32)
|
3618 |
|
|
{
|
3619 |
|
|
emit_insn (gen_tgd_add32 (o0, got, temp2, addr));
|
3620 |
|
|
insn = emit_call_insn (gen_tgd_call32 (o0, sparc_tls_get_addr (),
|
3621 |
|
|
addr, const1_rtx));
|
3622 |
|
|
}
|
3623 |
|
|
else
|
3624 |
|
|
{
|
3625 |
|
|
emit_insn (gen_tgd_add64 (o0, got, temp2, addr));
|
3626 |
|
|
insn = emit_call_insn (gen_tgd_call64 (o0, sparc_tls_get_addr (),
|
3627 |
|
|
addr, const1_rtx));
|
3628 |
|
|
}
|
3629 |
|
|
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), o0);
|
3630 |
|
|
insn = get_insns ();
|
3631 |
|
|
end_sequence ();
|
3632 |
|
|
emit_libcall_block (insn, ret, o0, addr);
|
3633 |
|
|
break;
|
3634 |
|
|
|
3635 |
|
|
case TLS_MODEL_LOCAL_DYNAMIC:
|
3636 |
|
|
start_sequence ();
|
3637 |
|
|
temp1 = gen_reg_rtx (SImode);
|
3638 |
|
|
temp2 = gen_reg_rtx (SImode);
|
3639 |
|
|
temp3 = gen_reg_rtx (Pmode);
|
3640 |
|
|
ret = gen_reg_rtx (Pmode);
|
3641 |
|
|
o0 = gen_rtx_REG (Pmode, 8);
|
3642 |
|
|
got = sparc_tls_got ();
|
3643 |
|
|
emit_insn (gen_tldm_hi22 (temp1));
|
3644 |
|
|
emit_insn (gen_tldm_lo10 (temp2, temp1));
|
3645 |
|
|
if (TARGET_ARCH32)
|
3646 |
|
|
{
|
3647 |
|
|
emit_insn (gen_tldm_add32 (o0, got, temp2));
|
3648 |
|
|
insn = emit_call_insn (gen_tldm_call32 (o0, sparc_tls_get_addr (),
|
3649 |
|
|
const1_rtx));
|
3650 |
|
|
}
|
3651 |
|
|
else
|
3652 |
|
|
{
|
3653 |
|
|
emit_insn (gen_tldm_add64 (o0, got, temp2));
|
3654 |
|
|
insn = emit_call_insn (gen_tldm_call64 (o0, sparc_tls_get_addr (),
|
3655 |
|
|
const1_rtx));
|
3656 |
|
|
}
|
3657 |
|
|
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), o0);
|
3658 |
|
|
insn = get_insns ();
|
3659 |
|
|
end_sequence ();
|
3660 |
|
|
emit_libcall_block (insn, temp3, o0,
|
3661 |
|
|
gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const0_rtx),
|
3662 |
|
|
UNSPEC_TLSLD_BASE));
|
3663 |
|
|
temp1 = gen_reg_rtx (SImode);
|
3664 |
|
|
temp2 = gen_reg_rtx (SImode);
|
3665 |
|
|
emit_insn (gen_tldo_hix22 (temp1, addr));
|
3666 |
|
|
emit_insn (gen_tldo_lox10 (temp2, temp1, addr));
|
3667 |
|
|
if (TARGET_ARCH32)
|
3668 |
|
|
emit_insn (gen_tldo_add32 (ret, temp3, temp2, addr));
|
3669 |
|
|
else
|
3670 |
|
|
emit_insn (gen_tldo_add64 (ret, temp3, temp2, addr));
|
3671 |
|
|
break;
|
3672 |
|
|
|
3673 |
|
|
case TLS_MODEL_INITIAL_EXEC:
|
3674 |
|
|
temp1 = gen_reg_rtx (SImode);
|
3675 |
|
|
temp2 = gen_reg_rtx (SImode);
|
3676 |
|
|
temp3 = gen_reg_rtx (Pmode);
|
3677 |
|
|
got = sparc_tls_got ();
|
3678 |
|
|
emit_insn (gen_tie_hi22 (temp1, addr));
|
3679 |
|
|
emit_insn (gen_tie_lo10 (temp2, temp1, addr));
|
3680 |
|
|
if (TARGET_ARCH32)
|
3681 |
|
|
emit_insn (gen_tie_ld32 (temp3, got, temp2, addr));
|
3682 |
|
|
else
|
3683 |
|
|
emit_insn (gen_tie_ld64 (temp3, got, temp2, addr));
|
3684 |
|
|
if (TARGET_SUN_TLS)
|
3685 |
|
|
{
|
3686 |
|
|
ret = gen_reg_rtx (Pmode);
|
3687 |
|
|
if (TARGET_ARCH32)
|
3688 |
|
|
emit_insn (gen_tie_add32 (ret, gen_rtx_REG (Pmode, 7),
|
3689 |
|
|
temp3, addr));
|
3690 |
|
|
else
|
3691 |
|
|
emit_insn (gen_tie_add64 (ret, gen_rtx_REG (Pmode, 7),
|
3692 |
|
|
temp3, addr));
|
3693 |
|
|
}
|
3694 |
|
|
else
|
3695 |
|
|
ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp3);
|
3696 |
|
|
break;
|
3697 |
|
|
|
3698 |
|
|
case TLS_MODEL_LOCAL_EXEC:
|
3699 |
|
|
temp1 = gen_reg_rtx (Pmode);
|
3700 |
|
|
temp2 = gen_reg_rtx (Pmode);
|
3701 |
|
|
if (TARGET_ARCH32)
|
3702 |
|
|
{
|
3703 |
|
|
emit_insn (gen_tle_hix22_sp32 (temp1, addr));
|
3704 |
|
|
emit_insn (gen_tle_lox10_sp32 (temp2, temp1, addr));
|
3705 |
|
|
}
|
3706 |
|
|
else
|
3707 |
|
|
{
|
3708 |
|
|
emit_insn (gen_tle_hix22_sp64 (temp1, addr));
|
3709 |
|
|
emit_insn (gen_tle_lox10_sp64 (temp2, temp1, addr));
|
3710 |
|
|
}
|
3711 |
|
|
ret = gen_rtx_PLUS (Pmode, gen_rtx_REG (Pmode, 7), temp2);
|
3712 |
|
|
break;
|
3713 |
|
|
|
3714 |
|
|
default:
|
3715 |
|
|
gcc_unreachable ();
|
3716 |
|
|
}
|
3717 |
|
|
|
3718 |
|
|
else if (GET_CODE (addr) == CONST)
|
3719 |
|
|
{
|
3720 |
|
|
rtx base, offset;
|
3721 |
|
|
|
3722 |
|
|
gcc_assert (GET_CODE (XEXP (addr, 0)) == PLUS);
|
3723 |
|
|
|
3724 |
|
|
base = sparc_legitimize_tls_address (XEXP (XEXP (addr, 0), 0));
|
3725 |
|
|
offset = XEXP (XEXP (addr, 0), 1);
|
3726 |
|
|
|
3727 |
|
|
base = force_operand (base, NULL_RTX);
|
3728 |
|
|
if (!(GET_CODE (offset) == CONST_INT && SMALL_INT (offset)))
|
3729 |
|
|
offset = force_reg (Pmode, offset);
|
3730 |
|
|
ret = gen_rtx_PLUS (Pmode, base, offset);
|
3731 |
|
|
}
|
3732 |
|
|
|
3733 |
|
|
else
|
3734 |
|
|
gcc_unreachable (); /* for now ... */
|
3735 |
|
|
|
3736 |
|
|
return ret;
|
3737 |
|
|
}
|
3738 |
|
|
|
3739 |
|
|
/* Legitimize PIC addresses. If the address is already position-independent,
|
3740 |
|
|
we return ORIG. Newly generated position-independent addresses go into a
|
3741 |
|
|
reg. This is REG if nonzero, otherwise we allocate register(s) as
|
3742 |
|
|
necessary. */
|
3743 |
|
|
|
3744 |
|
|
static rtx
|
3745 |
|
|
sparc_legitimize_pic_address (rtx orig, rtx reg)
|
3746 |
|
|
{
|
3747 |
|
|
bool gotdata_op = false;
|
3748 |
|
|
|
3749 |
|
|
if (GET_CODE (orig) == SYMBOL_REF
|
3750 |
|
|
/* See the comment in sparc_expand_move. */
|
3751 |
|
|
|| (GET_CODE (orig) == LABEL_REF && !can_use_mov_pic_label_ref (orig)))
|
3752 |
|
|
{
|
3753 |
|
|
rtx pic_ref, address;
|
3754 |
|
|
rtx insn;
|
3755 |
|
|
|
3756 |
|
|
if (reg == 0)
|
3757 |
|
|
{
|
3758 |
|
|
gcc_assert (can_create_pseudo_p ());
|
3759 |
|
|
reg = gen_reg_rtx (Pmode);
|
3760 |
|
|
}
|
3761 |
|
|
|
3762 |
|
|
if (flag_pic == 2)
|
3763 |
|
|
{
|
3764 |
|
|
/* If not during reload, allocate another temp reg here for loading
|
3765 |
|
|
in the address, so that these instructions can be optimized
|
3766 |
|
|
properly. */
|
3767 |
|
|
rtx temp_reg = (! can_create_pseudo_p ()
|
3768 |
|
|
? reg : gen_reg_rtx (Pmode));
|
3769 |
|
|
|
3770 |
|
|
/* Must put the SYMBOL_REF inside an UNSPEC here so that cse
|
3771 |
|
|
won't get confused into thinking that these two instructions
|
3772 |
|
|
are loading in the true address of the symbol. If in the
|
3773 |
|
|
future a PIC rtx exists, that should be used instead. */
|
3774 |
|
|
if (TARGET_ARCH64)
|
3775 |
|
|
{
|
3776 |
|
|
emit_insn (gen_movdi_high_pic (temp_reg, orig));
|
3777 |
|
|
emit_insn (gen_movdi_lo_sum_pic (temp_reg, temp_reg, orig));
|
3778 |
|
|
}
|
3779 |
|
|
else
|
3780 |
|
|
{
|
3781 |
|
|
emit_insn (gen_movsi_high_pic (temp_reg, orig));
|
3782 |
|
|
emit_insn (gen_movsi_lo_sum_pic (temp_reg, temp_reg, orig));
|
3783 |
|
|
}
|
3784 |
|
|
address = temp_reg;
|
3785 |
|
|
gotdata_op = true;
|
3786 |
|
|
}
|
3787 |
|
|
else
|
3788 |
|
|
address = orig;
|
3789 |
|
|
|
3790 |
|
|
crtl->uses_pic_offset_table = 1;
|
3791 |
|
|
if (gotdata_op)
|
3792 |
|
|
{
|
3793 |
|
|
if (TARGET_ARCH64)
|
3794 |
|
|
insn = emit_insn (gen_movdi_pic_gotdata_op (reg,
|
3795 |
|
|
pic_offset_table_rtx,
|
3796 |
|
|
address, orig));
|
3797 |
|
|
else
|
3798 |
|
|
insn = emit_insn (gen_movsi_pic_gotdata_op (reg,
|
3799 |
|
|
pic_offset_table_rtx,
|
3800 |
|
|
address, orig));
|
3801 |
|
|
}
|
3802 |
|
|
else
|
3803 |
|
|
{
|
3804 |
|
|
pic_ref
|
3805 |
|
|
= gen_const_mem (Pmode,
|
3806 |
|
|
gen_rtx_PLUS (Pmode,
|
3807 |
|
|
pic_offset_table_rtx, address));
|
3808 |
|
|
insn = emit_move_insn (reg, pic_ref);
|
3809 |
|
|
}
|
3810 |
|
|
|
3811 |
|
|
/* Put a REG_EQUAL note on this insn, so that it can be optimized
|
3812 |
|
|
by loop. */
|
3813 |
|
|
set_unique_reg_note (insn, REG_EQUAL, orig);
|
3814 |
|
|
return reg;
|
3815 |
|
|
}
|
3816 |
|
|
else if (GET_CODE (orig) == CONST)
|
3817 |
|
|
{
|
3818 |
|
|
rtx base, offset;
|
3819 |
|
|
|
3820 |
|
|
if (GET_CODE (XEXP (orig, 0)) == PLUS
|
3821 |
|
|
&& XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
|
3822 |
|
|
return orig;
|
3823 |
|
|
|
3824 |
|
|
if (reg == 0)
|
3825 |
|
|
{
|
3826 |
|
|
gcc_assert (can_create_pseudo_p ());
|
3827 |
|
|
reg = gen_reg_rtx (Pmode);
|
3828 |
|
|
}
|
3829 |
|
|
|
3830 |
|
|
gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
|
3831 |
|
|
base = sparc_legitimize_pic_address (XEXP (XEXP (orig, 0), 0), reg);
|
3832 |
|
|
offset = sparc_legitimize_pic_address (XEXP (XEXP (orig, 0), 1),
|
3833 |
|
|
base == reg ? NULL_RTX : reg);
|
3834 |
|
|
|
3835 |
|
|
if (GET_CODE (offset) == CONST_INT)
|
3836 |
|
|
{
|
3837 |
|
|
if (SMALL_INT (offset))
|
3838 |
|
|
return plus_constant (base, INTVAL (offset));
|
3839 |
|
|
else if (can_create_pseudo_p ())
|
3840 |
|
|
offset = force_reg (Pmode, offset);
|
3841 |
|
|
else
|
3842 |
|
|
/* If we reach here, then something is seriously wrong. */
|
3843 |
|
|
gcc_unreachable ();
|
3844 |
|
|
}
|
3845 |
|
|
return gen_rtx_PLUS (Pmode, base, offset);
|
3846 |
|
|
}
|
3847 |
|
|
else if (GET_CODE (orig) == LABEL_REF)
|
3848 |
|
|
/* ??? We ought to be checking that the register is live instead, in case
|
3849 |
|
|
it is eliminated. */
|
3850 |
|
|
crtl->uses_pic_offset_table = 1;
|
3851 |
|
|
|
3852 |
|
|
return orig;
|
3853 |
|
|
}
|
3854 |
|
|
|
3855 |
|
|
/* Try machine-dependent ways of modifying an illegitimate address X
|
3856 |
|
|
to be legitimate. If we find one, return the new, valid address.
|
3857 |
|
|
|
3858 |
|
|
OLDX is the address as it was before break_out_memory_refs was called.
|
3859 |
|
|
In some cases it is useful to look at this to decide what needs to be done.
|
3860 |
|
|
|
3861 |
|
|
MODE is the mode of the operand pointed to by X.
|
3862 |
|
|
|
3863 |
|
|
On SPARC, change REG+N into REG+REG, and REG+(X*Y) into REG+REG. */
|
3864 |
|
|
|
3865 |
|
|
static rtx
|
3866 |
|
|
sparc_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
|
3867 |
|
|
enum machine_mode mode)
|
3868 |
|
|
{
|
3869 |
|
|
rtx orig_x = x;
|
3870 |
|
|
|
3871 |
|
|
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == MULT)
|
3872 |
|
|
x = gen_rtx_PLUS (Pmode, XEXP (x, 1),
|
3873 |
|
|
force_operand (XEXP (x, 0), NULL_RTX));
|
3874 |
|
|
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == MULT)
|
3875 |
|
|
x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
|
3876 |
|
|
force_operand (XEXP (x, 1), NULL_RTX));
|
3877 |
|
|
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS)
|
3878 |
|
|
x = gen_rtx_PLUS (Pmode, force_operand (XEXP (x, 0), NULL_RTX),
|
3879 |
|
|
XEXP (x, 1));
|
3880 |
|
|
if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == PLUS)
|
3881 |
|
|
x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
|
3882 |
|
|
force_operand (XEXP (x, 1), NULL_RTX));
|
3883 |
|
|
|
3884 |
|
|
if (x != orig_x && sparc_legitimate_address_p (mode, x, FALSE))
|
3885 |
|
|
return x;
|
3886 |
|
|
|
3887 |
|
|
if (sparc_tls_referenced_p (x))
|
3888 |
|
|
x = sparc_legitimize_tls_address (x);
|
3889 |
|
|
else if (flag_pic)
|
3890 |
|
|
x = sparc_legitimize_pic_address (x, NULL_RTX);
|
3891 |
|
|
else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 1)))
|
3892 |
|
|
x = gen_rtx_PLUS (Pmode, XEXP (x, 0),
|
3893 |
|
|
copy_to_mode_reg (Pmode, XEXP (x, 1)));
|
3894 |
|
|
else if (GET_CODE (x) == PLUS && CONSTANT_ADDRESS_P (XEXP (x, 0)))
|
3895 |
|
|
x = gen_rtx_PLUS (Pmode, XEXP (x, 1),
|
3896 |
|
|
copy_to_mode_reg (Pmode, XEXP (x, 0)));
|
3897 |
|
|
else if (GET_CODE (x) == SYMBOL_REF
|
3898 |
|
|
|| GET_CODE (x) == CONST
|
3899 |
|
|
|| GET_CODE (x) == LABEL_REF)
|
3900 |
|
|
x = copy_to_suggested_reg (x, NULL_RTX, Pmode);
|
3901 |
|
|
|
3902 |
|
|
return x;
|
3903 |
|
|
}
|
3904 |
|
|
|
3905 |
|
|
/* Delegitimize an address that was legitimized by the above function. */
|
3906 |
|
|
|
3907 |
|
|
static rtx
|
3908 |
|
|
sparc_delegitimize_address (rtx x)
|
3909 |
|
|
{
|
3910 |
|
|
x = delegitimize_mem_from_attrs (x);
|
3911 |
|
|
|
3912 |
|
|
if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 1)) == UNSPEC)
|
3913 |
|
|
switch (XINT (XEXP (x, 1), 1))
|
3914 |
|
|
{
|
3915 |
|
|
case UNSPEC_MOVE_PIC:
|
3916 |
|
|
case UNSPEC_TLSLE:
|
3917 |
|
|
x = XVECEXP (XEXP (x, 1), 0, 0);
|
3918 |
|
|
gcc_assert (GET_CODE (x) == SYMBOL_REF);
|
3919 |
|
|
break;
|
3920 |
|
|
default:
|
3921 |
|
|
break;
|
3922 |
|
|
}
|
3923 |
|
|
|
3924 |
|
|
/* This is generated by mov{si,di}_pic_label_ref in PIC mode. */
|
3925 |
|
|
if (GET_CODE (x) == MINUS
|
3926 |
|
|
&& REG_P (XEXP (x, 0))
|
3927 |
|
|
&& REGNO (XEXP (x, 0)) == PIC_OFFSET_TABLE_REGNUM
|
3928 |
|
|
&& GET_CODE (XEXP (x, 1)) == LO_SUM
|
3929 |
|
|
&& GET_CODE (XEXP (XEXP (x, 1), 1)) == UNSPEC
|
3930 |
|
|
&& XINT (XEXP (XEXP (x, 1), 1), 1) == UNSPEC_MOVE_PIC_LABEL)
|
3931 |
|
|
{
|
3932 |
|
|
x = XVECEXP (XEXP (XEXP (x, 1), 1), 0, 0);
|
3933 |
|
|
gcc_assert (GET_CODE (x) == LABEL_REF);
|
3934 |
|
|
}
|
3935 |
|
|
|
3936 |
|
|
return x;
|
3937 |
|
|
}
|
3938 |
|
|
|
3939 |
|
|
/* SPARC implementation of LEGITIMIZE_RELOAD_ADDRESS. Returns a value to
|
3940 |
|
|
replace the input X, or the original X if no replacement is called for.
|
3941 |
|
|
The output parameter *WIN is 1 if the calling macro should goto WIN,
|
3942 |
|
|
|
3943 |
|
|
|
3944 |
|
|
For SPARC, we wish to handle addresses by splitting them into
|
3945 |
|
|
HIGH+LO_SUM pairs, retaining the LO_SUM in the memory reference.
|
3946 |
|
|
This cuts the number of extra insns by one.
|
3947 |
|
|
|
3948 |
|
|
Do nothing when generating PIC code and the address is a symbolic
|
3949 |
|
|
operand or requires a scratch register. */
|
3950 |
|
|
|
3951 |
|
|
rtx
|
3952 |
|
|
sparc_legitimize_reload_address (rtx x, enum machine_mode mode,
|
3953 |
|
|
int opnum, int type,
|
3954 |
|
|
int ind_levels ATTRIBUTE_UNUSED, int *win)
|
3955 |
|
|
{
|
3956 |
|
|
/* Decompose SImode constants into HIGH+LO_SUM. */
|
3957 |
|
|
if (CONSTANT_P (x)
|
3958 |
|
|
&& (mode != TFmode || TARGET_ARCH64)
|
3959 |
|
|
&& GET_MODE (x) == SImode
|
3960 |
|
|
&& GET_CODE (x) != LO_SUM
|
3961 |
|
|
&& GET_CODE (x) != HIGH
|
3962 |
|
|
&& sparc_cmodel <= CM_MEDLOW
|
3963 |
|
|
&& !(flag_pic
|
3964 |
|
|
&& (symbolic_operand (x, Pmode) || pic_address_needs_scratch (x))))
|
3965 |
|
|
{
|
3966 |
|
|
x = gen_rtx_LO_SUM (GET_MODE (x), gen_rtx_HIGH (GET_MODE (x), x), x);
|
3967 |
|
|
push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
|
3968 |
|
|
BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
|
3969 |
|
|
opnum, (enum reload_type)type);
|
3970 |
|
|
*win = 1;
|
3971 |
|
|
return x;
|
3972 |
|
|
}
|
3973 |
|
|
|
3974 |
|
|
/* We have to recognize what we have already generated above. */
|
3975 |
|
|
if (GET_CODE (x) == LO_SUM && GET_CODE (XEXP (x, 0)) == HIGH)
|
3976 |
|
|
{
|
3977 |
|
|
push_reload (XEXP (x, 0), NULL_RTX, &XEXP (x, 0), NULL,
|
3978 |
|
|
BASE_REG_CLASS, GET_MODE (x), VOIDmode, 0, 0,
|
3979 |
|
|
opnum, (enum reload_type)type);
|
3980 |
|
|
*win = 1;
|
3981 |
|
|
return x;
|
3982 |
|
|
}
|
3983 |
|
|
|
3984 |
|
|
*win = 0;
|
3985 |
|
|
return x;
|
3986 |
|
|
}
|
3987 |
|
|
|
3988 |
|
|
/* Return true if ADDR (a legitimate address expression)
|
3989 |
|
|
has an effect that depends on the machine mode it is used for.
|
3990 |
|
|
|
3991 |
|
|
In PIC mode,
|
3992 |
|
|
|
3993 |
|
|
(mem:HI [%l7+a])
|
3994 |
|
|
|
3995 |
|
|
is not equivalent to
|
3996 |
|
|
|
3997 |
|
|
(mem:QI [%l7+a]) (mem:QI [%l7+a+1])
|
3998 |
|
|
|
3999 |
|
|
because [%l7+a+1] is interpreted as the address of (a+1). */
|
4000 |
|
|
|
4001 |
|
|
|
4002 |
|
|
static bool
|
4003 |
|
|
sparc_mode_dependent_address_p (const_rtx addr)
|
4004 |
|
|
{
|
4005 |
|
|
if (flag_pic && GET_CODE (addr) == PLUS)
|
4006 |
|
|
{
|
4007 |
|
|
rtx op0 = XEXP (addr, 0);
|
4008 |
|
|
rtx op1 = XEXP (addr, 1);
|
4009 |
|
|
if (op0 == pic_offset_table_rtx
|
4010 |
|
|
&& symbolic_operand (op1, VOIDmode))
|
4011 |
|
|
return true;
|
4012 |
|
|
}
|
4013 |
|
|
|
4014 |
|
|
return false;
|
4015 |
|
|
}
|
4016 |
|
|
|
4017 |
|
|
#ifdef HAVE_GAS_HIDDEN
|
4018 |
|
|
# define USE_HIDDEN_LINKONCE 1
|
4019 |
|
|
#else
|
4020 |
|
|
# define USE_HIDDEN_LINKONCE 0
|
4021 |
|
|
#endif
|
4022 |
|
|
|
4023 |
|
|
static void
|
4024 |
|
|
get_pc_thunk_name (char name[32], unsigned int regno)
|
4025 |
|
|
{
|
4026 |
|
|
const char *reg_name = reg_names[regno];
|
4027 |
|
|
|
4028 |
|
|
/* Skip the leading '%' as that cannot be used in a
|
4029 |
|
|
symbol name. */
|
4030 |
|
|
reg_name += 1;
|
4031 |
|
|
|
4032 |
|
|
if (USE_HIDDEN_LINKONCE)
|
4033 |
|
|
sprintf (name, "__sparc_get_pc_thunk.%s", reg_name);
|
4034 |
|
|
else
|
4035 |
|
|
ASM_GENERATE_INTERNAL_LABEL (name, "LADDPC", regno);
|
4036 |
|
|
}
|
4037 |
|
|
|
4038 |
|
|
/* Wrapper around the load_pcrel_sym{si,di} patterns. */
|
4039 |
|
|
|
4040 |
|
|
static rtx
|
4041 |
|
|
gen_load_pcrel_sym (rtx op0, rtx op1, rtx op2, rtx op3)
|
4042 |
|
|
{
|
4043 |
|
|
int orig_flag_pic = flag_pic;
|
4044 |
|
|
rtx insn;
|
4045 |
|
|
|
4046 |
|
|
/* The load_pcrel_sym{si,di} patterns require absolute addressing. */
|
4047 |
|
|
flag_pic = 0;
|
4048 |
|
|
if (TARGET_ARCH64)
|
4049 |
|
|
insn = gen_load_pcrel_symdi (op0, op1, op2, op3);
|
4050 |
|
|
else
|
4051 |
|
|
insn = gen_load_pcrel_symsi (op0, op1, op2, op3);
|
4052 |
|
|
flag_pic = orig_flag_pic;
|
4053 |
|
|
|
4054 |
|
|
return insn;
|
4055 |
|
|
}
|
4056 |
|
|
|
4057 |
|
|
/* Emit code to load the GOT register. */
|
4058 |
|
|
|
4059 |
|
|
void
|
4060 |
|
|
load_got_register (void)
|
4061 |
|
|
{
|
4062 |
|
|
/* In PIC mode, this will retrieve pic_offset_table_rtx. */
|
4063 |
|
|
if (!global_offset_table_rtx)
|
4064 |
|
|
global_offset_table_rtx = gen_rtx_REG (Pmode, GLOBAL_OFFSET_TABLE_REGNUM);
|
4065 |
|
|
|
4066 |
|
|
if (TARGET_VXWORKS_RTP)
|
4067 |
|
|
emit_insn (gen_vxworks_load_got ());
|
4068 |
|
|
else
|
4069 |
|
|
{
|
4070 |
|
|
/* The GOT symbol is subject to a PC-relative relocation so we need a
|
4071 |
|
|
helper function to add the PC value and thus get the final value. */
|
4072 |
|
|
if (!got_helper_rtx)
|
4073 |
|
|
{
|
4074 |
|
|
char name[32];
|
4075 |
|
|
get_pc_thunk_name (name, GLOBAL_OFFSET_TABLE_REGNUM);
|
4076 |
|
|
got_helper_rtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name));
|
4077 |
|
|
}
|
4078 |
|
|
|
4079 |
|
|
emit_insn (gen_load_pcrel_sym (global_offset_table_rtx, sparc_got (),
|
4080 |
|
|
got_helper_rtx,
|
4081 |
|
|
GEN_INT (GLOBAL_OFFSET_TABLE_REGNUM)));
|
4082 |
|
|
}
|
4083 |
|
|
|
4084 |
|
|
/* Need to emit this whether or not we obey regdecls,
|
4085 |
|
|
since setjmp/longjmp can cause life info to screw up.
|
4086 |
|
|
??? In the case where we don't obey regdecls, this is not sufficient
|
4087 |
|
|
since we may not fall out the bottom. */
|
4088 |
|
|
emit_use (global_offset_table_rtx);
|
4089 |
|
|
}
|
4090 |
|
|
|
4091 |
|
|
/* Emit a call instruction with the pattern given by PAT. ADDR is the
|
4092 |
|
|
address of the call target. */
|
4093 |
|
|
|
4094 |
|
|
void
|
4095 |
|
|
sparc_emit_call_insn (rtx pat, rtx addr)
|
4096 |
|
|
{
|
4097 |
|
|
rtx insn;
|
4098 |
|
|
|
4099 |
|
|
insn = emit_call_insn (pat);
|
4100 |
|
|
|
4101 |
|
|
/* The PIC register is live on entry to VxWorks PIC PLT entries. */
|
4102 |
|
|
if (TARGET_VXWORKS_RTP
|
4103 |
|
|
&& flag_pic
|
4104 |
|
|
&& GET_CODE (addr) == SYMBOL_REF
|
4105 |
|
|
&& (SYMBOL_REF_DECL (addr)
|
4106 |
|
|
? !targetm.binds_local_p (SYMBOL_REF_DECL (addr))
|
4107 |
|
|
: !SYMBOL_REF_LOCAL_P (addr)))
|
4108 |
|
|
{
|
4109 |
|
|
use_reg (&CALL_INSN_FUNCTION_USAGE (insn), pic_offset_table_rtx);
|
4110 |
|
|
crtl->uses_pic_offset_table = 1;
|
4111 |
|
|
}
|
4112 |
|
|
}
|
4113 |
|
|
|
4114 |
|
|
/* Return 1 if RTX is a MEM which is known to be aligned to at
|
4115 |
|
|
least a DESIRED byte boundary. */
|
4116 |
|
|
|
4117 |
|
|
int
|
4118 |
|
|
mem_min_alignment (rtx mem, int desired)
|
4119 |
|
|
{
|
4120 |
|
|
rtx addr, base, offset;
|
4121 |
|
|
|
4122 |
|
|
/* If it's not a MEM we can't accept it. */
|
4123 |
|
|
if (GET_CODE (mem) != MEM)
|
4124 |
|
|
return 0;
|
4125 |
|
|
|
4126 |
|
|
/* Obviously... */
|
4127 |
|
|
if (!TARGET_UNALIGNED_DOUBLES
|
4128 |
|
|
&& MEM_ALIGN (mem) / BITS_PER_UNIT >= (unsigned)desired)
|
4129 |
|
|
return 1;
|
4130 |
|
|
|
4131 |
|
|
/* ??? The rest of the function predates MEM_ALIGN so
|
4132 |
|
|
there is probably a bit of redundancy. */
|
4133 |
|
|
addr = XEXP (mem, 0);
|
4134 |
|
|
base = offset = NULL_RTX;
|
4135 |
|
|
if (GET_CODE (addr) == PLUS)
|
4136 |
|
|
{
|
4137 |
|
|
if (GET_CODE (XEXP (addr, 0)) == REG)
|
4138 |
|
|
{
|
4139 |
|
|
base = XEXP (addr, 0);
|
4140 |
|
|
|
4141 |
|
|
/* What we are saying here is that if the base
|
4142 |
|
|
REG is aligned properly, the compiler will make
|
4143 |
|
|
sure any REG based index upon it will be so
|
4144 |
|
|
as well. */
|
4145 |
|
|
if (GET_CODE (XEXP (addr, 1)) == CONST_INT)
|
4146 |
|
|
offset = XEXP (addr, 1);
|
4147 |
|
|
else
|
4148 |
|
|
offset = const0_rtx;
|
4149 |
|
|
}
|
4150 |
|
|
}
|
4151 |
|
|
else if (GET_CODE (addr) == REG)
|
4152 |
|
|
{
|
4153 |
|
|
base = addr;
|
4154 |
|
|
offset = const0_rtx;
|
4155 |
|
|
}
|
4156 |
|
|
|
4157 |
|
|
if (base != NULL_RTX)
|
4158 |
|
|
{
|
4159 |
|
|
int regno = REGNO (base);
|
4160 |
|
|
|
4161 |
|
|
if (regno != HARD_FRAME_POINTER_REGNUM && regno != STACK_POINTER_REGNUM)
|
4162 |
|
|
{
|
4163 |
|
|
/* Check if the compiler has recorded some information
|
4164 |
|
|
about the alignment of the base REG. If reload has
|
4165 |
|
|
completed, we already matched with proper alignments.
|
4166 |
|
|
If not running global_alloc, reload might give us
|
4167 |
|
|
unaligned pointer to local stack though. */
|
4168 |
|
|
if (((cfun != 0
|
4169 |
|
|
&& REGNO_POINTER_ALIGN (regno) >= desired * BITS_PER_UNIT)
|
4170 |
|
|
|| (optimize && reload_completed))
|
4171 |
|
|
&& (INTVAL (offset) & (desired - 1)) == 0)
|
4172 |
|
|
return 1;
|
4173 |
|
|
}
|
4174 |
|
|
else
|
4175 |
|
|
{
|
4176 |
|
|
if (((INTVAL (offset) - SPARC_STACK_BIAS) & (desired - 1)) == 0)
|
4177 |
|
|
return 1;
|
4178 |
|
|
}
|
4179 |
|
|
}
|
4180 |
|
|
else if (! TARGET_UNALIGNED_DOUBLES
|
4181 |
|
|
|| CONSTANT_P (addr)
|
4182 |
|
|
|| GET_CODE (addr) == LO_SUM)
|
4183 |
|
|
{
|
4184 |
|
|
/* Anything else we know is properly aligned unless TARGET_UNALIGNED_DOUBLES
|
4185 |
|
|
is true, in which case we can only assume that an access is aligned if
|
4186 |
|
|
it is to a constant address, or the address involves a LO_SUM. */
|
4187 |
|
|
return 1;
|
4188 |
|
|
}
|
4189 |
|
|
|
4190 |
|
|
/* An obviously unaligned address. */
|
4191 |
|
|
return 0;
|
4192 |
|
|
}
|
4193 |
|
|
|
4194 |
|
|
|
4195 |
|
|
/* Vectors to keep interesting information about registers where it can easily
|
4196 |
|
|
be got. We used to use the actual mode value as the bit number, but there
|
4197 |
|
|
are more than 32 modes now. Instead we use two tables: one indexed by
|
4198 |
|
|
hard register number, and one indexed by mode. */
|
4199 |
|
|
|
4200 |
|
|
/* The purpose of sparc_mode_class is to shrink the range of modes so that
|
4201 |
|
|
they all fit (as bit numbers) in a 32-bit word (again). Each real mode is
|
4202 |
|
|
mapped into one sparc_mode_class mode. */
|
4203 |
|
|
|
4204 |
|
|
enum sparc_mode_class {
|
4205 |
|
|
S_MODE, D_MODE, T_MODE, O_MODE,
|
4206 |
|
|
SF_MODE, DF_MODE, TF_MODE, OF_MODE,
|
4207 |
|
|
CC_MODE, CCFP_MODE
|
4208 |
|
|
};
|
4209 |
|
|
|
4210 |
|
|
/* Modes for single-word and smaller quantities. */
|
4211 |
|
|
#define S_MODES ((1 << (int) S_MODE) | (1 << (int) SF_MODE))
|
4212 |
|
|
|
4213 |
|
|
/* Modes for double-word and smaller quantities. */
|
4214 |
|
|
#define D_MODES (S_MODES | (1 << (int) D_MODE) | (1 << DF_MODE))
|
4215 |
|
|
|
4216 |
|
|
/* Modes for quad-word and smaller quantities. */
|
4217 |
|
|
#define T_MODES (D_MODES | (1 << (int) T_MODE) | (1 << (int) TF_MODE))
|
4218 |
|
|
|
4219 |
|
|
/* Modes for 8-word and smaller quantities. */
|
4220 |
|
|
#define O_MODES (T_MODES | (1 << (int) O_MODE) | (1 << (int) OF_MODE))
|
4221 |
|
|
|
4222 |
|
|
/* Modes for single-float quantities. We must allow any single word or
|
4223 |
|
|
smaller quantity. This is because the fix/float conversion instructions
|
4224 |
|
|
take integer inputs/outputs from the float registers. */
|
4225 |
|
|
#define SF_MODES (S_MODES)
|
4226 |
|
|
|
4227 |
|
|
/* Modes for double-float and smaller quantities. */
|
4228 |
|
|
#define DF_MODES (D_MODES)
|
4229 |
|
|
|
4230 |
|
|
/* Modes for quad-float and smaller quantities. */
|
4231 |
|
|
#define TF_MODES (DF_MODES | (1 << (int) TF_MODE))
|
4232 |
|
|
|
4233 |
|
|
/* Modes for quad-float pairs and smaller quantities. */
|
4234 |
|
|
#define OF_MODES (TF_MODES | (1 << (int) OF_MODE))
|
4235 |
|
|
|
4236 |
|
|
/* Modes for double-float only quantities. */
|
4237 |
|
|
#define DF_MODES_NO_S ((1 << (int) D_MODE) | (1 << (int) DF_MODE))
|
4238 |
|
|
|
4239 |
|
|
/* Modes for quad-float and double-float only quantities. */
|
4240 |
|
|
#define TF_MODES_NO_S (DF_MODES_NO_S | (1 << (int) TF_MODE))
|
4241 |
|
|
|
4242 |
|
|
/* Modes for quad-float pairs and double-float only quantities. */
|
4243 |
|
|
#define OF_MODES_NO_S (TF_MODES_NO_S | (1 << (int) OF_MODE))
|
4244 |
|
|
|
4245 |
|
|
/* Modes for condition codes. */
|
4246 |
|
|
#define CC_MODES (1 << (int) CC_MODE)
|
4247 |
|
|
#define CCFP_MODES (1 << (int) CCFP_MODE)
|
4248 |
|
|
|
4249 |
|
|
/* Value is 1 if register/mode pair is acceptable on sparc.
|
4250 |
|
|
The funny mixture of D and T modes is because integer operations
|
4251 |
|
|
do not specially operate on tetra quantities, so non-quad-aligned
|
4252 |
|
|
registers can hold quadword quantities (except %o4 and %i4 because
|
4253 |
|
|
they cross fixed registers). */
|
4254 |
|
|
|
4255 |
|
|
/* This points to either the 32 bit or the 64 bit version. */
|
4256 |
|
|
const int *hard_regno_mode_classes;
|
4257 |
|
|
|
4258 |
|
|
static const int hard_32bit_mode_classes[] = {
|
4259 |
|
|
S_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
|
4260 |
|
|
T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
|
4261 |
|
|
T_MODES, S_MODES, T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES,
|
4262 |
|
|
T_MODES, S_MODES, T_MODES, S_MODES, D_MODES, S_MODES, D_MODES, S_MODES,
|
4263 |
|
|
|
4264 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4265 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4266 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4267 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4268 |
|
|
|
4269 |
|
|
/* FP regs f32 to f63. Only the even numbered registers actually exist,
|
4270 |
|
|
and none can hold SFmode/SImode values. */
|
4271 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4272 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4273 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4274 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4275 |
|
|
|
4276 |
|
|
/* %fcc[0123] */
|
4277 |
|
|
CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
|
4278 |
|
|
|
4279 |
|
|
/* %icc, %sfp, %gsr */
|
4280 |
|
|
CC_MODES, 0, D_MODES
|
4281 |
|
|
};
|
4282 |
|
|
|
4283 |
|
|
static const int hard_64bit_mode_classes[] = {
|
4284 |
|
|
D_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
|
4285 |
|
|
O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
|
4286 |
|
|
T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
|
4287 |
|
|
O_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES, T_MODES, D_MODES,
|
4288 |
|
|
|
4289 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4290 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4291 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, OF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4292 |
|
|
OF_MODES, SF_MODES, DF_MODES, SF_MODES, TF_MODES, SF_MODES, DF_MODES, SF_MODES,
|
4293 |
|
|
|
4294 |
|
|
/* FP regs f32 to f63. Only the even numbered registers actually exist,
|
4295 |
|
|
and none can hold SFmode/SImode values. */
|
4296 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4297 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4298 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, OF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4299 |
|
|
OF_MODES_NO_S, 0, DF_MODES_NO_S, 0, TF_MODES_NO_S, 0, DF_MODES_NO_S, 0,
|
4300 |
|
|
|
4301 |
|
|
/* %fcc[0123] */
|
4302 |
|
|
CCFP_MODES, CCFP_MODES, CCFP_MODES, CCFP_MODES,
|
4303 |
|
|
|
4304 |
|
|
/* %icc, %sfp, %gsr */
|
4305 |
|
|
CC_MODES, 0, D_MODES
|
4306 |
|
|
};
|
4307 |
|
|
|
4308 |
|
|
int sparc_mode_class [NUM_MACHINE_MODES];
|
4309 |
|
|
|
4310 |
|
|
enum reg_class sparc_regno_reg_class[FIRST_PSEUDO_REGISTER];
|
4311 |
|
|
|
4312 |
|
|
static void
|
4313 |
|
|
sparc_init_modes (void)
|
4314 |
|
|
{
|
4315 |
|
|
int i;
|
4316 |
|
|
|
4317 |
|
|
for (i = 0; i < NUM_MACHINE_MODES; i++)
|
4318 |
|
|
{
|
4319 |
|
|
switch (GET_MODE_CLASS (i))
|
4320 |
|
|
{
|
4321 |
|
|
case MODE_INT:
|
4322 |
|
|
case MODE_PARTIAL_INT:
|
4323 |
|
|
case MODE_COMPLEX_INT:
|
4324 |
|
|
if (GET_MODE_SIZE (i) <= 4)
|
4325 |
|
|
sparc_mode_class[i] = 1 << (int) S_MODE;
|
4326 |
|
|
else if (GET_MODE_SIZE (i) == 8)
|
4327 |
|
|
sparc_mode_class[i] = 1 << (int) D_MODE;
|
4328 |
|
|
else if (GET_MODE_SIZE (i) == 16)
|
4329 |
|
|
sparc_mode_class[i] = 1 << (int) T_MODE;
|
4330 |
|
|
else if (GET_MODE_SIZE (i) == 32)
|
4331 |
|
|
sparc_mode_class[i] = 1 << (int) O_MODE;
|
4332 |
|
|
else
|
4333 |
|
|
sparc_mode_class[i] = 0;
|
4334 |
|
|
break;
|
4335 |
|
|
case MODE_VECTOR_INT:
|
4336 |
|
|
if (GET_MODE_SIZE (i) <= 4)
|
4337 |
|
|
sparc_mode_class[i] = 1 << (int)SF_MODE;
|
4338 |
|
|
else if (GET_MODE_SIZE (i) == 8)
|
4339 |
|
|
sparc_mode_class[i] = 1 << (int)DF_MODE;
|
4340 |
|
|
break;
|
4341 |
|
|
case MODE_FLOAT:
|
4342 |
|
|
case MODE_COMPLEX_FLOAT:
|
4343 |
|
|
if (GET_MODE_SIZE (i) <= 4)
|
4344 |
|
|
sparc_mode_class[i] = 1 << (int) SF_MODE;
|
4345 |
|
|
else if (GET_MODE_SIZE (i) == 8)
|
4346 |
|
|
sparc_mode_class[i] = 1 << (int) DF_MODE;
|
4347 |
|
|
else if (GET_MODE_SIZE (i) == 16)
|
4348 |
|
|
sparc_mode_class[i] = 1 << (int) TF_MODE;
|
4349 |
|
|
else if (GET_MODE_SIZE (i) == 32)
|
4350 |
|
|
sparc_mode_class[i] = 1 << (int) OF_MODE;
|
4351 |
|
|
else
|
4352 |
|
|
sparc_mode_class[i] = 0;
|
4353 |
|
|
break;
|
4354 |
|
|
case MODE_CC:
|
4355 |
|
|
if (i == (int) CCFPmode || i == (int) CCFPEmode)
|
4356 |
|
|
sparc_mode_class[i] = 1 << (int) CCFP_MODE;
|
4357 |
|
|
else
|
4358 |
|
|
sparc_mode_class[i] = 1 << (int) CC_MODE;
|
4359 |
|
|
break;
|
4360 |
|
|
default:
|
4361 |
|
|
sparc_mode_class[i] = 0;
|
4362 |
|
|
break;
|
4363 |
|
|
}
|
4364 |
|
|
}
|
4365 |
|
|
|
4366 |
|
|
if (TARGET_ARCH64)
|
4367 |
|
|
hard_regno_mode_classes = hard_64bit_mode_classes;
|
4368 |
|
|
else
|
4369 |
|
|
hard_regno_mode_classes = hard_32bit_mode_classes;
|
4370 |
|
|
|
4371 |
|
|
/* Initialize the array used by REGNO_REG_CLASS. */
|
4372 |
|
|
for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
|
4373 |
|
|
{
|
4374 |
|
|
if (i < 16 && TARGET_V8PLUS)
|
4375 |
|
|
sparc_regno_reg_class[i] = I64_REGS;
|
4376 |
|
|
else if (i < 32 || i == FRAME_POINTER_REGNUM)
|
4377 |
|
|
sparc_regno_reg_class[i] = GENERAL_REGS;
|
4378 |
|
|
else if (i < 64)
|
4379 |
|
|
sparc_regno_reg_class[i] = FP_REGS;
|
4380 |
|
|
else if (i < 96)
|
4381 |
|
|
sparc_regno_reg_class[i] = EXTRA_FP_REGS;
|
4382 |
|
|
else if (i < 100)
|
4383 |
|
|
sparc_regno_reg_class[i] = FPCC_REGS;
|
4384 |
|
|
else
|
4385 |
|
|
sparc_regno_reg_class[i] = NO_REGS;
|
4386 |
|
|
}
|
4387 |
|
|
}
|
4388 |
|
|
|
4389 |
|
|
/* Return whether REGNO, a global or FP register, must be saved/restored. */
|
4390 |
|
|
|
4391 |
|
|
static inline bool
|
4392 |
|
|
save_global_or_fp_reg_p (unsigned int regno,
|
4393 |
|
|
int leaf_function ATTRIBUTE_UNUSED)
|
4394 |
|
|
{
|
4395 |
|
|
return !call_used_regs[regno] && df_regs_ever_live_p (regno);
|
4396 |
|
|
}
|
4397 |
|
|
|
4398 |
|
|
/* Return whether the return address register (%i7) is needed. */
|
4399 |
|
|
|
4400 |
|
|
static inline bool
|
4401 |
|
|
return_addr_reg_needed_p (int leaf_function)
|
4402 |
|
|
{
|
4403 |
|
|
/* If it is live, for example because of __builtin_return_address (0). */
|
4404 |
|
|
if (df_regs_ever_live_p (RETURN_ADDR_REGNUM))
|
4405 |
|
|
return true;
|
4406 |
|
|
|
4407 |
|
|
/* Otherwise, it is needed as save register if %o7 is clobbered. */
|
4408 |
|
|
if (!leaf_function
|
4409 |
|
|
/* Loading the GOT register clobbers %o7. */
|
4410 |
|
|
|| crtl->uses_pic_offset_table
|
4411 |
|
|
|| df_regs_ever_live_p (INCOMING_RETURN_ADDR_REGNUM))
|
4412 |
|
|
return true;
|
4413 |
|
|
|
4414 |
|
|
return false;
|
4415 |
|
|
}
|
4416 |
|
|
|
4417 |
|
|
/* Return whether REGNO, a local or in register, must be saved/restored. */
|
4418 |
|
|
|
4419 |
|
|
static bool
|
4420 |
|
|
save_local_or_in_reg_p (unsigned int regno, int leaf_function)
|
4421 |
|
|
{
|
4422 |
|
|
/* General case: call-saved registers live at some point. */
|
4423 |
|
|
if (!call_used_regs[regno] && df_regs_ever_live_p (regno))
|
4424 |
|
|
return true;
|
4425 |
|
|
|
4426 |
|
|
/* Frame pointer register (%fp) if needed. */
|
4427 |
|
|
if (regno == HARD_FRAME_POINTER_REGNUM && frame_pointer_needed)
|
4428 |
|
|
return true;
|
4429 |
|
|
|
4430 |
|
|
/* Return address register (%i7) if needed. */
|
4431 |
|
|
if (regno == RETURN_ADDR_REGNUM && return_addr_reg_needed_p (leaf_function))
|
4432 |
|
|
return true;
|
4433 |
|
|
|
4434 |
|
|
/* GOT register (%l7) if needed. */
|
4435 |
|
|
if (regno == PIC_OFFSET_TABLE_REGNUM && crtl->uses_pic_offset_table)
|
4436 |
|
|
return true;
|
4437 |
|
|
|
4438 |
|
|
/* If the function accesses prior frames, the frame pointer and the return
|
4439 |
|
|
address of the previous frame must be saved on the stack. */
|
4440 |
|
|
if (crtl->accesses_prior_frames
|
4441 |
|
|
&& (regno == HARD_FRAME_POINTER_REGNUM || regno == RETURN_ADDR_REGNUM))
|
4442 |
|
|
return true;
|
4443 |
|
|
|
4444 |
|
|
return false;
|
4445 |
|
|
}
|
4446 |
|
|
|
4447 |
|
|
/* Compute the frame size required by the function. This function is called
|
4448 |
|
|
during the reload pass and also by sparc_expand_prologue. */
|
4449 |
|
|
|
4450 |
|
|
HOST_WIDE_INT
|
4451 |
|
|
sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function)
|
4452 |
|
|
{
|
4453 |
|
|
HOST_WIDE_INT frame_size, apparent_frame_size;
|
4454 |
|
|
int args_size, n_global_fp_regs = 0;
|
4455 |
|
|
bool save_local_in_regs_p = false;
|
4456 |
|
|
unsigned int i;
|
4457 |
|
|
|
4458 |
|
|
/* If the function allocates dynamic stack space, the dynamic offset is
|
4459 |
|
|
computed early and contains REG_PARM_STACK_SPACE, so we need to cope. */
|
4460 |
|
|
if (leaf_function && !cfun->calls_alloca)
|
4461 |
|
|
args_size = 0;
|
4462 |
|
|
else
|
4463 |
|
|
args_size = crtl->outgoing_args_size + REG_PARM_STACK_SPACE (cfun->decl);
|
4464 |
|
|
|
4465 |
|
|
/* Calculate space needed for global registers. */
|
4466 |
|
|
if (TARGET_ARCH64)
|
4467 |
|
|
for (i = 0; i < 8; i++)
|
4468 |
|
|
if (save_global_or_fp_reg_p (i, 0))
|
4469 |
|
|
n_global_fp_regs += 2;
|
4470 |
|
|
else
|
4471 |
|
|
for (i = 0; i < 8; i += 2)
|
4472 |
|
|
if (save_global_or_fp_reg_p (i, 0) || save_global_or_fp_reg_p (i + 1, 0))
|
4473 |
|
|
n_global_fp_regs += 2;
|
4474 |
|
|
|
4475 |
|
|
/* In the flat window model, find out which local and in registers need to
|
4476 |
|
|
be saved. We don't reserve space in the current frame for them as they
|
4477 |
|
|
will be spilled into the register window save area of the caller's frame.
|
4478 |
|
|
However, as soon as we use this register window save area, we must create
|
4479 |
|
|
that of the current frame to make it the live one. */
|
4480 |
|
|
if (TARGET_FLAT)
|
4481 |
|
|
for (i = 16; i < 32; i++)
|
4482 |
|
|
if (save_local_or_in_reg_p (i, leaf_function))
|
4483 |
|
|
{
|
4484 |
|
|
save_local_in_regs_p = true;
|
4485 |
|
|
break;
|
4486 |
|
|
}
|
4487 |
|
|
|
4488 |
|
|
/* Calculate space needed for FP registers. */
|
4489 |
|
|
for (i = 32; i < (TARGET_V9 ? 96 : 64); i += 2)
|
4490 |
|
|
if (save_global_or_fp_reg_p (i, 0) || save_global_or_fp_reg_p (i + 1, 0))
|
4491 |
|
|
n_global_fp_regs += 2;
|
4492 |
|
|
|
4493 |
|
|
if (size == 0
|
4494 |
|
|
&& n_global_fp_regs == 0
|
4495 |
|
|
&& args_size == 0
|
4496 |
|
|
&& !save_local_in_regs_p)
|
4497 |
|
|
frame_size = apparent_frame_size = 0;
|
4498 |
|
|
else
|
4499 |
|
|
{
|
4500 |
|
|
/* We subtract STARTING_FRAME_OFFSET, remember it's negative. */
|
4501 |
|
|
apparent_frame_size = (size - STARTING_FRAME_OFFSET + 7) & -8;
|
4502 |
|
|
apparent_frame_size += n_global_fp_regs * 4;
|
4503 |
|
|
|
4504 |
|
|
/* We need to add the size of the outgoing argument area. */
|
4505 |
|
|
frame_size = apparent_frame_size + ((args_size + 7) & -8);
|
4506 |
|
|
|
4507 |
|
|
/* And that of the register window save area. */
|
4508 |
|
|
frame_size += FIRST_PARM_OFFSET (cfun->decl);
|
4509 |
|
|
|
4510 |
|
|
/* Finally, bump to the appropriate alignment. */
|
4511 |
|
|
frame_size = SPARC_STACK_ALIGN (frame_size);
|
4512 |
|
|
}
|
4513 |
|
|
|
4514 |
|
|
/* Set up values for use in prologue and epilogue. */
|
4515 |
|
|
sparc_frame_size = frame_size;
|
4516 |
|
|
sparc_apparent_frame_size = apparent_frame_size;
|
4517 |
|
|
sparc_n_global_fp_regs = n_global_fp_regs;
|
4518 |
|
|
sparc_save_local_in_regs_p = save_local_in_regs_p;
|
4519 |
|
|
|
4520 |
|
|
return frame_size;
|
4521 |
|
|
}
|
4522 |
|
|
|
4523 |
|
|
/* Output any necessary .register pseudo-ops. */
|
4524 |
|
|
|
4525 |
|
|
void
|
4526 |
|
|
sparc_output_scratch_registers (FILE *file ATTRIBUTE_UNUSED)
|
4527 |
|
|
{
|
4528 |
|
|
#ifdef HAVE_AS_REGISTER_PSEUDO_OP
|
4529 |
|
|
int i;
|
4530 |
|
|
|
4531 |
|
|
if (TARGET_ARCH32)
|
4532 |
|
|
return;
|
4533 |
|
|
|
4534 |
|
|
/* Check if %g[2367] were used without
|
4535 |
|
|
.register being printed for them already. */
|
4536 |
|
|
for (i = 2; i < 8; i++)
|
4537 |
|
|
{
|
4538 |
|
|
if (df_regs_ever_live_p (i)
|
4539 |
|
|
&& ! sparc_hard_reg_printed [i])
|
4540 |
|
|
{
|
4541 |
|
|
sparc_hard_reg_printed [i] = 1;
|
4542 |
|
|
/* %g7 is used as TLS base register, use #ignore
|
4543 |
|
|
for it instead of #scratch. */
|
4544 |
|
|
fprintf (file, "\t.register\t%%g%d, #%s\n", i,
|
4545 |
|
|
i == 7 ? "ignore" : "scratch");
|
4546 |
|
|
}
|
4547 |
|
|
if (i == 3) i = 5;
|
4548 |
|
|
}
|
4549 |
|
|
#endif
|
4550 |
|
|
}
|
4551 |
|
|
|
4552 |
|
|
#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
|
4553 |
|
|
|
4554 |
|
|
#if PROBE_INTERVAL > 4096
|
4555 |
|
|
#error Cannot use indexed addressing mode for stack probing
|
4556 |
|
|
#endif
|
4557 |
|
|
|
4558 |
|
|
/* Emit code to probe a range of stack addresses from FIRST to FIRST+SIZE,
|
4559 |
|
|
inclusive. These are offsets from the current stack pointer.
|
4560 |
|
|
|
4561 |
|
|
Note that we don't use the REG+REG addressing mode for the probes because
|
4562 |
|
|
of the stack bias in 64-bit mode. And it doesn't really buy us anything
|
4563 |
|
|
so the advantages of having a single code win here. */
|
4564 |
|
|
|
4565 |
|
|
static void
|
4566 |
|
|
sparc_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
|
4567 |
|
|
{
|
4568 |
|
|
rtx g1 = gen_rtx_REG (Pmode, 1);
|
4569 |
|
|
|
4570 |
|
|
/* See if we have a constant small number of probes to generate. If so,
|
4571 |
|
|
that's the easy case. */
|
4572 |
|
|
if (size <= PROBE_INTERVAL)
|
4573 |
|
|
{
|
4574 |
|
|
emit_move_insn (g1, GEN_INT (first));
|
4575 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, g1,
|
4576 |
|
|
gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1)));
|
4577 |
|
|
emit_stack_probe (plus_constant (g1, -size));
|
4578 |
|
|
}
|
4579 |
|
|
|
4580 |
|
|
/* The run-time loop is made up of 10 insns in the generic case while the
|
4581 |
|
|
compile-time loop is made up of 4+2*(n-2) insns for n # of intervals. */
|
4582 |
|
|
else if (size <= 5 * PROBE_INTERVAL)
|
4583 |
|
|
{
|
4584 |
|
|
HOST_WIDE_INT i;
|
4585 |
|
|
|
4586 |
|
|
emit_move_insn (g1, GEN_INT (first + PROBE_INTERVAL));
|
4587 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, g1,
|
4588 |
|
|
gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1)));
|
4589 |
|
|
emit_stack_probe (g1);
|
4590 |
|
|
|
4591 |
|
|
/* Probe at FIRST + N * PROBE_INTERVAL for values of N from 2 until
|
4592 |
|
|
it exceeds SIZE. If only two probes are needed, this will not
|
4593 |
|
|
generate any code. Then probe at FIRST + SIZE. */
|
4594 |
|
|
for (i = 2 * PROBE_INTERVAL; i < size; i += PROBE_INTERVAL)
|
4595 |
|
|
{
|
4596 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, g1,
|
4597 |
|
|
plus_constant (g1, -PROBE_INTERVAL)));
|
4598 |
|
|
emit_stack_probe (g1);
|
4599 |
|
|
}
|
4600 |
|
|
|
4601 |
|
|
emit_stack_probe (plus_constant (g1, (i - PROBE_INTERVAL) - size));
|
4602 |
|
|
}
|
4603 |
|
|
|
4604 |
|
|
/* Otherwise, do the same as above, but in a loop. Note that we must be
|
4605 |
|
|
extra careful with variables wrapping around because we might be at
|
4606 |
|
|
the very top (or the very bottom) of the address space and we have
|
4607 |
|
|
to be able to handle this case properly; in particular, we use an
|
4608 |
|
|
equality test for the loop condition. */
|
4609 |
|
|
else
|
4610 |
|
|
{
|
4611 |
|
|
HOST_WIDE_INT rounded_size;
|
4612 |
|
|
rtx g4 = gen_rtx_REG (Pmode, 4);
|
4613 |
|
|
|
4614 |
|
|
emit_move_insn (g1, GEN_INT (first));
|
4615 |
|
|
|
4616 |
|
|
|
4617 |
|
|
/* Step 1: round SIZE to the previous multiple of the interval. */
|
4618 |
|
|
|
4619 |
|
|
rounded_size = size & -PROBE_INTERVAL;
|
4620 |
|
|
emit_move_insn (g4, GEN_INT (rounded_size));
|
4621 |
|
|
|
4622 |
|
|
|
4623 |
|
|
/* Step 2: compute initial and final value of the loop counter. */
|
4624 |
|
|
|
4625 |
|
|
/* TEST_ADDR = SP + FIRST. */
|
4626 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, g1,
|
4627 |
|
|
gen_rtx_MINUS (Pmode, stack_pointer_rtx, g1)));
|
4628 |
|
|
|
4629 |
|
|
/* LAST_ADDR = SP + FIRST + ROUNDED_SIZE. */
|
4630 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, g4, gen_rtx_MINUS (Pmode, g1, g4)));
|
4631 |
|
|
|
4632 |
|
|
|
4633 |
|
|
/* Step 3: the loop
|
4634 |
|
|
|
4635 |
|
|
while (TEST_ADDR != LAST_ADDR)
|
4636 |
|
|
{
|
4637 |
|
|
TEST_ADDR = TEST_ADDR + PROBE_INTERVAL
|
4638 |
|
|
probe at TEST_ADDR
|
4639 |
|
|
}
|
4640 |
|
|
|
4641 |
|
|
probes at FIRST + N * PROBE_INTERVAL for values of N from 1
|
4642 |
|
|
until it is equal to ROUNDED_SIZE. */
|
4643 |
|
|
|
4644 |
|
|
if (TARGET_64BIT)
|
4645 |
|
|
emit_insn (gen_probe_stack_rangedi (g1, g1, g4));
|
4646 |
|
|
else
|
4647 |
|
|
emit_insn (gen_probe_stack_rangesi (g1, g1, g4));
|
4648 |
|
|
|
4649 |
|
|
|
4650 |
|
|
/* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
|
4651 |
|
|
that SIZE is equal to ROUNDED_SIZE. */
|
4652 |
|
|
|
4653 |
|
|
if (size != rounded_size)
|
4654 |
|
|
emit_stack_probe (plus_constant (g4, rounded_size - size));
|
4655 |
|
|
}
|
4656 |
|
|
|
4657 |
|
|
/* Make sure nothing is scheduled before we are done. */
|
4658 |
|
|
emit_insn (gen_blockage ());
|
4659 |
|
|
}
|
4660 |
|
|
|
4661 |
|
|
/* Probe a range of stack addresses from REG1 to REG2 inclusive. These are
|
4662 |
|
|
absolute addresses. */
|
4663 |
|
|
|
4664 |
|
|
const char *
|
4665 |
|
|
output_probe_stack_range (rtx reg1, rtx reg2)
|
4666 |
|
|
{
|
4667 |
|
|
static int labelno = 0;
|
4668 |
|
|
char loop_lab[32], end_lab[32];
|
4669 |
|
|
rtx xops[2];
|
4670 |
|
|
|
4671 |
|
|
ASM_GENERATE_INTERNAL_LABEL (loop_lab, "LPSRL", labelno);
|
4672 |
|
|
ASM_GENERATE_INTERNAL_LABEL (end_lab, "LPSRE", labelno++);
|
4673 |
|
|
|
4674 |
|
|
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, loop_lab);
|
4675 |
|
|
|
4676 |
|
|
/* Jump to END_LAB if TEST_ADDR == LAST_ADDR. */
|
4677 |
|
|
xops[0] = reg1;
|
4678 |
|
|
xops[1] = reg2;
|
4679 |
|
|
output_asm_insn ("cmp\t%0, %1", xops);
|
4680 |
|
|
if (TARGET_ARCH64)
|
4681 |
|
|
fputs ("\tbe,pn\t%xcc,", asm_out_file);
|
4682 |
|
|
else
|
4683 |
|
|
fputs ("\tbe\t", asm_out_file);
|
4684 |
|
|
assemble_name_raw (asm_out_file, end_lab);
|
4685 |
|
|
fputc ('\n', asm_out_file);
|
4686 |
|
|
|
4687 |
|
|
/* TEST_ADDR = TEST_ADDR + PROBE_INTERVAL. */
|
4688 |
|
|
xops[1] = GEN_INT (-PROBE_INTERVAL);
|
4689 |
|
|
output_asm_insn (" add\t%0, %1, %0", xops);
|
4690 |
|
|
|
4691 |
|
|
/* Probe at TEST_ADDR and branch. */
|
4692 |
|
|
if (TARGET_ARCH64)
|
4693 |
|
|
fputs ("\tba,pt\t%xcc,", asm_out_file);
|
4694 |
|
|
else
|
4695 |
|
|
fputs ("\tba\t", asm_out_file);
|
4696 |
|
|
assemble_name_raw (asm_out_file, loop_lab);
|
4697 |
|
|
fputc ('\n', asm_out_file);
|
4698 |
|
|
xops[1] = GEN_INT (SPARC_STACK_BIAS);
|
4699 |
|
|
output_asm_insn (" st\t%%g0, [%0+%1]", xops);
|
4700 |
|
|
|
4701 |
|
|
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, end_lab);
|
4702 |
|
|
|
4703 |
|
|
return "";
|
4704 |
|
|
}
|
4705 |
|
|
|
4706 |
|
|
/* Emit code to save/restore registers from LOW to HIGH at BASE+OFFSET as
|
4707 |
|
|
needed. LOW is supposed to be double-word aligned for 32-bit registers.
|
4708 |
|
|
SAVE_P decides whether a register must be saved/restored. ACTION_TRUE
|
4709 |
|
|
is the action to be performed if SAVE_P returns true and ACTION_FALSE
|
4710 |
|
|
the action to be performed if it returns false. Return the new offset. */
|
4711 |
|
|
|
4712 |
|
|
typedef bool (*sorr_pred_t) (unsigned int, int);
|
4713 |
|
|
typedef enum { SORR_NONE, SORR_ADVANCE, SORR_SAVE, SORR_RESTORE } sorr_act_t;
|
4714 |
|
|
|
4715 |
|
|
static int
|
4716 |
|
|
emit_save_or_restore_regs (unsigned int low, unsigned int high, rtx base,
|
4717 |
|
|
int offset, int leaf_function, sorr_pred_t save_p,
|
4718 |
|
|
sorr_act_t action_true, sorr_act_t action_false)
|
4719 |
|
|
{
|
4720 |
|
|
unsigned int i;
|
4721 |
|
|
rtx mem, insn;
|
4722 |
|
|
|
4723 |
|
|
if (TARGET_ARCH64 && high <= 32)
|
4724 |
|
|
{
|
4725 |
|
|
int fp_offset = -1;
|
4726 |
|
|
|
4727 |
|
|
for (i = low; i < high; i++)
|
4728 |
|
|
{
|
4729 |
|
|
if (save_p (i, leaf_function))
|
4730 |
|
|
{
|
4731 |
|
|
mem = gen_frame_mem (DImode, plus_constant (base, offset));
|
4732 |
|
|
if (action_true == SORR_SAVE)
|
4733 |
|
|
{
|
4734 |
|
|
insn = emit_move_insn (mem, gen_rtx_REG (DImode, i));
|
4735 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
4736 |
|
|
}
|
4737 |
|
|
else /* action_true == SORR_RESTORE */
|
4738 |
|
|
{
|
4739 |
|
|
/* The frame pointer must be restored last since its old
|
4740 |
|
|
value may be used as base address for the frame. This
|
4741 |
|
|
is problematic in 64-bit mode only because of the lack
|
4742 |
|
|
of double-word load instruction. */
|
4743 |
|
|
if (i == HARD_FRAME_POINTER_REGNUM)
|
4744 |
|
|
fp_offset = offset;
|
4745 |
|
|
else
|
4746 |
|
|
emit_move_insn (gen_rtx_REG (DImode, i), mem);
|
4747 |
|
|
}
|
4748 |
|
|
offset += 8;
|
4749 |
|
|
}
|
4750 |
|
|
else if (action_false == SORR_ADVANCE)
|
4751 |
|
|
offset += 8;
|
4752 |
|
|
}
|
4753 |
|
|
|
4754 |
|
|
if (fp_offset >= 0)
|
4755 |
|
|
{
|
4756 |
|
|
mem = gen_frame_mem (DImode, plus_constant (base, fp_offset));
|
4757 |
|
|
emit_move_insn (hard_frame_pointer_rtx, mem);
|
4758 |
|
|
}
|
4759 |
|
|
}
|
4760 |
|
|
else
|
4761 |
|
|
{
|
4762 |
|
|
for (i = low; i < high; i += 2)
|
4763 |
|
|
{
|
4764 |
|
|
bool reg0 = save_p (i, leaf_function);
|
4765 |
|
|
bool reg1 = save_p (i + 1, leaf_function);
|
4766 |
|
|
enum machine_mode mode;
|
4767 |
|
|
int regno;
|
4768 |
|
|
|
4769 |
|
|
if (reg0 && reg1)
|
4770 |
|
|
{
|
4771 |
|
|
mode = SPARC_INT_REG_P (i) ? DImode : DFmode;
|
4772 |
|
|
regno = i;
|
4773 |
|
|
}
|
4774 |
|
|
else if (reg0)
|
4775 |
|
|
{
|
4776 |
|
|
mode = SPARC_INT_REG_P (i) ? SImode : SFmode;
|
4777 |
|
|
regno = i;
|
4778 |
|
|
}
|
4779 |
|
|
else if (reg1)
|
4780 |
|
|
{
|
4781 |
|
|
mode = SPARC_INT_REG_P (i) ? SImode : SFmode;
|
4782 |
|
|
regno = i + 1;
|
4783 |
|
|
offset += 4;
|
4784 |
|
|
}
|
4785 |
|
|
else
|
4786 |
|
|
{
|
4787 |
|
|
if (action_false == SORR_ADVANCE)
|
4788 |
|
|
offset += 8;
|
4789 |
|
|
continue;
|
4790 |
|
|
}
|
4791 |
|
|
|
4792 |
|
|
mem = gen_frame_mem (mode, plus_constant (base, offset));
|
4793 |
|
|
if (action_true == SORR_SAVE)
|
4794 |
|
|
{
|
4795 |
|
|
insn = emit_move_insn (mem, gen_rtx_REG (mode, regno));
|
4796 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
4797 |
|
|
if (mode == DImode)
|
4798 |
|
|
{
|
4799 |
|
|
rtx set1, set2;
|
4800 |
|
|
mem = gen_frame_mem (SImode, plus_constant (base, offset));
|
4801 |
|
|
set1 = gen_rtx_SET (VOIDmode, mem,
|
4802 |
|
|
gen_rtx_REG (SImode, regno));
|
4803 |
|
|
RTX_FRAME_RELATED_P (set1) = 1;
|
4804 |
|
|
mem
|
4805 |
|
|
= gen_frame_mem (SImode, plus_constant (base, offset + 4));
|
4806 |
|
|
set2 = gen_rtx_SET (VOIDmode, mem,
|
4807 |
|
|
gen_rtx_REG (SImode, regno + 1));
|
4808 |
|
|
RTX_FRAME_RELATED_P (set2) = 1;
|
4809 |
|
|
add_reg_note (insn, REG_FRAME_RELATED_EXPR,
|
4810 |
|
|
gen_rtx_PARALLEL (VOIDmode,
|
4811 |
|
|
gen_rtvec (2, set1, set2)));
|
4812 |
|
|
}
|
4813 |
|
|
}
|
4814 |
|
|
else /* action_true == SORR_RESTORE */
|
4815 |
|
|
emit_move_insn (gen_rtx_REG (mode, regno), mem);
|
4816 |
|
|
|
4817 |
|
|
/* Always preserve double-word alignment. */
|
4818 |
|
|
offset = (offset + 8) & -8;
|
4819 |
|
|
}
|
4820 |
|
|
}
|
4821 |
|
|
|
4822 |
|
|
return offset;
|
4823 |
|
|
}
|
4824 |
|
|
|
4825 |
|
|
/* Emit code to adjust BASE to OFFSET. Return the new base. */
|
4826 |
|
|
|
4827 |
|
|
static rtx
|
4828 |
|
|
emit_adjust_base_to_offset (rtx base, int offset)
|
4829 |
|
|
{
|
4830 |
|
|
/* ??? This might be optimized a little as %g1 might already have a
|
4831 |
|
|
value close enough that a single add insn will do. */
|
4832 |
|
|
/* ??? Although, all of this is probably only a temporary fix because
|
4833 |
|
|
if %g1 can hold a function result, then sparc_expand_epilogue will
|
4834 |
|
|
lose (the result will be clobbered). */
|
4835 |
|
|
rtx new_base = gen_rtx_REG (Pmode, 1);
|
4836 |
|
|
emit_move_insn (new_base, GEN_INT (offset));
|
4837 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
4838 |
|
|
new_base, gen_rtx_PLUS (Pmode, base, new_base)));
|
4839 |
|
|
return new_base;
|
4840 |
|
|
}
|
4841 |
|
|
|
4842 |
|
|
/* Emit code to save/restore call-saved global and FP registers. */
|
4843 |
|
|
|
4844 |
|
|
static void
|
4845 |
|
|
emit_save_or_restore_global_fp_regs (rtx base, int offset, sorr_act_t action)
|
4846 |
|
|
{
|
4847 |
|
|
if (offset < -4096 || offset + sparc_n_global_fp_regs * 4 > 4095)
|
4848 |
|
|
{
|
4849 |
|
|
base = emit_adjust_base_to_offset (base, offset);
|
4850 |
|
|
offset = 0;
|
4851 |
|
|
}
|
4852 |
|
|
|
4853 |
|
|
offset
|
4854 |
|
|
= emit_save_or_restore_regs (0, 8, base, offset, 0,
|
4855 |
|
|
save_global_or_fp_reg_p, action, SORR_NONE);
|
4856 |
|
|
emit_save_or_restore_regs (32, TARGET_V9 ? 96 : 64, base, offset, 0,
|
4857 |
|
|
save_global_or_fp_reg_p, action, SORR_NONE);
|
4858 |
|
|
}
|
4859 |
|
|
|
4860 |
|
|
/* Emit code to save/restore call-saved local and in registers. */
|
4861 |
|
|
|
4862 |
|
|
static void
|
4863 |
|
|
emit_save_or_restore_local_in_regs (rtx base, int offset, sorr_act_t action)
|
4864 |
|
|
{
|
4865 |
|
|
if (offset < -4096 || offset + 16 * UNITS_PER_WORD > 4095)
|
4866 |
|
|
{
|
4867 |
|
|
base = emit_adjust_base_to_offset (base, offset);
|
4868 |
|
|
offset = 0;
|
4869 |
|
|
}
|
4870 |
|
|
|
4871 |
|
|
emit_save_or_restore_regs (16, 32, base, offset, sparc_leaf_function_p,
|
4872 |
|
|
save_local_or_in_reg_p, action, SORR_ADVANCE);
|
4873 |
|
|
}
|
4874 |
|
|
|
4875 |
|
|
/* Emit a window_save insn. */
|
4876 |
|
|
|
4877 |
|
|
static rtx
|
4878 |
|
|
emit_window_save (rtx increment)
|
4879 |
|
|
{
|
4880 |
|
|
rtx insn = emit_insn (gen_window_save (increment));
|
4881 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
4882 |
|
|
|
4883 |
|
|
/* The incoming return address (%o7) is saved in %i7. */
|
4884 |
|
|
add_reg_note (insn, REG_CFA_REGISTER,
|
4885 |
|
|
gen_rtx_SET (VOIDmode,
|
4886 |
|
|
gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM),
|
4887 |
|
|
gen_rtx_REG (Pmode,
|
4888 |
|
|
INCOMING_RETURN_ADDR_REGNUM)));
|
4889 |
|
|
|
4890 |
|
|
/* The window save event. */
|
4891 |
|
|
add_reg_note (insn, REG_CFA_WINDOW_SAVE, const0_rtx);
|
4892 |
|
|
|
4893 |
|
|
/* The CFA is %fp, the hard frame pointer. */
|
4894 |
|
|
add_reg_note (insn, REG_CFA_DEF_CFA,
|
4895 |
|
|
plus_constant (hard_frame_pointer_rtx,
|
4896 |
|
|
INCOMING_FRAME_SP_OFFSET));
|
4897 |
|
|
|
4898 |
|
|
return insn;
|
4899 |
|
|
}
|
4900 |
|
|
|
4901 |
|
|
/* Generate an increment for the stack pointer. */
|
4902 |
|
|
|
4903 |
|
|
static rtx
|
4904 |
|
|
gen_stack_pointer_inc (rtx increment)
|
4905 |
|
|
{
|
4906 |
|
|
return gen_rtx_SET (VOIDmode,
|
4907 |
|
|
stack_pointer_rtx,
|
4908 |
|
|
gen_rtx_PLUS (Pmode,
|
4909 |
|
|
stack_pointer_rtx,
|
4910 |
|
|
increment));
|
4911 |
|
|
}
|
4912 |
|
|
|
4913 |
|
|
/* Generate a decrement for the stack pointer. */
|
4914 |
|
|
|
4915 |
|
|
static rtx
|
4916 |
|
|
gen_stack_pointer_dec (rtx decrement)
|
4917 |
|
|
{
|
4918 |
|
|
return gen_rtx_SET (VOIDmode,
|
4919 |
|
|
stack_pointer_rtx,
|
4920 |
|
|
gen_rtx_MINUS (Pmode,
|
4921 |
|
|
stack_pointer_rtx,
|
4922 |
|
|
decrement));
|
4923 |
|
|
}
|
4924 |
|
|
|
4925 |
|
|
/* Expand the function prologue. The prologue is responsible for reserving
|
4926 |
|
|
storage for the frame, saving the call-saved registers and loading the
|
4927 |
|
|
GOT register if needed. */
|
4928 |
|
|
|
4929 |
|
|
void
|
4930 |
|
|
sparc_expand_prologue (void)
|
4931 |
|
|
{
|
4932 |
|
|
HOST_WIDE_INT size;
|
4933 |
|
|
rtx insn;
|
4934 |
|
|
|
4935 |
|
|
/* Compute a snapshot of current_function_uses_only_leaf_regs. Relying
|
4936 |
|
|
on the final value of the flag means deferring the prologue/epilogue
|
4937 |
|
|
expansion until just before the second scheduling pass, which is too
|
4938 |
|
|
late to emit multiple epilogues or return insns.
|
4939 |
|
|
|
4940 |
|
|
Of course we are making the assumption that the value of the flag
|
4941 |
|
|
will not change between now and its final value. Of the three parts
|
4942 |
|
|
of the formula, only the last one can reasonably vary. Let's take a
|
4943 |
|
|
closer look, after assuming that the first two ones are set to true
|
4944 |
|
|
(otherwise the last value is effectively silenced).
|
4945 |
|
|
|
4946 |
|
|
If only_leaf_regs_used returns false, the global predicate will also
|
4947 |
|
|
be false so the actual frame size calculated below will be positive.
|
4948 |
|
|
As a consequence, the save_register_window insn will be emitted in
|
4949 |
|
|
the instruction stream; now this insn explicitly references %fp
|
4950 |
|
|
which is not a leaf register so only_leaf_regs_used will always
|
4951 |
|
|
return false subsequently.
|
4952 |
|
|
|
4953 |
|
|
If only_leaf_regs_used returns true, we hope that the subsequent
|
4954 |
|
|
optimization passes won't cause non-leaf registers to pop up. For
|
4955 |
|
|
example, the regrename pass has special provisions to not rename to
|
4956 |
|
|
non-leaf registers in a leaf function. */
|
4957 |
|
|
sparc_leaf_function_p
|
4958 |
|
|
= optimize > 0 && current_function_is_leaf && only_leaf_regs_used ();
|
4959 |
|
|
|
4960 |
|
|
size = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
|
4961 |
|
|
|
4962 |
|
|
if (flag_stack_usage_info)
|
4963 |
|
|
current_function_static_stack_size = size;
|
4964 |
|
|
|
4965 |
|
|
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
|
4966 |
|
|
sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
|
4967 |
|
|
|
4968 |
|
|
if (size == 0)
|
4969 |
|
|
; /* do nothing. */
|
4970 |
|
|
else if (sparc_leaf_function_p)
|
4971 |
|
|
{
|
4972 |
|
|
rtx size_int_rtx = GEN_INT (-size);
|
4973 |
|
|
|
4974 |
|
|
if (size <= 4096)
|
4975 |
|
|
insn = emit_insn (gen_stack_pointer_inc (size_int_rtx));
|
4976 |
|
|
else if (size <= 8192)
|
4977 |
|
|
{
|
4978 |
|
|
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
|
4979 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
4980 |
|
|
|
4981 |
|
|
/* %sp is still the CFA register. */
|
4982 |
|
|
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
|
4983 |
|
|
}
|
4984 |
|
|
else
|
4985 |
|
|
{
|
4986 |
|
|
rtx size_rtx = gen_rtx_REG (Pmode, 1);
|
4987 |
|
|
emit_move_insn (size_rtx, size_int_rtx);
|
4988 |
|
|
insn = emit_insn (gen_stack_pointer_inc (size_rtx));
|
4989 |
|
|
add_reg_note (insn, REG_FRAME_RELATED_EXPR,
|
4990 |
|
|
gen_stack_pointer_inc (size_int_rtx));
|
4991 |
|
|
}
|
4992 |
|
|
|
4993 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
4994 |
|
|
}
|
4995 |
|
|
else
|
4996 |
|
|
{
|
4997 |
|
|
rtx size_int_rtx = GEN_INT (-size);
|
4998 |
|
|
|
4999 |
|
|
if (size <= 4096)
|
5000 |
|
|
emit_window_save (size_int_rtx);
|
5001 |
|
|
else if (size <= 8192)
|
5002 |
|
|
{
|
5003 |
|
|
emit_window_save (GEN_INT (-4096));
|
5004 |
|
|
|
5005 |
|
|
/* %sp is not the CFA register anymore. */
|
5006 |
|
|
emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
|
5007 |
|
|
|
5008 |
|
|
/* Make sure no %fp-based store is issued until after the frame is
|
5009 |
|
|
established. The offset between the frame pointer and the stack
|
5010 |
|
|
pointer is calculated relative to the value of the stack pointer
|
5011 |
|
|
at the end of the function prologue, and moving instructions that
|
5012 |
|
|
access the stack via the frame pointer between the instructions
|
5013 |
|
|
that decrement the stack pointer could result in accessing the
|
5014 |
|
|
register window save area, which is volatile. */
|
5015 |
|
|
emit_insn (gen_frame_blockage ());
|
5016 |
|
|
}
|
5017 |
|
|
else
|
5018 |
|
|
{
|
5019 |
|
|
rtx size_rtx = gen_rtx_REG (Pmode, 1);
|
5020 |
|
|
emit_move_insn (size_rtx, size_int_rtx);
|
5021 |
|
|
emit_window_save (size_rtx);
|
5022 |
|
|
}
|
5023 |
|
|
}
|
5024 |
|
|
|
5025 |
|
|
if (sparc_leaf_function_p)
|
5026 |
|
|
{
|
5027 |
|
|
sparc_frame_base_reg = stack_pointer_rtx;
|
5028 |
|
|
sparc_frame_base_offset = size + SPARC_STACK_BIAS;
|
5029 |
|
|
}
|
5030 |
|
|
else
|
5031 |
|
|
{
|
5032 |
|
|
sparc_frame_base_reg = hard_frame_pointer_rtx;
|
5033 |
|
|
sparc_frame_base_offset = SPARC_STACK_BIAS;
|
5034 |
|
|
}
|
5035 |
|
|
|
5036 |
|
|
if (sparc_n_global_fp_regs > 0)
|
5037 |
|
|
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
|
5038 |
|
|
sparc_frame_base_offset
|
5039 |
|
|
- sparc_apparent_frame_size,
|
5040 |
|
|
SORR_SAVE);
|
5041 |
|
|
|
5042 |
|
|
/* Load the GOT register if needed. */
|
5043 |
|
|
if (crtl->uses_pic_offset_table)
|
5044 |
|
|
load_got_register ();
|
5045 |
|
|
|
5046 |
|
|
/* Advertise that the data calculated just above are now valid. */
|
5047 |
|
|
sparc_prologue_data_valid_p = true;
|
5048 |
|
|
}
|
5049 |
|
|
|
5050 |
|
|
/* Expand the function prologue. The prologue is responsible for reserving
|
5051 |
|
|
storage for the frame, saving the call-saved registers and loading the
|
5052 |
|
|
GOT register if needed. */
|
5053 |
|
|
|
5054 |
|
|
void
|
5055 |
|
|
sparc_flat_expand_prologue (void)
|
5056 |
|
|
{
|
5057 |
|
|
HOST_WIDE_INT size;
|
5058 |
|
|
rtx insn;
|
5059 |
|
|
|
5060 |
|
|
sparc_leaf_function_p = optimize > 0 && current_function_is_leaf;
|
5061 |
|
|
|
5062 |
|
|
size = sparc_compute_frame_size (get_frame_size(), sparc_leaf_function_p);
|
5063 |
|
|
|
5064 |
|
|
if (flag_stack_usage_info)
|
5065 |
|
|
current_function_static_stack_size = size;
|
5066 |
|
|
|
5067 |
|
|
if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
|
5068 |
|
|
sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
|
5069 |
|
|
|
5070 |
|
|
if (sparc_save_local_in_regs_p)
|
5071 |
|
|
emit_save_or_restore_local_in_regs (stack_pointer_rtx, SPARC_STACK_BIAS,
|
5072 |
|
|
SORR_SAVE);
|
5073 |
|
|
|
5074 |
|
|
if (size == 0)
|
5075 |
|
|
; /* do nothing. */
|
5076 |
|
|
else
|
5077 |
|
|
{
|
5078 |
|
|
rtx size_int_rtx, size_rtx;
|
5079 |
|
|
|
5080 |
|
|
size_rtx = size_int_rtx = GEN_INT (-size);
|
5081 |
|
|
|
5082 |
|
|
/* We establish the frame (i.e. decrement the stack pointer) first, even
|
5083 |
|
|
if we use a frame pointer, because we cannot clobber any call-saved
|
5084 |
|
|
registers, including the frame pointer, if we haven't created a new
|
5085 |
|
|
register save area, for the sake of compatibility with the ABI. */
|
5086 |
|
|
if (size <= 4096)
|
5087 |
|
|
insn = emit_insn (gen_stack_pointer_inc (size_int_rtx));
|
5088 |
|
|
else if (size <= 8192 && !frame_pointer_needed)
|
5089 |
|
|
{
|
5090 |
|
|
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (-4096)));
|
5091 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
5092 |
|
|
insn = emit_insn (gen_stack_pointer_inc (GEN_INT (4096 - size)));
|
5093 |
|
|
}
|
5094 |
|
|
else
|
5095 |
|
|
{
|
5096 |
|
|
size_rtx = gen_rtx_REG (Pmode, 1);
|
5097 |
|
|
emit_move_insn (size_rtx, size_int_rtx);
|
5098 |
|
|
insn = emit_insn (gen_stack_pointer_inc (size_rtx));
|
5099 |
|
|
add_reg_note (insn, REG_CFA_ADJUST_CFA,
|
5100 |
|
|
gen_stack_pointer_inc (size_int_rtx));
|
5101 |
|
|
}
|
5102 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
5103 |
|
|
|
5104 |
|
|
/* Ensure nothing is scheduled until after the frame is established. */
|
5105 |
|
|
emit_insn (gen_blockage ());
|
5106 |
|
|
|
5107 |
|
|
if (frame_pointer_needed)
|
5108 |
|
|
{
|
5109 |
|
|
insn = emit_insn (gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
|
5110 |
|
|
gen_rtx_MINUS (Pmode,
|
5111 |
|
|
stack_pointer_rtx,
|
5112 |
|
|
size_rtx)));
|
5113 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
5114 |
|
|
|
5115 |
|
|
add_reg_note (insn, REG_CFA_ADJUST_CFA,
|
5116 |
|
|
gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
|
5117 |
|
|
plus_constant (stack_pointer_rtx,
|
5118 |
|
|
size)));
|
5119 |
|
|
}
|
5120 |
|
|
|
5121 |
|
|
if (return_addr_reg_needed_p (sparc_leaf_function_p))
|
5122 |
|
|
{
|
5123 |
|
|
rtx o7 = gen_rtx_REG (Pmode, INCOMING_RETURN_ADDR_REGNUM);
|
5124 |
|
|
rtx i7 = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
|
5125 |
|
|
|
5126 |
|
|
insn = emit_move_insn (i7, o7);
|
5127 |
|
|
RTX_FRAME_RELATED_P (insn) = 1;
|
5128 |
|
|
|
5129 |
|
|
add_reg_note (insn, REG_CFA_REGISTER,
|
5130 |
|
|
gen_rtx_SET (VOIDmode, i7, o7));
|
5131 |
|
|
|
5132 |
|
|
/* Prevent this instruction from ever being considered dead,
|
5133 |
|
|
even if this function has no epilogue. */
|
5134 |
|
|
emit_use (i7);
|
5135 |
|
|
}
|
5136 |
|
|
}
|
5137 |
|
|
|
5138 |
|
|
if (frame_pointer_needed)
|
5139 |
|
|
{
|
5140 |
|
|
sparc_frame_base_reg = hard_frame_pointer_rtx;
|
5141 |
|
|
sparc_frame_base_offset = SPARC_STACK_BIAS;
|
5142 |
|
|
}
|
5143 |
|
|
else
|
5144 |
|
|
{
|
5145 |
|
|
sparc_frame_base_reg = stack_pointer_rtx;
|
5146 |
|
|
sparc_frame_base_offset = size + SPARC_STACK_BIAS;
|
5147 |
|
|
}
|
5148 |
|
|
|
5149 |
|
|
if (sparc_n_global_fp_regs > 0)
|
5150 |
|
|
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
|
5151 |
|
|
sparc_frame_base_offset
|
5152 |
|
|
- sparc_apparent_frame_size,
|
5153 |
|
|
SORR_SAVE);
|
5154 |
|
|
|
5155 |
|
|
/* Load the GOT register if needed. */
|
5156 |
|
|
if (crtl->uses_pic_offset_table)
|
5157 |
|
|
load_got_register ();
|
5158 |
|
|
|
5159 |
|
|
/* Advertise that the data calculated just above are now valid. */
|
5160 |
|
|
sparc_prologue_data_valid_p = true;
|
5161 |
|
|
}
|
5162 |
|
|
|
5163 |
|
|
/* This function generates the assembly code for function entry, which boils
|
5164 |
|
|
down to emitting the necessary .register directives. */
|
5165 |
|
|
|
5166 |
|
|
static void
|
5167 |
|
|
sparc_asm_function_prologue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
|
5168 |
|
|
{
|
5169 |
|
|
/* Check that the assumption we made in sparc_expand_prologue is valid. */
|
5170 |
|
|
if (!TARGET_FLAT)
|
5171 |
|
|
gcc_assert (sparc_leaf_function_p == current_function_uses_only_leaf_regs);
|
5172 |
|
|
|
5173 |
|
|
sparc_output_scratch_registers (file);
|
5174 |
|
|
}
|
5175 |
|
|
|
5176 |
|
|
/* Expand the function epilogue, either normal or part of a sibcall.
|
5177 |
|
|
We emit all the instructions except the return or the call. */
|
5178 |
|
|
|
5179 |
|
|
void
|
5180 |
|
|
sparc_expand_epilogue (bool for_eh)
|
5181 |
|
|
{
|
5182 |
|
|
HOST_WIDE_INT size = sparc_frame_size;
|
5183 |
|
|
|
5184 |
|
|
if (sparc_n_global_fp_regs > 0)
|
5185 |
|
|
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
|
5186 |
|
|
sparc_frame_base_offset
|
5187 |
|
|
- sparc_apparent_frame_size,
|
5188 |
|
|
SORR_RESTORE);
|
5189 |
|
|
|
5190 |
|
|
if (size == 0 || for_eh)
|
5191 |
|
|
; /* do nothing. */
|
5192 |
|
|
else if (sparc_leaf_function_p)
|
5193 |
|
|
{
|
5194 |
|
|
if (size <= 4096)
|
5195 |
|
|
emit_insn (gen_stack_pointer_dec (GEN_INT (-size)));
|
5196 |
|
|
else if (size <= 8192)
|
5197 |
|
|
{
|
5198 |
|
|
emit_insn (gen_stack_pointer_dec (GEN_INT (-4096)));
|
5199 |
|
|
emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - size)));
|
5200 |
|
|
}
|
5201 |
|
|
else
|
5202 |
|
|
{
|
5203 |
|
|
rtx reg = gen_rtx_REG (Pmode, 1);
|
5204 |
|
|
emit_move_insn (reg, GEN_INT (-size));
|
5205 |
|
|
emit_insn (gen_stack_pointer_dec (reg));
|
5206 |
|
|
}
|
5207 |
|
|
}
|
5208 |
|
|
}
|
5209 |
|
|
|
5210 |
|
|
/* Expand the function epilogue, either normal or part of a sibcall.
|
5211 |
|
|
We emit all the instructions except the return or the call. */
|
5212 |
|
|
|
5213 |
|
|
void
|
5214 |
|
|
sparc_flat_expand_epilogue (bool for_eh)
|
5215 |
|
|
{
|
5216 |
|
|
HOST_WIDE_INT size = sparc_frame_size;
|
5217 |
|
|
|
5218 |
|
|
if (sparc_n_global_fp_regs > 0)
|
5219 |
|
|
emit_save_or_restore_global_fp_regs (sparc_frame_base_reg,
|
5220 |
|
|
sparc_frame_base_offset
|
5221 |
|
|
- sparc_apparent_frame_size,
|
5222 |
|
|
SORR_RESTORE);
|
5223 |
|
|
|
5224 |
|
|
/* If we have a frame pointer, we'll need both to restore it before the
|
5225 |
|
|
frame is destroyed and use its current value in destroying the frame.
|
5226 |
|
|
Since we don't have an atomic way to do that in the flat window model,
|
5227 |
|
|
we save the current value into a temporary register (%g1). */
|
5228 |
|
|
if (frame_pointer_needed && !for_eh)
|
5229 |
|
|
emit_move_insn (gen_rtx_REG (Pmode, 1), hard_frame_pointer_rtx);
|
5230 |
|
|
|
5231 |
|
|
if (return_addr_reg_needed_p (sparc_leaf_function_p))
|
5232 |
|
|
emit_move_insn (gen_rtx_REG (Pmode, INCOMING_RETURN_ADDR_REGNUM),
|
5233 |
|
|
gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM));
|
5234 |
|
|
|
5235 |
|
|
if (sparc_save_local_in_regs_p)
|
5236 |
|
|
emit_save_or_restore_local_in_regs (sparc_frame_base_reg,
|
5237 |
|
|
sparc_frame_base_offset,
|
5238 |
|
|
SORR_RESTORE);
|
5239 |
|
|
|
5240 |
|
|
if (size == 0 || for_eh)
|
5241 |
|
|
; /* do nothing. */
|
5242 |
|
|
else if (frame_pointer_needed)
|
5243 |
|
|
{
|
5244 |
|
|
/* Make sure the frame is destroyed after everything else is done. */
|
5245 |
|
|
emit_insn (gen_blockage ());
|
5246 |
|
|
|
5247 |
|
|
emit_move_insn (stack_pointer_rtx, gen_rtx_REG (Pmode, 1));
|
5248 |
|
|
}
|
5249 |
|
|
else
|
5250 |
|
|
{
|
5251 |
|
|
/* Likewise. */
|
5252 |
|
|
emit_insn (gen_blockage ());
|
5253 |
|
|
|
5254 |
|
|
if (size <= 4096)
|
5255 |
|
|
emit_insn (gen_stack_pointer_dec (GEN_INT (-size)));
|
5256 |
|
|
else if (size <= 8192)
|
5257 |
|
|
{
|
5258 |
|
|
emit_insn (gen_stack_pointer_dec (GEN_INT (-4096)));
|
5259 |
|
|
emit_insn (gen_stack_pointer_dec (GEN_INT (4096 - size)));
|
5260 |
|
|
}
|
5261 |
|
|
else
|
5262 |
|
|
{
|
5263 |
|
|
rtx reg = gen_rtx_REG (Pmode, 1);
|
5264 |
|
|
emit_move_insn (reg, GEN_INT (-size));
|
5265 |
|
|
emit_insn (gen_stack_pointer_dec (reg));
|
5266 |
|
|
}
|
5267 |
|
|
}
|
5268 |
|
|
}
|
5269 |
|
|
|
5270 |
|
|
/* Return true if it is appropriate to emit `return' instructions in the
|
5271 |
|
|
body of a function. */
|
5272 |
|
|
|
5273 |
|
|
bool
|
5274 |
|
|
sparc_can_use_return_insn_p (void)
|
5275 |
|
|
{
|
5276 |
|
|
return sparc_prologue_data_valid_p
|
5277 |
|
|
&& sparc_n_global_fp_regs == 0
|
5278 |
|
|
&& TARGET_FLAT
|
5279 |
|
|
? (sparc_frame_size == 0 && !sparc_save_local_in_regs_p)
|
5280 |
|
|
: (sparc_frame_size == 0 || !sparc_leaf_function_p);
|
5281 |
|
|
}
|
5282 |
|
|
|
5283 |
|
|
/* This function generates the assembly code for function exit. */
|
5284 |
|
|
|
5285 |
|
|
static void
|
5286 |
|
|
sparc_asm_function_epilogue (FILE *file, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
|
5287 |
|
|
{
|
5288 |
|
|
/* If the last two instructions of a function are "call foo; dslot;"
|
5289 |
|
|
the return address might point to the first instruction in the next
|
5290 |
|
|
function and we have to output a dummy nop for the sake of sane
|
5291 |
|
|
backtraces in such cases. This is pointless for sibling calls since
|
5292 |
|
|
the return address is explicitly adjusted. */
|
5293 |
|
|
|
5294 |
|
|
rtx insn, last_real_insn;
|
5295 |
|
|
|
5296 |
|
|
insn = get_last_insn ();
|
5297 |
|
|
|
5298 |
|
|
last_real_insn = prev_real_insn (insn);
|
5299 |
|
|
if (last_real_insn
|
5300 |
|
|
&& GET_CODE (last_real_insn) == INSN
|
5301 |
|
|
&& GET_CODE (PATTERN (last_real_insn)) == SEQUENCE)
|
5302 |
|
|
last_real_insn = XVECEXP (PATTERN (last_real_insn), 0, 0);
|
5303 |
|
|
|
5304 |
|
|
if (last_real_insn
|
5305 |
|
|
&& CALL_P (last_real_insn)
|
5306 |
|
|
&& !SIBLING_CALL_P (last_real_insn))
|
5307 |
|
|
fputs("\tnop\n", file);
|
5308 |
|
|
|
5309 |
|
|
sparc_output_deferred_case_vectors ();
|
5310 |
|
|
}
|
5311 |
|
|
|
5312 |
|
|
/* Output a 'restore' instruction. */
|
5313 |
|
|
|
5314 |
|
|
static void
|
5315 |
|
|
output_restore (rtx pat)
|
5316 |
|
|
{
|
5317 |
|
|
rtx operands[3];
|
5318 |
|
|
|
5319 |
|
|
if (! pat)
|
5320 |
|
|
{
|
5321 |
|
|
fputs ("\t restore\n", asm_out_file);
|
5322 |
|
|
return;
|
5323 |
|
|
}
|
5324 |
|
|
|
5325 |
|
|
gcc_assert (GET_CODE (pat) == SET);
|
5326 |
|
|
|
5327 |
|
|
operands[0] = SET_DEST (pat);
|
5328 |
|
|
pat = SET_SRC (pat);
|
5329 |
|
|
|
5330 |
|
|
switch (GET_CODE (pat))
|
5331 |
|
|
{
|
5332 |
|
|
case PLUS:
|
5333 |
|
|
operands[1] = XEXP (pat, 0);
|
5334 |
|
|
operands[2] = XEXP (pat, 1);
|
5335 |
|
|
output_asm_insn (" restore %r1, %2, %Y0", operands);
|
5336 |
|
|
break;
|
5337 |
|
|
case LO_SUM:
|
5338 |
|
|
operands[1] = XEXP (pat, 0);
|
5339 |
|
|
operands[2] = XEXP (pat, 1);
|
5340 |
|
|
output_asm_insn (" restore %r1, %%lo(%a2), %Y0", operands);
|
5341 |
|
|
break;
|
5342 |
|
|
case ASHIFT:
|
5343 |
|
|
operands[1] = XEXP (pat, 0);
|
5344 |
|
|
gcc_assert (XEXP (pat, 1) == const1_rtx);
|
5345 |
|
|
output_asm_insn (" restore %r1, %r1, %Y0", operands);
|
5346 |
|
|
break;
|
5347 |
|
|
default:
|
5348 |
|
|
operands[1] = pat;
|
5349 |
|
|
output_asm_insn (" restore %%g0, %1, %Y0", operands);
|
5350 |
|
|
break;
|
5351 |
|
|
}
|
5352 |
|
|
}
|
5353 |
|
|
|
5354 |
|
|
/* Output a return. */
|
5355 |
|
|
|
5356 |
|
|
const char *
|
5357 |
|
|
output_return (rtx insn)
|
5358 |
|
|
{
|
5359 |
|
|
if (crtl->calls_eh_return)
|
5360 |
|
|
{
|
5361 |
|
|
/* If the function uses __builtin_eh_return, the eh_return
|
5362 |
|
|
machinery occupies the delay slot. */
|
5363 |
|
|
gcc_assert (!final_sequence);
|
5364 |
|
|
|
5365 |
|
|
if (flag_delayed_branch)
|
5366 |
|
|
{
|
5367 |
|
|
if (!TARGET_FLAT && TARGET_V9)
|
5368 |
|
|
fputs ("\treturn\t%i7+8\n", asm_out_file);
|
5369 |
|
|
else
|
5370 |
|
|
{
|
5371 |
|
|
if (!TARGET_FLAT)
|
5372 |
|
|
fputs ("\trestore\n", asm_out_file);
|
5373 |
|
|
|
5374 |
|
|
fputs ("\tjmp\t%o7+8\n", asm_out_file);
|
5375 |
|
|
}
|
5376 |
|
|
|
5377 |
|
|
fputs ("\t add\t%sp, %g1, %sp\n", asm_out_file);
|
5378 |
|
|
}
|
5379 |
|
|
else
|
5380 |
|
|
{
|
5381 |
|
|
if (!TARGET_FLAT)
|
5382 |
|
|
fputs ("\trestore\n", asm_out_file);
|
5383 |
|
|
|
5384 |
|
|
fputs ("\tadd\t%sp, %g1, %sp\n", asm_out_file);
|
5385 |
|
|
fputs ("\tjmp\t%o7+8\n\t nop\n", asm_out_file);
|
5386 |
|
|
}
|
5387 |
|
|
}
|
5388 |
|
|
else if (sparc_leaf_function_p || TARGET_FLAT)
|
5389 |
|
|
{
|
5390 |
|
|
/* This is a leaf or flat function so we don't have to bother restoring
|
5391 |
|
|
the register window, which frees us from dealing with the convoluted
|
5392 |
|
|
semantics of restore/return. We simply output the jump to the
|
5393 |
|
|
return address and the insn in the delay slot (if any). */
|
5394 |
|
|
|
5395 |
|
|
return "jmp\t%%o7+%)%#";
|
5396 |
|
|
}
|
5397 |
|
|
else
|
5398 |
|
|
{
|
5399 |
|
|
/* This is a regular function so we have to restore the register window.
|
5400 |
|
|
We may have a pending insn for the delay slot, which will be either
|
5401 |
|
|
combined with the 'restore' instruction or put in the delay slot of
|
5402 |
|
|
the 'return' instruction. */
|
5403 |
|
|
|
5404 |
|
|
if (final_sequence)
|
5405 |
|
|
{
|
5406 |
|
|
rtx delay, pat;
|
5407 |
|
|
|
5408 |
|
|
delay = NEXT_INSN (insn);
|
5409 |
|
|
gcc_assert (delay);
|
5410 |
|
|
|
5411 |
|
|
pat = PATTERN (delay);
|
5412 |
|
|
|
5413 |
|
|
if (TARGET_V9 && ! epilogue_renumber (&pat, 1))
|
5414 |
|
|
{
|
5415 |
|
|
epilogue_renumber (&pat, 0);
|
5416 |
|
|
return "return\t%%i7+%)%#";
|
5417 |
|
|
}
|
5418 |
|
|
else
|
5419 |
|
|
{
|
5420 |
|
|
output_asm_insn ("jmp\t%%i7+%)", NULL);
|
5421 |
|
|
output_restore (pat);
|
5422 |
|
|
PATTERN (delay) = gen_blockage ();
|
5423 |
|
|
INSN_CODE (delay) = -1;
|
5424 |
|
|
}
|
5425 |
|
|
}
|
5426 |
|
|
else
|
5427 |
|
|
{
|
5428 |
|
|
/* The delay slot is empty. */
|
5429 |
|
|
if (TARGET_V9)
|
5430 |
|
|
return "return\t%%i7+%)\n\t nop";
|
5431 |
|
|
else if (flag_delayed_branch)
|
5432 |
|
|
return "jmp\t%%i7+%)\n\t restore";
|
5433 |
|
|
else
|
5434 |
|
|
return "restore\n\tjmp\t%%o7+%)\n\t nop";
|
5435 |
|
|
}
|
5436 |
|
|
}
|
5437 |
|
|
|
5438 |
|
|
return "";
|
5439 |
|
|
}
|
5440 |
|
|
|
5441 |
|
|
/* Output a sibling call. */
|
5442 |
|
|
|
5443 |
|
|
const char *
|
5444 |
|
|
output_sibcall (rtx insn, rtx call_operand)
|
5445 |
|
|
{
|
5446 |
|
|
rtx operands[1];
|
5447 |
|
|
|
5448 |
|
|
gcc_assert (flag_delayed_branch);
|
5449 |
|
|
|
5450 |
|
|
operands[0] = call_operand;
|
5451 |
|
|
|
5452 |
|
|
if (sparc_leaf_function_p || TARGET_FLAT)
|
5453 |
|
|
{
|
5454 |
|
|
/* This is a leaf or flat function so we don't have to bother restoring
|
5455 |
|
|
the register window. We simply output the jump to the function and
|
5456 |
|
|
the insn in the delay slot (if any). */
|
5457 |
|
|
|
5458 |
|
|
gcc_assert (!(LEAF_SIBCALL_SLOT_RESERVED_P && final_sequence));
|
5459 |
|
|
|
5460 |
|
|
if (final_sequence)
|
5461 |
|
|
output_asm_insn ("sethi\t%%hi(%a0), %%g1\n\tjmp\t%%g1 + %%lo(%a0)%#",
|
5462 |
|
|
operands);
|
5463 |
|
|
else
|
5464 |
|
|
/* Use or with rs2 %%g0 instead of mov, so that as/ld can optimize
|
5465 |
|
|
it into branch if possible. */
|
5466 |
|
|
output_asm_insn ("or\t%%o7, %%g0, %%g1\n\tcall\t%a0, 0\n\t or\t%%g1, %%g0, %%o7",
|
5467 |
|
|
operands);
|
5468 |
|
|
}
|
5469 |
|
|
else
|
5470 |
|
|
{
|
5471 |
|
|
/* This is a regular function so we have to restore the register window.
|
5472 |
|
|
We may have a pending insn for the delay slot, which will be combined
|
5473 |
|
|
with the 'restore' instruction. */
|
5474 |
|
|
|
5475 |
|
|
output_asm_insn ("call\t%a0, 0", operands);
|
5476 |
|
|
|
5477 |
|
|
if (final_sequence)
|
5478 |
|
|
{
|
5479 |
|
|
rtx delay = NEXT_INSN (insn);
|
5480 |
|
|
gcc_assert (delay);
|
5481 |
|
|
|
5482 |
|
|
output_restore (PATTERN (delay));
|
5483 |
|
|
|
5484 |
|
|
PATTERN (delay) = gen_blockage ();
|
5485 |
|
|
INSN_CODE (delay) = -1;
|
5486 |
|
|
}
|
5487 |
|
|
else
|
5488 |
|
|
output_restore (NULL_RTX);
|
5489 |
|
|
}
|
5490 |
|
|
|
5491 |
|
|
return "";
|
5492 |
|
|
}
|
5493 |
|
|
|
5494 |
|
|
/* Functions for handling argument passing.
|
5495 |
|
|
|
5496 |
|
|
For 32-bit, the first 6 args are normally in registers and the rest are
|
5497 |
|
|
pushed. Any arg that starts within the first 6 words is at least
|
5498 |
|
|
partially passed in a register unless its data type forbids.
|
5499 |
|
|
|
5500 |
|
|
For 64-bit, the argument registers are laid out as an array of 16 elements
|
5501 |
|
|
and arguments are added sequentially. The first 6 int args and up to the
|
5502 |
|
|
first 16 fp args (depending on size) are passed in regs.
|
5503 |
|
|
|
5504 |
|
|
Slot Stack Integral Float Float in structure Double Long Double
|
5505 |
|
|
---- ----- -------- ----- ------------------ ------ -----------
|
5506 |
|
|
15 [SP+248] %f31 %f30,%f31 %d30
|
5507 |
|
|
14 [SP+240] %f29 %f28,%f29 %d28 %q28
|
5508 |
|
|
13 [SP+232] %f27 %f26,%f27 %d26
|
5509 |
|
|
12 [SP+224] %f25 %f24,%f25 %d24 %q24
|
5510 |
|
|
11 [SP+216] %f23 %f22,%f23 %d22
|
5511 |
|
|
10 [SP+208] %f21 %f20,%f21 %d20 %q20
|
5512 |
|
|
9 [SP+200] %f19 %f18,%f19 %d18
|
5513 |
|
|
8 [SP+192] %f17 %f16,%f17 %d16 %q16
|
5514 |
|
|
7 [SP+184] %f15 %f14,%f15 %d14
|
5515 |
|
|
6 [SP+176] %f13 %f12,%f13 %d12 %q12
|
5516 |
|
|
5 [SP+168] %o5 %f11 %f10,%f11 %d10
|
5517 |
|
|
4 [SP+160] %o4 %f9 %f8,%f9 %d8 %q8
|
5518 |
|
|
3 [SP+152] %o3 %f7 %f6,%f7 %d6
|
5519 |
|
|
2 [SP+144] %o2 %f5 %f4,%f5 %d4 %q4
|
5520 |
|
|
1 [SP+136] %o1 %f3 %f2,%f3 %d2
|
5521 |
|
|
|
5522 |
|
|
|
5523 |
|
|
Here SP = %sp if -mno-stack-bias or %sp+stack_bias otherwise.
|
5524 |
|
|
|
5525 |
|
|
Integral arguments are always passed as 64-bit quantities appropriately
|
5526 |
|
|
extended.
|
5527 |
|
|
|
5528 |
|
|
Passing of floating point values is handled as follows.
|
5529 |
|
|
If a prototype is in scope:
|
5530 |
|
|
If the value is in a named argument (i.e. not a stdarg function or a
|
5531 |
|
|
value not part of the `...') then the value is passed in the appropriate
|
5532 |
|
|
fp reg.
|
5533 |
|
|
If the value is part of the `...' and is passed in one of the first 6
|
5534 |
|
|
slots then the value is passed in the appropriate int reg.
|
5535 |
|
|
If the value is part of the `...' and is not passed in one of the first 6
|
5536 |
|
|
slots then the value is passed in memory.
|
5537 |
|
|
If a prototype is not in scope:
|
5538 |
|
|
If the value is one of the first 6 arguments the value is passed in the
|
5539 |
|
|
appropriate integer reg and the appropriate fp reg.
|
5540 |
|
|
If the value is not one of the first 6 arguments the value is passed in
|
5541 |
|
|
the appropriate fp reg and in memory.
|
5542 |
|
|
|
5543 |
|
|
|
5544 |
|
|
Summary of the calling conventions implemented by GCC on the SPARC:
|
5545 |
|
|
|
5546 |
|
|
32-bit ABI:
|
5547 |
|
|
size argument return value
|
5548 |
|
|
|
5549 |
|
|
small integer <4 int. reg. int. reg.
|
5550 |
|
|
word 4 int. reg. int. reg.
|
5551 |
|
|
double word 8 int. reg. int. reg.
|
5552 |
|
|
|
5553 |
|
|
_Complex small integer <8 int. reg. int. reg.
|
5554 |
|
|
_Complex word 8 int. reg. int. reg.
|
5555 |
|
|
_Complex double word 16 memory int. reg.
|
5556 |
|
|
|
5557 |
|
|
vector integer <=8 int. reg. FP reg.
|
5558 |
|
|
vector integer >8 memory memory
|
5559 |
|
|
|
5560 |
|
|
float 4 int. reg. FP reg.
|
5561 |
|
|
double 8 int. reg. FP reg.
|
5562 |
|
|
long double 16 memory memory
|
5563 |
|
|
|
5564 |
|
|
_Complex float 8 memory FP reg.
|
5565 |
|
|
_Complex double 16 memory FP reg.
|
5566 |
|
|
_Complex long double 32 memory FP reg.
|
5567 |
|
|
|
5568 |
|
|
vector float any memory memory
|
5569 |
|
|
|
5570 |
|
|
aggregate any memory memory
|
5571 |
|
|
|
5572 |
|
|
|
5573 |
|
|
|
5574 |
|
|
64-bit ABI:
|
5575 |
|
|
size argument return value
|
5576 |
|
|
|
5577 |
|
|
small integer <8 int. reg. int. reg.
|
5578 |
|
|
word 8 int. reg. int. reg.
|
5579 |
|
|
double word 16 int. reg. int. reg.
|
5580 |
|
|
|
5581 |
|
|
_Complex small integer <16 int. reg. int. reg.
|
5582 |
|
|
_Complex word 16 int. reg. int. reg.
|
5583 |
|
|
_Complex double word 32 memory int. reg.
|
5584 |
|
|
|
5585 |
|
|
vector integer <=16 FP reg. FP reg.
|
5586 |
|
|
vector integer 16<s<=32 memory FP reg.
|
5587 |
|
|
vector integer >32 memory memory
|
5588 |
|
|
|
5589 |
|
|
float 4 FP reg. FP reg.
|
5590 |
|
|
double 8 FP reg. FP reg.
|
5591 |
|
|
long double 16 FP reg. FP reg.
|
5592 |
|
|
|
5593 |
|
|
_Complex float 8 FP reg. FP reg.
|
5594 |
|
|
_Complex double 16 FP reg. FP reg.
|
5595 |
|
|
_Complex long double 32 memory FP reg.
|
5596 |
|
|
|
5597 |
|
|
vector float <=16 FP reg. FP reg.
|
5598 |
|
|
vector float 16<s<=32 memory FP reg.
|
5599 |
|
|
vector float >32 memory memory
|
5600 |
|
|
|
5601 |
|
|
aggregate <=16 reg. reg.
|
5602 |
|
|
aggregate 16<s<=32 memory reg.
|
5603 |
|
|
aggregate >32 memory memory
|
5604 |
|
|
|
5605 |
|
|
|
5606 |
|
|
|
5607 |
|
|
Note #1: complex floating-point types follow the extended SPARC ABIs as
|
5608 |
|
|
implemented by the Sun compiler.
|
5609 |
|
|
|
5610 |
|
|
Note #2: integral vector types follow the scalar floating-point types
|
5611 |
|
|
conventions to match what is implemented by the Sun VIS SDK.
|
5612 |
|
|
|
5613 |
|
|
Note #3: floating-point vector types follow the aggregate types
|
5614 |
|
|
conventions. */
|
5615 |
|
|
|
5616 |
|
|
|
5617 |
|
|
/* Maximum number of int regs for args. */
|
5618 |
|
|
#define SPARC_INT_ARG_MAX 6
|
5619 |
|
|
/* Maximum number of fp regs for args. */
|
5620 |
|
|
#define SPARC_FP_ARG_MAX 16
|
5621 |
|
|
|
5622 |
|
|
#define ROUND_ADVANCE(SIZE) (((SIZE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
5623 |
|
|
|
5624 |
|
|
/* Handle the INIT_CUMULATIVE_ARGS macro.
|
5625 |
|
|
Initialize a variable CUM of type CUMULATIVE_ARGS
|
5626 |
|
|
for a call to a function whose data type is FNTYPE.
|
5627 |
|
|
For a library call, FNTYPE is 0. */
|
5628 |
|
|
|
5629 |
|
|
void
|
5630 |
|
|
init_cumulative_args (struct sparc_args *cum, tree fntype,
|
5631 |
|
|
rtx libname ATTRIBUTE_UNUSED,
|
5632 |
|
|
tree fndecl ATTRIBUTE_UNUSED)
|
5633 |
|
|
{
|
5634 |
|
|
cum->words = 0;
|
5635 |
|
|
cum->prototype_p = fntype && prototype_p (fntype);
|
5636 |
|
|
cum->libcall_p = fntype == 0;
|
5637 |
|
|
}
|
5638 |
|
|
|
5639 |
|
|
/* Handle promotion of pointer and integer arguments. */
|
5640 |
|
|
|
5641 |
|
|
static enum machine_mode
|
5642 |
|
|
sparc_promote_function_mode (const_tree type,
|
5643 |
|
|
enum machine_mode mode,
|
5644 |
|
|
int *punsignedp,
|
5645 |
|
|
const_tree fntype ATTRIBUTE_UNUSED,
|
5646 |
|
|
int for_return ATTRIBUTE_UNUSED)
|
5647 |
|
|
{
|
5648 |
|
|
if (type != NULL_TREE && POINTER_TYPE_P (type))
|
5649 |
|
|
{
|
5650 |
|
|
*punsignedp = POINTERS_EXTEND_UNSIGNED;
|
5651 |
|
|
return Pmode;
|
5652 |
|
|
}
|
5653 |
|
|
|
5654 |
|
|
/* Integral arguments are passed as full words, as per the ABI. */
|
5655 |
|
|
if (GET_MODE_CLASS (mode) == MODE_INT
|
5656 |
|
|
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
|
5657 |
|
|
return word_mode;
|
5658 |
|
|
|
5659 |
|
|
return mode;
|
5660 |
|
|
}
|
5661 |
|
|
|
5662 |
|
|
/* Handle the TARGET_STRICT_ARGUMENT_NAMING target hook. */
|
5663 |
|
|
|
5664 |
|
|
static bool
|
5665 |
|
|
sparc_strict_argument_naming (cumulative_args_t ca ATTRIBUTE_UNUSED)
|
5666 |
|
|
{
|
5667 |
|
|
return TARGET_ARCH64 ? true : false;
|
5668 |
|
|
}
|
5669 |
|
|
|
5670 |
|
|
/* Scan the record type TYPE and return the following predicates:
|
5671 |
|
|
- INTREGS_P: the record contains at least one field or sub-field
|
5672 |
|
|
that is eligible for promotion in integer registers.
|
5673 |
|
|
- FP_REGS_P: the record contains at least one field or sub-field
|
5674 |
|
|
that is eligible for promotion in floating-point registers.
|
5675 |
|
|
- PACKED_P: the record contains at least one field that is packed.
|
5676 |
|
|
|
5677 |
|
|
Sub-fields are not taken into account for the PACKED_P predicate. */
|
5678 |
|
|
|
5679 |
|
|
static void
|
5680 |
|
|
scan_record_type (const_tree type, int *intregs_p, int *fpregs_p,
|
5681 |
|
|
int *packed_p)
|
5682 |
|
|
{
|
5683 |
|
|
tree field;
|
5684 |
|
|
|
5685 |
|
|
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
5686 |
|
|
{
|
5687 |
|
|
if (TREE_CODE (field) == FIELD_DECL)
|
5688 |
|
|
{
|
5689 |
|
|
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
|
5690 |
|
|
scan_record_type (TREE_TYPE (field), intregs_p, fpregs_p, 0);
|
5691 |
|
|
else if ((FLOAT_TYPE_P (TREE_TYPE (field))
|
5692 |
|
|
|| TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
|
5693 |
|
|
&& TARGET_FPU)
|
5694 |
|
|
*fpregs_p = 1;
|
5695 |
|
|
else
|
5696 |
|
|
*intregs_p = 1;
|
5697 |
|
|
|
5698 |
|
|
if (packed_p && DECL_PACKED (field))
|
5699 |
|
|
*packed_p = 1;
|
5700 |
|
|
}
|
5701 |
|
|
}
|
5702 |
|
|
}
|
5703 |
|
|
|
5704 |
|
|
/* Compute the slot number to pass an argument in.
|
5705 |
|
|
Return the slot number or -1 if passing on the stack.
|
5706 |
|
|
|
5707 |
|
|
CUM is a variable of type CUMULATIVE_ARGS which gives info about
|
5708 |
|
|
the preceding args and about the function being called.
|
5709 |
|
|
MODE is the argument's machine mode.
|
5710 |
|
|
TYPE is the data type of the argument (as a tree).
|
5711 |
|
|
This is null for libcalls where that information may
|
5712 |
|
|
not be available.
|
5713 |
|
|
NAMED is nonzero if this argument is a named parameter
|
5714 |
|
|
(otherwise it is an extra parameter matching an ellipsis).
|
5715 |
|
|
INCOMING_P is zero for FUNCTION_ARG, nonzero for FUNCTION_INCOMING_ARG.
|
5716 |
|
|
*PREGNO records the register number to use if scalar type.
|
5717 |
|
|
*PPADDING records the amount of padding needed in words. */
|
5718 |
|
|
|
5719 |
|
|
static int
|
5720 |
|
|
function_arg_slotno (const struct sparc_args *cum, enum machine_mode mode,
|
5721 |
|
|
const_tree type, bool named, bool incoming_p,
|
5722 |
|
|
int *pregno, int *ppadding)
|
5723 |
|
|
{
|
5724 |
|
|
int regbase = (incoming_p
|
5725 |
|
|
? SPARC_INCOMING_INT_ARG_FIRST
|
5726 |
|
|
: SPARC_OUTGOING_INT_ARG_FIRST);
|
5727 |
|
|
int slotno = cum->words;
|
5728 |
|
|
enum mode_class mclass;
|
5729 |
|
|
int regno;
|
5730 |
|
|
|
5731 |
|
|
*ppadding = 0;
|
5732 |
|
|
|
5733 |
|
|
if (type && TREE_ADDRESSABLE (type))
|
5734 |
|
|
return -1;
|
5735 |
|
|
|
5736 |
|
|
if (TARGET_ARCH32
|
5737 |
|
|
&& mode == BLKmode
|
5738 |
|
|
&& type
|
5739 |
|
|
&& TYPE_ALIGN (type) % PARM_BOUNDARY != 0)
|
5740 |
|
|
return -1;
|
5741 |
|
|
|
5742 |
|
|
/* For SPARC64, objects requiring 16-byte alignment get it. */
|
5743 |
|
|
if (TARGET_ARCH64
|
5744 |
|
|
&& (type ? TYPE_ALIGN (type) : GET_MODE_ALIGNMENT (mode)) >= 128
|
5745 |
|
|
&& (slotno & 1) != 0)
|
5746 |
|
|
slotno++, *ppadding = 1;
|
5747 |
|
|
|
5748 |
|
|
mclass = GET_MODE_CLASS (mode);
|
5749 |
|
|
if (type && TREE_CODE (type) == VECTOR_TYPE)
|
5750 |
|
|
{
|
5751 |
|
|
/* Vector types deserve special treatment because they are
|
5752 |
|
|
polymorphic wrt their mode, depending upon whether VIS
|
5753 |
|
|
instructions are enabled. */
|
5754 |
|
|
if (TREE_CODE (TREE_TYPE (type)) == REAL_TYPE)
|
5755 |
|
|
{
|
5756 |
|
|
/* The SPARC port defines no floating-point vector modes. */
|
5757 |
|
|
gcc_assert (mode == BLKmode);
|
5758 |
|
|
}
|
5759 |
|
|
else
|
5760 |
|
|
{
|
5761 |
|
|
/* Integral vector types should either have a vector
|
5762 |
|
|
mode or an integral mode, because we are guaranteed
|
5763 |
|
|
by pass_by_reference that their size is not greater
|
5764 |
|
|
than 16 bytes and TImode is 16-byte wide. */
|
5765 |
|
|
gcc_assert (mode != BLKmode);
|
5766 |
|
|
|
5767 |
|
|
/* Vector integers are handled like floats according to
|
5768 |
|
|
the Sun VIS SDK. */
|
5769 |
|
|
mclass = MODE_FLOAT;
|
5770 |
|
|
}
|
5771 |
|
|
}
|
5772 |
|
|
|
5773 |
|
|
switch (mclass)
|
5774 |
|
|
{
|
5775 |
|
|
case MODE_FLOAT:
|
5776 |
|
|
case MODE_COMPLEX_FLOAT:
|
5777 |
|
|
case MODE_VECTOR_INT:
|
5778 |
|
|
if (TARGET_ARCH64 && TARGET_FPU && named)
|
5779 |
|
|
{
|
5780 |
|
|
if (slotno >= SPARC_FP_ARG_MAX)
|
5781 |
|
|
return -1;
|
5782 |
|
|
regno = SPARC_FP_ARG_FIRST + slotno * 2;
|
5783 |
|
|
/* Arguments filling only one single FP register are
|
5784 |
|
|
right-justified in the outer double FP register. */
|
5785 |
|
|
if (GET_MODE_SIZE (mode) <= 4)
|
5786 |
|
|
regno++;
|
5787 |
|
|
break;
|
5788 |
|
|
}
|
5789 |
|
|
/* fallthrough */
|
5790 |
|
|
|
5791 |
|
|
case MODE_INT:
|
5792 |
|
|
case MODE_COMPLEX_INT:
|
5793 |
|
|
if (slotno >= SPARC_INT_ARG_MAX)
|
5794 |
|
|
return -1;
|
5795 |
|
|
regno = regbase + slotno;
|
5796 |
|
|
break;
|
5797 |
|
|
|
5798 |
|
|
case MODE_RANDOM:
|
5799 |
|
|
if (mode == VOIDmode)
|
5800 |
|
|
/* MODE is VOIDmode when generating the actual call. */
|
5801 |
|
|
return -1;
|
5802 |
|
|
|
5803 |
|
|
gcc_assert (mode == BLKmode);
|
5804 |
|
|
|
5805 |
|
|
if (TARGET_ARCH32
|
5806 |
|
|
|| !type
|
5807 |
|
|
|| (TREE_CODE (type) != VECTOR_TYPE
|
5808 |
|
|
&& TREE_CODE (type) != RECORD_TYPE))
|
5809 |
|
|
{
|
5810 |
|
|
if (slotno >= SPARC_INT_ARG_MAX)
|
5811 |
|
|
return -1;
|
5812 |
|
|
regno = regbase + slotno;
|
5813 |
|
|
}
|
5814 |
|
|
else /* TARGET_ARCH64 && type */
|
5815 |
|
|
{
|
5816 |
|
|
int intregs_p = 0, fpregs_p = 0, packed_p = 0;
|
5817 |
|
|
|
5818 |
|
|
/* First see what kinds of registers we would need. */
|
5819 |
|
|
if (TREE_CODE (type) == VECTOR_TYPE)
|
5820 |
|
|
fpregs_p = 1;
|
5821 |
|
|
else
|
5822 |
|
|
scan_record_type (type, &intregs_p, &fpregs_p, &packed_p);
|
5823 |
|
|
|
5824 |
|
|
/* The ABI obviously doesn't specify how packed structures
|
5825 |
|
|
are passed. These are defined to be passed in int regs
|
5826 |
|
|
if possible, otherwise memory. */
|
5827 |
|
|
if (packed_p || !named)
|
5828 |
|
|
fpregs_p = 0, intregs_p = 1;
|
5829 |
|
|
|
5830 |
|
|
/* If all arg slots are filled, then must pass on stack. */
|
5831 |
|
|
if (fpregs_p && slotno >= SPARC_FP_ARG_MAX)
|
5832 |
|
|
return -1;
|
5833 |
|
|
|
5834 |
|
|
/* If there are only int args and all int arg slots are filled,
|
5835 |
|
|
then must pass on stack. */
|
5836 |
|
|
if (!fpregs_p && intregs_p && slotno >= SPARC_INT_ARG_MAX)
|
5837 |
|
|
return -1;
|
5838 |
|
|
|
5839 |
|
|
/* Note that even if all int arg slots are filled, fp members may
|
5840 |
|
|
still be passed in regs if such regs are available.
|
5841 |
|
|
*PREGNO isn't set because there may be more than one, it's up
|
5842 |
|
|
to the caller to compute them. */
|
5843 |
|
|
return slotno;
|
5844 |
|
|
}
|
5845 |
|
|
break;
|
5846 |
|
|
|
5847 |
|
|
default :
|
5848 |
|
|
gcc_unreachable ();
|
5849 |
|
|
}
|
5850 |
|
|
|
5851 |
|
|
*pregno = regno;
|
5852 |
|
|
return slotno;
|
5853 |
|
|
}
|
5854 |
|
|
|
5855 |
|
|
/* Handle recursive register counting for structure field layout. */
|
5856 |
|
|
|
5857 |
|
|
struct function_arg_record_value_parms
|
5858 |
|
|
{
|
5859 |
|
|
rtx ret; /* return expression being built. */
|
5860 |
|
|
int slotno; /* slot number of the argument. */
|
5861 |
|
|
int named; /* whether the argument is named. */
|
5862 |
|
|
int regbase; /* regno of the base register. */
|
5863 |
|
|
int stack; /* 1 if part of the argument is on the stack. */
|
5864 |
|
|
int intoffset; /* offset of the first pending integer field. */
|
5865 |
|
|
unsigned int nregs; /* number of words passed in registers. */
|
5866 |
|
|
};
|
5867 |
|
|
|
5868 |
|
|
static void function_arg_record_value_3
|
5869 |
|
|
(HOST_WIDE_INT, struct function_arg_record_value_parms *);
|
5870 |
|
|
static void function_arg_record_value_2
|
5871 |
|
|
(const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
|
5872 |
|
|
static void function_arg_record_value_1
|
5873 |
|
|
(const_tree, HOST_WIDE_INT, struct function_arg_record_value_parms *, bool);
|
5874 |
|
|
static rtx function_arg_record_value (const_tree, enum machine_mode, int, int, int);
|
5875 |
|
|
static rtx function_arg_union_value (int, enum machine_mode, int, int);
|
5876 |
|
|
|
5877 |
|
|
/* A subroutine of function_arg_record_value. Traverse the structure
|
5878 |
|
|
recursively and determine how many registers will be required. */
|
5879 |
|
|
|
5880 |
|
|
static void
|
5881 |
|
|
function_arg_record_value_1 (const_tree type, HOST_WIDE_INT startbitpos,
|
5882 |
|
|
struct function_arg_record_value_parms *parms,
|
5883 |
|
|
bool packed_p)
|
5884 |
|
|
{
|
5885 |
|
|
tree field;
|
5886 |
|
|
|
5887 |
|
|
/* We need to compute how many registers are needed so we can
|
5888 |
|
|
allocate the PARALLEL but before we can do that we need to know
|
5889 |
|
|
whether there are any packed fields. The ABI obviously doesn't
|
5890 |
|
|
specify how structures are passed in this case, so they are
|
5891 |
|
|
defined to be passed in int regs if possible, otherwise memory,
|
5892 |
|
|
regardless of whether there are fp values present. */
|
5893 |
|
|
|
5894 |
|
|
if (! packed_p)
|
5895 |
|
|
for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
|
5896 |
|
|
{
|
5897 |
|
|
if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
|
5898 |
|
|
{
|
5899 |
|
|
packed_p = true;
|
5900 |
|
|
break;
|
5901 |
|
|
}
|
5902 |
|
|
}
|
5903 |
|
|
|
5904 |
|
|
/* Compute how many registers we need. */
|
5905 |
|
|
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
5906 |
|
|
{
|
5907 |
|
|
if (TREE_CODE (field) == FIELD_DECL)
|
5908 |
|
|
{
|
5909 |
|
|
HOST_WIDE_INT bitpos = startbitpos;
|
5910 |
|
|
|
5911 |
|
|
if (DECL_SIZE (field) != 0)
|
5912 |
|
|
{
|
5913 |
|
|
if (integer_zerop (DECL_SIZE (field)))
|
5914 |
|
|
continue;
|
5915 |
|
|
|
5916 |
|
|
if (host_integerp (bit_position (field), 1))
|
5917 |
|
|
bitpos += int_bit_position (field);
|
5918 |
|
|
}
|
5919 |
|
|
|
5920 |
|
|
/* ??? FIXME: else assume zero offset. */
|
5921 |
|
|
|
5922 |
|
|
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
|
5923 |
|
|
function_arg_record_value_1 (TREE_TYPE (field),
|
5924 |
|
|
bitpos,
|
5925 |
|
|
parms,
|
5926 |
|
|
packed_p);
|
5927 |
|
|
else if ((FLOAT_TYPE_P (TREE_TYPE (field))
|
5928 |
|
|
|| TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
|
5929 |
|
|
&& TARGET_FPU
|
5930 |
|
|
&& parms->named
|
5931 |
|
|
&& ! packed_p)
|
5932 |
|
|
{
|
5933 |
|
|
if (parms->intoffset != -1)
|
5934 |
|
|
{
|
5935 |
|
|
unsigned int startbit, endbit;
|
5936 |
|
|
int intslots, this_slotno;
|
5937 |
|
|
|
5938 |
|
|
startbit = parms->intoffset & -BITS_PER_WORD;
|
5939 |
|
|
endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
|
5940 |
|
|
|
5941 |
|
|
intslots = (endbit - startbit) / BITS_PER_WORD;
|
5942 |
|
|
this_slotno = parms->slotno + parms->intoffset
|
5943 |
|
|
/ BITS_PER_WORD;
|
5944 |
|
|
|
5945 |
|
|
if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
|
5946 |
|
|
{
|
5947 |
|
|
intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
|
5948 |
|
|
/* We need to pass this field on the stack. */
|
5949 |
|
|
parms->stack = 1;
|
5950 |
|
|
}
|
5951 |
|
|
|
5952 |
|
|
parms->nregs += intslots;
|
5953 |
|
|
parms->intoffset = -1;
|
5954 |
|
|
}
|
5955 |
|
|
|
5956 |
|
|
/* There's no need to check this_slotno < SPARC_FP_ARG MAX.
|
5957 |
|
|
If it wasn't true we wouldn't be here. */
|
5958 |
|
|
if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
|
5959 |
|
|
&& DECL_MODE (field) == BLKmode)
|
5960 |
|
|
parms->nregs += TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
|
5961 |
|
|
else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
|
5962 |
|
|
parms->nregs += 2;
|
5963 |
|
|
else
|
5964 |
|
|
parms->nregs += 1;
|
5965 |
|
|
}
|
5966 |
|
|
else
|
5967 |
|
|
{
|
5968 |
|
|
if (parms->intoffset == -1)
|
5969 |
|
|
parms->intoffset = bitpos;
|
5970 |
|
|
}
|
5971 |
|
|
}
|
5972 |
|
|
}
|
5973 |
|
|
}
|
5974 |
|
|
|
5975 |
|
|
/* A subroutine of function_arg_record_value. Assign the bits of the
|
5976 |
|
|
structure between parms->intoffset and bitpos to integer registers. */
|
5977 |
|
|
|
5978 |
|
|
static void
|
5979 |
|
|
function_arg_record_value_3 (HOST_WIDE_INT bitpos,
|
5980 |
|
|
struct function_arg_record_value_parms *parms)
|
5981 |
|
|
{
|
5982 |
|
|
enum machine_mode mode;
|
5983 |
|
|
unsigned int regno;
|
5984 |
|
|
unsigned int startbit, endbit;
|
5985 |
|
|
int this_slotno, intslots, intoffset;
|
5986 |
|
|
rtx reg;
|
5987 |
|
|
|
5988 |
|
|
if (parms->intoffset == -1)
|
5989 |
|
|
return;
|
5990 |
|
|
|
5991 |
|
|
intoffset = parms->intoffset;
|
5992 |
|
|
parms->intoffset = -1;
|
5993 |
|
|
|
5994 |
|
|
startbit = intoffset & -BITS_PER_WORD;
|
5995 |
|
|
endbit = (bitpos + BITS_PER_WORD - 1) & -BITS_PER_WORD;
|
5996 |
|
|
intslots = (endbit - startbit) / BITS_PER_WORD;
|
5997 |
|
|
this_slotno = parms->slotno + intoffset / BITS_PER_WORD;
|
5998 |
|
|
|
5999 |
|
|
intslots = MIN (intslots, SPARC_INT_ARG_MAX - this_slotno);
|
6000 |
|
|
if (intslots <= 0)
|
6001 |
|
|
return;
|
6002 |
|
|
|
6003 |
|
|
/* If this is the trailing part of a word, only load that much into
|
6004 |
|
|
the register. Otherwise load the whole register. Note that in
|
6005 |
|
|
the latter case we may pick up unwanted bits. It's not a problem
|
6006 |
|
|
at the moment but may wish to revisit. */
|
6007 |
|
|
|
6008 |
|
|
if (intoffset % BITS_PER_WORD != 0)
|
6009 |
|
|
mode = smallest_mode_for_size (BITS_PER_WORD - intoffset % BITS_PER_WORD,
|
6010 |
|
|
MODE_INT);
|
6011 |
|
|
else
|
6012 |
|
|
mode = word_mode;
|
6013 |
|
|
|
6014 |
|
|
intoffset /= BITS_PER_UNIT;
|
6015 |
|
|
do
|
6016 |
|
|
{
|
6017 |
|
|
regno = parms->regbase + this_slotno;
|
6018 |
|
|
reg = gen_rtx_REG (mode, regno);
|
6019 |
|
|
XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
|
6020 |
|
|
= gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (intoffset));
|
6021 |
|
|
|
6022 |
|
|
this_slotno += 1;
|
6023 |
|
|
intoffset = (intoffset | (UNITS_PER_WORD-1)) + 1;
|
6024 |
|
|
mode = word_mode;
|
6025 |
|
|
parms->nregs += 1;
|
6026 |
|
|
intslots -= 1;
|
6027 |
|
|
}
|
6028 |
|
|
while (intslots > 0);
|
6029 |
|
|
}
|
6030 |
|
|
|
6031 |
|
|
/* A subroutine of function_arg_record_value. Traverse the structure
|
6032 |
|
|
recursively and assign bits to floating point registers. Track which
|
6033 |
|
|
bits in between need integer registers; invoke function_arg_record_value_3
|
6034 |
|
|
to make that happen. */
|
6035 |
|
|
|
6036 |
|
|
static void
|
6037 |
|
|
function_arg_record_value_2 (const_tree type, HOST_WIDE_INT startbitpos,
|
6038 |
|
|
struct function_arg_record_value_parms *parms,
|
6039 |
|
|
bool packed_p)
|
6040 |
|
|
{
|
6041 |
|
|
tree field;
|
6042 |
|
|
|
6043 |
|
|
if (! packed_p)
|
6044 |
|
|
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
6045 |
|
|
{
|
6046 |
|
|
if (TREE_CODE (field) == FIELD_DECL && DECL_PACKED (field))
|
6047 |
|
|
{
|
6048 |
|
|
packed_p = true;
|
6049 |
|
|
break;
|
6050 |
|
|
}
|
6051 |
|
|
}
|
6052 |
|
|
|
6053 |
|
|
for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
|
6054 |
|
|
{
|
6055 |
|
|
if (TREE_CODE (field) == FIELD_DECL)
|
6056 |
|
|
{
|
6057 |
|
|
HOST_WIDE_INT bitpos = startbitpos;
|
6058 |
|
|
|
6059 |
|
|
if (DECL_SIZE (field) != 0)
|
6060 |
|
|
{
|
6061 |
|
|
if (integer_zerop (DECL_SIZE (field)))
|
6062 |
|
|
continue;
|
6063 |
|
|
|
6064 |
|
|
if (host_integerp (bit_position (field), 1))
|
6065 |
|
|
bitpos += int_bit_position (field);
|
6066 |
|
|
}
|
6067 |
|
|
|
6068 |
|
|
/* ??? FIXME: else assume zero offset. */
|
6069 |
|
|
|
6070 |
|
|
if (TREE_CODE (TREE_TYPE (field)) == RECORD_TYPE)
|
6071 |
|
|
function_arg_record_value_2 (TREE_TYPE (field),
|
6072 |
|
|
bitpos,
|
6073 |
|
|
parms,
|
6074 |
|
|
packed_p);
|
6075 |
|
|
else if ((FLOAT_TYPE_P (TREE_TYPE (field))
|
6076 |
|
|
|| TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE)
|
6077 |
|
|
&& TARGET_FPU
|
6078 |
|
|
&& parms->named
|
6079 |
|
|
&& ! packed_p)
|
6080 |
|
|
{
|
6081 |
|
|
int this_slotno = parms->slotno + bitpos / BITS_PER_WORD;
|
6082 |
|
|
int regno, nregs, pos;
|
6083 |
|
|
enum machine_mode mode = DECL_MODE (field);
|
6084 |
|
|
rtx reg;
|
6085 |
|
|
|
6086 |
|
|
function_arg_record_value_3 (bitpos, parms);
|
6087 |
|
|
|
6088 |
|
|
if (TREE_CODE (TREE_TYPE (field)) == VECTOR_TYPE
|
6089 |
|
|
&& mode == BLKmode)
|
6090 |
|
|
{
|
6091 |
|
|
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
|
6092 |
|
|
nregs = TYPE_VECTOR_SUBPARTS (TREE_TYPE (field));
|
6093 |
|
|
}
|
6094 |
|
|
else if (TREE_CODE (TREE_TYPE (field)) == COMPLEX_TYPE)
|
6095 |
|
|
{
|
6096 |
|
|
mode = TYPE_MODE (TREE_TYPE (TREE_TYPE (field)));
|
6097 |
|
|
nregs = 2;
|
6098 |
|
|
}
|
6099 |
|
|
else
|
6100 |
|
|
nregs = 1;
|
6101 |
|
|
|
6102 |
|
|
regno = SPARC_FP_ARG_FIRST + this_slotno * 2;
|
6103 |
|
|
if (GET_MODE_SIZE (mode) <= 4 && (bitpos & 32) != 0)
|
6104 |
|
|
regno++;
|
6105 |
|
|
reg = gen_rtx_REG (mode, regno);
|
6106 |
|
|
pos = bitpos / BITS_PER_UNIT;
|
6107 |
|
|
XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
|
6108 |
|
|
= gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
|
6109 |
|
|
parms->nregs += 1;
|
6110 |
|
|
while (--nregs > 0)
|
6111 |
|
|
{
|
6112 |
|
|
regno += GET_MODE_SIZE (mode) / 4;
|
6113 |
|
|
reg = gen_rtx_REG (mode, regno);
|
6114 |
|
|
pos += GET_MODE_SIZE (mode);
|
6115 |
|
|
XVECEXP (parms->ret, 0, parms->stack + parms->nregs)
|
6116 |
|
|
= gen_rtx_EXPR_LIST (VOIDmode, reg, GEN_INT (pos));
|
6117 |
|
|
parms->nregs += 1;
|
6118 |
|
|
}
|
6119 |
|
|
}
|
6120 |
|
|
else
|
6121 |
|
|
{
|
6122 |
|
|
if (parms->intoffset == -1)
|
6123 |
|
|
parms->intoffset = bitpos;
|
6124 |
|
|
}
|
6125 |
|
|
}
|
6126 |
|
|
}
|
6127 |
|
|
}
|
6128 |
|
|
|
6129 |
|
|
/* Used by function_arg and sparc_function_value_1 to implement the complex
|
6130 |
|
|
conventions of the 64-bit ABI for passing and returning structures.
|
6131 |
|
|
Return an expression valid as a return value for the FUNCTION_ARG
|
6132 |
|
|
and TARGET_FUNCTION_VALUE.
|
6133 |
|
|
|
6134 |
|
|
TYPE is the data type of the argument (as a tree).
|
6135 |
|
|
This is null for libcalls where that information may
|
6136 |
|
|
not be available.
|
6137 |
|
|
MODE is the argument's machine mode.
|
6138 |
|
|
SLOTNO is the index number of the argument's slot in the parameter array.
|
6139 |
|
|
NAMED is nonzero if this argument is a named parameter
|
6140 |
|
|
(otherwise it is an extra parameter matching an ellipsis).
|
6141 |
|
|
REGBASE is the regno of the base register for the parameter array. */
|
6142 |
|
|
|
6143 |
|
|
static rtx
|
6144 |
|
|
function_arg_record_value (const_tree type, enum machine_mode mode,
|
6145 |
|
|
int slotno, int named, int regbase)
|
6146 |
|
|
{
|
6147 |
|
|
HOST_WIDE_INT typesize = int_size_in_bytes (type);
|
6148 |
|
|
struct function_arg_record_value_parms parms;
|
6149 |
|
|
unsigned int nregs;
|
6150 |
|
|
|
6151 |
|
|
parms.ret = NULL_RTX;
|
6152 |
|
|
parms.slotno = slotno;
|
6153 |
|
|
parms.named = named;
|
6154 |
|
|
parms.regbase = regbase;
|
6155 |
|
|
parms.stack = 0;
|
6156 |
|
|
|
6157 |
|
|
/* Compute how many registers we need. */
|
6158 |
|
|
parms.nregs = 0;
|
6159 |
|
|
parms.intoffset = 0;
|
6160 |
|
|
function_arg_record_value_1 (type, 0, &parms, false);
|
6161 |
|
|
|
6162 |
|
|
/* Take into account pending integer fields. */
|
6163 |
|
|
if (parms.intoffset != -1)
|
6164 |
|
|
{
|
6165 |
|
|
unsigned int startbit, endbit;
|
6166 |
|
|
int intslots, this_slotno;
|
6167 |
|
|
|
6168 |
|
|
startbit = parms.intoffset & -BITS_PER_WORD;
|
6169 |
|
|
endbit = (typesize*BITS_PER_UNIT + BITS_PER_WORD - 1) & -BITS_PER_WORD;
|
6170 |
|
|
intslots = (endbit - startbit) / BITS_PER_WORD;
|
6171 |
|
|
this_slotno = slotno + parms.intoffset / BITS_PER_WORD;
|
6172 |
|
|
|
6173 |
|
|
if (intslots > 0 && intslots > SPARC_INT_ARG_MAX - this_slotno)
|
6174 |
|
|
{
|
6175 |
|
|
intslots = MAX (0, SPARC_INT_ARG_MAX - this_slotno);
|
6176 |
|
|
/* We need to pass this field on the stack. */
|
6177 |
|
|
parms.stack = 1;
|
6178 |
|
|
}
|
6179 |
|
|
|
6180 |
|
|
parms.nregs += intslots;
|
6181 |
|
|
}
|
6182 |
|
|
nregs = parms.nregs;
|
6183 |
|
|
|
6184 |
|
|
/* Allocate the vector and handle some annoying special cases. */
|
6185 |
|
|
if (nregs == 0)
|
6186 |
|
|
{
|
6187 |
|
|
/* ??? Empty structure has no value? Duh? */
|
6188 |
|
|
if (typesize <= 0)
|
6189 |
|
|
{
|
6190 |
|
|
/* Though there's nothing really to store, return a word register
|
6191 |
|
|
anyway so the rest of gcc doesn't go nuts. Returning a PARALLEL
|
6192 |
|
|
leads to breakage due to the fact that there are zero bytes to
|
6193 |
|
|
load. */
|
6194 |
|
|
return gen_rtx_REG (mode, regbase);
|
6195 |
|
|
}
|
6196 |
|
|
else
|
6197 |
|
|
{
|
6198 |
|
|
/* ??? C++ has structures with no fields, and yet a size. Give up
|
6199 |
|
|
for now and pass everything back in integer registers. */
|
6200 |
|
|
nregs = (typesize + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
|
6201 |
|
|
}
|
6202 |
|
|
if (nregs + slotno > SPARC_INT_ARG_MAX)
|
6203 |
|
|
nregs = SPARC_INT_ARG_MAX - slotno;
|
6204 |
|
|
}
|
6205 |
|
|
gcc_assert (nregs != 0);
|
6206 |
|
|
|
6207 |
|
|
parms.ret = gen_rtx_PARALLEL (mode, rtvec_alloc (parms.stack + nregs));
|
6208 |
|
|
|
6209 |
|
|
/* If at least one field must be passed on the stack, generate
|
6210 |
|
|
(parallel [(expr_list (nil) ...) ...]) so that all fields will
|
6211 |
|
|
also be passed on the stack. We can't do much better because the
|
6212 |
|
|
semantics of TARGET_ARG_PARTIAL_BYTES doesn't handle the case
|
6213 |
|
|
of structures for which the fields passed exclusively in registers
|
6214 |
|
|
are not at the beginning of the structure. */
|
6215 |
|
|
if (parms.stack)
|
6216 |
|
|
XVECEXP (parms.ret, 0, 0)
|
6217 |
|
|
= gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
|
6218 |
|
|
|
6219 |
|
|
/* Fill in the entries. */
|
6220 |
|
|
parms.nregs = 0;
|
6221 |
|
|
parms.intoffset = 0;
|
6222 |
|
|
function_arg_record_value_2 (type, 0, &parms, false);
|
6223 |
|
|
function_arg_record_value_3 (typesize * BITS_PER_UNIT, &parms);
|
6224 |
|
|
|
6225 |
|
|
gcc_assert (parms.nregs == nregs);
|
6226 |
|
|
|
6227 |
|
|
return parms.ret;
|
6228 |
|
|
}
|
6229 |
|
|
|
6230 |
|
|
/* Used by function_arg and sparc_function_value_1 to implement the conventions
|
6231 |
|
|
of the 64-bit ABI for passing and returning unions.
|
6232 |
|
|
Return an expression valid as a return value for the FUNCTION_ARG
|
6233 |
|
|
and TARGET_FUNCTION_VALUE.
|
6234 |
|
|
|
6235 |
|
|
SIZE is the size in bytes of the union.
|
6236 |
|
|
MODE is the argument's machine mode.
|
6237 |
|
|
REGNO is the hard register the union will be passed in. */
|
6238 |
|
|
|
6239 |
|
|
static rtx
|
6240 |
|
|
function_arg_union_value (int size, enum machine_mode mode, int slotno,
|
6241 |
|
|
int regno)
|
6242 |
|
|
{
|
6243 |
|
|
int nwords = ROUND_ADVANCE (size), i;
|
6244 |
|
|
rtx regs;
|
6245 |
|
|
|
6246 |
|
|
/* See comment in previous function for empty structures. */
|
6247 |
|
|
if (nwords == 0)
|
6248 |
|
|
return gen_rtx_REG (mode, regno);
|
6249 |
|
|
|
6250 |
|
|
if (slotno == SPARC_INT_ARG_MAX - 1)
|
6251 |
|
|
nwords = 1;
|
6252 |
|
|
|
6253 |
|
|
regs = gen_rtx_PARALLEL (mode, rtvec_alloc (nwords));
|
6254 |
|
|
|
6255 |
|
|
for (i = 0; i < nwords; i++)
|
6256 |
|
|
{
|
6257 |
|
|
/* Unions are passed left-justified. */
|
6258 |
|
|
XVECEXP (regs, 0, i)
|
6259 |
|
|
= gen_rtx_EXPR_LIST (VOIDmode,
|
6260 |
|
|
gen_rtx_REG (word_mode, regno),
|
6261 |
|
|
GEN_INT (UNITS_PER_WORD * i));
|
6262 |
|
|
regno++;
|
6263 |
|
|
}
|
6264 |
|
|
|
6265 |
|
|
return regs;
|
6266 |
|
|
}
|
6267 |
|
|
|
6268 |
|
|
/* Used by function_arg and sparc_function_value_1 to implement the conventions
|
6269 |
|
|
for passing and returning large (BLKmode) vectors.
|
6270 |
|
|
Return an expression valid as a return value for the FUNCTION_ARG
|
6271 |
|
|
and TARGET_FUNCTION_VALUE.
|
6272 |
|
|
|
6273 |
|
|
SIZE is the size in bytes of the vector (at least 8 bytes).
|
6274 |
|
|
REGNO is the FP hard register the vector will be passed in. */
|
6275 |
|
|
|
6276 |
|
|
static rtx
|
6277 |
|
|
function_arg_vector_value (int size, int regno)
|
6278 |
|
|
{
|
6279 |
|
|
int i, nregs = size / 8;
|
6280 |
|
|
rtx regs;
|
6281 |
|
|
|
6282 |
|
|
regs = gen_rtx_PARALLEL (BLKmode, rtvec_alloc (nregs));
|
6283 |
|
|
|
6284 |
|
|
for (i = 0; i < nregs; i++)
|
6285 |
|
|
{
|
6286 |
|
|
XVECEXP (regs, 0, i)
|
6287 |
|
|
= gen_rtx_EXPR_LIST (VOIDmode,
|
6288 |
|
|
gen_rtx_REG (DImode, regno + 2*i),
|
6289 |
|
|
GEN_INT (i*8));
|
6290 |
|
|
}
|
6291 |
|
|
|
6292 |
|
|
return regs;
|
6293 |
|
|
}
|
6294 |
|
|
|
6295 |
|
|
/* Determine where to put an argument to a function.
|
6296 |
|
|
Value is zero to push the argument on the stack,
|
6297 |
|
|
or a hard register in which to store the argument.
|
6298 |
|
|
|
6299 |
|
|
CUM is a variable of type CUMULATIVE_ARGS which gives info about
|
6300 |
|
|
the preceding args and about the function being called.
|
6301 |
|
|
MODE is the argument's machine mode.
|
6302 |
|
|
TYPE is the data type of the argument (as a tree).
|
6303 |
|
|
This is null for libcalls where that information may
|
6304 |
|
|
not be available.
|
6305 |
|
|
NAMED is true if this argument is a named parameter
|
6306 |
|
|
(otherwise it is an extra parameter matching an ellipsis).
|
6307 |
|
|
INCOMING_P is false for TARGET_FUNCTION_ARG, true for
|
6308 |
|
|
TARGET_FUNCTION_INCOMING_ARG. */
|
6309 |
|
|
|
6310 |
|
|
static rtx
|
6311 |
|
|
sparc_function_arg_1 (cumulative_args_t cum_v, enum machine_mode mode,
|
6312 |
|
|
const_tree type, bool named, bool incoming_p)
|
6313 |
|
|
{
|
6314 |
|
|
const CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
|
6315 |
|
|
|
6316 |
|
|
int regbase = (incoming_p
|
6317 |
|
|
? SPARC_INCOMING_INT_ARG_FIRST
|
6318 |
|
|
: SPARC_OUTGOING_INT_ARG_FIRST);
|
6319 |
|
|
int slotno, regno, padding;
|
6320 |
|
|
enum mode_class mclass = GET_MODE_CLASS (mode);
|
6321 |
|
|
|
6322 |
|
|
slotno = function_arg_slotno (cum, mode, type, named, incoming_p,
|
6323 |
|
|
®no, &padding);
|
6324 |
|
|
if (slotno == -1)
|
6325 |
|
|
return 0;
|
6326 |
|
|
|
6327 |
|
|
/* Vector types deserve special treatment because they are polymorphic wrt
|
6328 |
|
|
their mode, depending upon whether VIS instructions are enabled. */
|
6329 |
|
|
if (type && TREE_CODE (type) == VECTOR_TYPE)
|
6330 |
|
|
{
|
6331 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6332 |
|
|
gcc_assert ((TARGET_ARCH32 && size <= 8)
|
6333 |
|
|
|| (TARGET_ARCH64 && size <= 16));
|
6334 |
|
|
|
6335 |
|
|
if (mode == BLKmode)
|
6336 |
|
|
return function_arg_vector_value (size,
|
6337 |
|
|
SPARC_FP_ARG_FIRST + 2*slotno);
|
6338 |
|
|
else
|
6339 |
|
|
mclass = MODE_FLOAT;
|
6340 |
|
|
}
|
6341 |
|
|
|
6342 |
|
|
if (TARGET_ARCH32)
|
6343 |
|
|
return gen_rtx_REG (mode, regno);
|
6344 |
|
|
|
6345 |
|
|
/* Structures up to 16 bytes in size are passed in arg slots on the stack
|
6346 |
|
|
and are promoted to registers if possible. */
|
6347 |
|
|
if (type && TREE_CODE (type) == RECORD_TYPE)
|
6348 |
|
|
{
|
6349 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6350 |
|
|
gcc_assert (size <= 16);
|
6351 |
|
|
|
6352 |
|
|
return function_arg_record_value (type, mode, slotno, named, regbase);
|
6353 |
|
|
}
|
6354 |
|
|
|
6355 |
|
|
/* Unions up to 16 bytes in size are passed in integer registers. */
|
6356 |
|
|
else if (type && TREE_CODE (type) == UNION_TYPE)
|
6357 |
|
|
{
|
6358 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6359 |
|
|
gcc_assert (size <= 16);
|
6360 |
|
|
|
6361 |
|
|
return function_arg_union_value (size, mode, slotno, regno);
|
6362 |
|
|
}
|
6363 |
|
|
|
6364 |
|
|
/* v9 fp args in reg slots beyond the int reg slots get passed in regs
|
6365 |
|
|
but also have the slot allocated for them.
|
6366 |
|
|
If no prototype is in scope fp values in register slots get passed
|
6367 |
|
|
in two places, either fp regs and int regs or fp regs and memory. */
|
6368 |
|
|
else if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
|
6369 |
|
|
&& SPARC_FP_REG_P (regno))
|
6370 |
|
|
{
|
6371 |
|
|
rtx reg = gen_rtx_REG (mode, regno);
|
6372 |
|
|
if (cum->prototype_p || cum->libcall_p)
|
6373 |
|
|
{
|
6374 |
|
|
/* "* 2" because fp reg numbers are recorded in 4 byte
|
6375 |
|
|
quantities. */
|
6376 |
|
|
#if 0
|
6377 |
|
|
/* ??? This will cause the value to be passed in the fp reg and
|
6378 |
|
|
in the stack. When a prototype exists we want to pass the
|
6379 |
|
|
value in the reg but reserve space on the stack. That's an
|
6380 |
|
|
optimization, and is deferred [for a bit]. */
|
6381 |
|
|
if ((regno - SPARC_FP_ARG_FIRST) >= SPARC_INT_ARG_MAX * 2)
|
6382 |
|
|
return gen_rtx_PARALLEL (mode,
|
6383 |
|
|
gen_rtvec (2,
|
6384 |
|
|
gen_rtx_EXPR_LIST (VOIDmode,
|
6385 |
|
|
NULL_RTX, const0_rtx),
|
6386 |
|
|
gen_rtx_EXPR_LIST (VOIDmode,
|
6387 |
|
|
reg, const0_rtx)));
|
6388 |
|
|
else
|
6389 |
|
|
#else
|
6390 |
|
|
/* ??? It seems that passing back a register even when past
|
6391 |
|
|
the area declared by REG_PARM_STACK_SPACE will allocate
|
6392 |
|
|
space appropriately, and will not copy the data onto the
|
6393 |
|
|
stack, exactly as we desire.
|
6394 |
|
|
|
6395 |
|
|
This is due to locate_and_pad_parm being called in
|
6396 |
|
|
expand_call whenever reg_parm_stack_space > 0, which
|
6397 |
|
|
while beneficial to our example here, would seem to be
|
6398 |
|
|
in error from what had been intended. Ho hum... -- r~ */
|
6399 |
|
|
#endif
|
6400 |
|
|
return reg;
|
6401 |
|
|
}
|
6402 |
|
|
else
|
6403 |
|
|
{
|
6404 |
|
|
rtx v0, v1;
|
6405 |
|
|
|
6406 |
|
|
if ((regno - SPARC_FP_ARG_FIRST) < SPARC_INT_ARG_MAX * 2)
|
6407 |
|
|
{
|
6408 |
|
|
int intreg;
|
6409 |
|
|
|
6410 |
|
|
/* On incoming, we don't need to know that the value
|
6411 |
|
|
is passed in %f0 and %i0, and it confuses other parts
|
6412 |
|
|
causing needless spillage even on the simplest cases. */
|
6413 |
|
|
if (incoming_p)
|
6414 |
|
|
return reg;
|
6415 |
|
|
|
6416 |
|
|
intreg = (SPARC_OUTGOING_INT_ARG_FIRST
|
6417 |
|
|
+ (regno - SPARC_FP_ARG_FIRST) / 2);
|
6418 |
|
|
|
6419 |
|
|
v0 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
|
6420 |
|
|
v1 = gen_rtx_EXPR_LIST (VOIDmode, gen_rtx_REG (mode, intreg),
|
6421 |
|
|
const0_rtx);
|
6422 |
|
|
return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1));
|
6423 |
|
|
}
|
6424 |
|
|
else
|
6425 |
|
|
{
|
6426 |
|
|
v0 = gen_rtx_EXPR_LIST (VOIDmode, NULL_RTX, const0_rtx);
|
6427 |
|
|
v1 = gen_rtx_EXPR_LIST (VOIDmode, reg, const0_rtx);
|
6428 |
|
|
return gen_rtx_PARALLEL (mode, gen_rtvec (2, v0, v1));
|
6429 |
|
|
}
|
6430 |
|
|
}
|
6431 |
|
|
}
|
6432 |
|
|
|
6433 |
|
|
/* All other aggregate types are passed in an integer register in a mode
|
6434 |
|
|
corresponding to the size of the type. */
|
6435 |
|
|
else if (type && AGGREGATE_TYPE_P (type))
|
6436 |
|
|
{
|
6437 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6438 |
|
|
gcc_assert (size <= 16);
|
6439 |
|
|
|
6440 |
|
|
mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
|
6441 |
|
|
}
|
6442 |
|
|
|
6443 |
|
|
return gen_rtx_REG (mode, regno);
|
6444 |
|
|
}
|
6445 |
|
|
|
6446 |
|
|
/* Handle the TARGET_FUNCTION_ARG target hook. */
|
6447 |
|
|
|
6448 |
|
|
static rtx
|
6449 |
|
|
sparc_function_arg (cumulative_args_t cum, enum machine_mode mode,
|
6450 |
|
|
const_tree type, bool named)
|
6451 |
|
|
{
|
6452 |
|
|
return sparc_function_arg_1 (cum, mode, type, named, false);
|
6453 |
|
|
}
|
6454 |
|
|
|
6455 |
|
|
/* Handle the TARGET_FUNCTION_INCOMING_ARG target hook. */
|
6456 |
|
|
|
6457 |
|
|
static rtx
|
6458 |
|
|
sparc_function_incoming_arg (cumulative_args_t cum, enum machine_mode mode,
|
6459 |
|
|
const_tree type, bool named)
|
6460 |
|
|
{
|
6461 |
|
|
return sparc_function_arg_1 (cum, mode, type, named, true);
|
6462 |
|
|
}
|
6463 |
|
|
|
6464 |
|
|
/* For sparc64, objects requiring 16 byte alignment are passed that way. */
|
6465 |
|
|
|
6466 |
|
|
static unsigned int
|
6467 |
|
|
sparc_function_arg_boundary (enum machine_mode mode, const_tree type)
|
6468 |
|
|
{
|
6469 |
|
|
return ((TARGET_ARCH64
|
6470 |
|
|
&& (GET_MODE_ALIGNMENT (mode) == 128
|
6471 |
|
|
|| (type && TYPE_ALIGN (type) == 128)))
|
6472 |
|
|
? 128
|
6473 |
|
|
: PARM_BOUNDARY);
|
6474 |
|
|
}
|
6475 |
|
|
|
6476 |
|
|
/* For an arg passed partly in registers and partly in memory,
|
6477 |
|
|
this is the number of bytes of registers used.
|
6478 |
|
|
For args passed entirely in registers or entirely in memory, zero.
|
6479 |
|
|
|
6480 |
|
|
Any arg that starts in the first 6 regs but won't entirely fit in them
|
6481 |
|
|
needs partial registers on v8. On v9, structures with integer
|
6482 |
|
|
values in arg slots 5,6 will be passed in %o5 and SP+176, and complex fp
|
6483 |
|
|
values that begin in the last fp reg [where "last fp reg" varies with the
|
6484 |
|
|
mode] will be split between that reg and memory. */
|
6485 |
|
|
|
6486 |
|
|
static int
|
6487 |
|
|
sparc_arg_partial_bytes (cumulative_args_t cum, enum machine_mode mode,
|
6488 |
|
|
tree type, bool named)
|
6489 |
|
|
{
|
6490 |
|
|
int slotno, regno, padding;
|
6491 |
|
|
|
6492 |
|
|
/* We pass false for incoming_p here, it doesn't matter. */
|
6493 |
|
|
slotno = function_arg_slotno (get_cumulative_args (cum), mode, type, named,
|
6494 |
|
|
false, ®no, &padding);
|
6495 |
|
|
|
6496 |
|
|
if (slotno == -1)
|
6497 |
|
|
return 0;
|
6498 |
|
|
|
6499 |
|
|
if (TARGET_ARCH32)
|
6500 |
|
|
{
|
6501 |
|
|
if ((slotno + (mode == BLKmode
|
6502 |
|
|
? ROUND_ADVANCE (int_size_in_bytes (type))
|
6503 |
|
|
: ROUND_ADVANCE (GET_MODE_SIZE (mode))))
|
6504 |
|
|
> SPARC_INT_ARG_MAX)
|
6505 |
|
|
return (SPARC_INT_ARG_MAX - slotno) * UNITS_PER_WORD;
|
6506 |
|
|
}
|
6507 |
|
|
else
|
6508 |
|
|
{
|
6509 |
|
|
/* We are guaranteed by pass_by_reference that the size of the
|
6510 |
|
|
argument is not greater than 16 bytes, so we only need to return
|
6511 |
|
|
one word if the argument is partially passed in registers. */
|
6512 |
|
|
|
6513 |
|
|
if (type && AGGREGATE_TYPE_P (type))
|
6514 |
|
|
{
|
6515 |
|
|
int size = int_size_in_bytes (type);
|
6516 |
|
|
|
6517 |
|
|
if (size > UNITS_PER_WORD
|
6518 |
|
|
&& slotno == SPARC_INT_ARG_MAX - 1)
|
6519 |
|
|
return UNITS_PER_WORD;
|
6520 |
|
|
}
|
6521 |
|
|
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_INT
|
6522 |
|
|
|| (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT
|
6523 |
|
|
&& ! (TARGET_FPU && named)))
|
6524 |
|
|
{
|
6525 |
|
|
/* The complex types are passed as packed types. */
|
6526 |
|
|
if (GET_MODE_SIZE (mode) > UNITS_PER_WORD
|
6527 |
|
|
&& slotno == SPARC_INT_ARG_MAX - 1)
|
6528 |
|
|
return UNITS_PER_WORD;
|
6529 |
|
|
}
|
6530 |
|
|
else if (GET_MODE_CLASS (mode) == MODE_COMPLEX_FLOAT)
|
6531 |
|
|
{
|
6532 |
|
|
if ((slotno + GET_MODE_SIZE (mode) / UNITS_PER_WORD)
|
6533 |
|
|
> SPARC_FP_ARG_MAX)
|
6534 |
|
|
return UNITS_PER_WORD;
|
6535 |
|
|
}
|
6536 |
|
|
}
|
6537 |
|
|
|
6538 |
|
|
return 0;
|
6539 |
|
|
}
|
6540 |
|
|
|
6541 |
|
|
/* Handle the TARGET_PASS_BY_REFERENCE target hook.
|
6542 |
|
|
Specify whether to pass the argument by reference. */
|
6543 |
|
|
|
6544 |
|
|
static bool
|
6545 |
|
|
sparc_pass_by_reference (cumulative_args_t cum ATTRIBUTE_UNUSED,
|
6546 |
|
|
enum machine_mode mode, const_tree type,
|
6547 |
|
|
bool named ATTRIBUTE_UNUSED)
|
6548 |
|
|
{
|
6549 |
|
|
if (TARGET_ARCH32)
|
6550 |
|
|
/* Original SPARC 32-bit ABI says that structures and unions,
|
6551 |
|
|
and quad-precision floats are passed by reference. For Pascal,
|
6552 |
|
|
also pass arrays by reference. All other base types are passed
|
6553 |
|
|
in registers.
|
6554 |
|
|
|
6555 |
|
|
Extended ABI (as implemented by the Sun compiler) says that all
|
6556 |
|
|
complex floats are passed by reference. Pass complex integers
|
6557 |
|
|
in registers up to 8 bytes. More generally, enforce the 2-word
|
6558 |
|
|
cap for passing arguments in registers.
|
6559 |
|
|
|
6560 |
|
|
Vector ABI (as implemented by the Sun VIS SDK) says that vector
|
6561 |
|
|
integers are passed like floats of the same size, that is in
|
6562 |
|
|
registers up to 8 bytes. Pass all vector floats by reference
|
6563 |
|
|
like structure and unions. */
|
6564 |
|
|
return ((type && (AGGREGATE_TYPE_P (type) || VECTOR_FLOAT_TYPE_P (type)))
|
6565 |
|
|
|| mode == SCmode
|
6566 |
|
|
/* Catch CDImode, TFmode, DCmode and TCmode. */
|
6567 |
|
|
|| GET_MODE_SIZE (mode) > 8
|
6568 |
|
|
|| (type
|
6569 |
|
|
&& TREE_CODE (type) == VECTOR_TYPE
|
6570 |
|
|
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
|
6571 |
|
|
else
|
6572 |
|
|
/* Original SPARC 64-bit ABI says that structures and unions
|
6573 |
|
|
smaller than 16 bytes are passed in registers, as well as
|
6574 |
|
|
all other base types.
|
6575 |
|
|
|
6576 |
|
|
Extended ABI (as implemented by the Sun compiler) says that
|
6577 |
|
|
complex floats are passed in registers up to 16 bytes. Pass
|
6578 |
|
|
all complex integers in registers up to 16 bytes. More generally,
|
6579 |
|
|
enforce the 2-word cap for passing arguments in registers.
|
6580 |
|
|
|
6581 |
|
|
Vector ABI (as implemented by the Sun VIS SDK) says that vector
|
6582 |
|
|
integers are passed like floats of the same size, that is in
|
6583 |
|
|
registers (up to 16 bytes). Pass all vector floats like structure
|
6584 |
|
|
and unions. */
|
6585 |
|
|
return ((type
|
6586 |
|
|
&& (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == VECTOR_TYPE)
|
6587 |
|
|
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 16)
|
6588 |
|
|
/* Catch CTImode and TCmode. */
|
6589 |
|
|
|| GET_MODE_SIZE (mode) > 16);
|
6590 |
|
|
}
|
6591 |
|
|
|
6592 |
|
|
/* Handle the TARGET_FUNCTION_ARG_ADVANCE hook.
|
6593 |
|
|
Update the data in CUM to advance over an argument
|
6594 |
|
|
of mode MODE and data type TYPE.
|
6595 |
|
|
TYPE is null for libcalls where that information may not be available. */
|
6596 |
|
|
|
6597 |
|
|
static void
|
6598 |
|
|
sparc_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
|
6599 |
|
|
const_tree type, bool named)
|
6600 |
|
|
{
|
6601 |
|
|
CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
|
6602 |
|
|
int regno, padding;
|
6603 |
|
|
|
6604 |
|
|
/* We pass false for incoming_p here, it doesn't matter. */
|
6605 |
|
|
function_arg_slotno (cum, mode, type, named, false, ®no, &padding);
|
6606 |
|
|
|
6607 |
|
|
/* If argument requires leading padding, add it. */
|
6608 |
|
|
cum->words += padding;
|
6609 |
|
|
|
6610 |
|
|
if (TARGET_ARCH32)
|
6611 |
|
|
{
|
6612 |
|
|
cum->words += (mode != BLKmode
|
6613 |
|
|
? ROUND_ADVANCE (GET_MODE_SIZE (mode))
|
6614 |
|
|
: ROUND_ADVANCE (int_size_in_bytes (type)));
|
6615 |
|
|
}
|
6616 |
|
|
else
|
6617 |
|
|
{
|
6618 |
|
|
if (type && AGGREGATE_TYPE_P (type))
|
6619 |
|
|
{
|
6620 |
|
|
int size = int_size_in_bytes (type);
|
6621 |
|
|
|
6622 |
|
|
if (size <= 8)
|
6623 |
|
|
++cum->words;
|
6624 |
|
|
else if (size <= 16)
|
6625 |
|
|
cum->words += 2;
|
6626 |
|
|
else /* passed by reference */
|
6627 |
|
|
++cum->words;
|
6628 |
|
|
}
|
6629 |
|
|
else
|
6630 |
|
|
{
|
6631 |
|
|
cum->words += (mode != BLKmode
|
6632 |
|
|
? ROUND_ADVANCE (GET_MODE_SIZE (mode))
|
6633 |
|
|
: ROUND_ADVANCE (int_size_in_bytes (type)));
|
6634 |
|
|
}
|
6635 |
|
|
}
|
6636 |
|
|
}
|
6637 |
|
|
|
6638 |
|
|
/* Handle the FUNCTION_ARG_PADDING macro.
|
6639 |
|
|
For the 64 bit ABI structs are always stored left shifted in their
|
6640 |
|
|
argument slot. */
|
6641 |
|
|
|
6642 |
|
|
enum direction
|
6643 |
|
|
function_arg_padding (enum machine_mode mode, const_tree type)
|
6644 |
|
|
{
|
6645 |
|
|
if (TARGET_ARCH64 && type != 0 && AGGREGATE_TYPE_P (type))
|
6646 |
|
|
return upward;
|
6647 |
|
|
|
6648 |
|
|
/* Fall back to the default. */
|
6649 |
|
|
return DEFAULT_FUNCTION_ARG_PADDING (mode, type);
|
6650 |
|
|
}
|
6651 |
|
|
|
6652 |
|
|
/* Handle the TARGET_RETURN_IN_MEMORY target hook.
|
6653 |
|
|
Specify whether to return the return value in memory. */
|
6654 |
|
|
|
6655 |
|
|
static bool
|
6656 |
|
|
sparc_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
|
6657 |
|
|
{
|
6658 |
|
|
if (TARGET_ARCH32)
|
6659 |
|
|
/* Original SPARC 32-bit ABI says that structures and unions,
|
6660 |
|
|
and quad-precision floats are returned in memory. All other
|
6661 |
|
|
base types are returned in registers.
|
6662 |
|
|
|
6663 |
|
|
Extended ABI (as implemented by the Sun compiler) says that
|
6664 |
|
|
all complex floats are returned in registers (8 FP registers
|
6665 |
|
|
at most for '_Complex long double'). Return all complex integers
|
6666 |
|
|
in registers (4 at most for '_Complex long long').
|
6667 |
|
|
|
6668 |
|
|
Vector ABI (as implemented by the Sun VIS SDK) says that vector
|
6669 |
|
|
integers are returned like floats of the same size, that is in
|
6670 |
|
|
registers up to 8 bytes and in memory otherwise. Return all
|
6671 |
|
|
vector floats in memory like structure and unions; note that
|
6672 |
|
|
they always have BLKmode like the latter. */
|
6673 |
|
|
return (TYPE_MODE (type) == BLKmode
|
6674 |
|
|
|| TYPE_MODE (type) == TFmode
|
6675 |
|
|
|| (TREE_CODE (type) == VECTOR_TYPE
|
6676 |
|
|
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 8));
|
6677 |
|
|
else
|
6678 |
|
|
/* Original SPARC 64-bit ABI says that structures and unions
|
6679 |
|
|
smaller than 32 bytes are returned in registers, as well as
|
6680 |
|
|
all other base types.
|
6681 |
|
|
|
6682 |
|
|
Extended ABI (as implemented by the Sun compiler) says that all
|
6683 |
|
|
complex floats are returned in registers (8 FP registers at most
|
6684 |
|
|
for '_Complex long double'). Return all complex integers in
|
6685 |
|
|
registers (4 at most for '_Complex TItype').
|
6686 |
|
|
|
6687 |
|
|
Vector ABI (as implemented by the Sun VIS SDK) says that vector
|
6688 |
|
|
integers are returned like floats of the same size, that is in
|
6689 |
|
|
registers. Return all vector floats like structure and unions;
|
6690 |
|
|
note that they always have BLKmode like the latter. */
|
6691 |
|
|
return (TYPE_MODE (type) == BLKmode
|
6692 |
|
|
&& (unsigned HOST_WIDE_INT) int_size_in_bytes (type) > 32);
|
6693 |
|
|
}
|
6694 |
|
|
|
6695 |
|
|
/* Handle the TARGET_STRUCT_VALUE target hook.
|
6696 |
|
|
Return where to find the structure return value address. */
|
6697 |
|
|
|
6698 |
|
|
static rtx
|
6699 |
|
|
sparc_struct_value_rtx (tree fndecl, int incoming)
|
6700 |
|
|
{
|
6701 |
|
|
if (TARGET_ARCH64)
|
6702 |
|
|
return 0;
|
6703 |
|
|
else
|
6704 |
|
|
{
|
6705 |
|
|
rtx mem;
|
6706 |
|
|
|
6707 |
|
|
if (incoming)
|
6708 |
|
|
mem = gen_frame_mem (Pmode, plus_constant (frame_pointer_rtx,
|
6709 |
|
|
STRUCT_VALUE_OFFSET));
|
6710 |
|
|
else
|
6711 |
|
|
mem = gen_frame_mem (Pmode, plus_constant (stack_pointer_rtx,
|
6712 |
|
|
STRUCT_VALUE_OFFSET));
|
6713 |
|
|
|
6714 |
|
|
/* Only follow the SPARC ABI for fixed-size structure returns.
|
6715 |
|
|
Variable size structure returns are handled per the normal
|
6716 |
|
|
procedures in GCC. This is enabled by -mstd-struct-return */
|
6717 |
|
|
if (incoming == 2
|
6718 |
|
|
&& sparc_std_struct_return
|
6719 |
|
|
&& TYPE_SIZE_UNIT (TREE_TYPE (fndecl))
|
6720 |
|
|
&& TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (fndecl))) == INTEGER_CST)
|
6721 |
|
|
{
|
6722 |
|
|
/* We must check and adjust the return address, as it is
|
6723 |
|
|
optional as to whether the return object is really
|
6724 |
|
|
provided. */
|
6725 |
|
|
rtx ret_reg = gen_rtx_REG (Pmode, 31);
|
6726 |
|
|
rtx scratch = gen_reg_rtx (SImode);
|
6727 |
|
|
rtx endlab = gen_label_rtx ();
|
6728 |
|
|
|
6729 |
|
|
/* Calculate the return object size */
|
6730 |
|
|
tree size = TYPE_SIZE_UNIT (TREE_TYPE (fndecl));
|
6731 |
|
|
rtx size_rtx = GEN_INT (TREE_INT_CST_LOW (size) & 0xfff);
|
6732 |
|
|
/* Construct a temporary return value */
|
6733 |
|
|
rtx temp_val
|
6734 |
|
|
= assign_stack_local (Pmode, TREE_INT_CST_LOW (size), 0);
|
6735 |
|
|
|
6736 |
|
|
/* Implement SPARC 32-bit psABI callee return struct checking:
|
6737 |
|
|
|
6738 |
|
|
Fetch the instruction where we will return to and see if
|
6739 |
|
|
it's an unimp instruction (the most significant 10 bits
|
6740 |
|
|
will be zero). */
|
6741 |
|
|
emit_move_insn (scratch, gen_rtx_MEM (SImode,
|
6742 |
|
|
plus_constant (ret_reg, 8)));
|
6743 |
|
|
/* Assume the size is valid and pre-adjust */
|
6744 |
|
|
emit_insn (gen_add3_insn (ret_reg, ret_reg, GEN_INT (4)));
|
6745 |
|
|
emit_cmp_and_jump_insns (scratch, size_rtx, EQ, const0_rtx, SImode,
|
6746 |
|
|
0, endlab);
|
6747 |
|
|
emit_insn (gen_sub3_insn (ret_reg, ret_reg, GEN_INT (4)));
|
6748 |
|
|
/* Write the address of the memory pointed to by temp_val into
|
6749 |
|
|
the memory pointed to by mem */
|
6750 |
|
|
emit_move_insn (mem, XEXP (temp_val, 0));
|
6751 |
|
|
emit_label (endlab);
|
6752 |
|
|
}
|
6753 |
|
|
|
6754 |
|
|
return mem;
|
6755 |
|
|
}
|
6756 |
|
|
}
|
6757 |
|
|
|
6758 |
|
|
/* Handle TARGET_FUNCTION_VALUE, and TARGET_LIBCALL_VALUE target hook.
|
6759 |
|
|
For v9, function return values are subject to the same rules as arguments,
|
6760 |
|
|
except that up to 32 bytes may be returned in registers. */
|
6761 |
|
|
|
6762 |
|
|
static rtx
|
6763 |
|
|
sparc_function_value_1 (const_tree type, enum machine_mode mode,
|
6764 |
|
|
bool outgoing)
|
6765 |
|
|
{
|
6766 |
|
|
/* Beware that the two values are swapped here wrt function_arg. */
|
6767 |
|
|
int regbase = (outgoing
|
6768 |
|
|
? SPARC_INCOMING_INT_ARG_FIRST
|
6769 |
|
|
: SPARC_OUTGOING_INT_ARG_FIRST);
|
6770 |
|
|
enum mode_class mclass = GET_MODE_CLASS (mode);
|
6771 |
|
|
int regno;
|
6772 |
|
|
|
6773 |
|
|
/* Vector types deserve special treatment because they are polymorphic wrt
|
6774 |
|
|
their mode, depending upon whether VIS instructions are enabled. */
|
6775 |
|
|
if (type && TREE_CODE (type) == VECTOR_TYPE)
|
6776 |
|
|
{
|
6777 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6778 |
|
|
gcc_assert ((TARGET_ARCH32 && size <= 8)
|
6779 |
|
|
|| (TARGET_ARCH64 && size <= 32));
|
6780 |
|
|
|
6781 |
|
|
if (mode == BLKmode)
|
6782 |
|
|
return function_arg_vector_value (size,
|
6783 |
|
|
SPARC_FP_ARG_FIRST);
|
6784 |
|
|
else
|
6785 |
|
|
mclass = MODE_FLOAT;
|
6786 |
|
|
}
|
6787 |
|
|
|
6788 |
|
|
if (TARGET_ARCH64 && type)
|
6789 |
|
|
{
|
6790 |
|
|
/* Structures up to 32 bytes in size are returned in registers. */
|
6791 |
|
|
if (TREE_CODE (type) == RECORD_TYPE)
|
6792 |
|
|
{
|
6793 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6794 |
|
|
gcc_assert (size <= 32);
|
6795 |
|
|
|
6796 |
|
|
return function_arg_record_value (type, mode, 0, 1, regbase);
|
6797 |
|
|
}
|
6798 |
|
|
|
6799 |
|
|
/* Unions up to 32 bytes in size are returned in integer registers. */
|
6800 |
|
|
else if (TREE_CODE (type) == UNION_TYPE)
|
6801 |
|
|
{
|
6802 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6803 |
|
|
gcc_assert (size <= 32);
|
6804 |
|
|
|
6805 |
|
|
return function_arg_union_value (size, mode, 0, regbase);
|
6806 |
|
|
}
|
6807 |
|
|
|
6808 |
|
|
/* Objects that require it are returned in FP registers. */
|
6809 |
|
|
else if (mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT)
|
6810 |
|
|
;
|
6811 |
|
|
|
6812 |
|
|
/* All other aggregate types are returned in an integer register in a
|
6813 |
|
|
mode corresponding to the size of the type. */
|
6814 |
|
|
else if (AGGREGATE_TYPE_P (type))
|
6815 |
|
|
{
|
6816 |
|
|
/* All other aggregate types are passed in an integer register
|
6817 |
|
|
in a mode corresponding to the size of the type. */
|
6818 |
|
|
HOST_WIDE_INT size = int_size_in_bytes (type);
|
6819 |
|
|
gcc_assert (size <= 32);
|
6820 |
|
|
|
6821 |
|
|
mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
|
6822 |
|
|
|
6823 |
|
|
/* ??? We probably should have made the same ABI change in
|
6824 |
|
|
3.4.0 as the one we made for unions. The latter was
|
6825 |
|
|
required by the SCD though, while the former is not
|
6826 |
|
|
specified, so we favored compatibility and efficiency.
|
6827 |
|
|
|
6828 |
|
|
Now we're stuck for aggregates larger than 16 bytes,
|
6829 |
|
|
because OImode vanished in the meantime. Let's not
|
6830 |
|
|
try to be unduly clever, and simply follow the ABI
|
6831 |
|
|
for unions in that case. */
|
6832 |
|
|
if (mode == BLKmode)
|
6833 |
|
|
return function_arg_union_value (size, mode, 0, regbase);
|
6834 |
|
|
else
|
6835 |
|
|
mclass = MODE_INT;
|
6836 |
|
|
}
|
6837 |
|
|
|
6838 |
|
|
/* We should only have pointer and integer types at this point. This
|
6839 |
|
|
must match sparc_promote_function_mode. */
|
6840 |
|
|
else if (mclass == MODE_INT && GET_MODE_SIZE (mode) < UNITS_PER_WORD)
|
6841 |
|
|
mode = word_mode;
|
6842 |
|
|
}
|
6843 |
|
|
|
6844 |
|
|
/* We should only have pointer and integer types at this point. This must
|
6845 |
|
|
match sparc_promote_function_mode. */
|
6846 |
|
|
else if (TARGET_ARCH32
|
6847 |
|
|
&& mclass == MODE_INT
|
6848 |
|
|
&& GET_MODE_SIZE (mode) < UNITS_PER_WORD)
|
6849 |
|
|
mode = word_mode;
|
6850 |
|
|
|
6851 |
|
|
if ((mclass == MODE_FLOAT || mclass == MODE_COMPLEX_FLOAT) && TARGET_FPU)
|
6852 |
|
|
regno = SPARC_FP_ARG_FIRST;
|
6853 |
|
|
else
|
6854 |
|
|
regno = regbase;
|
6855 |
|
|
|
6856 |
|
|
return gen_rtx_REG (mode, regno);
|
6857 |
|
|
}
|
6858 |
|
|
|
6859 |
|
|
/* Handle TARGET_FUNCTION_VALUE.
|
6860 |
|
|
On the SPARC, the value is found in the first "output" register, but the
|
6861 |
|
|
called function leaves it in the first "input" register. */
|
6862 |
|
|
|
6863 |
|
|
static rtx
|
6864 |
|
|
sparc_function_value (const_tree valtype,
|
6865 |
|
|
const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
|
6866 |
|
|
bool outgoing)
|
6867 |
|
|
{
|
6868 |
|
|
return sparc_function_value_1 (valtype, TYPE_MODE (valtype), outgoing);
|
6869 |
|
|
}
|
6870 |
|
|
|
6871 |
|
|
/* Handle TARGET_LIBCALL_VALUE. */
|
6872 |
|
|
|
6873 |
|
|
static rtx
|
6874 |
|
|
sparc_libcall_value (enum machine_mode mode,
|
6875 |
|
|
const_rtx fun ATTRIBUTE_UNUSED)
|
6876 |
|
|
{
|
6877 |
|
|
return sparc_function_value_1 (NULL_TREE, mode, false);
|
6878 |
|
|
}
|
6879 |
|
|
|
6880 |
|
|
/* Handle FUNCTION_VALUE_REGNO_P.
|
6881 |
|
|
On the SPARC, the first "output" reg is used for integer values, and the
|
6882 |
|
|
first floating point register is used for floating point values. */
|
6883 |
|
|
|
6884 |
|
|
static bool
|
6885 |
|
|
sparc_function_value_regno_p (const unsigned int regno)
|
6886 |
|
|
{
|
6887 |
|
|
return (regno == 8 || regno == 32);
|
6888 |
|
|
}
|
6889 |
|
|
|
6890 |
|
|
/* Do what is necessary for `va_start'. We look at the current function
|
6891 |
|
|
to determine if stdarg or varargs is used and return the address of
|
6892 |
|
|
the first unnamed parameter. */
|
6893 |
|
|
|
6894 |
|
|
static rtx
|
6895 |
|
|
sparc_builtin_saveregs (void)
|
6896 |
|
|
{
|
6897 |
|
|
int first_reg = crtl->args.info.words;
|
6898 |
|
|
rtx address;
|
6899 |
|
|
int regno;
|
6900 |
|
|
|
6901 |
|
|
for (regno = first_reg; regno < SPARC_INT_ARG_MAX; regno++)
|
6902 |
|
|
emit_move_insn (gen_rtx_MEM (word_mode,
|
6903 |
|
|
gen_rtx_PLUS (Pmode,
|
6904 |
|
|
frame_pointer_rtx,
|
6905 |
|
|
GEN_INT (FIRST_PARM_OFFSET (0)
|
6906 |
|
|
+ (UNITS_PER_WORD
|
6907 |
|
|
* regno)))),
|
6908 |
|
|
gen_rtx_REG (word_mode,
|
6909 |
|
|
SPARC_INCOMING_INT_ARG_FIRST + regno));
|
6910 |
|
|
|
6911 |
|
|
address = gen_rtx_PLUS (Pmode,
|
6912 |
|
|
frame_pointer_rtx,
|
6913 |
|
|
GEN_INT (FIRST_PARM_OFFSET (0)
|
6914 |
|
|
+ UNITS_PER_WORD * first_reg));
|
6915 |
|
|
|
6916 |
|
|
return address;
|
6917 |
|
|
}
|
6918 |
|
|
|
6919 |
|
|
/* Implement `va_start' for stdarg. */
|
6920 |
|
|
|
6921 |
|
|
static void
|
6922 |
|
|
sparc_va_start (tree valist, rtx nextarg)
|
6923 |
|
|
{
|
6924 |
|
|
nextarg = expand_builtin_saveregs ();
|
6925 |
|
|
std_expand_builtin_va_start (valist, nextarg);
|
6926 |
|
|
}
|
6927 |
|
|
|
6928 |
|
|
/* Implement `va_arg' for stdarg. */
|
6929 |
|
|
|
6930 |
|
|
static tree
|
6931 |
|
|
sparc_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p,
|
6932 |
|
|
gimple_seq *post_p)
|
6933 |
|
|
{
|
6934 |
|
|
HOST_WIDE_INT size, rsize, align;
|
6935 |
|
|
tree addr, incr;
|
6936 |
|
|
bool indirect;
|
6937 |
|
|
tree ptrtype = build_pointer_type (type);
|
6938 |
|
|
|
6939 |
|
|
if (pass_by_reference (NULL, TYPE_MODE (type), type, false))
|
6940 |
|
|
{
|
6941 |
|
|
indirect = true;
|
6942 |
|
|
size = rsize = UNITS_PER_WORD;
|
6943 |
|
|
align = 0;
|
6944 |
|
|
}
|
6945 |
|
|
else
|
6946 |
|
|
{
|
6947 |
|
|
indirect = false;
|
6948 |
|
|
size = int_size_in_bytes (type);
|
6949 |
|
|
rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
|
6950 |
|
|
align = 0;
|
6951 |
|
|
|
6952 |
|
|
if (TARGET_ARCH64)
|
6953 |
|
|
{
|
6954 |
|
|
/* For SPARC64, objects requiring 16-byte alignment get it. */
|
6955 |
|
|
if (TYPE_ALIGN (type) >= 2 * (unsigned) BITS_PER_WORD)
|
6956 |
|
|
align = 2 * UNITS_PER_WORD;
|
6957 |
|
|
|
6958 |
|
|
/* SPARC-V9 ABI states that structures up to 16 bytes in size
|
6959 |
|
|
are left-justified in their slots. */
|
6960 |
|
|
if (AGGREGATE_TYPE_P (type))
|
6961 |
|
|
{
|
6962 |
|
|
if (size == 0)
|
6963 |
|
|
size = rsize = UNITS_PER_WORD;
|
6964 |
|
|
else
|
6965 |
|
|
size = rsize;
|
6966 |
|
|
}
|
6967 |
|
|
}
|
6968 |
|
|
}
|
6969 |
|
|
|
6970 |
|
|
incr = valist;
|
6971 |
|
|
if (align)
|
6972 |
|
|
{
|
6973 |
|
|
incr = fold_build_pointer_plus_hwi (incr, align - 1);
|
6974 |
|
|
incr = fold_convert (sizetype, incr);
|
6975 |
|
|
incr = fold_build2 (BIT_AND_EXPR, sizetype, incr,
|
6976 |
|
|
size_int (-align));
|
6977 |
|
|
incr = fold_convert (ptr_type_node, incr);
|
6978 |
|
|
}
|
6979 |
|
|
|
6980 |
|
|
gimplify_expr (&incr, pre_p, post_p, is_gimple_val, fb_rvalue);
|
6981 |
|
|
addr = incr;
|
6982 |
|
|
|
6983 |
|
|
if (BYTES_BIG_ENDIAN && size < rsize)
|
6984 |
|
|
addr = fold_build_pointer_plus_hwi (incr, rsize - size);
|
6985 |
|
|
|
6986 |
|
|
if (indirect)
|
6987 |
|
|
{
|
6988 |
|
|
addr = fold_convert (build_pointer_type (ptrtype), addr);
|
6989 |
|
|
addr = build_va_arg_indirect_ref (addr);
|
6990 |
|
|
}
|
6991 |
|
|
|
6992 |
|
|
/* If the address isn't aligned properly for the type, we need a temporary.
|
6993 |
|
|
FIXME: This is inefficient, usually we can do this in registers. */
|
6994 |
|
|
else if (align == 0 && TYPE_ALIGN (type) > BITS_PER_WORD)
|
6995 |
|
|
{
|
6996 |
|
|
tree tmp = create_tmp_var (type, "va_arg_tmp");
|
6997 |
|
|
tree dest_addr = build_fold_addr_expr (tmp);
|
6998 |
|
|
tree copy = build_call_expr (builtin_decl_implicit (BUILT_IN_MEMCPY),
|
6999 |
|
|
3, dest_addr, addr, size_int (rsize));
|
7000 |
|
|
TREE_ADDRESSABLE (tmp) = 1;
|
7001 |
|
|
gimplify_and_add (copy, pre_p);
|
7002 |
|
|
addr = dest_addr;
|
7003 |
|
|
}
|
7004 |
|
|
|
7005 |
|
|
else
|
7006 |
|
|
addr = fold_convert (ptrtype, addr);
|
7007 |
|
|
|
7008 |
|
|
incr = fold_build_pointer_plus_hwi (incr, rsize);
|
7009 |
|
|
gimplify_assign (valist, incr, post_p);
|
7010 |
|
|
|
7011 |
|
|
return build_va_arg_indirect_ref (addr);
|
7012 |
|
|
}
|
7013 |
|
|
|
7014 |
|
|
/* Implement the TARGET_VECTOR_MODE_SUPPORTED_P target hook.
|
7015 |
|
|
Specify whether the vector mode is supported by the hardware. */
|
7016 |
|
|
|
7017 |
|
|
static bool
|
7018 |
|
|
sparc_vector_mode_supported_p (enum machine_mode mode)
|
7019 |
|
|
{
|
7020 |
|
|
return TARGET_VIS && VECTOR_MODE_P (mode) ? true : false;
|
7021 |
|
|
}
|
7022 |
|
|
|
7023 |
|
|
/* Implement the TARGET_VECTORIZE_PREFERRED_SIMD_MODE target hook. */
|
7024 |
|
|
|
7025 |
|
|
static enum machine_mode
|
7026 |
|
|
sparc_preferred_simd_mode (enum machine_mode mode)
|
7027 |
|
|
{
|
7028 |
|
|
if (TARGET_VIS)
|
7029 |
|
|
switch (mode)
|
7030 |
|
|
{
|
7031 |
|
|
case SImode:
|
7032 |
|
|
return V2SImode;
|
7033 |
|
|
case HImode:
|
7034 |
|
|
return V4HImode;
|
7035 |
|
|
case QImode:
|
7036 |
|
|
return V8QImode;
|
7037 |
|
|
|
7038 |
|
|
default:;
|
7039 |
|
|
}
|
7040 |
|
|
|
7041 |
|
|
return word_mode;
|
7042 |
|
|
}
|
7043 |
|
|
|
7044 |
|
|
/* Return the string to output an unconditional branch to LABEL, which is
|
7045 |
|
|
the operand number of the label.
|
7046 |
|
|
|
7047 |
|
|
DEST is the destination insn (i.e. the label), INSN is the source. */
|
7048 |
|
|
|
7049 |
|
|
const char *
|
7050 |
|
|
output_ubranch (rtx dest, int label, rtx insn)
|
7051 |
|
|
{
|
7052 |
|
|
static char string[64];
|
7053 |
|
|
bool v9_form = false;
|
7054 |
|
|
char *p;
|
7055 |
|
|
|
7056 |
|
|
if (TARGET_V9 && INSN_ADDRESSES_SET_P ())
|
7057 |
|
|
{
|
7058 |
|
|
int delta = (INSN_ADDRESSES (INSN_UID (dest))
|
7059 |
|
|
- INSN_ADDRESSES (INSN_UID (insn)));
|
7060 |
|
|
/* Leave some instructions for "slop". */
|
7061 |
|
|
if (delta >= -260000 && delta < 260000)
|
7062 |
|
|
v9_form = true;
|
7063 |
|
|
}
|
7064 |
|
|
|
7065 |
|
|
if (v9_form)
|
7066 |
|
|
strcpy (string, "ba%*,pt\t%%xcc, ");
|
7067 |
|
|
else
|
7068 |
|
|
strcpy (string, "b%*\t");
|
7069 |
|
|
|
7070 |
|
|
p = strchr (string, '\0');
|
7071 |
|
|
*p++ = '%';
|
7072 |
|
|
*p++ = 'l';
|
7073 |
|
|
*p++ = '0' + label;
|
7074 |
|
|
*p++ = '%';
|
7075 |
|
|
*p++ = '(';
|
7076 |
|
|
*p = '\0';
|
7077 |
|
|
|
7078 |
|
|
return string;
|
7079 |
|
|
}
|
7080 |
|
|
|
7081 |
|
|
/* Return the string to output a conditional branch to LABEL, which is
|
7082 |
|
|
the operand number of the label. OP is the conditional expression.
|
7083 |
|
|
XEXP (OP, 0) is assumed to be a condition code register (integer or
|
7084 |
|
|
floating point) and its mode specifies what kind of comparison we made.
|
7085 |
|
|
|
7086 |
|
|
DEST is the destination insn (i.e. the label), INSN is the source.
|
7087 |
|
|
|
7088 |
|
|
REVERSED is nonzero if we should reverse the sense of the comparison.
|
7089 |
|
|
|
7090 |
|
|
ANNUL is nonzero if we should generate an annulling branch. */
|
7091 |
|
|
|
7092 |
|
|
const char *
|
7093 |
|
|
output_cbranch (rtx op, rtx dest, int label, int reversed, int annul,
|
7094 |
|
|
rtx insn)
|
7095 |
|
|
{
|
7096 |
|
|
static char string[64];
|
7097 |
|
|
enum rtx_code code = GET_CODE (op);
|
7098 |
|
|
rtx cc_reg = XEXP (op, 0);
|
7099 |
|
|
enum machine_mode mode = GET_MODE (cc_reg);
|
7100 |
|
|
const char *labelno, *branch;
|
7101 |
|
|
int spaces = 8, far;
|
7102 |
|
|
char *p;
|
7103 |
|
|
|
7104 |
|
|
/* v9 branches are limited to +-1MB. If it is too far away,
|
7105 |
|
|
change
|
7106 |
|
|
|
7107 |
|
|
bne,pt %xcc, .LC30
|
7108 |
|
|
|
7109 |
|
|
to
|
7110 |
|
|
|
7111 |
|
|
be,pn %xcc, .+12
|
7112 |
|
|
nop
|
7113 |
|
|
ba .LC30
|
7114 |
|
|
|
7115 |
|
|
and
|
7116 |
|
|
|
7117 |
|
|
fbne,a,pn %fcc2, .LC29
|
7118 |
|
|
|
7119 |
|
|
to
|
7120 |
|
|
|
7121 |
|
|
fbe,pt %fcc2, .+16
|
7122 |
|
|
nop
|
7123 |
|
|
ba .LC29 */
|
7124 |
|
|
|
7125 |
|
|
far = TARGET_V9 && (get_attr_length (insn) >= 3);
|
7126 |
|
|
if (reversed ^ far)
|
7127 |
|
|
{
|
7128 |
|
|
/* Reversal of FP compares takes care -- an ordered compare
|
7129 |
|
|
becomes an unordered compare and vice versa. */
|
7130 |
|
|
if (mode == CCFPmode || mode == CCFPEmode)
|
7131 |
|
|
code = reverse_condition_maybe_unordered (code);
|
7132 |
|
|
else
|
7133 |
|
|
code = reverse_condition (code);
|
7134 |
|
|
}
|
7135 |
|
|
|
7136 |
|
|
/* Start by writing the branch condition. */
|
7137 |
|
|
if (mode == CCFPmode || mode == CCFPEmode)
|
7138 |
|
|
{
|
7139 |
|
|
switch (code)
|
7140 |
|
|
{
|
7141 |
|
|
case NE:
|
7142 |
|
|
branch = "fbne";
|
7143 |
|
|
break;
|
7144 |
|
|
case EQ:
|
7145 |
|
|
branch = "fbe";
|
7146 |
|
|
break;
|
7147 |
|
|
case GE:
|
7148 |
|
|
branch = "fbge";
|
7149 |
|
|
break;
|
7150 |
|
|
case GT:
|
7151 |
|
|
branch = "fbg";
|
7152 |
|
|
break;
|
7153 |
|
|
case LE:
|
7154 |
|
|
branch = "fble";
|
7155 |
|
|
break;
|
7156 |
|
|
case LT:
|
7157 |
|
|
branch = "fbl";
|
7158 |
|
|
break;
|
7159 |
|
|
case UNORDERED:
|
7160 |
|
|
branch = "fbu";
|
7161 |
|
|
break;
|
7162 |
|
|
case ORDERED:
|
7163 |
|
|
branch = "fbo";
|
7164 |
|
|
break;
|
7165 |
|
|
case UNGT:
|
7166 |
|
|
branch = "fbug";
|
7167 |
|
|
break;
|
7168 |
|
|
case UNLT:
|
7169 |
|
|
branch = "fbul";
|
7170 |
|
|
break;
|
7171 |
|
|
case UNEQ:
|
7172 |
|
|
branch = "fbue";
|
7173 |
|
|
break;
|
7174 |
|
|
case UNGE:
|
7175 |
|
|
branch = "fbuge";
|
7176 |
|
|
break;
|
7177 |
|
|
case UNLE:
|
7178 |
|
|
branch = "fbule";
|
7179 |
|
|
break;
|
7180 |
|
|
case LTGT:
|
7181 |
|
|
branch = "fblg";
|
7182 |
|
|
break;
|
7183 |
|
|
|
7184 |
|
|
default:
|
7185 |
|
|
gcc_unreachable ();
|
7186 |
|
|
}
|
7187 |
|
|
|
7188 |
|
|
/* ??? !v9: FP branches cannot be preceded by another floating point
|
7189 |
|
|
insn. Because there is currently no concept of pre-delay slots,
|
7190 |
|
|
we can fix this only by always emitting a nop before a floating
|
7191 |
|
|
point branch. */
|
7192 |
|
|
|
7193 |
|
|
string[0] = '\0';
|
7194 |
|
|
if (! TARGET_V9)
|
7195 |
|
|
strcpy (string, "nop\n\t");
|
7196 |
|
|
strcat (string, branch);
|
7197 |
|
|
}
|
7198 |
|
|
else
|
7199 |
|
|
{
|
7200 |
|
|
switch (code)
|
7201 |
|
|
{
|
7202 |
|
|
case NE:
|
7203 |
|
|
branch = "bne";
|
7204 |
|
|
break;
|
7205 |
|
|
case EQ:
|
7206 |
|
|
branch = "be";
|
7207 |
|
|
break;
|
7208 |
|
|
case GE:
|
7209 |
|
|
if (mode == CC_NOOVmode || mode == CCX_NOOVmode)
|
7210 |
|
|
branch = "bpos";
|
7211 |
|
|
else
|
7212 |
|
|
branch = "bge";
|
7213 |
|
|
break;
|
7214 |
|
|
case GT:
|
7215 |
|
|
branch = "bg";
|
7216 |
|
|
break;
|
7217 |
|
|
case LE:
|
7218 |
|
|
branch = "ble";
|
7219 |
|
|
break;
|
7220 |
|
|
case LT:
|
7221 |
|
|
if (mode == CC_NOOVmode || mode == CCX_NOOVmode)
|
7222 |
|
|
branch = "bneg";
|
7223 |
|
|
else
|
7224 |
|
|
branch = "bl";
|
7225 |
|
|
break;
|
7226 |
|
|
case GEU:
|
7227 |
|
|
branch = "bgeu";
|
7228 |
|
|
break;
|
7229 |
|
|
case GTU:
|
7230 |
|
|
branch = "bgu";
|
7231 |
|
|
break;
|
7232 |
|
|
case LEU:
|
7233 |
|
|
branch = "bleu";
|
7234 |
|
|
break;
|
7235 |
|
|
case LTU:
|
7236 |
|
|
branch = "blu";
|
7237 |
|
|
break;
|
7238 |
|
|
|
7239 |
|
|
default:
|
7240 |
|
|
gcc_unreachable ();
|
7241 |
|
|
}
|
7242 |
|
|
strcpy (string, branch);
|
7243 |
|
|
}
|
7244 |
|
|
spaces -= strlen (branch);
|
7245 |
|
|
p = strchr (string, '\0');
|
7246 |
|
|
|
7247 |
|
|
/* Now add the annulling, the label, and a possible noop. */
|
7248 |
|
|
if (annul && ! far)
|
7249 |
|
|
{
|
7250 |
|
|
strcpy (p, ",a");
|
7251 |
|
|
p += 2;
|
7252 |
|
|
spaces -= 2;
|
7253 |
|
|
}
|
7254 |
|
|
|
7255 |
|
|
if (TARGET_V9)
|
7256 |
|
|
{
|
7257 |
|
|
rtx note;
|
7258 |
|
|
int v8 = 0;
|
7259 |
|
|
|
7260 |
|
|
if (! far && insn && INSN_ADDRESSES_SET_P ())
|
7261 |
|
|
{
|
7262 |
|
|
int delta = (INSN_ADDRESSES (INSN_UID (dest))
|
7263 |
|
|
- INSN_ADDRESSES (INSN_UID (insn)));
|
7264 |
|
|
/* Leave some instructions for "slop". */
|
7265 |
|
|
if (delta < -260000 || delta >= 260000)
|
7266 |
|
|
v8 = 1;
|
7267 |
|
|
}
|
7268 |
|
|
|
7269 |
|
|
if (mode == CCFPmode || mode == CCFPEmode)
|
7270 |
|
|
{
|
7271 |
|
|
static char v9_fcc_labelno[] = "%%fccX, ";
|
7272 |
|
|
/* Set the char indicating the number of the fcc reg to use. */
|
7273 |
|
|
v9_fcc_labelno[5] = REGNO (cc_reg) - SPARC_FIRST_V9_FCC_REG + '0';
|
7274 |
|
|
labelno = v9_fcc_labelno;
|
7275 |
|
|
if (v8)
|
7276 |
|
|
{
|
7277 |
|
|
gcc_assert (REGNO (cc_reg) == SPARC_FCC_REG);
|
7278 |
|
|
labelno = "";
|
7279 |
|
|
}
|
7280 |
|
|
}
|
7281 |
|
|
else if (mode == CCXmode || mode == CCX_NOOVmode)
|
7282 |
|
|
{
|
7283 |
|
|
labelno = "%%xcc, ";
|
7284 |
|
|
gcc_assert (! v8);
|
7285 |
|
|
}
|
7286 |
|
|
else
|
7287 |
|
|
{
|
7288 |
|
|
labelno = "%%icc, ";
|
7289 |
|
|
if (v8)
|
7290 |
|
|
labelno = "";
|
7291 |
|
|
}
|
7292 |
|
|
|
7293 |
|
|
if (*labelno && insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX)))
|
7294 |
|
|
{
|
7295 |
|
|
strcpy (p,
|
7296 |
|
|
((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far)
|
7297 |
|
|
? ",pt" : ",pn");
|
7298 |
|
|
p += 3;
|
7299 |
|
|
spaces -= 3;
|
7300 |
|
|
}
|
7301 |
|
|
}
|
7302 |
|
|
else
|
7303 |
|
|
labelno = "";
|
7304 |
|
|
|
7305 |
|
|
if (spaces > 0)
|
7306 |
|
|
*p++ = '\t';
|
7307 |
|
|
else
|
7308 |
|
|
*p++ = ' ';
|
7309 |
|
|
strcpy (p, labelno);
|
7310 |
|
|
p = strchr (p, '\0');
|
7311 |
|
|
if (far)
|
7312 |
|
|
{
|
7313 |
|
|
strcpy (p, ".+12\n\t nop\n\tb\t");
|
7314 |
|
|
/* Skip the next insn if requested or
|
7315 |
|
|
if we know that it will be a nop. */
|
7316 |
|
|
if (annul || ! final_sequence)
|
7317 |
|
|
p[3] = '6';
|
7318 |
|
|
p += 14;
|
7319 |
|
|
}
|
7320 |
|
|
*p++ = '%';
|
7321 |
|
|
*p++ = 'l';
|
7322 |
|
|
*p++ = label + '0';
|
7323 |
|
|
*p++ = '%';
|
7324 |
|
|
*p++ = '#';
|
7325 |
|
|
*p = '\0';
|
7326 |
|
|
|
7327 |
|
|
return string;
|
7328 |
|
|
}
|
7329 |
|
|
|
7330 |
|
|
/* Emit a library call comparison between floating point X and Y.
|
7331 |
|
|
COMPARISON is the operator to compare with (EQ, NE, GT, etc).
|
7332 |
|
|
Return the new operator to be used in the comparison sequence.
|
7333 |
|
|
|
7334 |
|
|
TARGET_ARCH64 uses _Qp_* functions, which use pointers to TFmode
|
7335 |
|
|
values as arguments instead of the TFmode registers themselves,
|
7336 |
|
|
that's why we cannot call emit_float_lib_cmp. */
|
7337 |
|
|
|
7338 |
|
|
rtx
|
7339 |
|
|
sparc_emit_float_lib_cmp (rtx x, rtx y, enum rtx_code comparison)
|
7340 |
|
|
{
|
7341 |
|
|
const char *qpfunc;
|
7342 |
|
|
rtx slot0, slot1, result, tem, tem2, libfunc;
|
7343 |
|
|
enum machine_mode mode;
|
7344 |
|
|
enum rtx_code new_comparison;
|
7345 |
|
|
|
7346 |
|
|
switch (comparison)
|
7347 |
|
|
{
|
7348 |
|
|
case EQ:
|
7349 |
|
|
qpfunc = (TARGET_ARCH64 ? "_Qp_feq" : "_Q_feq");
|
7350 |
|
|
break;
|
7351 |
|
|
|
7352 |
|
|
case NE:
|
7353 |
|
|
qpfunc = (TARGET_ARCH64 ? "_Qp_fne" : "_Q_fne");
|
7354 |
|
|
break;
|
7355 |
|
|
|
7356 |
|
|
case GT:
|
7357 |
|
|
qpfunc = (TARGET_ARCH64 ? "_Qp_fgt" : "_Q_fgt");
|
7358 |
|
|
break;
|
7359 |
|
|
|
7360 |
|
|
case GE:
|
7361 |
|
|
qpfunc = (TARGET_ARCH64 ? "_Qp_fge" : "_Q_fge");
|
7362 |
|
|
break;
|
7363 |
|
|
|
7364 |
|
|
case LT:
|
7365 |
|
|
qpfunc = (TARGET_ARCH64 ? "_Qp_flt" : "_Q_flt");
|
7366 |
|
|
break;
|
7367 |
|
|
|
7368 |
|
|
case LE:
|
7369 |
|
|
qpfunc = (TARGET_ARCH64 ? "_Qp_fle" : "_Q_fle");
|
7370 |
|
|
break;
|
7371 |
|
|
|
7372 |
|
|
case ORDERED:
|
7373 |
|
|
case UNORDERED:
|
7374 |
|
|
case UNGT:
|
7375 |
|
|
case UNLT:
|
7376 |
|
|
case UNEQ:
|
7377 |
|
|
case UNGE:
|
7378 |
|
|
case UNLE:
|
7379 |
|
|
case LTGT:
|
7380 |
|
|
qpfunc = (TARGET_ARCH64 ? "_Qp_cmp" : "_Q_cmp");
|
7381 |
|
|
break;
|
7382 |
|
|
|
7383 |
|
|
default:
|
7384 |
|
|
gcc_unreachable ();
|
7385 |
|
|
}
|
7386 |
|
|
|
7387 |
|
|
if (TARGET_ARCH64)
|
7388 |
|
|
{
|
7389 |
|
|
if (MEM_P (x))
|
7390 |
|
|
slot0 = x;
|
7391 |
|
|
else
|
7392 |
|
|
{
|
7393 |
|
|
slot0 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
|
7394 |
|
|
emit_move_insn (slot0, x);
|
7395 |
|
|
}
|
7396 |
|
|
|
7397 |
|
|
if (MEM_P (y))
|
7398 |
|
|
slot1 = y;
|
7399 |
|
|
else
|
7400 |
|
|
{
|
7401 |
|
|
slot1 = assign_stack_temp (TFmode, GET_MODE_SIZE(TFmode), 0);
|
7402 |
|
|
emit_move_insn (slot1, y);
|
7403 |
|
|
}
|
7404 |
|
|
|
7405 |
|
|
libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
|
7406 |
|
|
emit_library_call (libfunc, LCT_NORMAL,
|
7407 |
|
|
DImode, 2,
|
7408 |
|
|
XEXP (slot0, 0), Pmode,
|
7409 |
|
|
XEXP (slot1, 0), Pmode);
|
7410 |
|
|
mode = DImode;
|
7411 |
|
|
}
|
7412 |
|
|
else
|
7413 |
|
|
{
|
7414 |
|
|
libfunc = gen_rtx_SYMBOL_REF (Pmode, qpfunc);
|
7415 |
|
|
emit_library_call (libfunc, LCT_NORMAL,
|
7416 |
|
|
SImode, 2,
|
7417 |
|
|
x, TFmode, y, TFmode);
|
7418 |
|
|
mode = SImode;
|
7419 |
|
|
}
|
7420 |
|
|
|
7421 |
|
|
|
7422 |
|
|
/* Immediately move the result of the libcall into a pseudo
|
7423 |
|
|
register so reload doesn't clobber the value if it needs
|
7424 |
|
|
the return register for a spill reg. */
|
7425 |
|
|
result = gen_reg_rtx (mode);
|
7426 |
|
|
emit_move_insn (result, hard_libcall_value (mode, libfunc));
|
7427 |
|
|
|
7428 |
|
|
switch (comparison)
|
7429 |
|
|
{
|
7430 |
|
|
default:
|
7431 |
|
|
return gen_rtx_NE (VOIDmode, result, const0_rtx);
|
7432 |
|
|
case ORDERED:
|
7433 |
|
|
case UNORDERED:
|
7434 |
|
|
new_comparison = (comparison == UNORDERED ? EQ : NE);
|
7435 |
|
|
return gen_rtx_fmt_ee (new_comparison, VOIDmode, result, GEN_INT(3));
|
7436 |
|
|
case UNGT:
|
7437 |
|
|
case UNGE:
|
7438 |
|
|
new_comparison = (comparison == UNGT ? GT : NE);
|
7439 |
|
|
return gen_rtx_fmt_ee (new_comparison, VOIDmode, result, const1_rtx);
|
7440 |
|
|
case UNLE:
|
7441 |
|
|
return gen_rtx_NE (VOIDmode, result, const2_rtx);
|
7442 |
|
|
case UNLT:
|
7443 |
|
|
tem = gen_reg_rtx (mode);
|
7444 |
|
|
if (TARGET_ARCH32)
|
7445 |
|
|
emit_insn (gen_andsi3 (tem, result, const1_rtx));
|
7446 |
|
|
else
|
7447 |
|
|
emit_insn (gen_anddi3 (tem, result, const1_rtx));
|
7448 |
|
|
return gen_rtx_NE (VOIDmode, tem, const0_rtx);
|
7449 |
|
|
case UNEQ:
|
7450 |
|
|
case LTGT:
|
7451 |
|
|
tem = gen_reg_rtx (mode);
|
7452 |
|
|
if (TARGET_ARCH32)
|
7453 |
|
|
emit_insn (gen_addsi3 (tem, result, const1_rtx));
|
7454 |
|
|
else
|
7455 |
|
|
emit_insn (gen_adddi3 (tem, result, const1_rtx));
|
7456 |
|
|
tem2 = gen_reg_rtx (mode);
|
7457 |
|
|
if (TARGET_ARCH32)
|
7458 |
|
|
emit_insn (gen_andsi3 (tem2, tem, const2_rtx));
|
7459 |
|
|
else
|
7460 |
|
|
emit_insn (gen_anddi3 (tem2, tem, const2_rtx));
|
7461 |
|
|
new_comparison = (comparison == UNEQ ? EQ : NE);
|
7462 |
|
|
return gen_rtx_fmt_ee (new_comparison, VOIDmode, tem2, const0_rtx);
|
7463 |
|
|
}
|
7464 |
|
|
|
7465 |
|
|
gcc_unreachable ();
|
7466 |
|
|
}
|
7467 |
|
|
|
7468 |
|
|
/* Generate an unsigned DImode to FP conversion. This is the same code
|
7469 |
|
|
optabs would emit if we didn't have TFmode patterns. */
|
7470 |
|
|
|
7471 |
|
|
void
|
7472 |
|
|
sparc_emit_floatunsdi (rtx *operands, enum machine_mode mode)
|
7473 |
|
|
{
|
7474 |
|
|
rtx neglab, donelab, i0, i1, f0, in, out;
|
7475 |
|
|
|
7476 |
|
|
out = operands[0];
|
7477 |
|
|
in = force_reg (DImode, operands[1]);
|
7478 |
|
|
neglab = gen_label_rtx ();
|
7479 |
|
|
donelab = gen_label_rtx ();
|
7480 |
|
|
i0 = gen_reg_rtx (DImode);
|
7481 |
|
|
i1 = gen_reg_rtx (DImode);
|
7482 |
|
|
f0 = gen_reg_rtx (mode);
|
7483 |
|
|
|
7484 |
|
|
emit_cmp_and_jump_insns (in, const0_rtx, LT, const0_rtx, DImode, 0, neglab);
|
7485 |
|
|
|
7486 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_FLOAT (mode, in)));
|
7487 |
|
|
emit_jump_insn (gen_jump (donelab));
|
7488 |
|
|
emit_barrier ();
|
7489 |
|
|
|
7490 |
|
|
emit_label (neglab);
|
7491 |
|
|
|
7492 |
|
|
emit_insn (gen_lshrdi3 (i0, in, const1_rtx));
|
7493 |
|
|
emit_insn (gen_anddi3 (i1, in, const1_rtx));
|
7494 |
|
|
emit_insn (gen_iordi3 (i0, i0, i1));
|
7495 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_FLOAT (mode, i0)));
|
7496 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, out, gen_rtx_PLUS (mode, f0, f0)));
|
7497 |
|
|
|
7498 |
|
|
emit_label (donelab);
|
7499 |
|
|
}
|
7500 |
|
|
|
7501 |
|
|
/* Generate an FP to unsigned DImode conversion. This is the same code
|
7502 |
|
|
optabs would emit if we didn't have TFmode patterns. */
|
7503 |
|
|
|
7504 |
|
|
void
|
7505 |
|
|
sparc_emit_fixunsdi (rtx *operands, enum machine_mode mode)
|
7506 |
|
|
{
|
7507 |
|
|
rtx neglab, donelab, i0, i1, f0, in, out, limit;
|
7508 |
|
|
|
7509 |
|
|
out = operands[0];
|
7510 |
|
|
in = force_reg (mode, operands[1]);
|
7511 |
|
|
neglab = gen_label_rtx ();
|
7512 |
|
|
donelab = gen_label_rtx ();
|
7513 |
|
|
i0 = gen_reg_rtx (DImode);
|
7514 |
|
|
i1 = gen_reg_rtx (DImode);
|
7515 |
|
|
limit = gen_reg_rtx (mode);
|
7516 |
|
|
f0 = gen_reg_rtx (mode);
|
7517 |
|
|
|
7518 |
|
|
emit_move_insn (limit,
|
7519 |
|
|
CONST_DOUBLE_FROM_REAL_VALUE (
|
7520 |
|
|
REAL_VALUE_ATOF ("9223372036854775808.0", mode), mode));
|
7521 |
|
|
emit_cmp_and_jump_insns (in, limit, GE, NULL_RTX, mode, 0, neglab);
|
7522 |
|
|
|
7523 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
7524 |
|
|
out,
|
7525 |
|
|
gen_rtx_FIX (DImode, gen_rtx_FIX (mode, in))));
|
7526 |
|
|
emit_jump_insn (gen_jump (donelab));
|
7527 |
|
|
emit_barrier ();
|
7528 |
|
|
|
7529 |
|
|
emit_label (neglab);
|
7530 |
|
|
|
7531 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, f0, gen_rtx_MINUS (mode, in, limit)));
|
7532 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
7533 |
|
|
i0,
|
7534 |
|
|
gen_rtx_FIX (DImode, gen_rtx_FIX (mode, f0))));
|
7535 |
|
|
emit_insn (gen_movdi (i1, const1_rtx));
|
7536 |
|
|
emit_insn (gen_ashldi3 (i1, i1, GEN_INT (63)));
|
7537 |
|
|
emit_insn (gen_xordi3 (out, i0, i1));
|
7538 |
|
|
|
7539 |
|
|
emit_label (donelab);
|
7540 |
|
|
}
|
7541 |
|
|
|
7542 |
|
|
/* Return the string to output a conditional branch to LABEL, testing
|
7543 |
|
|
register REG. LABEL is the operand number of the label; REG is the
|
7544 |
|
|
operand number of the reg. OP is the conditional expression. The mode
|
7545 |
|
|
of REG says what kind of comparison we made.
|
7546 |
|
|
|
7547 |
|
|
DEST is the destination insn (i.e. the label), INSN is the source.
|
7548 |
|
|
|
7549 |
|
|
REVERSED is nonzero if we should reverse the sense of the comparison.
|
7550 |
|
|
|
7551 |
|
|
ANNUL is nonzero if we should generate an annulling branch. */
|
7552 |
|
|
|
7553 |
|
|
const char *
|
7554 |
|
|
output_v9branch (rtx op, rtx dest, int reg, int label, int reversed,
|
7555 |
|
|
int annul, rtx insn)
|
7556 |
|
|
{
|
7557 |
|
|
static char string[64];
|
7558 |
|
|
enum rtx_code code = GET_CODE (op);
|
7559 |
|
|
enum machine_mode mode = GET_MODE (XEXP (op, 0));
|
7560 |
|
|
rtx note;
|
7561 |
|
|
int far;
|
7562 |
|
|
char *p;
|
7563 |
|
|
|
7564 |
|
|
/* branch on register are limited to +-128KB. If it is too far away,
|
7565 |
|
|
change
|
7566 |
|
|
|
7567 |
|
|
brnz,pt %g1, .LC30
|
7568 |
|
|
|
7569 |
|
|
to
|
7570 |
|
|
|
7571 |
|
|
brz,pn %g1, .+12
|
7572 |
|
|
nop
|
7573 |
|
|
ba,pt %xcc, .LC30
|
7574 |
|
|
|
7575 |
|
|
and
|
7576 |
|
|
|
7577 |
|
|
brgez,a,pn %o1, .LC29
|
7578 |
|
|
|
7579 |
|
|
to
|
7580 |
|
|
|
7581 |
|
|
brlz,pt %o1, .+16
|
7582 |
|
|
nop
|
7583 |
|
|
ba,pt %xcc, .LC29 */
|
7584 |
|
|
|
7585 |
|
|
far = get_attr_length (insn) >= 3;
|
7586 |
|
|
|
7587 |
|
|
/* If not floating-point or if EQ or NE, we can just reverse the code. */
|
7588 |
|
|
if (reversed ^ far)
|
7589 |
|
|
code = reverse_condition (code);
|
7590 |
|
|
|
7591 |
|
|
/* Only 64 bit versions of these instructions exist. */
|
7592 |
|
|
gcc_assert (mode == DImode);
|
7593 |
|
|
|
7594 |
|
|
/* Start by writing the branch condition. */
|
7595 |
|
|
|
7596 |
|
|
switch (code)
|
7597 |
|
|
{
|
7598 |
|
|
case NE:
|
7599 |
|
|
strcpy (string, "brnz");
|
7600 |
|
|
break;
|
7601 |
|
|
|
7602 |
|
|
case EQ:
|
7603 |
|
|
strcpy (string, "brz");
|
7604 |
|
|
break;
|
7605 |
|
|
|
7606 |
|
|
case GE:
|
7607 |
|
|
strcpy (string, "brgez");
|
7608 |
|
|
break;
|
7609 |
|
|
|
7610 |
|
|
case LT:
|
7611 |
|
|
strcpy (string, "brlz");
|
7612 |
|
|
break;
|
7613 |
|
|
|
7614 |
|
|
case LE:
|
7615 |
|
|
strcpy (string, "brlez");
|
7616 |
|
|
break;
|
7617 |
|
|
|
7618 |
|
|
case GT:
|
7619 |
|
|
strcpy (string, "brgz");
|
7620 |
|
|
break;
|
7621 |
|
|
|
7622 |
|
|
default:
|
7623 |
|
|
gcc_unreachable ();
|
7624 |
|
|
}
|
7625 |
|
|
|
7626 |
|
|
p = strchr (string, '\0');
|
7627 |
|
|
|
7628 |
|
|
/* Now add the annulling, reg, label, and nop. */
|
7629 |
|
|
if (annul && ! far)
|
7630 |
|
|
{
|
7631 |
|
|
strcpy (p, ",a");
|
7632 |
|
|
p += 2;
|
7633 |
|
|
}
|
7634 |
|
|
|
7635 |
|
|
if (insn && (note = find_reg_note (insn, REG_BR_PROB, NULL_RTX)))
|
7636 |
|
|
{
|
7637 |
|
|
strcpy (p,
|
7638 |
|
|
((INTVAL (XEXP (note, 0)) >= REG_BR_PROB_BASE / 2) ^ far)
|
7639 |
|
|
? ",pt" : ",pn");
|
7640 |
|
|
p += 3;
|
7641 |
|
|
}
|
7642 |
|
|
|
7643 |
|
|
*p = p < string + 8 ? '\t' : ' ';
|
7644 |
|
|
p++;
|
7645 |
|
|
*p++ = '%';
|
7646 |
|
|
*p++ = '0' + reg;
|
7647 |
|
|
*p++ = ',';
|
7648 |
|
|
*p++ = ' ';
|
7649 |
|
|
if (far)
|
7650 |
|
|
{
|
7651 |
|
|
int veryfar = 1, delta;
|
7652 |
|
|
|
7653 |
|
|
if (INSN_ADDRESSES_SET_P ())
|
7654 |
|
|
{
|
7655 |
|
|
delta = (INSN_ADDRESSES (INSN_UID (dest))
|
7656 |
|
|
- INSN_ADDRESSES (INSN_UID (insn)));
|
7657 |
|
|
/* Leave some instructions for "slop". */
|
7658 |
|
|
if (delta >= -260000 && delta < 260000)
|
7659 |
|
|
veryfar = 0;
|
7660 |
|
|
}
|
7661 |
|
|
|
7662 |
|
|
strcpy (p, ".+12\n\t nop\n\t");
|
7663 |
|
|
/* Skip the next insn if requested or
|
7664 |
|
|
if we know that it will be a nop. */
|
7665 |
|
|
if (annul || ! final_sequence)
|
7666 |
|
|
p[3] = '6';
|
7667 |
|
|
p += 12;
|
7668 |
|
|
if (veryfar)
|
7669 |
|
|
{
|
7670 |
|
|
strcpy (p, "b\t");
|
7671 |
|
|
p += 2;
|
7672 |
|
|
}
|
7673 |
|
|
else
|
7674 |
|
|
{
|
7675 |
|
|
strcpy (p, "ba,pt\t%%xcc, ");
|
7676 |
|
|
p += 13;
|
7677 |
|
|
}
|
7678 |
|
|
}
|
7679 |
|
|
*p++ = '%';
|
7680 |
|
|
*p++ = 'l';
|
7681 |
|
|
*p++ = '0' + label;
|
7682 |
|
|
*p++ = '%';
|
7683 |
|
|
*p++ = '#';
|
7684 |
|
|
*p = '\0';
|
7685 |
|
|
|
7686 |
|
|
return string;
|
7687 |
|
|
}
|
7688 |
|
|
|
7689 |
|
|
/* Return 1, if any of the registers of the instruction are %l[0-7] or %o[0-7].
|
7690 |
|
|
Such instructions cannot be used in the delay slot of return insn on v9.
|
7691 |
|
|
If TEST is 0, also rename all %i[0-7] registers to their %o[0-7] counterparts.
|
7692 |
|
|
*/
|
7693 |
|
|
|
7694 |
|
|
static int
|
7695 |
|
|
epilogue_renumber (register rtx *where, int test)
|
7696 |
|
|
{
|
7697 |
|
|
register const char *fmt;
|
7698 |
|
|
register int i;
|
7699 |
|
|
register enum rtx_code code;
|
7700 |
|
|
|
7701 |
|
|
if (*where == 0)
|
7702 |
|
|
return 0;
|
7703 |
|
|
|
7704 |
|
|
code = GET_CODE (*where);
|
7705 |
|
|
|
7706 |
|
|
switch (code)
|
7707 |
|
|
{
|
7708 |
|
|
case REG:
|
7709 |
|
|
if (REGNO (*where) >= 8 && REGNO (*where) < 24) /* oX or lX */
|
7710 |
|
|
return 1;
|
7711 |
|
|
if (! test && REGNO (*where) >= 24 && REGNO (*where) < 32)
|
7712 |
|
|
*where = gen_rtx_REG (GET_MODE (*where), OUTGOING_REGNO (REGNO(*where)));
|
7713 |
|
|
case SCRATCH:
|
7714 |
|
|
case CC0:
|
7715 |
|
|
case PC:
|
7716 |
|
|
case CONST_INT:
|
7717 |
|
|
case CONST_DOUBLE:
|
7718 |
|
|
return 0;
|
7719 |
|
|
|
7720 |
|
|
/* Do not replace the frame pointer with the stack pointer because
|
7721 |
|
|
it can cause the delayed instruction to load below the stack.
|
7722 |
|
|
This occurs when instructions like:
|
7723 |
|
|
|
7724 |
|
|
(set (reg/i:SI 24 %i0)
|
7725 |
|
|
(mem/f:SI (plus:SI (reg/f:SI 30 %fp)
|
7726 |
|
|
(const_int -20 [0xffffffec])) 0))
|
7727 |
|
|
|
7728 |
|
|
are in the return delayed slot. */
|
7729 |
|
|
case PLUS:
|
7730 |
|
|
if (GET_CODE (XEXP (*where, 0)) == REG
|
7731 |
|
|
&& REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM
|
7732 |
|
|
&& (GET_CODE (XEXP (*where, 1)) != CONST_INT
|
7733 |
|
|
|| INTVAL (XEXP (*where, 1)) < SPARC_STACK_BIAS))
|
7734 |
|
|
return 1;
|
7735 |
|
|
break;
|
7736 |
|
|
|
7737 |
|
|
case MEM:
|
7738 |
|
|
if (SPARC_STACK_BIAS
|
7739 |
|
|
&& GET_CODE (XEXP (*where, 0)) == REG
|
7740 |
|
|
&& REGNO (XEXP (*where, 0)) == HARD_FRAME_POINTER_REGNUM)
|
7741 |
|
|
return 1;
|
7742 |
|
|
break;
|
7743 |
|
|
|
7744 |
|
|
default:
|
7745 |
|
|
break;
|
7746 |
|
|
}
|
7747 |
|
|
|
7748 |
|
|
fmt = GET_RTX_FORMAT (code);
|
7749 |
|
|
|
7750 |
|
|
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
|
7751 |
|
|
{
|
7752 |
|
|
if (fmt[i] == 'E')
|
7753 |
|
|
{
|
7754 |
|
|
register int j;
|
7755 |
|
|
for (j = XVECLEN (*where, i) - 1; j >= 0; j--)
|
7756 |
|
|
if (epilogue_renumber (&(XVECEXP (*where, i, j)), test))
|
7757 |
|
|
return 1;
|
7758 |
|
|
}
|
7759 |
|
|
else if (fmt[i] == 'e'
|
7760 |
|
|
&& epilogue_renumber (&(XEXP (*where, i)), test))
|
7761 |
|
|
return 1;
|
7762 |
|
|
}
|
7763 |
|
|
return 0;
|
7764 |
|
|
}
|
7765 |
|
|
|
7766 |
|
|
/* Leaf functions and non-leaf functions have different needs. */
|
7767 |
|
|
|
7768 |
|
|
static const int
|
7769 |
|
|
reg_leaf_alloc_order[] = REG_LEAF_ALLOC_ORDER;
|
7770 |
|
|
|
7771 |
|
|
static const int
|
7772 |
|
|
reg_nonleaf_alloc_order[] = REG_ALLOC_ORDER;
|
7773 |
|
|
|
7774 |
|
|
static const int *const reg_alloc_orders[] = {
|
7775 |
|
|
reg_leaf_alloc_order,
|
7776 |
|
|
reg_nonleaf_alloc_order};
|
7777 |
|
|
|
7778 |
|
|
void
|
7779 |
|
|
order_regs_for_local_alloc (void)
|
7780 |
|
|
{
|
7781 |
|
|
static int last_order_nonleaf = 1;
|
7782 |
|
|
|
7783 |
|
|
if (df_regs_ever_live_p (15) != last_order_nonleaf)
|
7784 |
|
|
{
|
7785 |
|
|
last_order_nonleaf = !last_order_nonleaf;
|
7786 |
|
|
memcpy ((char *) reg_alloc_order,
|
7787 |
|
|
(const char *) reg_alloc_orders[last_order_nonleaf],
|
7788 |
|
|
FIRST_PSEUDO_REGISTER * sizeof (int));
|
7789 |
|
|
}
|
7790 |
|
|
}
|
7791 |
|
|
|
7792 |
|
|
/* Return 1 if REG and MEM are legitimate enough to allow the various
|
7793 |
|
|
mem<-->reg splits to be run. */
|
7794 |
|
|
|
7795 |
|
|
int
|
7796 |
|
|
sparc_splitdi_legitimate (rtx reg, rtx mem)
|
7797 |
|
|
{
|
7798 |
|
|
/* Punt if we are here by mistake. */
|
7799 |
|
|
gcc_assert (reload_completed);
|
7800 |
|
|
|
7801 |
|
|
/* We must have an offsettable memory reference. */
|
7802 |
|
|
if (! offsettable_memref_p (mem))
|
7803 |
|
|
return 0;
|
7804 |
|
|
|
7805 |
|
|
/* If we have legitimate args for ldd/std, we do not want
|
7806 |
|
|
the split to happen. */
|
7807 |
|
|
if ((REGNO (reg) % 2) == 0
|
7808 |
|
|
&& mem_min_alignment (mem, 8))
|
7809 |
|
|
return 0;
|
7810 |
|
|
|
7811 |
|
|
/* Success. */
|
7812 |
|
|
return 1;
|
7813 |
|
|
}
|
7814 |
|
|
|
7815 |
|
|
/* Like sparc_splitdi_legitimate but for REG <--> REG moves. */
|
7816 |
|
|
|
7817 |
|
|
int
|
7818 |
|
|
sparc_split_regreg_legitimate (rtx reg1, rtx reg2)
|
7819 |
|
|
{
|
7820 |
|
|
int regno1, regno2;
|
7821 |
|
|
|
7822 |
|
|
if (GET_CODE (reg1) == SUBREG)
|
7823 |
|
|
reg1 = SUBREG_REG (reg1);
|
7824 |
|
|
if (GET_CODE (reg1) != REG)
|
7825 |
|
|
return 0;
|
7826 |
|
|
regno1 = REGNO (reg1);
|
7827 |
|
|
|
7828 |
|
|
if (GET_CODE (reg2) == SUBREG)
|
7829 |
|
|
reg2 = SUBREG_REG (reg2);
|
7830 |
|
|
if (GET_CODE (reg2) != REG)
|
7831 |
|
|
return 0;
|
7832 |
|
|
regno2 = REGNO (reg2);
|
7833 |
|
|
|
7834 |
|
|
if (SPARC_INT_REG_P (regno1) && SPARC_INT_REG_P (regno2))
|
7835 |
|
|
return 1;
|
7836 |
|
|
|
7837 |
|
|
if (TARGET_VIS3)
|
7838 |
|
|
{
|
7839 |
|
|
if ((SPARC_INT_REG_P (regno1) && SPARC_FP_REG_P (regno2))
|
7840 |
|
|
|| (SPARC_FP_REG_P (regno1) && SPARC_INT_REG_P (regno2)))
|
7841 |
|
|
return 1;
|
7842 |
|
|
}
|
7843 |
|
|
|
7844 |
|
|
return 0;
|
7845 |
|
|
}
|
7846 |
|
|
|
7847 |
|
|
/* Return 1 if x and y are some kind of REG and they refer to
|
7848 |
|
|
different hard registers. This test is guaranteed to be
|
7849 |
|
|
run after reload. */
|
7850 |
|
|
|
7851 |
|
|
int
|
7852 |
|
|
sparc_absnegfloat_split_legitimate (rtx x, rtx y)
|
7853 |
|
|
{
|
7854 |
|
|
if (GET_CODE (x) != REG)
|
7855 |
|
|
return 0;
|
7856 |
|
|
if (GET_CODE (y) != REG)
|
7857 |
|
|
return 0;
|
7858 |
|
|
if (REGNO (x) == REGNO (y))
|
7859 |
|
|
return 0;
|
7860 |
|
|
return 1;
|
7861 |
|
|
}
|
7862 |
|
|
|
7863 |
|
|
/* Return 1 if REGNO (reg1) is even and REGNO (reg1) == REGNO (reg2) - 1.
|
7864 |
|
|
This makes them candidates for using ldd and std insns.
|
7865 |
|
|
|
7866 |
|
|
Note reg1 and reg2 *must* be hard registers. */
|
7867 |
|
|
|
7868 |
|
|
int
|
7869 |
|
|
registers_ok_for_ldd_peep (rtx reg1, rtx reg2)
|
7870 |
|
|
{
|
7871 |
|
|
/* We might have been passed a SUBREG. */
|
7872 |
|
|
if (GET_CODE (reg1) != REG || GET_CODE (reg2) != REG)
|
7873 |
|
|
return 0;
|
7874 |
|
|
|
7875 |
|
|
if (REGNO (reg1) % 2 != 0)
|
7876 |
|
|
return 0;
|
7877 |
|
|
|
7878 |
|
|
/* Integer ldd is deprecated in SPARC V9 */
|
7879 |
|
|
if (TARGET_V9 && SPARC_INT_REG_P (REGNO (reg1)))
|
7880 |
|
|
return 0;
|
7881 |
|
|
|
7882 |
|
|
return (REGNO (reg1) == REGNO (reg2) - 1);
|
7883 |
|
|
}
|
7884 |
|
|
|
7885 |
|
|
/* Return 1 if the addresses in mem1 and mem2 are suitable for use in
|
7886 |
|
|
an ldd or std insn.
|
7887 |
|
|
|
7888 |
|
|
This can only happen when addr1 and addr2, the addresses in mem1
|
7889 |
|
|
and mem2, are consecutive memory locations (addr1 + 4 == addr2).
|
7890 |
|
|
addr1 must also be aligned on a 64-bit boundary.
|
7891 |
|
|
|
7892 |
|
|
Also iff dependent_reg_rtx is not null it should not be used to
|
7893 |
|
|
compute the address for mem1, i.e. we cannot optimize a sequence
|
7894 |
|
|
like:
|
7895 |
|
|
ld [%o0], %o0
|
7896 |
|
|
ld [%o0 + 4], %o1
|
7897 |
|
|
to
|
7898 |
|
|
ldd [%o0], %o0
|
7899 |
|
|
nor:
|
7900 |
|
|
ld [%g3 + 4], %g3
|
7901 |
|
|
ld [%g3], %g2
|
7902 |
|
|
to
|
7903 |
|
|
ldd [%g3], %g2
|
7904 |
|
|
|
7905 |
|
|
But, note that the transformation from:
|
7906 |
|
|
ld [%g2 + 4], %g3
|
7907 |
|
|
ld [%g2], %g2
|
7908 |
|
|
to
|
7909 |
|
|
ldd [%g2], %g2
|
7910 |
|
|
is perfectly fine. Thus, the peephole2 patterns always pass us
|
7911 |
|
|
the destination register of the first load, never the second one.
|
7912 |
|
|
|
7913 |
|
|
For stores we don't have a similar problem, so dependent_reg_rtx is
|
7914 |
|
|
NULL_RTX. */
|
7915 |
|
|
|
7916 |
|
|
int
|
7917 |
|
|
mems_ok_for_ldd_peep (rtx mem1, rtx mem2, rtx dependent_reg_rtx)
|
7918 |
|
|
{
|
7919 |
|
|
rtx addr1, addr2;
|
7920 |
|
|
unsigned int reg1;
|
7921 |
|
|
HOST_WIDE_INT offset1;
|
7922 |
|
|
|
7923 |
|
|
/* The mems cannot be volatile. */
|
7924 |
|
|
if (MEM_VOLATILE_P (mem1) || MEM_VOLATILE_P (mem2))
|
7925 |
|
|
return 0;
|
7926 |
|
|
|
7927 |
|
|
/* MEM1 should be aligned on a 64-bit boundary. */
|
7928 |
|
|
if (MEM_ALIGN (mem1) < 64)
|
7929 |
|
|
return 0;
|
7930 |
|
|
|
7931 |
|
|
addr1 = XEXP (mem1, 0);
|
7932 |
|
|
addr2 = XEXP (mem2, 0);
|
7933 |
|
|
|
7934 |
|
|
/* Extract a register number and offset (if used) from the first addr. */
|
7935 |
|
|
if (GET_CODE (addr1) == PLUS)
|
7936 |
|
|
{
|
7937 |
|
|
/* If not a REG, return zero. */
|
7938 |
|
|
if (GET_CODE (XEXP (addr1, 0)) != REG)
|
7939 |
|
|
return 0;
|
7940 |
|
|
else
|
7941 |
|
|
{
|
7942 |
|
|
reg1 = REGNO (XEXP (addr1, 0));
|
7943 |
|
|
/* The offset must be constant! */
|
7944 |
|
|
if (GET_CODE (XEXP (addr1, 1)) != CONST_INT)
|
7945 |
|
|
return 0;
|
7946 |
|
|
offset1 = INTVAL (XEXP (addr1, 1));
|
7947 |
|
|
}
|
7948 |
|
|
}
|
7949 |
|
|
else if (GET_CODE (addr1) != REG)
|
7950 |
|
|
return 0;
|
7951 |
|
|
else
|
7952 |
|
|
{
|
7953 |
|
|
reg1 = REGNO (addr1);
|
7954 |
|
|
/* This was a simple (mem (reg)) expression. Offset is 0. */
|
7955 |
|
|
offset1 = 0;
|
7956 |
|
|
}
|
7957 |
|
|
|
7958 |
|
|
/* Make sure the second address is a (mem (plus (reg) (const_int). */
|
7959 |
|
|
if (GET_CODE (addr2) != PLUS)
|
7960 |
|
|
return 0;
|
7961 |
|
|
|
7962 |
|
|
if (GET_CODE (XEXP (addr2, 0)) != REG
|
7963 |
|
|
|| GET_CODE (XEXP (addr2, 1)) != CONST_INT)
|
7964 |
|
|
return 0;
|
7965 |
|
|
|
7966 |
|
|
if (reg1 != REGNO (XEXP (addr2, 0)))
|
7967 |
|
|
return 0;
|
7968 |
|
|
|
7969 |
|
|
if (dependent_reg_rtx != NULL_RTX && reg1 == REGNO (dependent_reg_rtx))
|
7970 |
|
|
return 0;
|
7971 |
|
|
|
7972 |
|
|
/* The first offset must be evenly divisible by 8 to ensure the
|
7973 |
|
|
address is 64 bit aligned. */
|
7974 |
|
|
if (offset1 % 8 != 0)
|
7975 |
|
|
return 0;
|
7976 |
|
|
|
7977 |
|
|
/* The offset for the second addr must be 4 more than the first addr. */
|
7978 |
|
|
if (INTVAL (XEXP (addr2, 1)) != offset1 + 4)
|
7979 |
|
|
return 0;
|
7980 |
|
|
|
7981 |
|
|
/* All the tests passed. addr1 and addr2 are valid for ldd and std
|
7982 |
|
|
instructions. */
|
7983 |
|
|
return 1;
|
7984 |
|
|
}
|
7985 |
|
|
|
7986 |
|
|
/* Return 1 if reg is a pseudo, or is the first register in
|
7987 |
|
|
a hard register pair. This makes it suitable for use in
|
7988 |
|
|
ldd and std insns. */
|
7989 |
|
|
|
7990 |
|
|
int
|
7991 |
|
|
register_ok_for_ldd (rtx reg)
|
7992 |
|
|
{
|
7993 |
|
|
/* We might have been passed a SUBREG. */
|
7994 |
|
|
if (!REG_P (reg))
|
7995 |
|
|
return 0;
|
7996 |
|
|
|
7997 |
|
|
if (REGNO (reg) < FIRST_PSEUDO_REGISTER)
|
7998 |
|
|
return (REGNO (reg) % 2 == 0);
|
7999 |
|
|
|
8000 |
|
|
return 1;
|
8001 |
|
|
}
|
8002 |
|
|
|
8003 |
|
|
/* Return 1 if OP is a memory whose address is known to be
|
8004 |
|
|
aligned to 8-byte boundary, or a pseudo during reload.
|
8005 |
|
|
This makes it suitable for use in ldd and std insns. */
|
8006 |
|
|
|
8007 |
|
|
int
|
8008 |
|
|
memory_ok_for_ldd (rtx op)
|
8009 |
|
|
{
|
8010 |
|
|
if (MEM_P (op))
|
8011 |
|
|
{
|
8012 |
|
|
/* In 64-bit mode, we assume that the address is word-aligned. */
|
8013 |
|
|
if (TARGET_ARCH32 && !mem_min_alignment (op, 8))
|
8014 |
|
|
return 0;
|
8015 |
|
|
|
8016 |
|
|
if (! can_create_pseudo_p ()
|
8017 |
|
|
&& !strict_memory_address_p (Pmode, XEXP (op, 0)))
|
8018 |
|
|
return 0;
|
8019 |
|
|
}
|
8020 |
|
|
else if (REG_P (op) && REGNO (op) >= FIRST_PSEUDO_REGISTER)
|
8021 |
|
|
{
|
8022 |
|
|
if (!(reload_in_progress && reg_renumber [REGNO (op)] < 0))
|
8023 |
|
|
return 0;
|
8024 |
|
|
}
|
8025 |
|
|
else
|
8026 |
|
|
return 0;
|
8027 |
|
|
|
8028 |
|
|
return 1;
|
8029 |
|
|
}
|
8030 |
|
|
|
8031 |
|
|
/* Implement TARGET_PRINT_OPERAND_PUNCT_VALID_P. */
|
8032 |
|
|
|
8033 |
|
|
static bool
|
8034 |
|
|
sparc_print_operand_punct_valid_p (unsigned char code)
|
8035 |
|
|
{
|
8036 |
|
|
if (code == '#'
|
8037 |
|
|
|| code == '*'
|
8038 |
|
|
|| code == '('
|
8039 |
|
|
|| code == ')'
|
8040 |
|
|
|| code == '_'
|
8041 |
|
|
|| code == '&')
|
8042 |
|
|
return true;
|
8043 |
|
|
|
8044 |
|
|
return false;
|
8045 |
|
|
}
|
8046 |
|
|
|
8047 |
|
|
/* Implement TARGET_PRINT_OPERAND.
|
8048 |
|
|
Print operand X (an rtx) in assembler syntax to file FILE.
|
8049 |
|
|
CODE is a letter or dot (`z' in `%z0') or 0 if no letter was specified.
|
8050 |
|
|
For `%' followed by punctuation, CODE is the punctuation and X is null. */
|
8051 |
|
|
|
8052 |
|
|
static void
|
8053 |
|
|
sparc_print_operand (FILE *file, rtx x, int code)
|
8054 |
|
|
{
|
8055 |
|
|
switch (code)
|
8056 |
|
|
{
|
8057 |
|
|
case '#':
|
8058 |
|
|
/* Output an insn in a delay slot. */
|
8059 |
|
|
if (final_sequence)
|
8060 |
|
|
sparc_indent_opcode = 1;
|
8061 |
|
|
else
|
8062 |
|
|
fputs ("\n\t nop", file);
|
8063 |
|
|
return;
|
8064 |
|
|
case '*':
|
8065 |
|
|
/* Output an annul flag if there's nothing for the delay slot and we
|
8066 |
|
|
are optimizing. This is always used with '(' below.
|
8067 |
|
|
Sun OS 4.1.1 dbx can't handle an annulled unconditional branch;
|
8068 |
|
|
this is a dbx bug. So, we only do this when optimizing.
|
8069 |
|
|
On UltraSPARC, a branch in a delay slot causes a pipeline flush.
|
8070 |
|
|
Always emit a nop in case the next instruction is a branch. */
|
8071 |
|
|
if (! final_sequence && (optimize && (int)sparc_cpu < PROCESSOR_V9))
|
8072 |
|
|
fputs (",a", file);
|
8073 |
|
|
return;
|
8074 |
|
|
case '(':
|
8075 |
|
|
/* Output a 'nop' if there's nothing for the delay slot and we are
|
8076 |
|
|
not optimizing. This is always used with '*' above. */
|
8077 |
|
|
if (! final_sequence && ! (optimize && (int)sparc_cpu < PROCESSOR_V9))
|
8078 |
|
|
fputs ("\n\t nop", file);
|
8079 |
|
|
else if (final_sequence)
|
8080 |
|
|
sparc_indent_opcode = 1;
|
8081 |
|
|
return;
|
8082 |
|
|
case ')':
|
8083 |
|
|
/* Output the right displacement from the saved PC on function return.
|
8084 |
|
|
The caller may have placed an "unimp" insn immediately after the call
|
8085 |
|
|
so we have to account for it. This insn is used in the 32-bit ABI
|
8086 |
|
|
when calling a function that returns a non zero-sized structure. The
|
8087 |
|
|
64-bit ABI doesn't have it. Be careful to have this test be the same
|
8088 |
|
|
as that for the call. The exception is when sparc_std_struct_return
|
8089 |
|
|
is enabled, the psABI is followed exactly and the adjustment is made
|
8090 |
|
|
by the code in sparc_struct_value_rtx. The call emitted is the same
|
8091 |
|
|
when sparc_std_struct_return is enabled. */
|
8092 |
|
|
if (!TARGET_ARCH64
|
8093 |
|
|
&& cfun->returns_struct
|
8094 |
|
|
&& !sparc_std_struct_return
|
8095 |
|
|
&& DECL_SIZE (DECL_RESULT (current_function_decl))
|
8096 |
|
|
&& TREE_CODE (DECL_SIZE (DECL_RESULT (current_function_decl)))
|
8097 |
|
|
== INTEGER_CST
|
8098 |
|
|
&& !integer_zerop (DECL_SIZE (DECL_RESULT (current_function_decl))))
|
8099 |
|
|
fputs ("12", file);
|
8100 |
|
|
else
|
8101 |
|
|
fputc ('8', file);
|
8102 |
|
|
return;
|
8103 |
|
|
case '_':
|
8104 |
|
|
/* Output the Embedded Medium/Anywhere code model base register. */
|
8105 |
|
|
fputs (EMBMEDANY_BASE_REG, file);
|
8106 |
|
|
return;
|
8107 |
|
|
case '&':
|
8108 |
|
|
/* Print some local dynamic TLS name. */
|
8109 |
|
|
assemble_name (file, get_some_local_dynamic_name ());
|
8110 |
|
|
return;
|
8111 |
|
|
|
8112 |
|
|
case 'Y':
|
8113 |
|
|
/* Adjust the operand to take into account a RESTORE operation. */
|
8114 |
|
|
if (GET_CODE (x) == CONST_INT)
|
8115 |
|
|
break;
|
8116 |
|
|
else if (GET_CODE (x) != REG)
|
8117 |
|
|
output_operand_lossage ("invalid %%Y operand");
|
8118 |
|
|
else if (REGNO (x) < 8)
|
8119 |
|
|
fputs (reg_names[REGNO (x)], file);
|
8120 |
|
|
else if (REGNO (x) >= 24 && REGNO (x) < 32)
|
8121 |
|
|
fputs (reg_names[REGNO (x)-16], file);
|
8122 |
|
|
else
|
8123 |
|
|
output_operand_lossage ("invalid %%Y operand");
|
8124 |
|
|
return;
|
8125 |
|
|
case 'L':
|
8126 |
|
|
/* Print out the low order register name of a register pair. */
|
8127 |
|
|
if (WORDS_BIG_ENDIAN)
|
8128 |
|
|
fputs (reg_names[REGNO (x)+1], file);
|
8129 |
|
|
else
|
8130 |
|
|
fputs (reg_names[REGNO (x)], file);
|
8131 |
|
|
return;
|
8132 |
|
|
case 'H':
|
8133 |
|
|
/* Print out the high order register name of a register pair. */
|
8134 |
|
|
if (WORDS_BIG_ENDIAN)
|
8135 |
|
|
fputs (reg_names[REGNO (x)], file);
|
8136 |
|
|
else
|
8137 |
|
|
fputs (reg_names[REGNO (x)+1], file);
|
8138 |
|
|
return;
|
8139 |
|
|
case 'R':
|
8140 |
|
|
/* Print out the second register name of a register pair or quad.
|
8141 |
|
|
I.e., R (%o0) => %o1. */
|
8142 |
|
|
fputs (reg_names[REGNO (x)+1], file);
|
8143 |
|
|
return;
|
8144 |
|
|
case 'S':
|
8145 |
|
|
/* Print out the third register name of a register quad.
|
8146 |
|
|
I.e., S (%o0) => %o2. */
|
8147 |
|
|
fputs (reg_names[REGNO (x)+2], file);
|
8148 |
|
|
return;
|
8149 |
|
|
case 'T':
|
8150 |
|
|
/* Print out the fourth register name of a register quad.
|
8151 |
|
|
I.e., T (%o0) => %o3. */
|
8152 |
|
|
fputs (reg_names[REGNO (x)+3], file);
|
8153 |
|
|
return;
|
8154 |
|
|
case 'x':
|
8155 |
|
|
/* Print a condition code register. */
|
8156 |
|
|
if (REGNO (x) == SPARC_ICC_REG)
|
8157 |
|
|
{
|
8158 |
|
|
/* We don't handle CC[X]_NOOVmode because they're not supposed
|
8159 |
|
|
to occur here. */
|
8160 |
|
|
if (GET_MODE (x) == CCmode)
|
8161 |
|
|
fputs ("%icc", file);
|
8162 |
|
|
else if (GET_MODE (x) == CCXmode)
|
8163 |
|
|
fputs ("%xcc", file);
|
8164 |
|
|
else
|
8165 |
|
|
gcc_unreachable ();
|
8166 |
|
|
}
|
8167 |
|
|
else
|
8168 |
|
|
/* %fccN register */
|
8169 |
|
|
fputs (reg_names[REGNO (x)], file);
|
8170 |
|
|
return;
|
8171 |
|
|
case 'm':
|
8172 |
|
|
/* Print the operand's address only. */
|
8173 |
|
|
output_address (XEXP (x, 0));
|
8174 |
|
|
return;
|
8175 |
|
|
case 'r':
|
8176 |
|
|
/* In this case we need a register. Use %g0 if the
|
8177 |
|
|
operand is const0_rtx. */
|
8178 |
|
|
if (x == const0_rtx
|
8179 |
|
|
|| (GET_MODE (x) != VOIDmode && x == CONST0_RTX (GET_MODE (x))))
|
8180 |
|
|
{
|
8181 |
|
|
fputs ("%g0", file);
|
8182 |
|
|
return;
|
8183 |
|
|
}
|
8184 |
|
|
else
|
8185 |
|
|
break;
|
8186 |
|
|
|
8187 |
|
|
case 'A':
|
8188 |
|
|
switch (GET_CODE (x))
|
8189 |
|
|
{
|
8190 |
|
|
case IOR: fputs ("or", file); break;
|
8191 |
|
|
case AND: fputs ("and", file); break;
|
8192 |
|
|
case XOR: fputs ("xor", file); break;
|
8193 |
|
|
default: output_operand_lossage ("invalid %%A operand");
|
8194 |
|
|
}
|
8195 |
|
|
return;
|
8196 |
|
|
|
8197 |
|
|
case 'B':
|
8198 |
|
|
switch (GET_CODE (x))
|
8199 |
|
|
{
|
8200 |
|
|
case IOR: fputs ("orn", file); break;
|
8201 |
|
|
case AND: fputs ("andn", file); break;
|
8202 |
|
|
case XOR: fputs ("xnor", file); break;
|
8203 |
|
|
default: output_operand_lossage ("invalid %%B operand");
|
8204 |
|
|
}
|
8205 |
|
|
return;
|
8206 |
|
|
|
8207 |
|
|
/* This is used by the conditional move instructions. */
|
8208 |
|
|
case 'C':
|
8209 |
|
|
{
|
8210 |
|
|
enum rtx_code rc = GET_CODE (x);
|
8211 |
|
|
|
8212 |
|
|
switch (rc)
|
8213 |
|
|
{
|
8214 |
|
|
case NE: fputs ("ne", file); break;
|
8215 |
|
|
case EQ: fputs ("e", file); break;
|
8216 |
|
|
case GE: fputs ("ge", file); break;
|
8217 |
|
|
case GT: fputs ("g", file); break;
|
8218 |
|
|
case LE: fputs ("le", file); break;
|
8219 |
|
|
case LT: fputs ("l", file); break;
|
8220 |
|
|
case GEU: fputs ("geu", file); break;
|
8221 |
|
|
case GTU: fputs ("gu", file); break;
|
8222 |
|
|
case LEU: fputs ("leu", file); break;
|
8223 |
|
|
case LTU: fputs ("lu", file); break;
|
8224 |
|
|
case LTGT: fputs ("lg", file); break;
|
8225 |
|
|
case UNORDERED: fputs ("u", file); break;
|
8226 |
|
|
case ORDERED: fputs ("o", file); break;
|
8227 |
|
|
case UNLT: fputs ("ul", file); break;
|
8228 |
|
|
case UNLE: fputs ("ule", file); break;
|
8229 |
|
|
case UNGT: fputs ("ug", file); break;
|
8230 |
|
|
case UNGE: fputs ("uge", file); break;
|
8231 |
|
|
case UNEQ: fputs ("ue", file); break;
|
8232 |
|
|
default: output_operand_lossage ("invalid %%C operand");
|
8233 |
|
|
}
|
8234 |
|
|
return;
|
8235 |
|
|
}
|
8236 |
|
|
|
8237 |
|
|
/* This are used by the movr instruction pattern. */
|
8238 |
|
|
case 'D':
|
8239 |
|
|
{
|
8240 |
|
|
enum rtx_code rc = GET_CODE (x);
|
8241 |
|
|
switch (rc)
|
8242 |
|
|
{
|
8243 |
|
|
case NE: fputs ("ne", file); break;
|
8244 |
|
|
case EQ: fputs ("e", file); break;
|
8245 |
|
|
case GE: fputs ("gez", file); break;
|
8246 |
|
|
case LT: fputs ("lz", file); break;
|
8247 |
|
|
case LE: fputs ("lez", file); break;
|
8248 |
|
|
case GT: fputs ("gz", file); break;
|
8249 |
|
|
default: output_operand_lossage ("invalid %%D operand");
|
8250 |
|
|
}
|
8251 |
|
|
return;
|
8252 |
|
|
}
|
8253 |
|
|
|
8254 |
|
|
case 'b':
|
8255 |
|
|
{
|
8256 |
|
|
/* Print a sign-extended character. */
|
8257 |
|
|
int i = trunc_int_for_mode (INTVAL (x), QImode);
|
8258 |
|
|
fprintf (file, "%d", i);
|
8259 |
|
|
return;
|
8260 |
|
|
}
|
8261 |
|
|
|
8262 |
|
|
case 'f':
|
8263 |
|
|
/* Operand must be a MEM; write its address. */
|
8264 |
|
|
if (GET_CODE (x) != MEM)
|
8265 |
|
|
output_operand_lossage ("invalid %%f operand");
|
8266 |
|
|
output_address (XEXP (x, 0));
|
8267 |
|
|
return;
|
8268 |
|
|
|
8269 |
|
|
case 's':
|
8270 |
|
|
{
|
8271 |
|
|
/* Print a sign-extended 32-bit value. */
|
8272 |
|
|
HOST_WIDE_INT i;
|
8273 |
|
|
if (GET_CODE(x) == CONST_INT)
|
8274 |
|
|
i = INTVAL (x);
|
8275 |
|
|
else if (GET_CODE(x) == CONST_DOUBLE)
|
8276 |
|
|
i = CONST_DOUBLE_LOW (x);
|
8277 |
|
|
else
|
8278 |
|
|
{
|
8279 |
|
|
output_operand_lossage ("invalid %%s operand");
|
8280 |
|
|
return;
|
8281 |
|
|
}
|
8282 |
|
|
i = trunc_int_for_mode (i, SImode);
|
8283 |
|
|
fprintf (file, HOST_WIDE_INT_PRINT_DEC, i);
|
8284 |
|
|
return;
|
8285 |
|
|
}
|
8286 |
|
|
|
8287 |
|
|
case 0:
|
8288 |
|
|
/* Do nothing special. */
|
8289 |
|
|
break;
|
8290 |
|
|
|
8291 |
|
|
default:
|
8292 |
|
|
/* Undocumented flag. */
|
8293 |
|
|
output_operand_lossage ("invalid operand output code");
|
8294 |
|
|
}
|
8295 |
|
|
|
8296 |
|
|
if (GET_CODE (x) == REG)
|
8297 |
|
|
fputs (reg_names[REGNO (x)], file);
|
8298 |
|
|
else if (GET_CODE (x) == MEM)
|
8299 |
|
|
{
|
8300 |
|
|
fputc ('[', file);
|
8301 |
|
|
/* Poor Sun assembler doesn't understand absolute addressing. */
|
8302 |
|
|
if (CONSTANT_P (XEXP (x, 0)))
|
8303 |
|
|
fputs ("%g0+", file);
|
8304 |
|
|
output_address (XEXP (x, 0));
|
8305 |
|
|
fputc (']', file);
|
8306 |
|
|
}
|
8307 |
|
|
else if (GET_CODE (x) == HIGH)
|
8308 |
|
|
{
|
8309 |
|
|
fputs ("%hi(", file);
|
8310 |
|
|
output_addr_const (file, XEXP (x, 0));
|
8311 |
|
|
fputc (')', file);
|
8312 |
|
|
}
|
8313 |
|
|
else if (GET_CODE (x) == LO_SUM)
|
8314 |
|
|
{
|
8315 |
|
|
sparc_print_operand (file, XEXP (x, 0), 0);
|
8316 |
|
|
if (TARGET_CM_MEDMID)
|
8317 |
|
|
fputs ("+%l44(", file);
|
8318 |
|
|
else
|
8319 |
|
|
fputs ("+%lo(", file);
|
8320 |
|
|
output_addr_const (file, XEXP (x, 1));
|
8321 |
|
|
fputc (')', file);
|
8322 |
|
|
}
|
8323 |
|
|
else if (GET_CODE (x) == CONST_DOUBLE
|
8324 |
|
|
&& (GET_MODE (x) == VOIDmode
|
8325 |
|
|
|| GET_MODE_CLASS (GET_MODE (x)) == MODE_INT))
|
8326 |
|
|
{
|
8327 |
|
|
if (CONST_DOUBLE_HIGH (x) == 0)
|
8328 |
|
|
fprintf (file, "%u", (unsigned int) CONST_DOUBLE_LOW (x));
|
8329 |
|
|
else if (CONST_DOUBLE_HIGH (x) == -1
|
8330 |
|
|
&& CONST_DOUBLE_LOW (x) < 0)
|
8331 |
|
|
fprintf (file, "%d", (int) CONST_DOUBLE_LOW (x));
|
8332 |
|
|
else
|
8333 |
|
|
output_operand_lossage ("long long constant not a valid immediate operand");
|
8334 |
|
|
}
|
8335 |
|
|
else if (GET_CODE (x) == CONST_DOUBLE)
|
8336 |
|
|
output_operand_lossage ("floating point constant not a valid immediate operand");
|
8337 |
|
|
else { output_addr_const (file, x); }
|
8338 |
|
|
}
|
8339 |
|
|
|
8340 |
|
|
/* Implement TARGET_PRINT_OPERAND_ADDRESS. */
|
8341 |
|
|
|
8342 |
|
|
static void
|
8343 |
|
|
sparc_print_operand_address (FILE *file, rtx x)
|
8344 |
|
|
{
|
8345 |
|
|
register rtx base, index = 0;
|
8346 |
|
|
int offset = 0;
|
8347 |
|
|
register rtx addr = x;
|
8348 |
|
|
|
8349 |
|
|
if (REG_P (addr))
|
8350 |
|
|
fputs (reg_names[REGNO (addr)], file);
|
8351 |
|
|
else if (GET_CODE (addr) == PLUS)
|
8352 |
|
|
{
|
8353 |
|
|
if (CONST_INT_P (XEXP (addr, 0)))
|
8354 |
|
|
offset = INTVAL (XEXP (addr, 0)), base = XEXP (addr, 1);
|
8355 |
|
|
else if (CONST_INT_P (XEXP (addr, 1)))
|
8356 |
|
|
offset = INTVAL (XEXP (addr, 1)), base = XEXP (addr, 0);
|
8357 |
|
|
else
|
8358 |
|
|
base = XEXP (addr, 0), index = XEXP (addr, 1);
|
8359 |
|
|
if (GET_CODE (base) == LO_SUM)
|
8360 |
|
|
{
|
8361 |
|
|
gcc_assert (USE_AS_OFFSETABLE_LO10
|
8362 |
|
|
&& TARGET_ARCH64
|
8363 |
|
|
&& ! TARGET_CM_MEDMID);
|
8364 |
|
|
output_operand (XEXP (base, 0), 0);
|
8365 |
|
|
fputs ("+%lo(", file);
|
8366 |
|
|
output_address (XEXP (base, 1));
|
8367 |
|
|
fprintf (file, ")+%d", offset);
|
8368 |
|
|
}
|
8369 |
|
|
else
|
8370 |
|
|
{
|
8371 |
|
|
fputs (reg_names[REGNO (base)], file);
|
8372 |
|
|
if (index == 0)
|
8373 |
|
|
fprintf (file, "%+d", offset);
|
8374 |
|
|
else if (REG_P (index))
|
8375 |
|
|
fprintf (file, "+%s", reg_names[REGNO (index)]);
|
8376 |
|
|
else if (GET_CODE (index) == SYMBOL_REF
|
8377 |
|
|
|| GET_CODE (index) == LABEL_REF
|
8378 |
|
|
|| GET_CODE (index) == CONST)
|
8379 |
|
|
fputc ('+', file), output_addr_const (file, index);
|
8380 |
|
|
else gcc_unreachable ();
|
8381 |
|
|
}
|
8382 |
|
|
}
|
8383 |
|
|
else if (GET_CODE (addr) == MINUS
|
8384 |
|
|
&& GET_CODE (XEXP (addr, 1)) == LABEL_REF)
|
8385 |
|
|
{
|
8386 |
|
|
output_addr_const (file, XEXP (addr, 0));
|
8387 |
|
|
fputs ("-(", file);
|
8388 |
|
|
output_addr_const (file, XEXP (addr, 1));
|
8389 |
|
|
fputs ("-.)", file);
|
8390 |
|
|
}
|
8391 |
|
|
else if (GET_CODE (addr) == LO_SUM)
|
8392 |
|
|
{
|
8393 |
|
|
output_operand (XEXP (addr, 0), 0);
|
8394 |
|
|
if (TARGET_CM_MEDMID)
|
8395 |
|
|
fputs ("+%l44(", file);
|
8396 |
|
|
else
|
8397 |
|
|
fputs ("+%lo(", file);
|
8398 |
|
|
output_address (XEXP (addr, 1));
|
8399 |
|
|
fputc (')', file);
|
8400 |
|
|
}
|
8401 |
|
|
else if (flag_pic
|
8402 |
|
|
&& GET_CODE (addr) == CONST
|
8403 |
|
|
&& GET_CODE (XEXP (addr, 0)) == MINUS
|
8404 |
|
|
&& GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST
|
8405 |
|
|
&& GET_CODE (XEXP (XEXP (XEXP (addr, 0), 1), 0)) == MINUS
|
8406 |
|
|
&& XEXP (XEXP (XEXP (XEXP (addr, 0), 1), 0), 1) == pc_rtx)
|
8407 |
|
|
{
|
8408 |
|
|
addr = XEXP (addr, 0);
|
8409 |
|
|
output_addr_const (file, XEXP (addr, 0));
|
8410 |
|
|
/* Group the args of the second CONST in parenthesis. */
|
8411 |
|
|
fputs ("-(", file);
|
8412 |
|
|
/* Skip past the second CONST--it does nothing for us. */
|
8413 |
|
|
output_addr_const (file, XEXP (XEXP (addr, 1), 0));
|
8414 |
|
|
/* Close the parenthesis. */
|
8415 |
|
|
fputc (')', file);
|
8416 |
|
|
}
|
8417 |
|
|
else
|
8418 |
|
|
{
|
8419 |
|
|
output_addr_const (file, addr);
|
8420 |
|
|
}
|
8421 |
|
|
}
|
8422 |
|
|
|
8423 |
|
|
/* Target hook for assembling integer objects. The sparc version has
|
8424 |
|
|
special handling for aligned DI-mode objects. */
|
8425 |
|
|
|
8426 |
|
|
static bool
|
8427 |
|
|
sparc_assemble_integer (rtx x, unsigned int size, int aligned_p)
|
8428 |
|
|
{
|
8429 |
|
|
/* ??? We only output .xword's for symbols and only then in environments
|
8430 |
|
|
where the assembler can handle them. */
|
8431 |
|
|
if (aligned_p && size == 8
|
8432 |
|
|
&& (GET_CODE (x) != CONST_INT && GET_CODE (x) != CONST_DOUBLE))
|
8433 |
|
|
{
|
8434 |
|
|
if (TARGET_V9)
|
8435 |
|
|
{
|
8436 |
|
|
assemble_integer_with_op ("\t.xword\t", x);
|
8437 |
|
|
return true;
|
8438 |
|
|
}
|
8439 |
|
|
else
|
8440 |
|
|
{
|
8441 |
|
|
assemble_aligned_integer (4, const0_rtx);
|
8442 |
|
|
assemble_aligned_integer (4, x);
|
8443 |
|
|
return true;
|
8444 |
|
|
}
|
8445 |
|
|
}
|
8446 |
|
|
return default_assemble_integer (x, size, aligned_p);
|
8447 |
|
|
}
|
8448 |
|
|
|
8449 |
|
|
/* Return the value of a code used in the .proc pseudo-op that says
|
8450 |
|
|
what kind of result this function returns. For non-C types, we pick
|
8451 |
|
|
the closest C type. */
|
8452 |
|
|
|
8453 |
|
|
#ifndef SHORT_TYPE_SIZE
|
8454 |
|
|
#define SHORT_TYPE_SIZE (BITS_PER_UNIT * 2)
|
8455 |
|
|
#endif
|
8456 |
|
|
|
8457 |
|
|
#ifndef INT_TYPE_SIZE
|
8458 |
|
|
#define INT_TYPE_SIZE BITS_PER_WORD
|
8459 |
|
|
#endif
|
8460 |
|
|
|
8461 |
|
|
#ifndef LONG_TYPE_SIZE
|
8462 |
|
|
#define LONG_TYPE_SIZE BITS_PER_WORD
|
8463 |
|
|
#endif
|
8464 |
|
|
|
8465 |
|
|
#ifndef LONG_LONG_TYPE_SIZE
|
8466 |
|
|
#define LONG_LONG_TYPE_SIZE (BITS_PER_WORD * 2)
|
8467 |
|
|
#endif
|
8468 |
|
|
|
8469 |
|
|
#ifndef FLOAT_TYPE_SIZE
|
8470 |
|
|
#define FLOAT_TYPE_SIZE BITS_PER_WORD
|
8471 |
|
|
#endif
|
8472 |
|
|
|
8473 |
|
|
#ifndef DOUBLE_TYPE_SIZE
|
8474 |
|
|
#define DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
|
8475 |
|
|
#endif
|
8476 |
|
|
|
8477 |
|
|
#ifndef LONG_DOUBLE_TYPE_SIZE
|
8478 |
|
|
#define LONG_DOUBLE_TYPE_SIZE (BITS_PER_WORD * 2)
|
8479 |
|
|
#endif
|
8480 |
|
|
|
8481 |
|
|
unsigned long
|
8482 |
|
|
sparc_type_code (register tree type)
|
8483 |
|
|
{
|
8484 |
|
|
register unsigned long qualifiers = 0;
|
8485 |
|
|
register unsigned shift;
|
8486 |
|
|
|
8487 |
|
|
/* Only the first 30 bits of the qualifier are valid. We must refrain from
|
8488 |
|
|
setting more, since some assemblers will give an error for this. Also,
|
8489 |
|
|
we must be careful to avoid shifts of 32 bits or more to avoid getting
|
8490 |
|
|
unpredictable results. */
|
8491 |
|
|
|
8492 |
|
|
for (shift = 6; shift < 30; shift += 2, type = TREE_TYPE (type))
|
8493 |
|
|
{
|
8494 |
|
|
switch (TREE_CODE (type))
|
8495 |
|
|
{
|
8496 |
|
|
case ERROR_MARK:
|
8497 |
|
|
return qualifiers;
|
8498 |
|
|
|
8499 |
|
|
case ARRAY_TYPE:
|
8500 |
|
|
qualifiers |= (3 << shift);
|
8501 |
|
|
break;
|
8502 |
|
|
|
8503 |
|
|
case FUNCTION_TYPE:
|
8504 |
|
|
case METHOD_TYPE:
|
8505 |
|
|
qualifiers |= (2 << shift);
|
8506 |
|
|
break;
|
8507 |
|
|
|
8508 |
|
|
case POINTER_TYPE:
|
8509 |
|
|
case REFERENCE_TYPE:
|
8510 |
|
|
case OFFSET_TYPE:
|
8511 |
|
|
qualifiers |= (1 << shift);
|
8512 |
|
|
break;
|
8513 |
|
|
|
8514 |
|
|
case RECORD_TYPE:
|
8515 |
|
|
return (qualifiers | 8);
|
8516 |
|
|
|
8517 |
|
|
case UNION_TYPE:
|
8518 |
|
|
case QUAL_UNION_TYPE:
|
8519 |
|
|
return (qualifiers | 9);
|
8520 |
|
|
|
8521 |
|
|
case ENUMERAL_TYPE:
|
8522 |
|
|
return (qualifiers | 10);
|
8523 |
|
|
|
8524 |
|
|
case VOID_TYPE:
|
8525 |
|
|
return (qualifiers | 16);
|
8526 |
|
|
|
8527 |
|
|
case INTEGER_TYPE:
|
8528 |
|
|
/* If this is a range type, consider it to be the underlying
|
8529 |
|
|
type. */
|
8530 |
|
|
if (TREE_TYPE (type) != 0)
|
8531 |
|
|
break;
|
8532 |
|
|
|
8533 |
|
|
/* Carefully distinguish all the standard types of C,
|
8534 |
|
|
without messing up if the language is not C. We do this by
|
8535 |
|
|
testing TYPE_PRECISION and TYPE_UNSIGNED. The old code used to
|
8536 |
|
|
look at both the names and the above fields, but that's redundant.
|
8537 |
|
|
Any type whose size is between two C types will be considered
|
8538 |
|
|
to be the wider of the two types. Also, we do not have a
|
8539 |
|
|
special code to use for "long long", so anything wider than
|
8540 |
|
|
long is treated the same. Note that we can't distinguish
|
8541 |
|
|
between "int" and "long" in this code if they are the same
|
8542 |
|
|
size, but that's fine, since neither can the assembler. */
|
8543 |
|
|
|
8544 |
|
|
if (TYPE_PRECISION (type) <= CHAR_TYPE_SIZE)
|
8545 |
|
|
return (qualifiers | (TYPE_UNSIGNED (type) ? 12 : 2));
|
8546 |
|
|
|
8547 |
|
|
else if (TYPE_PRECISION (type) <= SHORT_TYPE_SIZE)
|
8548 |
|
|
return (qualifiers | (TYPE_UNSIGNED (type) ? 13 : 3));
|
8549 |
|
|
|
8550 |
|
|
else if (TYPE_PRECISION (type) <= INT_TYPE_SIZE)
|
8551 |
|
|
return (qualifiers | (TYPE_UNSIGNED (type) ? 14 : 4));
|
8552 |
|
|
|
8553 |
|
|
else
|
8554 |
|
|
return (qualifiers | (TYPE_UNSIGNED (type) ? 15 : 5));
|
8555 |
|
|
|
8556 |
|
|
case REAL_TYPE:
|
8557 |
|
|
/* If this is a range type, consider it to be the underlying
|
8558 |
|
|
type. */
|
8559 |
|
|
if (TREE_TYPE (type) != 0)
|
8560 |
|
|
break;
|
8561 |
|
|
|
8562 |
|
|
/* Carefully distinguish all the standard types of C,
|
8563 |
|
|
without messing up if the language is not C. */
|
8564 |
|
|
|
8565 |
|
|
if (TYPE_PRECISION (type) == FLOAT_TYPE_SIZE)
|
8566 |
|
|
return (qualifiers | 6);
|
8567 |
|
|
|
8568 |
|
|
else
|
8569 |
|
|
return (qualifiers | 7);
|
8570 |
|
|
|
8571 |
|
|
case COMPLEX_TYPE: /* GNU Fortran COMPLEX type. */
|
8572 |
|
|
/* ??? We need to distinguish between double and float complex types,
|
8573 |
|
|
but I don't know how yet because I can't reach this code from
|
8574 |
|
|
existing front-ends. */
|
8575 |
|
|
return (qualifiers | 7); /* Who knows? */
|
8576 |
|
|
|
8577 |
|
|
case VECTOR_TYPE:
|
8578 |
|
|
case BOOLEAN_TYPE: /* Boolean truth value type. */
|
8579 |
|
|
case LANG_TYPE:
|
8580 |
|
|
case NULLPTR_TYPE:
|
8581 |
|
|
return qualifiers;
|
8582 |
|
|
|
8583 |
|
|
default:
|
8584 |
|
|
gcc_unreachable (); /* Not a type! */
|
8585 |
|
|
}
|
8586 |
|
|
}
|
8587 |
|
|
|
8588 |
|
|
return qualifiers;
|
8589 |
|
|
}
|
8590 |
|
|
|
8591 |
|
|
/* Nested function support. */
|
8592 |
|
|
|
8593 |
|
|
/* Emit RTL insns to initialize the variable parts of a trampoline.
|
8594 |
|
|
FNADDR is an RTX for the address of the function's pure code.
|
8595 |
|
|
CXT is an RTX for the static chain value for the function.
|
8596 |
|
|
|
8597 |
|
|
This takes 16 insns: 2 shifts & 2 ands (to split up addresses), 4 sethi
|
8598 |
|
|
(to load in opcodes), 4 iors (to merge address and opcodes), and 4 writes
|
8599 |
|
|
(to store insns). This is a bit excessive. Perhaps a different
|
8600 |
|
|
mechanism would be better here.
|
8601 |
|
|
|
8602 |
|
|
Emit enough FLUSH insns to synchronize the data and instruction caches. */
|
8603 |
|
|
|
8604 |
|
|
static void
|
8605 |
|
|
sparc32_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
|
8606 |
|
|
{
|
8607 |
|
|
/* SPARC 32-bit trampoline:
|
8608 |
|
|
|
8609 |
|
|
sethi %hi(fn), %g1
|
8610 |
|
|
sethi %hi(static), %g2
|
8611 |
|
|
jmp %g1+%lo(fn)
|
8612 |
|
|
or %g2, %lo(static), %g2
|
8613 |
|
|
|
8614 |
|
|
SETHI i,r = 00rr rrr1 00ii iiii iiii iiii iiii iiii
|
8615 |
|
|
JMPL r+i,d = 10dd ddd1 1100 0rrr rr1i iiii iiii iiii
|
8616 |
|
|
*/
|
8617 |
|
|
|
8618 |
|
|
emit_move_insn
|
8619 |
|
|
(adjust_address (m_tramp, SImode, 0),
|
8620 |
|
|
expand_binop (SImode, ior_optab,
|
8621 |
|
|
expand_shift (RSHIFT_EXPR, SImode, fnaddr, 10, 0, 1),
|
8622 |
|
|
GEN_INT (trunc_int_for_mode (0x03000000, SImode)),
|
8623 |
|
|
NULL_RTX, 1, OPTAB_DIRECT));
|
8624 |
|
|
|
8625 |
|
|
emit_move_insn
|
8626 |
|
|
(adjust_address (m_tramp, SImode, 4),
|
8627 |
|
|
expand_binop (SImode, ior_optab,
|
8628 |
|
|
expand_shift (RSHIFT_EXPR, SImode, cxt, 10, 0, 1),
|
8629 |
|
|
GEN_INT (trunc_int_for_mode (0x05000000, SImode)),
|
8630 |
|
|
NULL_RTX, 1, OPTAB_DIRECT));
|
8631 |
|
|
|
8632 |
|
|
emit_move_insn
|
8633 |
|
|
(adjust_address (m_tramp, SImode, 8),
|
8634 |
|
|
expand_binop (SImode, ior_optab,
|
8635 |
|
|
expand_and (SImode, fnaddr, GEN_INT (0x3ff), NULL_RTX),
|
8636 |
|
|
GEN_INT (trunc_int_for_mode (0x81c06000, SImode)),
|
8637 |
|
|
NULL_RTX, 1, OPTAB_DIRECT));
|
8638 |
|
|
|
8639 |
|
|
emit_move_insn
|
8640 |
|
|
(adjust_address (m_tramp, SImode, 12),
|
8641 |
|
|
expand_binop (SImode, ior_optab,
|
8642 |
|
|
expand_and (SImode, cxt, GEN_INT (0x3ff), NULL_RTX),
|
8643 |
|
|
GEN_INT (trunc_int_for_mode (0x8410a000, SImode)),
|
8644 |
|
|
NULL_RTX, 1, OPTAB_DIRECT));
|
8645 |
|
|
|
8646 |
|
|
/* On UltraSPARC a flush flushes an entire cache line. The trampoline is
|
8647 |
|
|
aligned on a 16 byte boundary so one flush clears it all. */
|
8648 |
|
|
emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 0))));
|
8649 |
|
|
if (sparc_cpu != PROCESSOR_ULTRASPARC
|
8650 |
|
|
&& sparc_cpu != PROCESSOR_ULTRASPARC3
|
8651 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA
|
8652 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA2
|
8653 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA3
|
8654 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA4)
|
8655 |
|
|
emit_insn (gen_flush (validize_mem (adjust_address (m_tramp, SImode, 8))));
|
8656 |
|
|
|
8657 |
|
|
/* Call __enable_execute_stack after writing onto the stack to make sure
|
8658 |
|
|
the stack address is accessible. */
|
8659 |
|
|
#ifdef HAVE_ENABLE_EXECUTE_STACK
|
8660 |
|
|
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
|
8661 |
|
|
LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
|
8662 |
|
|
#endif
|
8663 |
|
|
|
8664 |
|
|
}
|
8665 |
|
|
|
8666 |
|
|
/* The 64-bit version is simpler because it makes more sense to load the
|
8667 |
|
|
values as "immediate" data out of the trampoline. It's also easier since
|
8668 |
|
|
we can read the PC without clobbering a register. */
|
8669 |
|
|
|
8670 |
|
|
static void
|
8671 |
|
|
sparc64_initialize_trampoline (rtx m_tramp, rtx fnaddr, rtx cxt)
|
8672 |
|
|
{
|
8673 |
|
|
/* SPARC 64-bit trampoline:
|
8674 |
|
|
|
8675 |
|
|
rd %pc, %g1
|
8676 |
|
|
ldx [%g1+24], %g5
|
8677 |
|
|
jmp %g5
|
8678 |
|
|
ldx [%g1+16], %g5
|
8679 |
|
|
+16 bytes data
|
8680 |
|
|
*/
|
8681 |
|
|
|
8682 |
|
|
emit_move_insn (adjust_address (m_tramp, SImode, 0),
|
8683 |
|
|
GEN_INT (trunc_int_for_mode (0x83414000, SImode)));
|
8684 |
|
|
emit_move_insn (adjust_address (m_tramp, SImode, 4),
|
8685 |
|
|
GEN_INT (trunc_int_for_mode (0xca586018, SImode)));
|
8686 |
|
|
emit_move_insn (adjust_address (m_tramp, SImode, 8),
|
8687 |
|
|
GEN_INT (trunc_int_for_mode (0x81c14000, SImode)));
|
8688 |
|
|
emit_move_insn (adjust_address (m_tramp, SImode, 12),
|
8689 |
|
|
GEN_INT (trunc_int_for_mode (0xca586010, SImode)));
|
8690 |
|
|
emit_move_insn (adjust_address (m_tramp, DImode, 16), cxt);
|
8691 |
|
|
emit_move_insn (adjust_address (m_tramp, DImode, 24), fnaddr);
|
8692 |
|
|
emit_insn (gen_flushdi (validize_mem (adjust_address (m_tramp, DImode, 0))));
|
8693 |
|
|
|
8694 |
|
|
if (sparc_cpu != PROCESSOR_ULTRASPARC
|
8695 |
|
|
&& sparc_cpu != PROCESSOR_ULTRASPARC3
|
8696 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA
|
8697 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA2
|
8698 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA3
|
8699 |
|
|
&& sparc_cpu != PROCESSOR_NIAGARA4)
|
8700 |
|
|
emit_insn (gen_flushdi (validize_mem (adjust_address (m_tramp, DImode, 8))));
|
8701 |
|
|
|
8702 |
|
|
/* Call __enable_execute_stack after writing onto the stack to make sure
|
8703 |
|
|
the stack address is accessible. */
|
8704 |
|
|
#ifdef HAVE_ENABLE_EXECUTE_STACK
|
8705 |
|
|
emit_library_call (gen_rtx_SYMBOL_REF (Pmode, "__enable_execute_stack"),
|
8706 |
|
|
LCT_NORMAL, VOIDmode, 1, XEXP (m_tramp, 0), Pmode);
|
8707 |
|
|
#endif
|
8708 |
|
|
}
|
8709 |
|
|
|
8710 |
|
|
/* Worker for TARGET_TRAMPOLINE_INIT. */
|
8711 |
|
|
|
8712 |
|
|
static void
|
8713 |
|
|
sparc_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt)
|
8714 |
|
|
{
|
8715 |
|
|
rtx fnaddr = force_reg (Pmode, XEXP (DECL_RTL (fndecl), 0));
|
8716 |
|
|
cxt = force_reg (Pmode, cxt);
|
8717 |
|
|
if (TARGET_ARCH64)
|
8718 |
|
|
sparc64_initialize_trampoline (m_tramp, fnaddr, cxt);
|
8719 |
|
|
else
|
8720 |
|
|
sparc32_initialize_trampoline (m_tramp, fnaddr, cxt);
|
8721 |
|
|
}
|
8722 |
|
|
|
8723 |
|
|
/* Adjust the cost of a scheduling dependency. Return the new cost of
|
8724 |
|
|
a dependency LINK or INSN on DEP_INSN. COST is the current cost. */
|
8725 |
|
|
|
8726 |
|
|
static int
|
8727 |
|
|
supersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
|
8728 |
|
|
{
|
8729 |
|
|
enum attr_type insn_type;
|
8730 |
|
|
|
8731 |
|
|
if (! recog_memoized (insn))
|
8732 |
|
|
return 0;
|
8733 |
|
|
|
8734 |
|
|
insn_type = get_attr_type (insn);
|
8735 |
|
|
|
8736 |
|
|
if (REG_NOTE_KIND (link) == 0)
|
8737 |
|
|
{
|
8738 |
|
|
/* Data dependency; DEP_INSN writes a register that INSN reads some
|
8739 |
|
|
cycles later. */
|
8740 |
|
|
|
8741 |
|
|
/* if a load, then the dependence must be on the memory address;
|
8742 |
|
|
add an extra "cycle". Note that the cost could be two cycles
|
8743 |
|
|
if the reg was written late in an instruction group; we ca not tell
|
8744 |
|
|
here. */
|
8745 |
|
|
if (insn_type == TYPE_LOAD || insn_type == TYPE_FPLOAD)
|
8746 |
|
|
return cost + 3;
|
8747 |
|
|
|
8748 |
|
|
/* Get the delay only if the address of the store is the dependence. */
|
8749 |
|
|
if (insn_type == TYPE_STORE || insn_type == TYPE_FPSTORE)
|
8750 |
|
|
{
|
8751 |
|
|
rtx pat = PATTERN(insn);
|
8752 |
|
|
rtx dep_pat = PATTERN (dep_insn);
|
8753 |
|
|
|
8754 |
|
|
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
|
8755 |
|
|
return cost; /* This should not happen! */
|
8756 |
|
|
|
8757 |
|
|
/* The dependency between the two instructions was on the data that
|
8758 |
|
|
is being stored. Assume that this implies that the address of the
|
8759 |
|
|
store is not dependent. */
|
8760 |
|
|
if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
|
8761 |
|
|
return cost;
|
8762 |
|
|
|
8763 |
|
|
return cost + 3; /* An approximation. */
|
8764 |
|
|
}
|
8765 |
|
|
|
8766 |
|
|
/* A shift instruction cannot receive its data from an instruction
|
8767 |
|
|
in the same cycle; add a one cycle penalty. */
|
8768 |
|
|
if (insn_type == TYPE_SHIFT)
|
8769 |
|
|
return cost + 3; /* Split before cascade into shift. */
|
8770 |
|
|
}
|
8771 |
|
|
else
|
8772 |
|
|
{
|
8773 |
|
|
/* Anti- or output- dependency; DEP_INSN reads/writes a register that
|
8774 |
|
|
INSN writes some cycles later. */
|
8775 |
|
|
|
8776 |
|
|
/* These are only significant for the fpu unit; writing a fp reg before
|
8777 |
|
|
the fpu has finished with it stalls the processor. */
|
8778 |
|
|
|
8779 |
|
|
/* Reusing an integer register causes no problems. */
|
8780 |
|
|
if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT)
|
8781 |
|
|
return 0;
|
8782 |
|
|
}
|
8783 |
|
|
|
8784 |
|
|
return cost;
|
8785 |
|
|
}
|
8786 |
|
|
|
8787 |
|
|
static int
|
8788 |
|
|
hypersparc_adjust_cost (rtx insn, rtx link, rtx dep_insn, int cost)
|
8789 |
|
|
{
|
8790 |
|
|
enum attr_type insn_type, dep_type;
|
8791 |
|
|
rtx pat = PATTERN(insn);
|
8792 |
|
|
rtx dep_pat = PATTERN (dep_insn);
|
8793 |
|
|
|
8794 |
|
|
if (recog_memoized (insn) < 0 || recog_memoized (dep_insn) < 0)
|
8795 |
|
|
return cost;
|
8796 |
|
|
|
8797 |
|
|
insn_type = get_attr_type (insn);
|
8798 |
|
|
dep_type = get_attr_type (dep_insn);
|
8799 |
|
|
|
8800 |
|
|
switch (REG_NOTE_KIND (link))
|
8801 |
|
|
{
|
8802 |
|
|
case 0:
|
8803 |
|
|
/* Data dependency; DEP_INSN writes a register that INSN reads some
|
8804 |
|
|
cycles later. */
|
8805 |
|
|
|
8806 |
|
|
switch (insn_type)
|
8807 |
|
|
{
|
8808 |
|
|
case TYPE_STORE:
|
8809 |
|
|
case TYPE_FPSTORE:
|
8810 |
|
|
/* Get the delay iff the address of the store is the dependence. */
|
8811 |
|
|
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET)
|
8812 |
|
|
return cost;
|
8813 |
|
|
|
8814 |
|
|
if (rtx_equal_p (SET_DEST (dep_pat), SET_SRC (pat)))
|
8815 |
|
|
return cost;
|
8816 |
|
|
return cost + 3;
|
8817 |
|
|
|
8818 |
|
|
case TYPE_LOAD:
|
8819 |
|
|
case TYPE_SLOAD:
|
8820 |
|
|
case TYPE_FPLOAD:
|
8821 |
|
|
/* If a load, then the dependence must be on the memory address. If
|
8822 |
|
|
the addresses aren't equal, then it might be a false dependency */
|
8823 |
|
|
if (dep_type == TYPE_STORE || dep_type == TYPE_FPSTORE)
|
8824 |
|
|
{
|
8825 |
|
|
if (GET_CODE (pat) != SET || GET_CODE (dep_pat) != SET
|
8826 |
|
|
|| GET_CODE (SET_DEST (dep_pat)) != MEM
|
8827 |
|
|
|| GET_CODE (SET_SRC (pat)) != MEM
|
8828 |
|
|
|| ! rtx_equal_p (XEXP (SET_DEST (dep_pat), 0),
|
8829 |
|
|
XEXP (SET_SRC (pat), 0)))
|
8830 |
|
|
return cost + 2;
|
8831 |
|
|
|
8832 |
|
|
return cost + 8;
|
8833 |
|
|
}
|
8834 |
|
|
break;
|
8835 |
|
|
|
8836 |
|
|
case TYPE_BRANCH:
|
8837 |
|
|
/* Compare to branch latency is 0. There is no benefit from
|
8838 |
|
|
separating compare and branch. */
|
8839 |
|
|
if (dep_type == TYPE_COMPARE)
|
8840 |
|
|
return 0;
|
8841 |
|
|
/* Floating point compare to branch latency is less than
|
8842 |
|
|
compare to conditional move. */
|
8843 |
|
|
if (dep_type == TYPE_FPCMP)
|
8844 |
|
|
return cost - 1;
|
8845 |
|
|
break;
|
8846 |
|
|
default:
|
8847 |
|
|
break;
|
8848 |
|
|
}
|
8849 |
|
|
break;
|
8850 |
|
|
|
8851 |
|
|
case REG_DEP_ANTI:
|
8852 |
|
|
/* Anti-dependencies only penalize the fpu unit. */
|
8853 |
|
|
if (insn_type == TYPE_IALU || insn_type == TYPE_SHIFT)
|
8854 |
|
|
return 0;
|
8855 |
|
|
break;
|
8856 |
|
|
|
8857 |
|
|
default:
|
8858 |
|
|
break;
|
8859 |
|
|
}
|
8860 |
|
|
|
8861 |
|
|
return cost;
|
8862 |
|
|
}
|
8863 |
|
|
|
8864 |
|
|
static int
|
8865 |
|
|
sparc_adjust_cost(rtx insn, rtx link, rtx dep, int cost)
|
8866 |
|
|
{
|
8867 |
|
|
switch (sparc_cpu)
|
8868 |
|
|
{
|
8869 |
|
|
case PROCESSOR_SUPERSPARC:
|
8870 |
|
|
cost = supersparc_adjust_cost (insn, link, dep, cost);
|
8871 |
|
|
break;
|
8872 |
|
|
case PROCESSOR_HYPERSPARC:
|
8873 |
|
|
case PROCESSOR_SPARCLITE86X:
|
8874 |
|
|
cost = hypersparc_adjust_cost (insn, link, dep, cost);
|
8875 |
|
|
break;
|
8876 |
|
|
default:
|
8877 |
|
|
break;
|
8878 |
|
|
}
|
8879 |
|
|
return cost;
|
8880 |
|
|
}
|
8881 |
|
|
|
8882 |
|
|
static void
|
8883 |
|
|
sparc_sched_init (FILE *dump ATTRIBUTE_UNUSED,
|
8884 |
|
|
int sched_verbose ATTRIBUTE_UNUSED,
|
8885 |
|
|
int max_ready ATTRIBUTE_UNUSED)
|
8886 |
|
|
{}
|
8887 |
|
|
|
8888 |
|
|
static int
|
8889 |
|
|
sparc_use_sched_lookahead (void)
|
8890 |
|
|
{
|
8891 |
|
|
if (sparc_cpu == PROCESSOR_NIAGARA
|
8892 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA2
|
8893 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA3
|
8894 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA4)
|
8895 |
|
|
return 0;
|
8896 |
|
|
if (sparc_cpu == PROCESSOR_ULTRASPARC
|
8897 |
|
|
|| sparc_cpu == PROCESSOR_ULTRASPARC3)
|
8898 |
|
|
return 4;
|
8899 |
|
|
if ((1 << sparc_cpu) &
|
8900 |
|
|
((1 << PROCESSOR_SUPERSPARC) | (1 << PROCESSOR_HYPERSPARC) |
|
8901 |
|
|
(1 << PROCESSOR_SPARCLITE86X)))
|
8902 |
|
|
return 3;
|
8903 |
|
|
return 0;
|
8904 |
|
|
}
|
8905 |
|
|
|
8906 |
|
|
static int
|
8907 |
|
|
sparc_issue_rate (void)
|
8908 |
|
|
{
|
8909 |
|
|
switch (sparc_cpu)
|
8910 |
|
|
{
|
8911 |
|
|
case PROCESSOR_NIAGARA:
|
8912 |
|
|
case PROCESSOR_NIAGARA2:
|
8913 |
|
|
case PROCESSOR_NIAGARA3:
|
8914 |
|
|
case PROCESSOR_NIAGARA4:
|
8915 |
|
|
default:
|
8916 |
|
|
return 1;
|
8917 |
|
|
case PROCESSOR_V9:
|
8918 |
|
|
/* Assume V9 processors are capable of at least dual-issue. */
|
8919 |
|
|
return 2;
|
8920 |
|
|
case PROCESSOR_SUPERSPARC:
|
8921 |
|
|
return 3;
|
8922 |
|
|
case PROCESSOR_HYPERSPARC:
|
8923 |
|
|
case PROCESSOR_SPARCLITE86X:
|
8924 |
|
|
return 2;
|
8925 |
|
|
case PROCESSOR_ULTRASPARC:
|
8926 |
|
|
case PROCESSOR_ULTRASPARC3:
|
8927 |
|
|
return 4;
|
8928 |
|
|
}
|
8929 |
|
|
}
|
8930 |
|
|
|
8931 |
|
|
static int
|
8932 |
|
|
set_extends (rtx insn)
|
8933 |
|
|
{
|
8934 |
|
|
register rtx pat = PATTERN (insn);
|
8935 |
|
|
|
8936 |
|
|
switch (GET_CODE (SET_SRC (pat)))
|
8937 |
|
|
{
|
8938 |
|
|
/* Load and some shift instructions zero extend. */
|
8939 |
|
|
case MEM:
|
8940 |
|
|
case ZERO_EXTEND:
|
8941 |
|
|
/* sethi clears the high bits */
|
8942 |
|
|
case HIGH:
|
8943 |
|
|
/* LO_SUM is used with sethi. sethi cleared the high
|
8944 |
|
|
bits and the values used with lo_sum are positive */
|
8945 |
|
|
case LO_SUM:
|
8946 |
|
|
/* Store flag stores 0 or 1 */
|
8947 |
|
|
case LT: case LTU:
|
8948 |
|
|
case GT: case GTU:
|
8949 |
|
|
case LE: case LEU:
|
8950 |
|
|
case GE: case GEU:
|
8951 |
|
|
case EQ:
|
8952 |
|
|
case NE:
|
8953 |
|
|
return 1;
|
8954 |
|
|
case AND:
|
8955 |
|
|
{
|
8956 |
|
|
rtx op0 = XEXP (SET_SRC (pat), 0);
|
8957 |
|
|
rtx op1 = XEXP (SET_SRC (pat), 1);
|
8958 |
|
|
if (GET_CODE (op1) == CONST_INT)
|
8959 |
|
|
return INTVAL (op1) >= 0;
|
8960 |
|
|
if (GET_CODE (op0) != REG)
|
8961 |
|
|
return 0;
|
8962 |
|
|
if (sparc_check_64 (op0, insn) == 1)
|
8963 |
|
|
return 1;
|
8964 |
|
|
return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
|
8965 |
|
|
}
|
8966 |
|
|
case IOR:
|
8967 |
|
|
case XOR:
|
8968 |
|
|
{
|
8969 |
|
|
rtx op0 = XEXP (SET_SRC (pat), 0);
|
8970 |
|
|
rtx op1 = XEXP (SET_SRC (pat), 1);
|
8971 |
|
|
if (GET_CODE (op0) != REG || sparc_check_64 (op0, insn) <= 0)
|
8972 |
|
|
return 0;
|
8973 |
|
|
if (GET_CODE (op1) == CONST_INT)
|
8974 |
|
|
return INTVAL (op1) >= 0;
|
8975 |
|
|
return (GET_CODE (op1) == REG && sparc_check_64 (op1, insn) == 1);
|
8976 |
|
|
}
|
8977 |
|
|
case LSHIFTRT:
|
8978 |
|
|
return GET_MODE (SET_SRC (pat)) == SImode;
|
8979 |
|
|
/* Positive integers leave the high bits zero. */
|
8980 |
|
|
case CONST_DOUBLE:
|
8981 |
|
|
return ! (CONST_DOUBLE_LOW (SET_SRC (pat)) & 0x80000000);
|
8982 |
|
|
case CONST_INT:
|
8983 |
|
|
return ! (INTVAL (SET_SRC (pat)) & 0x80000000);
|
8984 |
|
|
case ASHIFTRT:
|
8985 |
|
|
case SIGN_EXTEND:
|
8986 |
|
|
return - (GET_MODE (SET_SRC (pat)) == SImode);
|
8987 |
|
|
case REG:
|
8988 |
|
|
return sparc_check_64 (SET_SRC (pat), insn);
|
8989 |
|
|
default:
|
8990 |
|
|
return 0;
|
8991 |
|
|
}
|
8992 |
|
|
}
|
8993 |
|
|
|
8994 |
|
|
/* We _ought_ to have only one kind per function, but... */
|
8995 |
|
|
static GTY(()) rtx sparc_addr_diff_list;
|
8996 |
|
|
static GTY(()) rtx sparc_addr_list;
|
8997 |
|
|
|
8998 |
|
|
void
|
8999 |
|
|
sparc_defer_case_vector (rtx lab, rtx vec, int diff)
|
9000 |
|
|
{
|
9001 |
|
|
vec = gen_rtx_EXPR_LIST (VOIDmode, lab, vec);
|
9002 |
|
|
if (diff)
|
9003 |
|
|
sparc_addr_diff_list
|
9004 |
|
|
= gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_diff_list);
|
9005 |
|
|
else
|
9006 |
|
|
sparc_addr_list = gen_rtx_EXPR_LIST (VOIDmode, vec, sparc_addr_list);
|
9007 |
|
|
}
|
9008 |
|
|
|
9009 |
|
|
static void
|
9010 |
|
|
sparc_output_addr_vec (rtx vec)
|
9011 |
|
|
{
|
9012 |
|
|
rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
|
9013 |
|
|
int idx, vlen = XVECLEN (body, 0);
|
9014 |
|
|
|
9015 |
|
|
#ifdef ASM_OUTPUT_ADDR_VEC_START
|
9016 |
|
|
ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
|
9017 |
|
|
#endif
|
9018 |
|
|
|
9019 |
|
|
#ifdef ASM_OUTPUT_CASE_LABEL
|
9020 |
|
|
ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
|
9021 |
|
|
NEXT_INSN (lab));
|
9022 |
|
|
#else
|
9023 |
|
|
(*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
|
9024 |
|
|
#endif
|
9025 |
|
|
|
9026 |
|
|
for (idx = 0; idx < vlen; idx++)
|
9027 |
|
|
{
|
9028 |
|
|
ASM_OUTPUT_ADDR_VEC_ELT
|
9029 |
|
|
(asm_out_file, CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 0, idx), 0)));
|
9030 |
|
|
}
|
9031 |
|
|
|
9032 |
|
|
#ifdef ASM_OUTPUT_ADDR_VEC_END
|
9033 |
|
|
ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
|
9034 |
|
|
#endif
|
9035 |
|
|
}
|
9036 |
|
|
|
9037 |
|
|
static void
|
9038 |
|
|
sparc_output_addr_diff_vec (rtx vec)
|
9039 |
|
|
{
|
9040 |
|
|
rtx lab = XEXP (vec, 0), body = XEXP (vec, 1);
|
9041 |
|
|
rtx base = XEXP (XEXP (body, 0), 0);
|
9042 |
|
|
int idx, vlen = XVECLEN (body, 1);
|
9043 |
|
|
|
9044 |
|
|
#ifdef ASM_OUTPUT_ADDR_VEC_START
|
9045 |
|
|
ASM_OUTPUT_ADDR_VEC_START (asm_out_file);
|
9046 |
|
|
#endif
|
9047 |
|
|
|
9048 |
|
|
#ifdef ASM_OUTPUT_CASE_LABEL
|
9049 |
|
|
ASM_OUTPUT_CASE_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (lab),
|
9050 |
|
|
NEXT_INSN (lab));
|
9051 |
|
|
#else
|
9052 |
|
|
(*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (lab));
|
9053 |
|
|
#endif
|
9054 |
|
|
|
9055 |
|
|
for (idx = 0; idx < vlen; idx++)
|
9056 |
|
|
{
|
9057 |
|
|
ASM_OUTPUT_ADDR_DIFF_ELT
|
9058 |
|
|
(asm_out_file,
|
9059 |
|
|
body,
|
9060 |
|
|
CODE_LABEL_NUMBER (XEXP (XVECEXP (body, 1, idx), 0)),
|
9061 |
|
|
CODE_LABEL_NUMBER (base));
|
9062 |
|
|
}
|
9063 |
|
|
|
9064 |
|
|
#ifdef ASM_OUTPUT_ADDR_VEC_END
|
9065 |
|
|
ASM_OUTPUT_ADDR_VEC_END (asm_out_file);
|
9066 |
|
|
#endif
|
9067 |
|
|
}
|
9068 |
|
|
|
9069 |
|
|
static void
|
9070 |
|
|
sparc_output_deferred_case_vectors (void)
|
9071 |
|
|
{
|
9072 |
|
|
rtx t;
|
9073 |
|
|
int align;
|
9074 |
|
|
|
9075 |
|
|
if (sparc_addr_list == NULL_RTX
|
9076 |
|
|
&& sparc_addr_diff_list == NULL_RTX)
|
9077 |
|
|
return;
|
9078 |
|
|
|
9079 |
|
|
/* Align to cache line in the function's code section. */
|
9080 |
|
|
switch_to_section (current_function_section ());
|
9081 |
|
|
|
9082 |
|
|
align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
|
9083 |
|
|
if (align > 0)
|
9084 |
|
|
ASM_OUTPUT_ALIGN (asm_out_file, align);
|
9085 |
|
|
|
9086 |
|
|
for (t = sparc_addr_list; t ; t = XEXP (t, 1))
|
9087 |
|
|
sparc_output_addr_vec (XEXP (t, 0));
|
9088 |
|
|
for (t = sparc_addr_diff_list; t ; t = XEXP (t, 1))
|
9089 |
|
|
sparc_output_addr_diff_vec (XEXP (t, 0));
|
9090 |
|
|
|
9091 |
|
|
sparc_addr_list = sparc_addr_diff_list = NULL_RTX;
|
9092 |
|
|
}
|
9093 |
|
|
|
9094 |
|
|
/* Return 0 if the high 32 bits of X (the low word of X, if DImode) are
|
9095 |
|
|
unknown. Return 1 if the high bits are zero, -1 if the register is
|
9096 |
|
|
sign extended. */
|
9097 |
|
|
int
|
9098 |
|
|
sparc_check_64 (rtx x, rtx insn)
|
9099 |
|
|
{
|
9100 |
|
|
/* If a register is set only once it is safe to ignore insns this
|
9101 |
|
|
code does not know how to handle. The loop will either recognize
|
9102 |
|
|
the single set and return the correct value or fail to recognize
|
9103 |
|
|
it and return 0. */
|
9104 |
|
|
int set_once = 0;
|
9105 |
|
|
rtx y = x;
|
9106 |
|
|
|
9107 |
|
|
gcc_assert (GET_CODE (x) == REG);
|
9108 |
|
|
|
9109 |
|
|
if (GET_MODE (x) == DImode)
|
9110 |
|
|
y = gen_rtx_REG (SImode, REGNO (x) + WORDS_BIG_ENDIAN);
|
9111 |
|
|
|
9112 |
|
|
if (flag_expensive_optimizations
|
9113 |
|
|
&& df && DF_REG_DEF_COUNT (REGNO (y)) == 1)
|
9114 |
|
|
set_once = 1;
|
9115 |
|
|
|
9116 |
|
|
if (insn == 0)
|
9117 |
|
|
{
|
9118 |
|
|
if (set_once)
|
9119 |
|
|
insn = get_last_insn_anywhere ();
|
9120 |
|
|
else
|
9121 |
|
|
return 0;
|
9122 |
|
|
}
|
9123 |
|
|
|
9124 |
|
|
while ((insn = PREV_INSN (insn)))
|
9125 |
|
|
{
|
9126 |
|
|
switch (GET_CODE (insn))
|
9127 |
|
|
{
|
9128 |
|
|
case JUMP_INSN:
|
9129 |
|
|
case NOTE:
|
9130 |
|
|
break;
|
9131 |
|
|
case CODE_LABEL:
|
9132 |
|
|
case CALL_INSN:
|
9133 |
|
|
default:
|
9134 |
|
|
if (! set_once)
|
9135 |
|
|
return 0;
|
9136 |
|
|
break;
|
9137 |
|
|
case INSN:
|
9138 |
|
|
{
|
9139 |
|
|
rtx pat = PATTERN (insn);
|
9140 |
|
|
if (GET_CODE (pat) != SET)
|
9141 |
|
|
return 0;
|
9142 |
|
|
if (rtx_equal_p (x, SET_DEST (pat)))
|
9143 |
|
|
return set_extends (insn);
|
9144 |
|
|
if (y && rtx_equal_p (y, SET_DEST (pat)))
|
9145 |
|
|
return set_extends (insn);
|
9146 |
|
|
if (reg_overlap_mentioned_p (SET_DEST (pat), y))
|
9147 |
|
|
return 0;
|
9148 |
|
|
}
|
9149 |
|
|
}
|
9150 |
|
|
}
|
9151 |
|
|
return 0;
|
9152 |
|
|
}
|
9153 |
|
|
|
9154 |
|
|
/* Output a wide shift instruction in V8+ mode. INSN is the instruction,
|
9155 |
|
|
OPERANDS are its operands and OPCODE is the mnemonic to be used. */
|
9156 |
|
|
|
9157 |
|
|
const char *
|
9158 |
|
|
output_v8plus_shift (rtx insn, rtx *operands, const char *opcode)
|
9159 |
|
|
{
|
9160 |
|
|
static char asm_code[60];
|
9161 |
|
|
|
9162 |
|
|
/* The scratch register is only required when the destination
|
9163 |
|
|
register is not a 64-bit global or out register. */
|
9164 |
|
|
if (which_alternative != 2)
|
9165 |
|
|
operands[3] = operands[0];
|
9166 |
|
|
|
9167 |
|
|
/* We can only shift by constants <= 63. */
|
9168 |
|
|
if (GET_CODE (operands[2]) == CONST_INT)
|
9169 |
|
|
operands[2] = GEN_INT (INTVAL (operands[2]) & 0x3f);
|
9170 |
|
|
|
9171 |
|
|
if (GET_CODE (operands[1]) == CONST_INT)
|
9172 |
|
|
{
|
9173 |
|
|
output_asm_insn ("mov\t%1, %3", operands);
|
9174 |
|
|
}
|
9175 |
|
|
else
|
9176 |
|
|
{
|
9177 |
|
|
output_asm_insn ("sllx\t%H1, 32, %3", operands);
|
9178 |
|
|
if (sparc_check_64 (operands[1], insn) <= 0)
|
9179 |
|
|
output_asm_insn ("srl\t%L1, 0, %L1", operands);
|
9180 |
|
|
output_asm_insn ("or\t%L1, %3, %3", operands);
|
9181 |
|
|
}
|
9182 |
|
|
|
9183 |
|
|
strcpy (asm_code, opcode);
|
9184 |
|
|
|
9185 |
|
|
if (which_alternative != 2)
|
9186 |
|
|
return strcat (asm_code, "\t%0, %2, %L0\n\tsrlx\t%L0, 32, %H0");
|
9187 |
|
|
else
|
9188 |
|
|
return
|
9189 |
|
|
strcat (asm_code, "\t%3, %2, %3\n\tsrlx\t%3, 32, %H0\n\tmov\t%3, %L0");
|
9190 |
|
|
}
|
9191 |
|
|
|
9192 |
|
|
/* Output rtl to increment the profiler label LABELNO
|
9193 |
|
|
for profiling a function entry. */
|
9194 |
|
|
|
9195 |
|
|
void
|
9196 |
|
|
sparc_profile_hook (int labelno)
|
9197 |
|
|
{
|
9198 |
|
|
char buf[32];
|
9199 |
|
|
rtx lab, fun;
|
9200 |
|
|
|
9201 |
|
|
fun = gen_rtx_SYMBOL_REF (Pmode, MCOUNT_FUNCTION);
|
9202 |
|
|
if (NO_PROFILE_COUNTERS)
|
9203 |
|
|
{
|
9204 |
|
|
emit_library_call (fun, LCT_NORMAL, VOIDmode, 0);
|
9205 |
|
|
}
|
9206 |
|
|
else
|
9207 |
|
|
{
|
9208 |
|
|
ASM_GENERATE_INTERNAL_LABEL (buf, "LP", labelno);
|
9209 |
|
|
lab = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf));
|
9210 |
|
|
emit_library_call (fun, LCT_NORMAL, VOIDmode, 1, lab, Pmode);
|
9211 |
|
|
}
|
9212 |
|
|
}
|
9213 |
|
|
|
9214 |
|
|
#ifdef TARGET_SOLARIS
|
9215 |
|
|
/* Solaris implementation of TARGET_ASM_NAMED_SECTION. */
|
9216 |
|
|
|
9217 |
|
|
static void
|
9218 |
|
|
sparc_solaris_elf_asm_named_section (const char *name, unsigned int flags,
|
9219 |
|
|
tree decl ATTRIBUTE_UNUSED)
|
9220 |
|
|
{
|
9221 |
|
|
if (HAVE_COMDAT_GROUP && flags & SECTION_LINKONCE)
|
9222 |
|
|
{
|
9223 |
|
|
solaris_elf_asm_comdat_section (name, flags, decl);
|
9224 |
|
|
return;
|
9225 |
|
|
}
|
9226 |
|
|
|
9227 |
|
|
fprintf (asm_out_file, "\t.section\t\"%s\"", name);
|
9228 |
|
|
|
9229 |
|
|
if (!(flags & SECTION_DEBUG))
|
9230 |
|
|
fputs (",#alloc", asm_out_file);
|
9231 |
|
|
if (flags & SECTION_WRITE)
|
9232 |
|
|
fputs (",#write", asm_out_file);
|
9233 |
|
|
if (flags & SECTION_TLS)
|
9234 |
|
|
fputs (",#tls", asm_out_file);
|
9235 |
|
|
if (flags & SECTION_CODE)
|
9236 |
|
|
fputs (",#execinstr", asm_out_file);
|
9237 |
|
|
|
9238 |
|
|
/* ??? Handle SECTION_BSS. */
|
9239 |
|
|
|
9240 |
|
|
fputc ('\n', asm_out_file);
|
9241 |
|
|
}
|
9242 |
|
|
#endif /* TARGET_SOLARIS */
|
9243 |
|
|
|
9244 |
|
|
/* We do not allow indirect calls to be optimized into sibling calls.
|
9245 |
|
|
|
9246 |
|
|
We cannot use sibling calls when delayed branches are disabled
|
9247 |
|
|
because they will likely require the call delay slot to be filled.
|
9248 |
|
|
|
9249 |
|
|
Also, on SPARC 32-bit we cannot emit a sibling call when the
|
9250 |
|
|
current function returns a structure. This is because the "unimp
|
9251 |
|
|
after call" convention would cause the callee to return to the
|
9252 |
|
|
wrong place. The generic code already disallows cases where the
|
9253 |
|
|
function being called returns a structure.
|
9254 |
|
|
|
9255 |
|
|
It may seem strange how this last case could occur. Usually there
|
9256 |
|
|
is code after the call which jumps to epilogue code which dumps the
|
9257 |
|
|
return value into the struct return area. That ought to invalidate
|
9258 |
|
|
the sibling call right? Well, in the C++ case we can end up passing
|
9259 |
|
|
the pointer to the struct return area to a constructor (which returns
|
9260 |
|
|
void) and then nothing else happens. Such a sibling call would look
|
9261 |
|
|
valid without the added check here.
|
9262 |
|
|
|
9263 |
|
|
VxWorks PIC PLT entries require the global pointer to be initialized
|
9264 |
|
|
on entry. We therefore can't emit sibling calls to them. */
|
9265 |
|
|
static bool
|
9266 |
|
|
sparc_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
|
9267 |
|
|
{
|
9268 |
|
|
return (decl
|
9269 |
|
|
&& flag_delayed_branch
|
9270 |
|
|
&& (TARGET_ARCH64 || ! cfun->returns_struct)
|
9271 |
|
|
&& !(TARGET_VXWORKS_RTP
|
9272 |
|
|
&& flag_pic
|
9273 |
|
|
&& !targetm.binds_local_p (decl)));
|
9274 |
|
|
}
|
9275 |
|
|
|
9276 |
|
|
/* libfunc renaming. */
|
9277 |
|
|
|
9278 |
|
|
static void
|
9279 |
|
|
sparc_init_libfuncs (void)
|
9280 |
|
|
{
|
9281 |
|
|
if (TARGET_ARCH32)
|
9282 |
|
|
{
|
9283 |
|
|
/* Use the subroutines that Sun's library provides for integer
|
9284 |
|
|
multiply and divide. The `*' prevents an underscore from
|
9285 |
|
|
being prepended by the compiler. .umul is a little faster
|
9286 |
|
|
than .mul. */
|
9287 |
|
|
set_optab_libfunc (smul_optab, SImode, "*.umul");
|
9288 |
|
|
set_optab_libfunc (sdiv_optab, SImode, "*.div");
|
9289 |
|
|
set_optab_libfunc (udiv_optab, SImode, "*.udiv");
|
9290 |
|
|
set_optab_libfunc (smod_optab, SImode, "*.rem");
|
9291 |
|
|
set_optab_libfunc (umod_optab, SImode, "*.urem");
|
9292 |
|
|
|
9293 |
|
|
/* TFmode arithmetic. These names are part of the SPARC 32bit ABI. */
|
9294 |
|
|
set_optab_libfunc (add_optab, TFmode, "_Q_add");
|
9295 |
|
|
set_optab_libfunc (sub_optab, TFmode, "_Q_sub");
|
9296 |
|
|
set_optab_libfunc (neg_optab, TFmode, "_Q_neg");
|
9297 |
|
|
set_optab_libfunc (smul_optab, TFmode, "_Q_mul");
|
9298 |
|
|
set_optab_libfunc (sdiv_optab, TFmode, "_Q_div");
|
9299 |
|
|
|
9300 |
|
|
/* We can define the TFmode sqrt optab only if TARGET_FPU. This
|
9301 |
|
|
is because with soft-float, the SFmode and DFmode sqrt
|
9302 |
|
|
instructions will be absent, and the compiler will notice and
|
9303 |
|
|
try to use the TFmode sqrt instruction for calls to the
|
9304 |
|
|
builtin function sqrt, but this fails. */
|
9305 |
|
|
if (TARGET_FPU)
|
9306 |
|
|
set_optab_libfunc (sqrt_optab, TFmode, "_Q_sqrt");
|
9307 |
|
|
|
9308 |
|
|
set_optab_libfunc (eq_optab, TFmode, "_Q_feq");
|
9309 |
|
|
set_optab_libfunc (ne_optab, TFmode, "_Q_fne");
|
9310 |
|
|
set_optab_libfunc (gt_optab, TFmode, "_Q_fgt");
|
9311 |
|
|
set_optab_libfunc (ge_optab, TFmode, "_Q_fge");
|
9312 |
|
|
set_optab_libfunc (lt_optab, TFmode, "_Q_flt");
|
9313 |
|
|
set_optab_libfunc (le_optab, TFmode, "_Q_fle");
|
9314 |
|
|
|
9315 |
|
|
set_conv_libfunc (sext_optab, TFmode, SFmode, "_Q_stoq");
|
9316 |
|
|
set_conv_libfunc (sext_optab, TFmode, DFmode, "_Q_dtoq");
|
9317 |
|
|
set_conv_libfunc (trunc_optab, SFmode, TFmode, "_Q_qtos");
|
9318 |
|
|
set_conv_libfunc (trunc_optab, DFmode, TFmode, "_Q_qtod");
|
9319 |
|
|
|
9320 |
|
|
set_conv_libfunc (sfix_optab, SImode, TFmode, "_Q_qtoi");
|
9321 |
|
|
set_conv_libfunc (ufix_optab, SImode, TFmode, "_Q_qtou");
|
9322 |
|
|
set_conv_libfunc (sfloat_optab, TFmode, SImode, "_Q_itoq");
|
9323 |
|
|
set_conv_libfunc (ufloat_optab, TFmode, SImode, "_Q_utoq");
|
9324 |
|
|
|
9325 |
|
|
if (DITF_CONVERSION_LIBFUNCS)
|
9326 |
|
|
{
|
9327 |
|
|
set_conv_libfunc (sfix_optab, DImode, TFmode, "_Q_qtoll");
|
9328 |
|
|
set_conv_libfunc (ufix_optab, DImode, TFmode, "_Q_qtoull");
|
9329 |
|
|
set_conv_libfunc (sfloat_optab, TFmode, DImode, "_Q_lltoq");
|
9330 |
|
|
set_conv_libfunc (ufloat_optab, TFmode, DImode, "_Q_ulltoq");
|
9331 |
|
|
}
|
9332 |
|
|
|
9333 |
|
|
if (SUN_CONVERSION_LIBFUNCS)
|
9334 |
|
|
{
|
9335 |
|
|
set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftoll");
|
9336 |
|
|
set_conv_libfunc (ufix_optab, DImode, SFmode, "__ftoull");
|
9337 |
|
|
set_conv_libfunc (sfix_optab, DImode, DFmode, "__dtoll");
|
9338 |
|
|
set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoull");
|
9339 |
|
|
}
|
9340 |
|
|
}
|
9341 |
|
|
if (TARGET_ARCH64)
|
9342 |
|
|
{
|
9343 |
|
|
/* In the SPARC 64bit ABI, SImode multiply and divide functions
|
9344 |
|
|
do not exist in the library. Make sure the compiler does not
|
9345 |
|
|
emit calls to them by accident. (It should always use the
|
9346 |
|
|
hardware instructions.) */
|
9347 |
|
|
set_optab_libfunc (smul_optab, SImode, 0);
|
9348 |
|
|
set_optab_libfunc (sdiv_optab, SImode, 0);
|
9349 |
|
|
set_optab_libfunc (udiv_optab, SImode, 0);
|
9350 |
|
|
set_optab_libfunc (smod_optab, SImode, 0);
|
9351 |
|
|
set_optab_libfunc (umod_optab, SImode, 0);
|
9352 |
|
|
|
9353 |
|
|
if (SUN_INTEGER_MULTIPLY_64)
|
9354 |
|
|
{
|
9355 |
|
|
set_optab_libfunc (smul_optab, DImode, "__mul64");
|
9356 |
|
|
set_optab_libfunc (sdiv_optab, DImode, "__div64");
|
9357 |
|
|
set_optab_libfunc (udiv_optab, DImode, "__udiv64");
|
9358 |
|
|
set_optab_libfunc (smod_optab, DImode, "__rem64");
|
9359 |
|
|
set_optab_libfunc (umod_optab, DImode, "__urem64");
|
9360 |
|
|
}
|
9361 |
|
|
|
9362 |
|
|
if (SUN_CONVERSION_LIBFUNCS)
|
9363 |
|
|
{
|
9364 |
|
|
set_conv_libfunc (sfix_optab, DImode, SFmode, "__ftol");
|
9365 |
|
|
set_conv_libfunc (ufix_optab, DImode, SFmode, "__ftoul");
|
9366 |
|
|
set_conv_libfunc (sfix_optab, DImode, DFmode, "__dtol");
|
9367 |
|
|
set_conv_libfunc (ufix_optab, DImode, DFmode, "__dtoul");
|
9368 |
|
|
}
|
9369 |
|
|
}
|
9370 |
|
|
}
|
9371 |
|
|
|
9372 |
|
|
static tree def_builtin(const char *name, int code, tree type)
|
9373 |
|
|
{
|
9374 |
|
|
return add_builtin_function(name, type, code, BUILT_IN_MD, NULL,
|
9375 |
|
|
NULL_TREE);
|
9376 |
|
|
}
|
9377 |
|
|
|
9378 |
|
|
static tree def_builtin_const(const char *name, int code, tree type)
|
9379 |
|
|
{
|
9380 |
|
|
tree t = def_builtin(name, code, type);
|
9381 |
|
|
|
9382 |
|
|
if (t)
|
9383 |
|
|
TREE_READONLY (t) = 1;
|
9384 |
|
|
|
9385 |
|
|
return t;
|
9386 |
|
|
}
|
9387 |
|
|
|
9388 |
|
|
/* Implement the TARGET_INIT_BUILTINS target hook.
|
9389 |
|
|
Create builtin functions for special SPARC instructions. */
|
9390 |
|
|
|
9391 |
|
|
static void
|
9392 |
|
|
sparc_init_builtins (void)
|
9393 |
|
|
{
|
9394 |
|
|
if (TARGET_VIS)
|
9395 |
|
|
sparc_vis_init_builtins ();
|
9396 |
|
|
}
|
9397 |
|
|
|
9398 |
|
|
/* Create builtin functions for VIS 1.0 instructions. */
|
9399 |
|
|
|
9400 |
|
|
static void
|
9401 |
|
|
sparc_vis_init_builtins (void)
|
9402 |
|
|
{
|
9403 |
|
|
tree v4qi = build_vector_type (unsigned_intQI_type_node, 4);
|
9404 |
|
|
tree v8qi = build_vector_type (unsigned_intQI_type_node, 8);
|
9405 |
|
|
tree v4hi = build_vector_type (intHI_type_node, 4);
|
9406 |
|
|
tree v2hi = build_vector_type (intHI_type_node, 2);
|
9407 |
|
|
tree v2si = build_vector_type (intSI_type_node, 2);
|
9408 |
|
|
tree v1si = build_vector_type (intSI_type_node, 1);
|
9409 |
|
|
|
9410 |
|
|
tree v4qi_ftype_v4hi = build_function_type_list (v4qi, v4hi, 0);
|
9411 |
|
|
tree v8qi_ftype_v2si_v8qi = build_function_type_list (v8qi, v2si, v8qi, 0);
|
9412 |
|
|
tree v2hi_ftype_v2si = build_function_type_list (v2hi, v2si, 0);
|
9413 |
|
|
tree v4hi_ftype_v4qi = build_function_type_list (v4hi, v4qi, 0);
|
9414 |
|
|
tree v8qi_ftype_v4qi_v4qi = build_function_type_list (v8qi, v4qi, v4qi, 0);
|
9415 |
|
|
tree v4hi_ftype_v4qi_v4hi = build_function_type_list (v4hi, v4qi, v4hi, 0);
|
9416 |
|
|
tree v4hi_ftype_v4qi_v2hi = build_function_type_list (v4hi, v4qi, v2hi, 0);
|
9417 |
|
|
tree v2si_ftype_v4qi_v2hi = build_function_type_list (v2si, v4qi, v2hi, 0);
|
9418 |
|
|
tree v4hi_ftype_v8qi_v4hi = build_function_type_list (v4hi, v8qi, v4hi, 0);
|
9419 |
|
|
tree v4hi_ftype_v4hi_v4hi = build_function_type_list (v4hi, v4hi, v4hi, 0);
|
9420 |
|
|
tree v2si_ftype_v2si_v2si = build_function_type_list (v2si, v2si, v2si, 0);
|
9421 |
|
|
tree v8qi_ftype_v8qi_v8qi = build_function_type_list (v8qi, v8qi, v8qi, 0);
|
9422 |
|
|
tree v2hi_ftype_v2hi_v2hi = build_function_type_list (v2hi, v2hi, v2hi, 0);
|
9423 |
|
|
tree v1si_ftype_v1si_v1si = build_function_type_list (v1si, v1si, v1si, 0);
|
9424 |
|
|
tree di_ftype_v8qi_v8qi_di = build_function_type_list (intDI_type_node,
|
9425 |
|
|
v8qi, v8qi,
|
9426 |
|
|
intDI_type_node, 0);
|
9427 |
|
|
tree di_ftype_v8qi_v8qi = build_function_type_list (intDI_type_node,
|
9428 |
|
|
v8qi, v8qi, 0);
|
9429 |
|
|
tree si_ftype_v8qi_v8qi = build_function_type_list (intSI_type_node,
|
9430 |
|
|
v8qi, v8qi, 0);
|
9431 |
|
|
tree di_ftype_di_di = build_function_type_list (intDI_type_node,
|
9432 |
|
|
intDI_type_node,
|
9433 |
|
|
intDI_type_node, 0);
|
9434 |
|
|
tree si_ftype_si_si = build_function_type_list (intSI_type_node,
|
9435 |
|
|
intSI_type_node,
|
9436 |
|
|
intSI_type_node, 0);
|
9437 |
|
|
tree ptr_ftype_ptr_si = build_function_type_list (ptr_type_node,
|
9438 |
|
|
ptr_type_node,
|
9439 |
|
|
intSI_type_node, 0);
|
9440 |
|
|
tree ptr_ftype_ptr_di = build_function_type_list (ptr_type_node,
|
9441 |
|
|
ptr_type_node,
|
9442 |
|
|
intDI_type_node, 0);
|
9443 |
|
|
tree si_ftype_ptr_ptr = build_function_type_list (intSI_type_node,
|
9444 |
|
|
ptr_type_node,
|
9445 |
|
|
ptr_type_node, 0);
|
9446 |
|
|
tree di_ftype_ptr_ptr = build_function_type_list (intDI_type_node,
|
9447 |
|
|
ptr_type_node,
|
9448 |
|
|
ptr_type_node, 0);
|
9449 |
|
|
tree si_ftype_v4hi_v4hi = build_function_type_list (intSI_type_node,
|
9450 |
|
|
v4hi, v4hi, 0);
|
9451 |
|
|
tree si_ftype_v2si_v2si = build_function_type_list (intSI_type_node,
|
9452 |
|
|
v2si, v2si, 0);
|
9453 |
|
|
tree di_ftype_v4hi_v4hi = build_function_type_list (intDI_type_node,
|
9454 |
|
|
v4hi, v4hi, 0);
|
9455 |
|
|
tree di_ftype_v2si_v2si = build_function_type_list (intDI_type_node,
|
9456 |
|
|
v2si, v2si, 0);
|
9457 |
|
|
tree void_ftype_di = build_function_type_list (void_type_node,
|
9458 |
|
|
intDI_type_node, 0);
|
9459 |
|
|
tree di_ftype_void = build_function_type_list (intDI_type_node,
|
9460 |
|
|
void_type_node, 0);
|
9461 |
|
|
tree void_ftype_si = build_function_type_list (void_type_node,
|
9462 |
|
|
intSI_type_node, 0);
|
9463 |
|
|
tree sf_ftype_sf_sf = build_function_type_list (float_type_node,
|
9464 |
|
|
float_type_node,
|
9465 |
|
|
float_type_node, 0);
|
9466 |
|
|
tree df_ftype_df_df = build_function_type_list (double_type_node,
|
9467 |
|
|
double_type_node,
|
9468 |
|
|
double_type_node, 0);
|
9469 |
|
|
|
9470 |
|
|
/* Packing and expanding vectors. */
|
9471 |
|
|
def_builtin ("__builtin_vis_fpack16", CODE_FOR_fpack16_vis,
|
9472 |
|
|
v4qi_ftype_v4hi);
|
9473 |
|
|
def_builtin ("__builtin_vis_fpack32", CODE_FOR_fpack32_vis,
|
9474 |
|
|
v8qi_ftype_v2si_v8qi);
|
9475 |
|
|
def_builtin ("__builtin_vis_fpackfix", CODE_FOR_fpackfix_vis,
|
9476 |
|
|
v2hi_ftype_v2si);
|
9477 |
|
|
def_builtin_const ("__builtin_vis_fexpand", CODE_FOR_fexpand_vis,
|
9478 |
|
|
v4hi_ftype_v4qi);
|
9479 |
|
|
def_builtin_const ("__builtin_vis_fpmerge", CODE_FOR_fpmerge_vis,
|
9480 |
|
|
v8qi_ftype_v4qi_v4qi);
|
9481 |
|
|
|
9482 |
|
|
/* Multiplications. */
|
9483 |
|
|
def_builtin_const ("__builtin_vis_fmul8x16", CODE_FOR_fmul8x16_vis,
|
9484 |
|
|
v4hi_ftype_v4qi_v4hi);
|
9485 |
|
|
def_builtin_const ("__builtin_vis_fmul8x16au", CODE_FOR_fmul8x16au_vis,
|
9486 |
|
|
v4hi_ftype_v4qi_v2hi);
|
9487 |
|
|
def_builtin_const ("__builtin_vis_fmul8x16al", CODE_FOR_fmul8x16al_vis,
|
9488 |
|
|
v4hi_ftype_v4qi_v2hi);
|
9489 |
|
|
def_builtin_const ("__builtin_vis_fmul8sux16", CODE_FOR_fmul8sux16_vis,
|
9490 |
|
|
v4hi_ftype_v8qi_v4hi);
|
9491 |
|
|
def_builtin_const ("__builtin_vis_fmul8ulx16", CODE_FOR_fmul8ulx16_vis,
|
9492 |
|
|
v4hi_ftype_v8qi_v4hi);
|
9493 |
|
|
def_builtin_const ("__builtin_vis_fmuld8sux16", CODE_FOR_fmuld8sux16_vis,
|
9494 |
|
|
v2si_ftype_v4qi_v2hi);
|
9495 |
|
|
def_builtin_const ("__builtin_vis_fmuld8ulx16", CODE_FOR_fmuld8ulx16_vis,
|
9496 |
|
|
v2si_ftype_v4qi_v2hi);
|
9497 |
|
|
|
9498 |
|
|
/* Data aligning. */
|
9499 |
|
|
def_builtin ("__builtin_vis_faligndatav4hi", CODE_FOR_faligndatav4hi_vis,
|
9500 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9501 |
|
|
def_builtin ("__builtin_vis_faligndatav8qi", CODE_FOR_faligndatav8qi_vis,
|
9502 |
|
|
v8qi_ftype_v8qi_v8qi);
|
9503 |
|
|
def_builtin ("__builtin_vis_faligndatav2si", CODE_FOR_faligndatav2si_vis,
|
9504 |
|
|
v2si_ftype_v2si_v2si);
|
9505 |
|
|
def_builtin ("__builtin_vis_faligndatadi", CODE_FOR_faligndatav1di_vis,
|
9506 |
|
|
di_ftype_di_di);
|
9507 |
|
|
|
9508 |
|
|
def_builtin ("__builtin_vis_write_gsr", CODE_FOR_wrgsr_vis,
|
9509 |
|
|
void_ftype_di);
|
9510 |
|
|
def_builtin ("__builtin_vis_read_gsr", CODE_FOR_rdgsr_vis,
|
9511 |
|
|
di_ftype_void);
|
9512 |
|
|
|
9513 |
|
|
if (TARGET_ARCH64)
|
9514 |
|
|
{
|
9515 |
|
|
def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrdi_vis,
|
9516 |
|
|
ptr_ftype_ptr_di);
|
9517 |
|
|
def_builtin ("__builtin_vis_alignaddrl", CODE_FOR_alignaddrldi_vis,
|
9518 |
|
|
ptr_ftype_ptr_di);
|
9519 |
|
|
}
|
9520 |
|
|
else
|
9521 |
|
|
{
|
9522 |
|
|
def_builtin ("__builtin_vis_alignaddr", CODE_FOR_alignaddrsi_vis,
|
9523 |
|
|
ptr_ftype_ptr_si);
|
9524 |
|
|
def_builtin ("__builtin_vis_alignaddrl", CODE_FOR_alignaddrlsi_vis,
|
9525 |
|
|
ptr_ftype_ptr_si);
|
9526 |
|
|
}
|
9527 |
|
|
|
9528 |
|
|
/* Pixel distance. */
|
9529 |
|
|
def_builtin_const ("__builtin_vis_pdist", CODE_FOR_pdist_vis,
|
9530 |
|
|
di_ftype_v8qi_v8qi_di);
|
9531 |
|
|
|
9532 |
|
|
/* Edge handling. */
|
9533 |
|
|
if (TARGET_ARCH64)
|
9534 |
|
|
{
|
9535 |
|
|
def_builtin_const ("__builtin_vis_edge8", CODE_FOR_edge8di_vis,
|
9536 |
|
|
di_ftype_ptr_ptr);
|
9537 |
|
|
def_builtin_const ("__builtin_vis_edge8l", CODE_FOR_edge8ldi_vis,
|
9538 |
|
|
di_ftype_ptr_ptr);
|
9539 |
|
|
def_builtin_const ("__builtin_vis_edge16", CODE_FOR_edge16di_vis,
|
9540 |
|
|
di_ftype_ptr_ptr);
|
9541 |
|
|
def_builtin_const ("__builtin_vis_edge16l", CODE_FOR_edge16ldi_vis,
|
9542 |
|
|
di_ftype_ptr_ptr);
|
9543 |
|
|
def_builtin_const ("__builtin_vis_edge32", CODE_FOR_edge32di_vis,
|
9544 |
|
|
di_ftype_ptr_ptr);
|
9545 |
|
|
def_builtin_const ("__builtin_vis_edge32l", CODE_FOR_edge32ldi_vis,
|
9546 |
|
|
di_ftype_ptr_ptr);
|
9547 |
|
|
if (TARGET_VIS2)
|
9548 |
|
|
{
|
9549 |
|
|
def_builtin_const ("__builtin_vis_edge8n", CODE_FOR_edge8ndi_vis,
|
9550 |
|
|
di_ftype_ptr_ptr);
|
9551 |
|
|
def_builtin_const ("__builtin_vis_edge8ln", CODE_FOR_edge8lndi_vis,
|
9552 |
|
|
di_ftype_ptr_ptr);
|
9553 |
|
|
def_builtin_const ("__builtin_vis_edge16n", CODE_FOR_edge16ndi_vis,
|
9554 |
|
|
di_ftype_ptr_ptr);
|
9555 |
|
|
def_builtin_const ("__builtin_vis_edge16ln", CODE_FOR_edge16lndi_vis,
|
9556 |
|
|
di_ftype_ptr_ptr);
|
9557 |
|
|
def_builtin_const ("__builtin_vis_edge32n", CODE_FOR_edge32ndi_vis,
|
9558 |
|
|
di_ftype_ptr_ptr);
|
9559 |
|
|
def_builtin_const ("__builtin_vis_edge32ln", CODE_FOR_edge32lndi_vis,
|
9560 |
|
|
di_ftype_ptr_ptr);
|
9561 |
|
|
}
|
9562 |
|
|
}
|
9563 |
|
|
else
|
9564 |
|
|
{
|
9565 |
|
|
def_builtin_const ("__builtin_vis_edge8", CODE_FOR_edge8si_vis,
|
9566 |
|
|
si_ftype_ptr_ptr);
|
9567 |
|
|
def_builtin_const ("__builtin_vis_edge8l", CODE_FOR_edge8lsi_vis,
|
9568 |
|
|
si_ftype_ptr_ptr);
|
9569 |
|
|
def_builtin_const ("__builtin_vis_edge16", CODE_FOR_edge16si_vis,
|
9570 |
|
|
si_ftype_ptr_ptr);
|
9571 |
|
|
def_builtin_const ("__builtin_vis_edge16l", CODE_FOR_edge16lsi_vis,
|
9572 |
|
|
si_ftype_ptr_ptr);
|
9573 |
|
|
def_builtin_const ("__builtin_vis_edge32", CODE_FOR_edge32si_vis,
|
9574 |
|
|
si_ftype_ptr_ptr);
|
9575 |
|
|
def_builtin_const ("__builtin_vis_edge32l", CODE_FOR_edge32lsi_vis,
|
9576 |
|
|
si_ftype_ptr_ptr);
|
9577 |
|
|
if (TARGET_VIS2)
|
9578 |
|
|
{
|
9579 |
|
|
def_builtin_const ("__builtin_vis_edge8n", CODE_FOR_edge8nsi_vis,
|
9580 |
|
|
si_ftype_ptr_ptr);
|
9581 |
|
|
def_builtin_const ("__builtin_vis_edge8ln", CODE_FOR_edge8lnsi_vis,
|
9582 |
|
|
si_ftype_ptr_ptr);
|
9583 |
|
|
def_builtin_const ("__builtin_vis_edge16n", CODE_FOR_edge16nsi_vis,
|
9584 |
|
|
si_ftype_ptr_ptr);
|
9585 |
|
|
def_builtin_const ("__builtin_vis_edge16ln", CODE_FOR_edge16lnsi_vis,
|
9586 |
|
|
si_ftype_ptr_ptr);
|
9587 |
|
|
def_builtin_const ("__builtin_vis_edge32n", CODE_FOR_edge32nsi_vis,
|
9588 |
|
|
si_ftype_ptr_ptr);
|
9589 |
|
|
def_builtin_const ("__builtin_vis_edge32ln", CODE_FOR_edge32lnsi_vis,
|
9590 |
|
|
si_ftype_ptr_ptr);
|
9591 |
|
|
}
|
9592 |
|
|
}
|
9593 |
|
|
|
9594 |
|
|
/* Pixel compare. */
|
9595 |
|
|
if (TARGET_ARCH64)
|
9596 |
|
|
{
|
9597 |
|
|
def_builtin_const ("__builtin_vis_fcmple16", CODE_FOR_fcmple16di_vis,
|
9598 |
|
|
di_ftype_v4hi_v4hi);
|
9599 |
|
|
def_builtin_const ("__builtin_vis_fcmple32", CODE_FOR_fcmple32di_vis,
|
9600 |
|
|
di_ftype_v2si_v2si);
|
9601 |
|
|
def_builtin_const ("__builtin_vis_fcmpne16", CODE_FOR_fcmpne16di_vis,
|
9602 |
|
|
di_ftype_v4hi_v4hi);
|
9603 |
|
|
def_builtin_const ("__builtin_vis_fcmpne32", CODE_FOR_fcmpne32di_vis,
|
9604 |
|
|
di_ftype_v2si_v2si);
|
9605 |
|
|
def_builtin_const ("__builtin_vis_fcmpgt16", CODE_FOR_fcmpgt16di_vis,
|
9606 |
|
|
di_ftype_v4hi_v4hi);
|
9607 |
|
|
def_builtin_const ("__builtin_vis_fcmpgt32", CODE_FOR_fcmpgt32di_vis,
|
9608 |
|
|
di_ftype_v2si_v2si);
|
9609 |
|
|
def_builtin_const ("__builtin_vis_fcmpeq16", CODE_FOR_fcmpeq16di_vis,
|
9610 |
|
|
di_ftype_v4hi_v4hi);
|
9611 |
|
|
def_builtin_const ("__builtin_vis_fcmpeq32", CODE_FOR_fcmpeq32di_vis,
|
9612 |
|
|
di_ftype_v2si_v2si);
|
9613 |
|
|
}
|
9614 |
|
|
else
|
9615 |
|
|
{
|
9616 |
|
|
def_builtin_const ("__builtin_vis_fcmple16", CODE_FOR_fcmple16si_vis,
|
9617 |
|
|
si_ftype_v4hi_v4hi);
|
9618 |
|
|
def_builtin_const ("__builtin_vis_fcmple32", CODE_FOR_fcmple32si_vis,
|
9619 |
|
|
si_ftype_v2si_v2si);
|
9620 |
|
|
def_builtin_const ("__builtin_vis_fcmpne16", CODE_FOR_fcmpne16si_vis,
|
9621 |
|
|
si_ftype_v4hi_v4hi);
|
9622 |
|
|
def_builtin_const ("__builtin_vis_fcmpne32", CODE_FOR_fcmpne32si_vis,
|
9623 |
|
|
si_ftype_v2si_v2si);
|
9624 |
|
|
def_builtin_const ("__builtin_vis_fcmpgt16", CODE_FOR_fcmpgt16si_vis,
|
9625 |
|
|
si_ftype_v4hi_v4hi);
|
9626 |
|
|
def_builtin_const ("__builtin_vis_fcmpgt32", CODE_FOR_fcmpgt32si_vis,
|
9627 |
|
|
si_ftype_v2si_v2si);
|
9628 |
|
|
def_builtin_const ("__builtin_vis_fcmpeq16", CODE_FOR_fcmpeq16si_vis,
|
9629 |
|
|
si_ftype_v4hi_v4hi);
|
9630 |
|
|
def_builtin_const ("__builtin_vis_fcmpeq32", CODE_FOR_fcmpeq32si_vis,
|
9631 |
|
|
si_ftype_v2si_v2si);
|
9632 |
|
|
}
|
9633 |
|
|
|
9634 |
|
|
/* Addition and subtraction. */
|
9635 |
|
|
def_builtin_const ("__builtin_vis_fpadd16", CODE_FOR_addv4hi3,
|
9636 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9637 |
|
|
def_builtin_const ("__builtin_vis_fpadd16s", CODE_FOR_addv2hi3,
|
9638 |
|
|
v2hi_ftype_v2hi_v2hi);
|
9639 |
|
|
def_builtin_const ("__builtin_vis_fpadd32", CODE_FOR_addv2si3,
|
9640 |
|
|
v2si_ftype_v2si_v2si);
|
9641 |
|
|
def_builtin_const ("__builtin_vis_fpadd32s", CODE_FOR_addv1si3,
|
9642 |
|
|
v1si_ftype_v1si_v1si);
|
9643 |
|
|
def_builtin_const ("__builtin_vis_fpsub16", CODE_FOR_subv4hi3,
|
9644 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9645 |
|
|
def_builtin_const ("__builtin_vis_fpsub16s", CODE_FOR_subv2hi3,
|
9646 |
|
|
v2hi_ftype_v2hi_v2hi);
|
9647 |
|
|
def_builtin_const ("__builtin_vis_fpsub32", CODE_FOR_subv2si3,
|
9648 |
|
|
v2si_ftype_v2si_v2si);
|
9649 |
|
|
def_builtin_const ("__builtin_vis_fpsub32s", CODE_FOR_subv1si3,
|
9650 |
|
|
v1si_ftype_v1si_v1si);
|
9651 |
|
|
|
9652 |
|
|
/* Three-dimensional array addressing. */
|
9653 |
|
|
if (TARGET_ARCH64)
|
9654 |
|
|
{
|
9655 |
|
|
def_builtin_const ("__builtin_vis_array8", CODE_FOR_array8di_vis,
|
9656 |
|
|
di_ftype_di_di);
|
9657 |
|
|
def_builtin_const ("__builtin_vis_array16", CODE_FOR_array16di_vis,
|
9658 |
|
|
di_ftype_di_di);
|
9659 |
|
|
def_builtin_const ("__builtin_vis_array32", CODE_FOR_array32di_vis,
|
9660 |
|
|
di_ftype_di_di);
|
9661 |
|
|
}
|
9662 |
|
|
else
|
9663 |
|
|
{
|
9664 |
|
|
def_builtin_const ("__builtin_vis_array8", CODE_FOR_array8si_vis,
|
9665 |
|
|
si_ftype_si_si);
|
9666 |
|
|
def_builtin_const ("__builtin_vis_array16", CODE_FOR_array16si_vis,
|
9667 |
|
|
si_ftype_si_si);
|
9668 |
|
|
def_builtin_const ("__builtin_vis_array32", CODE_FOR_array32si_vis,
|
9669 |
|
|
si_ftype_si_si);
|
9670 |
|
|
}
|
9671 |
|
|
|
9672 |
|
|
if (TARGET_VIS2)
|
9673 |
|
|
{
|
9674 |
|
|
/* Byte mask and shuffle */
|
9675 |
|
|
if (TARGET_ARCH64)
|
9676 |
|
|
def_builtin ("__builtin_vis_bmask", CODE_FOR_bmaskdi_vis,
|
9677 |
|
|
di_ftype_di_di);
|
9678 |
|
|
else
|
9679 |
|
|
def_builtin ("__builtin_vis_bmask", CODE_FOR_bmasksi_vis,
|
9680 |
|
|
si_ftype_si_si);
|
9681 |
|
|
def_builtin ("__builtin_vis_bshufflev4hi", CODE_FOR_bshufflev4hi_vis,
|
9682 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9683 |
|
|
def_builtin ("__builtin_vis_bshufflev8qi", CODE_FOR_bshufflev8qi_vis,
|
9684 |
|
|
v8qi_ftype_v8qi_v8qi);
|
9685 |
|
|
def_builtin ("__builtin_vis_bshufflev2si", CODE_FOR_bshufflev2si_vis,
|
9686 |
|
|
v2si_ftype_v2si_v2si);
|
9687 |
|
|
def_builtin ("__builtin_vis_bshuffledi", CODE_FOR_bshufflev1di_vis,
|
9688 |
|
|
di_ftype_di_di);
|
9689 |
|
|
}
|
9690 |
|
|
|
9691 |
|
|
if (TARGET_VIS3)
|
9692 |
|
|
{
|
9693 |
|
|
if (TARGET_ARCH64)
|
9694 |
|
|
{
|
9695 |
|
|
def_builtin ("__builtin_vis_cmask8", CODE_FOR_cmask8di_vis,
|
9696 |
|
|
void_ftype_di);
|
9697 |
|
|
def_builtin ("__builtin_vis_cmask16", CODE_FOR_cmask16di_vis,
|
9698 |
|
|
void_ftype_di);
|
9699 |
|
|
def_builtin ("__builtin_vis_cmask32", CODE_FOR_cmask32di_vis,
|
9700 |
|
|
void_ftype_di);
|
9701 |
|
|
}
|
9702 |
|
|
else
|
9703 |
|
|
{
|
9704 |
|
|
def_builtin ("__builtin_vis_cmask8", CODE_FOR_cmask8si_vis,
|
9705 |
|
|
void_ftype_si);
|
9706 |
|
|
def_builtin ("__builtin_vis_cmask16", CODE_FOR_cmask16si_vis,
|
9707 |
|
|
void_ftype_si);
|
9708 |
|
|
def_builtin ("__builtin_vis_cmask32", CODE_FOR_cmask32si_vis,
|
9709 |
|
|
void_ftype_si);
|
9710 |
|
|
}
|
9711 |
|
|
|
9712 |
|
|
def_builtin_const ("__builtin_vis_fchksm16", CODE_FOR_fchksm16_vis,
|
9713 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9714 |
|
|
|
9715 |
|
|
def_builtin_const ("__builtin_vis_fsll16", CODE_FOR_vashlv4hi3,
|
9716 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9717 |
|
|
def_builtin_const ("__builtin_vis_fslas16", CODE_FOR_vssashlv4hi3,
|
9718 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9719 |
|
|
def_builtin_const ("__builtin_vis_fsrl16", CODE_FOR_vlshrv4hi3,
|
9720 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9721 |
|
|
def_builtin_const ("__builtin_vis_fsra16", CODE_FOR_vashrv4hi3,
|
9722 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9723 |
|
|
def_builtin_const ("__builtin_vis_fsll32", CODE_FOR_vashlv2si3,
|
9724 |
|
|
v2si_ftype_v2si_v2si);
|
9725 |
|
|
def_builtin_const ("__builtin_vis_fslas32", CODE_FOR_vssashlv2si3,
|
9726 |
|
|
v2si_ftype_v2si_v2si);
|
9727 |
|
|
def_builtin_const ("__builtin_vis_fsrl32", CODE_FOR_vlshrv2si3,
|
9728 |
|
|
v2si_ftype_v2si_v2si);
|
9729 |
|
|
def_builtin_const ("__builtin_vis_fsra32", CODE_FOR_vashrv2si3,
|
9730 |
|
|
v2si_ftype_v2si_v2si);
|
9731 |
|
|
|
9732 |
|
|
if (TARGET_ARCH64)
|
9733 |
|
|
def_builtin_const ("__builtin_vis_pdistn", CODE_FOR_pdistndi_vis,
|
9734 |
|
|
di_ftype_v8qi_v8qi);
|
9735 |
|
|
else
|
9736 |
|
|
def_builtin_const ("__builtin_vis_pdistn", CODE_FOR_pdistnsi_vis,
|
9737 |
|
|
si_ftype_v8qi_v8qi);
|
9738 |
|
|
|
9739 |
|
|
def_builtin_const ("__builtin_vis_fmean16", CODE_FOR_fmean16_vis,
|
9740 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9741 |
|
|
def_builtin_const ("__builtin_vis_fpadd64", CODE_FOR_fpadd64_vis,
|
9742 |
|
|
di_ftype_di_di);
|
9743 |
|
|
def_builtin_const ("__builtin_vis_fpsub64", CODE_FOR_fpsub64_vis,
|
9744 |
|
|
di_ftype_di_di);
|
9745 |
|
|
|
9746 |
|
|
def_builtin_const ("__builtin_vis_fpadds16", CODE_FOR_ssaddv4hi3,
|
9747 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9748 |
|
|
def_builtin_const ("__builtin_vis_fpadds16s", CODE_FOR_ssaddv2hi3,
|
9749 |
|
|
v2hi_ftype_v2hi_v2hi);
|
9750 |
|
|
def_builtin_const ("__builtin_vis_fpsubs16", CODE_FOR_sssubv4hi3,
|
9751 |
|
|
v4hi_ftype_v4hi_v4hi);
|
9752 |
|
|
def_builtin_const ("__builtin_vis_fpsubs16s", CODE_FOR_sssubv2hi3,
|
9753 |
|
|
v2hi_ftype_v2hi_v2hi);
|
9754 |
|
|
def_builtin_const ("__builtin_vis_fpadds32", CODE_FOR_ssaddv2si3,
|
9755 |
|
|
v2si_ftype_v2si_v2si);
|
9756 |
|
|
def_builtin_const ("__builtin_vis_fpadds32s", CODE_FOR_ssaddv1si3,
|
9757 |
|
|
v1si_ftype_v1si_v1si);
|
9758 |
|
|
def_builtin_const ("__builtin_vis_fpsubs32", CODE_FOR_sssubv2si3,
|
9759 |
|
|
v2si_ftype_v2si_v2si);
|
9760 |
|
|
def_builtin_const ("__builtin_vis_fpsubs32s", CODE_FOR_sssubv1si3,
|
9761 |
|
|
v1si_ftype_v1si_v1si);
|
9762 |
|
|
|
9763 |
|
|
if (TARGET_ARCH64)
|
9764 |
|
|
{
|
9765 |
|
|
def_builtin_const ("__builtin_vis_fucmple8", CODE_FOR_fucmple8di_vis,
|
9766 |
|
|
di_ftype_v8qi_v8qi);
|
9767 |
|
|
def_builtin_const ("__builtin_vis_fucmpne8", CODE_FOR_fucmpne8di_vis,
|
9768 |
|
|
di_ftype_v8qi_v8qi);
|
9769 |
|
|
def_builtin_const ("__builtin_vis_fucmpgt8", CODE_FOR_fucmpgt8di_vis,
|
9770 |
|
|
di_ftype_v8qi_v8qi);
|
9771 |
|
|
def_builtin_const ("__builtin_vis_fucmpeq8", CODE_FOR_fucmpeq8di_vis,
|
9772 |
|
|
di_ftype_v8qi_v8qi);
|
9773 |
|
|
}
|
9774 |
|
|
else
|
9775 |
|
|
{
|
9776 |
|
|
def_builtin_const ("__builtin_vis_fucmple8", CODE_FOR_fucmple8si_vis,
|
9777 |
|
|
si_ftype_v8qi_v8qi);
|
9778 |
|
|
def_builtin_const ("__builtin_vis_fucmpne8", CODE_FOR_fucmpne8si_vis,
|
9779 |
|
|
si_ftype_v8qi_v8qi);
|
9780 |
|
|
def_builtin_const ("__builtin_vis_fucmpgt8", CODE_FOR_fucmpgt8si_vis,
|
9781 |
|
|
si_ftype_v8qi_v8qi);
|
9782 |
|
|
def_builtin_const ("__builtin_vis_fucmpeq8", CODE_FOR_fucmpeq8si_vis,
|
9783 |
|
|
si_ftype_v8qi_v8qi);
|
9784 |
|
|
}
|
9785 |
|
|
|
9786 |
|
|
def_builtin_const ("__builtin_vis_fhadds", CODE_FOR_fhaddsf_vis,
|
9787 |
|
|
sf_ftype_sf_sf);
|
9788 |
|
|
def_builtin_const ("__builtin_vis_fhaddd", CODE_FOR_fhadddf_vis,
|
9789 |
|
|
df_ftype_df_df);
|
9790 |
|
|
def_builtin_const ("__builtin_vis_fhsubs", CODE_FOR_fhsubsf_vis,
|
9791 |
|
|
sf_ftype_sf_sf);
|
9792 |
|
|
def_builtin_const ("__builtin_vis_fhsubd", CODE_FOR_fhsubdf_vis,
|
9793 |
|
|
df_ftype_df_df);
|
9794 |
|
|
def_builtin_const ("__builtin_vis_fnhadds", CODE_FOR_fnhaddsf_vis,
|
9795 |
|
|
sf_ftype_sf_sf);
|
9796 |
|
|
def_builtin_const ("__builtin_vis_fnhaddd", CODE_FOR_fnhadddf_vis,
|
9797 |
|
|
df_ftype_df_df);
|
9798 |
|
|
|
9799 |
|
|
def_builtin_const ("__builtin_vis_umulxhi", CODE_FOR_umulxhi_vis,
|
9800 |
|
|
di_ftype_di_di);
|
9801 |
|
|
def_builtin_const ("__builtin_vis_xmulx", CODE_FOR_xmulx_vis,
|
9802 |
|
|
di_ftype_di_di);
|
9803 |
|
|
def_builtin_const ("__builtin_vis_xmulxhi", CODE_FOR_xmulxhi_vis,
|
9804 |
|
|
di_ftype_di_di);
|
9805 |
|
|
}
|
9806 |
|
|
}
|
9807 |
|
|
|
9808 |
|
|
/* Handle TARGET_EXPAND_BUILTIN target hook.
|
9809 |
|
|
Expand builtin functions for sparc intrinsics. */
|
9810 |
|
|
|
9811 |
|
|
static rtx
|
9812 |
|
|
sparc_expand_builtin (tree exp, rtx target,
|
9813 |
|
|
rtx subtarget ATTRIBUTE_UNUSED,
|
9814 |
|
|
enum machine_mode tmode ATTRIBUTE_UNUSED,
|
9815 |
|
|
int ignore ATTRIBUTE_UNUSED)
|
9816 |
|
|
{
|
9817 |
|
|
tree arg;
|
9818 |
|
|
call_expr_arg_iterator iter;
|
9819 |
|
|
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
|
9820 |
|
|
unsigned int icode = DECL_FUNCTION_CODE (fndecl);
|
9821 |
|
|
rtx pat, op[4];
|
9822 |
|
|
int arg_count = 0;
|
9823 |
|
|
bool nonvoid;
|
9824 |
|
|
|
9825 |
|
|
nonvoid = TREE_TYPE (TREE_TYPE (fndecl)) != void_type_node;
|
9826 |
|
|
|
9827 |
|
|
if (nonvoid)
|
9828 |
|
|
{
|
9829 |
|
|
enum machine_mode tmode = insn_data[icode].operand[0].mode;
|
9830 |
|
|
if (!target
|
9831 |
|
|
|| GET_MODE (target) != tmode
|
9832 |
|
|
|| ! (*insn_data[icode].operand[0].predicate) (target, tmode))
|
9833 |
|
|
op[0] = gen_reg_rtx (tmode);
|
9834 |
|
|
else
|
9835 |
|
|
op[0] = target;
|
9836 |
|
|
}
|
9837 |
|
|
FOR_EACH_CALL_EXPR_ARG (arg, iter, exp)
|
9838 |
|
|
{
|
9839 |
|
|
const struct insn_operand_data *insn_op;
|
9840 |
|
|
int idx;
|
9841 |
|
|
|
9842 |
|
|
if (arg == error_mark_node)
|
9843 |
|
|
return NULL_RTX;
|
9844 |
|
|
|
9845 |
|
|
arg_count++;
|
9846 |
|
|
idx = arg_count - !nonvoid;
|
9847 |
|
|
insn_op = &insn_data[icode].operand[idx];
|
9848 |
|
|
op[arg_count] = expand_normal (arg);
|
9849 |
|
|
|
9850 |
|
|
if (insn_op->mode == V1DImode
|
9851 |
|
|
&& GET_MODE (op[arg_count]) == DImode)
|
9852 |
|
|
op[arg_count] = gen_lowpart (V1DImode, op[arg_count]);
|
9853 |
|
|
else if (insn_op->mode == V1SImode
|
9854 |
|
|
&& GET_MODE (op[arg_count]) == SImode)
|
9855 |
|
|
op[arg_count] = gen_lowpart (V1SImode, op[arg_count]);
|
9856 |
|
|
|
9857 |
|
|
if (! (*insn_data[icode].operand[idx].predicate) (op[arg_count],
|
9858 |
|
|
insn_op->mode))
|
9859 |
|
|
op[arg_count] = copy_to_mode_reg (insn_op->mode, op[arg_count]);
|
9860 |
|
|
}
|
9861 |
|
|
|
9862 |
|
|
switch (arg_count)
|
9863 |
|
|
{
|
9864 |
|
|
case 0:
|
9865 |
|
|
pat = GEN_FCN (icode) (op[0]);
|
9866 |
|
|
break;
|
9867 |
|
|
case 1:
|
9868 |
|
|
if (nonvoid)
|
9869 |
|
|
pat = GEN_FCN (icode) (op[0], op[1]);
|
9870 |
|
|
else
|
9871 |
|
|
pat = GEN_FCN (icode) (op[1]);
|
9872 |
|
|
break;
|
9873 |
|
|
case 2:
|
9874 |
|
|
pat = GEN_FCN (icode) (op[0], op[1], op[2]);
|
9875 |
|
|
break;
|
9876 |
|
|
case 3:
|
9877 |
|
|
pat = GEN_FCN (icode) (op[0], op[1], op[2], op[3]);
|
9878 |
|
|
break;
|
9879 |
|
|
default:
|
9880 |
|
|
gcc_unreachable ();
|
9881 |
|
|
}
|
9882 |
|
|
|
9883 |
|
|
if (!pat)
|
9884 |
|
|
return NULL_RTX;
|
9885 |
|
|
|
9886 |
|
|
emit_insn (pat);
|
9887 |
|
|
|
9888 |
|
|
if (nonvoid)
|
9889 |
|
|
return op[0];
|
9890 |
|
|
else
|
9891 |
|
|
return const0_rtx;
|
9892 |
|
|
}
|
9893 |
|
|
|
9894 |
|
|
static int
|
9895 |
|
|
sparc_vis_mul8x16 (int e8, int e16)
|
9896 |
|
|
{
|
9897 |
|
|
return (e8 * e16 + 128) / 256;
|
9898 |
|
|
}
|
9899 |
|
|
|
9900 |
|
|
/* Multiply the vector elements in ELTS0 to the elements in ELTS1 as specified
|
9901 |
|
|
by FNCODE. All of the elements in ELTS0 and ELTS1 lists must be integer
|
9902 |
|
|
constants. A tree list with the results of the multiplications is returned,
|
9903 |
|
|
and each element in the list is of INNER_TYPE. */
|
9904 |
|
|
|
9905 |
|
|
static tree
|
9906 |
|
|
sparc_handle_vis_mul8x16 (int fncode, tree inner_type, tree elts0, tree elts1)
|
9907 |
|
|
{
|
9908 |
|
|
tree n_elts = NULL_TREE;
|
9909 |
|
|
int scale;
|
9910 |
|
|
|
9911 |
|
|
switch (fncode)
|
9912 |
|
|
{
|
9913 |
|
|
case CODE_FOR_fmul8x16_vis:
|
9914 |
|
|
for (; elts0 && elts1;
|
9915 |
|
|
elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
|
9916 |
|
|
{
|
9917 |
|
|
int val
|
9918 |
|
|
= sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
|
9919 |
|
|
TREE_INT_CST_LOW (TREE_VALUE (elts1)));
|
9920 |
|
|
n_elts = tree_cons (NULL_TREE,
|
9921 |
|
|
build_int_cst (inner_type, val),
|
9922 |
|
|
n_elts);
|
9923 |
|
|
}
|
9924 |
|
|
break;
|
9925 |
|
|
|
9926 |
|
|
case CODE_FOR_fmul8x16au_vis:
|
9927 |
|
|
scale = TREE_INT_CST_LOW (TREE_VALUE (elts1));
|
9928 |
|
|
|
9929 |
|
|
for (; elts0; elts0 = TREE_CHAIN (elts0))
|
9930 |
|
|
{
|
9931 |
|
|
int val
|
9932 |
|
|
= sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
|
9933 |
|
|
scale);
|
9934 |
|
|
n_elts = tree_cons (NULL_TREE,
|
9935 |
|
|
build_int_cst (inner_type, val),
|
9936 |
|
|
n_elts);
|
9937 |
|
|
}
|
9938 |
|
|
break;
|
9939 |
|
|
|
9940 |
|
|
case CODE_FOR_fmul8x16al_vis:
|
9941 |
|
|
scale = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN (elts1)));
|
9942 |
|
|
|
9943 |
|
|
for (; elts0; elts0 = TREE_CHAIN (elts0))
|
9944 |
|
|
{
|
9945 |
|
|
int val
|
9946 |
|
|
= sparc_vis_mul8x16 (TREE_INT_CST_LOW (TREE_VALUE (elts0)),
|
9947 |
|
|
scale);
|
9948 |
|
|
n_elts = tree_cons (NULL_TREE,
|
9949 |
|
|
build_int_cst (inner_type, val),
|
9950 |
|
|
n_elts);
|
9951 |
|
|
}
|
9952 |
|
|
break;
|
9953 |
|
|
|
9954 |
|
|
default:
|
9955 |
|
|
gcc_unreachable ();
|
9956 |
|
|
}
|
9957 |
|
|
|
9958 |
|
|
return nreverse (n_elts);
|
9959 |
|
|
|
9960 |
|
|
}
|
9961 |
|
|
/* Handle TARGET_FOLD_BUILTIN target hook.
|
9962 |
|
|
Fold builtin functions for SPARC intrinsics. If IGNORE is true the
|
9963 |
|
|
result of the function call is ignored. NULL_TREE is returned if the
|
9964 |
|
|
function could not be folded. */
|
9965 |
|
|
|
9966 |
|
|
static tree
|
9967 |
|
|
sparc_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
|
9968 |
|
|
tree *args, bool ignore)
|
9969 |
|
|
{
|
9970 |
|
|
tree arg0, arg1, arg2;
|
9971 |
|
|
tree rtype = TREE_TYPE (TREE_TYPE (fndecl));
|
9972 |
|
|
enum insn_code icode = (enum insn_code) DECL_FUNCTION_CODE (fndecl);
|
9973 |
|
|
|
9974 |
|
|
if (ignore)
|
9975 |
|
|
{
|
9976 |
|
|
/* Note that a switch statement instead of the sequence of tests would
|
9977 |
|
|
be incorrect as many of the CODE_FOR values could be CODE_FOR_nothing
|
9978 |
|
|
and that would yield multiple alternatives with identical values. */
|
9979 |
|
|
if (icode == CODE_FOR_alignaddrsi_vis
|
9980 |
|
|
|| icode == CODE_FOR_alignaddrdi_vis
|
9981 |
|
|
|| icode == CODE_FOR_wrgsr_vis
|
9982 |
|
|
|| icode == CODE_FOR_bmasksi_vis
|
9983 |
|
|
|| icode == CODE_FOR_bmaskdi_vis
|
9984 |
|
|
|| icode == CODE_FOR_cmask8si_vis
|
9985 |
|
|
|| icode == CODE_FOR_cmask8di_vis
|
9986 |
|
|
|| icode == CODE_FOR_cmask16si_vis
|
9987 |
|
|
|| icode == CODE_FOR_cmask16di_vis
|
9988 |
|
|
|| icode == CODE_FOR_cmask32si_vis
|
9989 |
|
|
|| icode == CODE_FOR_cmask32di_vis)
|
9990 |
|
|
;
|
9991 |
|
|
else
|
9992 |
|
|
return build_zero_cst (rtype);
|
9993 |
|
|
}
|
9994 |
|
|
|
9995 |
|
|
switch (icode)
|
9996 |
|
|
{
|
9997 |
|
|
case CODE_FOR_fexpand_vis:
|
9998 |
|
|
arg0 = args[0];
|
9999 |
|
|
STRIP_NOPS (arg0);
|
10000 |
|
|
|
10001 |
|
|
if (TREE_CODE (arg0) == VECTOR_CST)
|
10002 |
|
|
{
|
10003 |
|
|
tree inner_type = TREE_TYPE (rtype);
|
10004 |
|
|
tree elts = TREE_VECTOR_CST_ELTS (arg0);
|
10005 |
|
|
tree n_elts = NULL_TREE;
|
10006 |
|
|
|
10007 |
|
|
for (; elts; elts = TREE_CHAIN (elts))
|
10008 |
|
|
{
|
10009 |
|
|
unsigned int val = TREE_INT_CST_LOW (TREE_VALUE (elts)) << 4;
|
10010 |
|
|
n_elts = tree_cons (NULL_TREE,
|
10011 |
|
|
build_int_cst (inner_type, val),
|
10012 |
|
|
n_elts);
|
10013 |
|
|
}
|
10014 |
|
|
return build_vector (rtype, nreverse (n_elts));
|
10015 |
|
|
}
|
10016 |
|
|
break;
|
10017 |
|
|
|
10018 |
|
|
case CODE_FOR_fmul8x16_vis:
|
10019 |
|
|
case CODE_FOR_fmul8x16au_vis:
|
10020 |
|
|
case CODE_FOR_fmul8x16al_vis:
|
10021 |
|
|
arg0 = args[0];
|
10022 |
|
|
arg1 = args[1];
|
10023 |
|
|
STRIP_NOPS (arg0);
|
10024 |
|
|
STRIP_NOPS (arg1);
|
10025 |
|
|
|
10026 |
|
|
if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
|
10027 |
|
|
{
|
10028 |
|
|
tree inner_type = TREE_TYPE (rtype);
|
10029 |
|
|
tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
|
10030 |
|
|
tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
|
10031 |
|
|
tree n_elts = sparc_handle_vis_mul8x16 (icode, inner_type, elts0,
|
10032 |
|
|
elts1);
|
10033 |
|
|
|
10034 |
|
|
return build_vector (rtype, n_elts);
|
10035 |
|
|
}
|
10036 |
|
|
break;
|
10037 |
|
|
|
10038 |
|
|
case CODE_FOR_fpmerge_vis:
|
10039 |
|
|
arg0 = args[0];
|
10040 |
|
|
arg1 = args[1];
|
10041 |
|
|
STRIP_NOPS (arg0);
|
10042 |
|
|
STRIP_NOPS (arg1);
|
10043 |
|
|
|
10044 |
|
|
if (TREE_CODE (arg0) == VECTOR_CST && TREE_CODE (arg1) == VECTOR_CST)
|
10045 |
|
|
{
|
10046 |
|
|
tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
|
10047 |
|
|
tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
|
10048 |
|
|
tree n_elts = NULL_TREE;
|
10049 |
|
|
|
10050 |
|
|
for (; elts0 && elts1;
|
10051 |
|
|
elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
|
10052 |
|
|
{
|
10053 |
|
|
n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts0), n_elts);
|
10054 |
|
|
n_elts = tree_cons (NULL_TREE, TREE_VALUE (elts1), n_elts);
|
10055 |
|
|
}
|
10056 |
|
|
|
10057 |
|
|
return build_vector (rtype, nreverse (n_elts));
|
10058 |
|
|
}
|
10059 |
|
|
break;
|
10060 |
|
|
|
10061 |
|
|
case CODE_FOR_pdist_vis:
|
10062 |
|
|
arg0 = args[0];
|
10063 |
|
|
arg1 = args[1];
|
10064 |
|
|
arg2 = args[2];
|
10065 |
|
|
STRIP_NOPS (arg0);
|
10066 |
|
|
STRIP_NOPS (arg1);
|
10067 |
|
|
STRIP_NOPS (arg2);
|
10068 |
|
|
|
10069 |
|
|
if (TREE_CODE (arg0) == VECTOR_CST
|
10070 |
|
|
&& TREE_CODE (arg1) == VECTOR_CST
|
10071 |
|
|
&& TREE_CODE (arg2) == INTEGER_CST)
|
10072 |
|
|
{
|
10073 |
|
|
int overflow = 0;
|
10074 |
|
|
unsigned HOST_WIDE_INT low = TREE_INT_CST_LOW (arg2);
|
10075 |
|
|
HOST_WIDE_INT high = TREE_INT_CST_HIGH (arg2);
|
10076 |
|
|
tree elts0 = TREE_VECTOR_CST_ELTS (arg0);
|
10077 |
|
|
tree elts1 = TREE_VECTOR_CST_ELTS (arg1);
|
10078 |
|
|
|
10079 |
|
|
for (; elts0 && elts1;
|
10080 |
|
|
elts0 = TREE_CHAIN (elts0), elts1 = TREE_CHAIN (elts1))
|
10081 |
|
|
{
|
10082 |
|
|
unsigned HOST_WIDE_INT
|
10083 |
|
|
low0 = TREE_INT_CST_LOW (TREE_VALUE (elts0)),
|
10084 |
|
|
low1 = TREE_INT_CST_LOW (TREE_VALUE (elts1));
|
10085 |
|
|
HOST_WIDE_INT high0 = TREE_INT_CST_HIGH (TREE_VALUE (elts0));
|
10086 |
|
|
HOST_WIDE_INT high1 = TREE_INT_CST_HIGH (TREE_VALUE (elts1));
|
10087 |
|
|
|
10088 |
|
|
unsigned HOST_WIDE_INT l;
|
10089 |
|
|
HOST_WIDE_INT h;
|
10090 |
|
|
|
10091 |
|
|
overflow |= neg_double (low1, high1, &l, &h);
|
10092 |
|
|
overflow |= add_double (low0, high0, l, h, &l, &h);
|
10093 |
|
|
if (h < 0)
|
10094 |
|
|
overflow |= neg_double (l, h, &l, &h);
|
10095 |
|
|
|
10096 |
|
|
overflow |= add_double (low, high, l, h, &low, &high);
|
10097 |
|
|
}
|
10098 |
|
|
|
10099 |
|
|
gcc_assert (overflow == 0);
|
10100 |
|
|
|
10101 |
|
|
return build_int_cst_wide (rtype, low, high);
|
10102 |
|
|
}
|
10103 |
|
|
|
10104 |
|
|
default:
|
10105 |
|
|
break;
|
10106 |
|
|
}
|
10107 |
|
|
|
10108 |
|
|
return NULL_TREE;
|
10109 |
|
|
}
|
10110 |
|
|
|
10111 |
|
|
/* ??? This duplicates information provided to the compiler by the
|
10112 |
|
|
??? scheduler description. Some day, teach genautomata to output
|
10113 |
|
|
??? the latencies and then CSE will just use that. */
|
10114 |
|
|
|
10115 |
|
|
static bool
|
10116 |
|
|
sparc_rtx_costs (rtx x, int code, int outer_code, int opno ATTRIBUTE_UNUSED,
|
10117 |
|
|
int *total, bool speed ATTRIBUTE_UNUSED)
|
10118 |
|
|
{
|
10119 |
|
|
enum machine_mode mode = GET_MODE (x);
|
10120 |
|
|
bool float_mode_p = FLOAT_MODE_P (mode);
|
10121 |
|
|
|
10122 |
|
|
switch (code)
|
10123 |
|
|
{
|
10124 |
|
|
case CONST_INT:
|
10125 |
|
|
if (INTVAL (x) < 0x1000 && INTVAL (x) >= -0x1000)
|
10126 |
|
|
{
|
10127 |
|
|
*total = 0;
|
10128 |
|
|
return true;
|
10129 |
|
|
}
|
10130 |
|
|
/* FALLTHRU */
|
10131 |
|
|
|
10132 |
|
|
case HIGH:
|
10133 |
|
|
*total = 2;
|
10134 |
|
|
return true;
|
10135 |
|
|
|
10136 |
|
|
case CONST:
|
10137 |
|
|
case LABEL_REF:
|
10138 |
|
|
case SYMBOL_REF:
|
10139 |
|
|
*total = 4;
|
10140 |
|
|
return true;
|
10141 |
|
|
|
10142 |
|
|
case CONST_DOUBLE:
|
10143 |
|
|
if (GET_MODE (x) == VOIDmode
|
10144 |
|
|
&& ((CONST_DOUBLE_HIGH (x) == 0
|
10145 |
|
|
&& CONST_DOUBLE_LOW (x) < 0x1000)
|
10146 |
|
|
|| (CONST_DOUBLE_HIGH (x) == -1
|
10147 |
|
|
&& CONST_DOUBLE_LOW (x) < 0
|
10148 |
|
|
&& CONST_DOUBLE_LOW (x) >= -0x1000)))
|
10149 |
|
|
*total = 0;
|
10150 |
|
|
else
|
10151 |
|
|
*total = 8;
|
10152 |
|
|
return true;
|
10153 |
|
|
|
10154 |
|
|
case MEM:
|
10155 |
|
|
/* If outer-code was a sign or zero extension, a cost
|
10156 |
|
|
of COSTS_N_INSNS (1) was already added in. This is
|
10157 |
|
|
why we are subtracting it back out. */
|
10158 |
|
|
if (outer_code == ZERO_EXTEND)
|
10159 |
|
|
{
|
10160 |
|
|
*total = sparc_costs->int_zload - COSTS_N_INSNS (1);
|
10161 |
|
|
}
|
10162 |
|
|
else if (outer_code == SIGN_EXTEND)
|
10163 |
|
|
{
|
10164 |
|
|
*total = sparc_costs->int_sload - COSTS_N_INSNS (1);
|
10165 |
|
|
}
|
10166 |
|
|
else if (float_mode_p)
|
10167 |
|
|
{
|
10168 |
|
|
*total = sparc_costs->float_load;
|
10169 |
|
|
}
|
10170 |
|
|
else
|
10171 |
|
|
{
|
10172 |
|
|
*total = sparc_costs->int_load;
|
10173 |
|
|
}
|
10174 |
|
|
|
10175 |
|
|
return true;
|
10176 |
|
|
|
10177 |
|
|
case PLUS:
|
10178 |
|
|
case MINUS:
|
10179 |
|
|
if (float_mode_p)
|
10180 |
|
|
*total = sparc_costs->float_plusminus;
|
10181 |
|
|
else
|
10182 |
|
|
*total = COSTS_N_INSNS (1);
|
10183 |
|
|
return false;
|
10184 |
|
|
|
10185 |
|
|
case FMA:
|
10186 |
|
|
{
|
10187 |
|
|
rtx sub;
|
10188 |
|
|
|
10189 |
|
|
gcc_assert (float_mode_p);
|
10190 |
|
|
*total = sparc_costs->float_mul;
|
10191 |
|
|
|
10192 |
|
|
sub = XEXP (x, 0);
|
10193 |
|
|
if (GET_CODE (sub) == NEG)
|
10194 |
|
|
sub = XEXP (sub, 0);
|
10195 |
|
|
*total += rtx_cost (sub, FMA, 0, speed);
|
10196 |
|
|
|
10197 |
|
|
sub = XEXP (x, 2);
|
10198 |
|
|
if (GET_CODE (sub) == NEG)
|
10199 |
|
|
sub = XEXP (sub, 0);
|
10200 |
|
|
*total += rtx_cost (sub, FMA, 2, speed);
|
10201 |
|
|
return true;
|
10202 |
|
|
}
|
10203 |
|
|
|
10204 |
|
|
case MULT:
|
10205 |
|
|
if (float_mode_p)
|
10206 |
|
|
*total = sparc_costs->float_mul;
|
10207 |
|
|
else if (! TARGET_HARD_MUL)
|
10208 |
|
|
*total = COSTS_N_INSNS (25);
|
10209 |
|
|
else
|
10210 |
|
|
{
|
10211 |
|
|
int bit_cost;
|
10212 |
|
|
|
10213 |
|
|
bit_cost = 0;
|
10214 |
|
|
if (sparc_costs->int_mul_bit_factor)
|
10215 |
|
|
{
|
10216 |
|
|
int nbits;
|
10217 |
|
|
|
10218 |
|
|
if (GET_CODE (XEXP (x, 1)) == CONST_INT)
|
10219 |
|
|
{
|
10220 |
|
|
unsigned HOST_WIDE_INT value = INTVAL (XEXP (x, 1));
|
10221 |
|
|
for (nbits = 0; value != 0; value &= value - 1)
|
10222 |
|
|
nbits++;
|
10223 |
|
|
}
|
10224 |
|
|
else if (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
|
10225 |
|
|
&& GET_MODE (XEXP (x, 1)) == VOIDmode)
|
10226 |
|
|
{
|
10227 |
|
|
rtx x1 = XEXP (x, 1);
|
10228 |
|
|
unsigned HOST_WIDE_INT value1 = CONST_DOUBLE_LOW (x1);
|
10229 |
|
|
unsigned HOST_WIDE_INT value2 = CONST_DOUBLE_HIGH (x1);
|
10230 |
|
|
|
10231 |
|
|
for (nbits = 0; value1 != 0; value1 &= value1 - 1)
|
10232 |
|
|
nbits++;
|
10233 |
|
|
for (; value2 != 0; value2 &= value2 - 1)
|
10234 |
|
|
nbits++;
|
10235 |
|
|
}
|
10236 |
|
|
else
|
10237 |
|
|
nbits = 7;
|
10238 |
|
|
|
10239 |
|
|
if (nbits < 3)
|
10240 |
|
|
nbits = 3;
|
10241 |
|
|
bit_cost = (nbits - 3) / sparc_costs->int_mul_bit_factor;
|
10242 |
|
|
bit_cost = COSTS_N_INSNS (bit_cost);
|
10243 |
|
|
}
|
10244 |
|
|
|
10245 |
|
|
if (mode == DImode)
|
10246 |
|
|
*total = sparc_costs->int_mulX + bit_cost;
|
10247 |
|
|
else
|
10248 |
|
|
*total = sparc_costs->int_mul + bit_cost;
|
10249 |
|
|
}
|
10250 |
|
|
return false;
|
10251 |
|
|
|
10252 |
|
|
case ASHIFT:
|
10253 |
|
|
case ASHIFTRT:
|
10254 |
|
|
case LSHIFTRT:
|
10255 |
|
|
*total = COSTS_N_INSNS (1) + sparc_costs->shift_penalty;
|
10256 |
|
|
return false;
|
10257 |
|
|
|
10258 |
|
|
case DIV:
|
10259 |
|
|
case UDIV:
|
10260 |
|
|
case MOD:
|
10261 |
|
|
case UMOD:
|
10262 |
|
|
if (float_mode_p)
|
10263 |
|
|
{
|
10264 |
|
|
if (mode == DFmode)
|
10265 |
|
|
*total = sparc_costs->float_div_df;
|
10266 |
|
|
else
|
10267 |
|
|
*total = sparc_costs->float_div_sf;
|
10268 |
|
|
}
|
10269 |
|
|
else
|
10270 |
|
|
{
|
10271 |
|
|
if (mode == DImode)
|
10272 |
|
|
*total = sparc_costs->int_divX;
|
10273 |
|
|
else
|
10274 |
|
|
*total = sparc_costs->int_div;
|
10275 |
|
|
}
|
10276 |
|
|
return false;
|
10277 |
|
|
|
10278 |
|
|
case NEG:
|
10279 |
|
|
if (! float_mode_p)
|
10280 |
|
|
{
|
10281 |
|
|
*total = COSTS_N_INSNS (1);
|
10282 |
|
|
return false;
|
10283 |
|
|
}
|
10284 |
|
|
/* FALLTHRU */
|
10285 |
|
|
|
10286 |
|
|
case ABS:
|
10287 |
|
|
case FLOAT:
|
10288 |
|
|
case UNSIGNED_FLOAT:
|
10289 |
|
|
case FIX:
|
10290 |
|
|
case UNSIGNED_FIX:
|
10291 |
|
|
case FLOAT_EXTEND:
|
10292 |
|
|
case FLOAT_TRUNCATE:
|
10293 |
|
|
*total = sparc_costs->float_move;
|
10294 |
|
|
return false;
|
10295 |
|
|
|
10296 |
|
|
case SQRT:
|
10297 |
|
|
if (mode == DFmode)
|
10298 |
|
|
*total = sparc_costs->float_sqrt_df;
|
10299 |
|
|
else
|
10300 |
|
|
*total = sparc_costs->float_sqrt_sf;
|
10301 |
|
|
return false;
|
10302 |
|
|
|
10303 |
|
|
case COMPARE:
|
10304 |
|
|
if (float_mode_p)
|
10305 |
|
|
*total = sparc_costs->float_cmp;
|
10306 |
|
|
else
|
10307 |
|
|
*total = COSTS_N_INSNS (1);
|
10308 |
|
|
return false;
|
10309 |
|
|
|
10310 |
|
|
case IF_THEN_ELSE:
|
10311 |
|
|
if (float_mode_p)
|
10312 |
|
|
*total = sparc_costs->float_cmove;
|
10313 |
|
|
else
|
10314 |
|
|
*total = sparc_costs->int_cmove;
|
10315 |
|
|
return false;
|
10316 |
|
|
|
10317 |
|
|
case IOR:
|
10318 |
|
|
/* Handle the NAND vector patterns. */
|
10319 |
|
|
if (sparc_vector_mode_supported_p (GET_MODE (x))
|
10320 |
|
|
&& GET_CODE (XEXP (x, 0)) == NOT
|
10321 |
|
|
&& GET_CODE (XEXP (x, 1)) == NOT)
|
10322 |
|
|
{
|
10323 |
|
|
*total = COSTS_N_INSNS (1);
|
10324 |
|
|
return true;
|
10325 |
|
|
}
|
10326 |
|
|
else
|
10327 |
|
|
return false;
|
10328 |
|
|
|
10329 |
|
|
default:
|
10330 |
|
|
return false;
|
10331 |
|
|
}
|
10332 |
|
|
}
|
10333 |
|
|
|
10334 |
|
|
/* Return true if CLASS is either GENERAL_REGS or I64_REGS. */
|
10335 |
|
|
|
10336 |
|
|
static inline bool
|
10337 |
|
|
general_or_i64_p (reg_class_t rclass)
|
10338 |
|
|
{
|
10339 |
|
|
return (rclass == GENERAL_REGS || rclass == I64_REGS);
|
10340 |
|
|
}
|
10341 |
|
|
|
10342 |
|
|
/* Implement TARGET_REGISTER_MOVE_COST. */
|
10343 |
|
|
|
10344 |
|
|
static int
|
10345 |
|
|
sparc_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
|
10346 |
|
|
reg_class_t from, reg_class_t to)
|
10347 |
|
|
{
|
10348 |
|
|
bool need_memory = false;
|
10349 |
|
|
|
10350 |
|
|
if (from == FPCC_REGS || to == FPCC_REGS)
|
10351 |
|
|
need_memory = true;
|
10352 |
|
|
else if ((FP_REG_CLASS_P (from) && general_or_i64_p (to))
|
10353 |
|
|
|| (general_or_i64_p (from) && FP_REG_CLASS_P (to)))
|
10354 |
|
|
{
|
10355 |
|
|
if (TARGET_VIS3)
|
10356 |
|
|
{
|
10357 |
|
|
int size = GET_MODE_SIZE (mode);
|
10358 |
|
|
if (size == 8 || size == 4)
|
10359 |
|
|
{
|
10360 |
|
|
if (! TARGET_ARCH32 || size == 4)
|
10361 |
|
|
return 4;
|
10362 |
|
|
else
|
10363 |
|
|
return 6;
|
10364 |
|
|
}
|
10365 |
|
|
}
|
10366 |
|
|
need_memory = true;
|
10367 |
|
|
}
|
10368 |
|
|
|
10369 |
|
|
if (need_memory)
|
10370 |
|
|
{
|
10371 |
|
|
if (sparc_cpu == PROCESSOR_ULTRASPARC
|
10372 |
|
|
|| sparc_cpu == PROCESSOR_ULTRASPARC3
|
10373 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA
|
10374 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA2
|
10375 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA3
|
10376 |
|
|
|| sparc_cpu == PROCESSOR_NIAGARA4)
|
10377 |
|
|
return 12;
|
10378 |
|
|
|
10379 |
|
|
return 6;
|
10380 |
|
|
}
|
10381 |
|
|
|
10382 |
|
|
return 2;
|
10383 |
|
|
}
|
10384 |
|
|
|
10385 |
|
|
/* Emit the sequence of insns SEQ while preserving the registers REG and REG2.
|
10386 |
|
|
This is achieved by means of a manual dynamic stack space allocation in
|
10387 |
|
|
the current frame. We make the assumption that SEQ doesn't contain any
|
10388 |
|
|
function calls, with the possible exception of calls to the GOT helper. */
|
10389 |
|
|
|
10390 |
|
|
static void
|
10391 |
|
|
emit_and_preserve (rtx seq, rtx reg, rtx reg2)
|
10392 |
|
|
{
|
10393 |
|
|
/* We must preserve the lowest 16 words for the register save area. */
|
10394 |
|
|
HOST_WIDE_INT offset = 16*UNITS_PER_WORD;
|
10395 |
|
|
/* We really need only 2 words of fresh stack space. */
|
10396 |
|
|
HOST_WIDE_INT size = SPARC_STACK_ALIGN (offset + 2*UNITS_PER_WORD);
|
10397 |
|
|
|
10398 |
|
|
rtx slot
|
10399 |
|
|
= gen_rtx_MEM (word_mode, plus_constant (stack_pointer_rtx,
|
10400 |
|
|
SPARC_STACK_BIAS + offset));
|
10401 |
|
|
|
10402 |
|
|
emit_insn (gen_stack_pointer_dec (GEN_INT (size)));
|
10403 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, slot, reg));
|
10404 |
|
|
if (reg2)
|
10405 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
10406 |
|
|
adjust_address (slot, word_mode, UNITS_PER_WORD),
|
10407 |
|
|
reg2));
|
10408 |
|
|
emit_insn (seq);
|
10409 |
|
|
if (reg2)
|
10410 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
10411 |
|
|
reg2,
|
10412 |
|
|
adjust_address (slot, word_mode, UNITS_PER_WORD)));
|
10413 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, reg, slot));
|
10414 |
|
|
emit_insn (gen_stack_pointer_inc (GEN_INT (size)));
|
10415 |
|
|
}
|
10416 |
|
|
|
10417 |
|
|
/* Output the assembler code for a thunk function. THUNK_DECL is the
|
10418 |
|
|
declaration for the thunk function itself, FUNCTION is the decl for
|
10419 |
|
|
the target function. DELTA is an immediate constant offset to be
|
10420 |
|
|
added to THIS. If VCALL_OFFSET is nonzero, the word at address
|
10421 |
|
|
(*THIS + VCALL_OFFSET) should be additionally added to THIS. */
|
10422 |
|
|
|
10423 |
|
|
static void
|
10424 |
|
|
sparc_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
|
10425 |
|
|
HOST_WIDE_INT delta, HOST_WIDE_INT vcall_offset,
|
10426 |
|
|
tree function)
|
10427 |
|
|
{
|
10428 |
|
|
rtx this_rtx, insn, funexp;
|
10429 |
|
|
unsigned int int_arg_first;
|
10430 |
|
|
|
10431 |
|
|
reload_completed = 1;
|
10432 |
|
|
epilogue_completed = 1;
|
10433 |
|
|
|
10434 |
|
|
emit_note (NOTE_INSN_PROLOGUE_END);
|
10435 |
|
|
|
10436 |
|
|
if (TARGET_FLAT)
|
10437 |
|
|
{
|
10438 |
|
|
sparc_leaf_function_p = 1;
|
10439 |
|
|
|
10440 |
|
|
int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
|
10441 |
|
|
}
|
10442 |
|
|
else if (flag_delayed_branch)
|
10443 |
|
|
{
|
10444 |
|
|
/* We will emit a regular sibcall below, so we need to instruct
|
10445 |
|
|
output_sibcall that we are in a leaf function. */
|
10446 |
|
|
sparc_leaf_function_p = current_function_uses_only_leaf_regs = 1;
|
10447 |
|
|
|
10448 |
|
|
/* This will cause final.c to invoke leaf_renumber_regs so we
|
10449 |
|
|
must behave as if we were in a not-yet-leafified function. */
|
10450 |
|
|
int_arg_first = SPARC_INCOMING_INT_ARG_FIRST;
|
10451 |
|
|
}
|
10452 |
|
|
else
|
10453 |
|
|
{
|
10454 |
|
|
/* We will emit the sibcall manually below, so we will need to
|
10455 |
|
|
manually spill non-leaf registers. */
|
10456 |
|
|
sparc_leaf_function_p = current_function_uses_only_leaf_regs = 0;
|
10457 |
|
|
|
10458 |
|
|
/* We really are in a leaf function. */
|
10459 |
|
|
int_arg_first = SPARC_OUTGOING_INT_ARG_FIRST;
|
10460 |
|
|
}
|
10461 |
|
|
|
10462 |
|
|
/* Find the "this" pointer. Normally in %o0, but in ARCH64 if the function
|
10463 |
|
|
returns a structure, the structure return pointer is there instead. */
|
10464 |
|
|
if (TARGET_ARCH64
|
10465 |
|
|
&& aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function))
|
10466 |
|
|
this_rtx = gen_rtx_REG (Pmode, int_arg_first + 1);
|
10467 |
|
|
else
|
10468 |
|
|
this_rtx = gen_rtx_REG (Pmode, int_arg_first);
|
10469 |
|
|
|
10470 |
|
|
/* Add DELTA. When possible use a plain add, otherwise load it into
|
10471 |
|
|
a register first. */
|
10472 |
|
|
if (delta)
|
10473 |
|
|
{
|
10474 |
|
|
rtx delta_rtx = GEN_INT (delta);
|
10475 |
|
|
|
10476 |
|
|
if (! SPARC_SIMM13_P (delta))
|
10477 |
|
|
{
|
10478 |
|
|
rtx scratch = gen_rtx_REG (Pmode, 1);
|
10479 |
|
|
emit_move_insn (scratch, delta_rtx);
|
10480 |
|
|
delta_rtx = scratch;
|
10481 |
|
|
}
|
10482 |
|
|
|
10483 |
|
|
/* THIS_RTX += DELTA. */
|
10484 |
|
|
emit_insn (gen_add2_insn (this_rtx, delta_rtx));
|
10485 |
|
|
}
|
10486 |
|
|
|
10487 |
|
|
/* Add the word at address (*THIS_RTX + VCALL_OFFSET). */
|
10488 |
|
|
if (vcall_offset)
|
10489 |
|
|
{
|
10490 |
|
|
rtx vcall_offset_rtx = GEN_INT (vcall_offset);
|
10491 |
|
|
rtx scratch = gen_rtx_REG (Pmode, 1);
|
10492 |
|
|
|
10493 |
|
|
gcc_assert (vcall_offset < 0);
|
10494 |
|
|
|
10495 |
|
|
/* SCRATCH = *THIS_RTX. */
|
10496 |
|
|
emit_move_insn (scratch, gen_rtx_MEM (Pmode, this_rtx));
|
10497 |
|
|
|
10498 |
|
|
/* Prepare for adding VCALL_OFFSET. The difficulty is that we
|
10499 |
|
|
may not have any available scratch register at this point. */
|
10500 |
|
|
if (SPARC_SIMM13_P (vcall_offset))
|
10501 |
|
|
;
|
10502 |
|
|
/* This is the case if ARCH64 (unless -ffixed-g5 is passed). */
|
10503 |
|
|
else if (! fixed_regs[5]
|
10504 |
|
|
/* The below sequence is made up of at least 2 insns,
|
10505 |
|
|
while the default method may need only one. */
|
10506 |
|
|
&& vcall_offset < -8192)
|
10507 |
|
|
{
|
10508 |
|
|
rtx scratch2 = gen_rtx_REG (Pmode, 5);
|
10509 |
|
|
emit_move_insn (scratch2, vcall_offset_rtx);
|
10510 |
|
|
vcall_offset_rtx = scratch2;
|
10511 |
|
|
}
|
10512 |
|
|
else
|
10513 |
|
|
{
|
10514 |
|
|
rtx increment = GEN_INT (-4096);
|
10515 |
|
|
|
10516 |
|
|
/* VCALL_OFFSET is a negative number whose typical range can be
|
10517 |
|
|
estimated as -32768..0 in 32-bit mode. In almost all cases
|
10518 |
|
|
it is therefore cheaper to emit multiple add insns than
|
10519 |
|
|
spilling and loading the constant into a register (at least
|
10520 |
|
|
6 insns). */
|
10521 |
|
|
while (! SPARC_SIMM13_P (vcall_offset))
|
10522 |
|
|
{
|
10523 |
|
|
emit_insn (gen_add2_insn (scratch, increment));
|
10524 |
|
|
vcall_offset += 4096;
|
10525 |
|
|
}
|
10526 |
|
|
vcall_offset_rtx = GEN_INT (vcall_offset); /* cannot be 0 */
|
10527 |
|
|
}
|
10528 |
|
|
|
10529 |
|
|
/* SCRATCH = *(*THIS_RTX + VCALL_OFFSET). */
|
10530 |
|
|
emit_move_insn (scratch, gen_rtx_MEM (Pmode,
|
10531 |
|
|
gen_rtx_PLUS (Pmode,
|
10532 |
|
|
scratch,
|
10533 |
|
|
vcall_offset_rtx)));
|
10534 |
|
|
|
10535 |
|
|
/* THIS_RTX += *(*THIS_RTX + VCALL_OFFSET). */
|
10536 |
|
|
emit_insn (gen_add2_insn (this_rtx, scratch));
|
10537 |
|
|
}
|
10538 |
|
|
|
10539 |
|
|
/* Generate a tail call to the target function. */
|
10540 |
|
|
if (! TREE_USED (function))
|
10541 |
|
|
{
|
10542 |
|
|
assemble_external (function);
|
10543 |
|
|
TREE_USED (function) = 1;
|
10544 |
|
|
}
|
10545 |
|
|
funexp = XEXP (DECL_RTL (function), 0);
|
10546 |
|
|
|
10547 |
|
|
if (flag_delayed_branch)
|
10548 |
|
|
{
|
10549 |
|
|
funexp = gen_rtx_MEM (FUNCTION_MODE, funexp);
|
10550 |
|
|
insn = emit_call_insn (gen_sibcall (funexp));
|
10551 |
|
|
SIBLING_CALL_P (insn) = 1;
|
10552 |
|
|
}
|
10553 |
|
|
else
|
10554 |
|
|
{
|
10555 |
|
|
/* The hoops we have to jump through in order to generate a sibcall
|
10556 |
|
|
without using delay slots... */
|
10557 |
|
|
rtx spill_reg, seq, scratch = gen_rtx_REG (Pmode, 1);
|
10558 |
|
|
|
10559 |
|
|
if (flag_pic)
|
10560 |
|
|
{
|
10561 |
|
|
spill_reg = gen_rtx_REG (word_mode, 15); /* %o7 */
|
10562 |
|
|
start_sequence ();
|
10563 |
|
|
load_got_register (); /* clobbers %o7 */
|
10564 |
|
|
scratch = sparc_legitimize_pic_address (funexp, scratch);
|
10565 |
|
|
seq = get_insns ();
|
10566 |
|
|
end_sequence ();
|
10567 |
|
|
emit_and_preserve (seq, spill_reg, pic_offset_table_rtx);
|
10568 |
|
|
}
|
10569 |
|
|
else if (TARGET_ARCH32)
|
10570 |
|
|
{
|
10571 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
10572 |
|
|
scratch,
|
10573 |
|
|
gen_rtx_HIGH (SImode, funexp)));
|
10574 |
|
|
emit_insn (gen_rtx_SET (VOIDmode,
|
10575 |
|
|
scratch,
|
10576 |
|
|
gen_rtx_LO_SUM (SImode, scratch, funexp)));
|
10577 |
|
|
}
|
10578 |
|
|
else /* TARGET_ARCH64 */
|
10579 |
|
|
{
|
10580 |
|
|
switch (sparc_cmodel)
|
10581 |
|
|
{
|
10582 |
|
|
case CM_MEDLOW:
|
10583 |
|
|
case CM_MEDMID:
|
10584 |
|
|
/* The destination can serve as a temporary. */
|
10585 |
|
|
sparc_emit_set_symbolic_const64 (scratch, funexp, scratch);
|
10586 |
|
|
break;
|
10587 |
|
|
|
10588 |
|
|
case CM_MEDANY:
|
10589 |
|
|
case CM_EMBMEDANY:
|
10590 |
|
|
/* The destination cannot serve as a temporary. */
|
10591 |
|
|
spill_reg = gen_rtx_REG (DImode, 15); /* %o7 */
|
10592 |
|
|
start_sequence ();
|
10593 |
|
|
sparc_emit_set_symbolic_const64 (scratch, funexp, spill_reg);
|
10594 |
|
|
seq = get_insns ();
|
10595 |
|
|
end_sequence ();
|
10596 |
|
|
emit_and_preserve (seq, spill_reg, 0);
|
10597 |
|
|
break;
|
10598 |
|
|
|
10599 |
|
|
default:
|
10600 |
|
|
gcc_unreachable ();
|
10601 |
|
|
}
|
10602 |
|
|
}
|
10603 |
|
|
|
10604 |
|
|
emit_jump_insn (gen_indirect_jump (scratch));
|
10605 |
|
|
}
|
10606 |
|
|
|
10607 |
|
|
emit_barrier ();
|
10608 |
|
|
|
10609 |
|
|
/* Run just enough of rest_of_compilation to get the insns emitted.
|
10610 |
|
|
There's not really enough bulk here to make other passes such as
|
10611 |
|
|
instruction scheduling worth while. Note that use_thunk calls
|
10612 |
|
|
assemble_start_function and assemble_end_function. */
|
10613 |
|
|
insn = get_insns ();
|
10614 |
|
|
insn_locators_alloc ();
|
10615 |
|
|
shorten_branches (insn);
|
10616 |
|
|
final_start_function (insn, file, 1);
|
10617 |
|
|
final (insn, file, 1);
|
10618 |
|
|
final_end_function ();
|
10619 |
|
|
|
10620 |
|
|
reload_completed = 0;
|
10621 |
|
|
epilogue_completed = 0;
|
10622 |
|
|
}
|
10623 |
|
|
|
10624 |
|
|
/* Return true if sparc_output_mi_thunk would be able to output the
|
10625 |
|
|
assembler code for the thunk function specified by the arguments
|
10626 |
|
|
it is passed, and false otherwise. */
|
10627 |
|
|
static bool
|
10628 |
|
|
sparc_can_output_mi_thunk (const_tree thunk_fndecl ATTRIBUTE_UNUSED,
|
10629 |
|
|
HOST_WIDE_INT delta ATTRIBUTE_UNUSED,
|
10630 |
|
|
HOST_WIDE_INT vcall_offset,
|
10631 |
|
|
const_tree function ATTRIBUTE_UNUSED)
|
10632 |
|
|
{
|
10633 |
|
|
/* Bound the loop used in the default method above. */
|
10634 |
|
|
return (vcall_offset >= -32768 || ! fixed_regs[5]);
|
10635 |
|
|
}
|
10636 |
|
|
|
10637 |
|
|
/* We use the machine specific reorg pass to enable workarounds for errata. */
|
10638 |
|
|
|
10639 |
|
|
static void
|
10640 |
|
|
sparc_reorg (void)
|
10641 |
|
|
{
|
10642 |
|
|
rtx insn, next;
|
10643 |
|
|
|
10644 |
|
|
/* The only erratum we handle for now is that of the AT697F processor. */
|
10645 |
|
|
if (!sparc_fix_at697f)
|
10646 |
|
|
return;
|
10647 |
|
|
|
10648 |
|
|
/* We need to have the (essentially) final form of the insn stream in order
|
10649 |
|
|
to properly detect the various hazards. Run delay slot scheduling. */
|
10650 |
|
|
if (optimize > 0 && flag_delayed_branch)
|
10651 |
|
|
dbr_schedule (get_insns ());
|
10652 |
|
|
|
10653 |
|
|
/* Now look for specific patterns in the insn stream. */
|
10654 |
|
|
for (insn = get_insns (); insn; insn = next)
|
10655 |
|
|
{
|
10656 |
|
|
bool insert_nop = false;
|
10657 |
|
|
rtx set;
|
10658 |
|
|
|
10659 |
|
|
/* Look for a single-word load into an odd-numbered FP register. */
|
10660 |
|
|
if (NONJUMP_INSN_P (insn)
|
10661 |
|
|
&& (set = single_set (insn)) != NULL_RTX
|
10662 |
|
|
&& GET_MODE_SIZE (GET_MODE (SET_SRC (set))) == 4
|
10663 |
|
|
&& MEM_P (SET_SRC (set))
|
10664 |
|
|
&& REG_P (SET_DEST (set))
|
10665 |
|
|
&& REGNO (SET_DEST (set)) > 31
|
10666 |
|
|
&& REGNO (SET_DEST (set)) % 2 != 0)
|
10667 |
|
|
{
|
10668 |
|
|
/* The wrong dependency is on the enclosing double register. */
|
10669 |
|
|
unsigned int x = REGNO (SET_DEST (set)) - 1;
|
10670 |
|
|
unsigned int src1, src2, dest;
|
10671 |
|
|
int code;
|
10672 |
|
|
|
10673 |
|
|
/* If the insn has a delay slot, then it cannot be problematic. */
|
10674 |
|
|
next = next_active_insn (insn);
|
10675 |
|
|
if (NONJUMP_INSN_P (next) && GET_CODE (PATTERN (next)) == SEQUENCE)
|
10676 |
|
|
code = -1;
|
10677 |
|
|
else
|
10678 |
|
|
{
|
10679 |
|
|
extract_insn (next);
|
10680 |
|
|
code = INSN_CODE (next);
|
10681 |
|
|
}
|
10682 |
|
|
|
10683 |
|
|
switch (code)
|
10684 |
|
|
{
|
10685 |
|
|
case CODE_FOR_adddf3:
|
10686 |
|
|
case CODE_FOR_subdf3:
|
10687 |
|
|
case CODE_FOR_muldf3:
|
10688 |
|
|
case CODE_FOR_divdf3:
|
10689 |
|
|
dest = REGNO (recog_data.operand[0]);
|
10690 |
|
|
src1 = REGNO (recog_data.operand[1]);
|
10691 |
|
|
src2 = REGNO (recog_data.operand[2]);
|
10692 |
|
|
if (src1 != src2)
|
10693 |
|
|
{
|
10694 |
|
|
/* Case [1-4]:
|
10695 |
|
|
ld [address], %fx+1
|
10696 |
|
|
FPOPd %f{x,y}, %f{y,x}, %f{x,y} */
|
10697 |
|
|
if ((src1 == x || src2 == x)
|
10698 |
|
|
&& (dest == src1 || dest == src2))
|
10699 |
|
|
insert_nop = true;
|
10700 |
|
|
}
|
10701 |
|
|
else
|
10702 |
|
|
{
|
10703 |
|
|
/* Case 5:
|
10704 |
|
|
ld [address], %fx+1
|
10705 |
|
|
FPOPd %fx, %fx, %fx */
|
10706 |
|
|
if (src1 == x
|
10707 |
|
|
&& dest == src1
|
10708 |
|
|
&& (code == CODE_FOR_adddf3 || code == CODE_FOR_muldf3))
|
10709 |
|
|
insert_nop = true;
|
10710 |
|
|
}
|
10711 |
|
|
break;
|
10712 |
|
|
|
10713 |
|
|
case CODE_FOR_sqrtdf2:
|
10714 |
|
|
dest = REGNO (recog_data.operand[0]);
|
10715 |
|
|
src1 = REGNO (recog_data.operand[1]);
|
10716 |
|
|
/* Case 6:
|
10717 |
|
|
ld [address], %fx+1
|
10718 |
|
|
fsqrtd %fx, %fx */
|
10719 |
|
|
if (src1 == x && dest == src1)
|
10720 |
|
|
insert_nop = true;
|
10721 |
|
|
break;
|
10722 |
|
|
|
10723 |
|
|
default:
|
10724 |
|
|
break;
|
10725 |
|
|
}
|
10726 |
|
|
}
|
10727 |
|
|
else
|
10728 |
|
|
next = NEXT_INSN (insn);
|
10729 |
|
|
|
10730 |
|
|
if (insert_nop)
|
10731 |
|
|
emit_insn_after (gen_nop (), insn);
|
10732 |
|
|
}
|
10733 |
|
|
}
|
10734 |
|
|
|
10735 |
|
|
/* How to allocate a 'struct machine_function'. */
|
10736 |
|
|
|
10737 |
|
|
static struct machine_function *
|
10738 |
|
|
sparc_init_machine_status (void)
|
10739 |
|
|
{
|
10740 |
|
|
return ggc_alloc_cleared_machine_function ();
|
10741 |
|
|
}
|
10742 |
|
|
|
10743 |
|
|
/* Locate some local-dynamic symbol still in use by this function
|
10744 |
|
|
so that we can print its name in local-dynamic base patterns. */
|
10745 |
|
|
|
10746 |
|
|
static const char *
|
10747 |
|
|
get_some_local_dynamic_name (void)
|
10748 |
|
|
{
|
10749 |
|
|
rtx insn;
|
10750 |
|
|
|
10751 |
|
|
if (cfun->machine->some_ld_name)
|
10752 |
|
|
return cfun->machine->some_ld_name;
|
10753 |
|
|
|
10754 |
|
|
for (insn = get_insns (); insn ; insn = NEXT_INSN (insn))
|
10755 |
|
|
if (INSN_P (insn)
|
10756 |
|
|
&& for_each_rtx (&PATTERN (insn), get_some_local_dynamic_name_1, 0))
|
10757 |
|
|
return cfun->machine->some_ld_name;
|
10758 |
|
|
|
10759 |
|
|
gcc_unreachable ();
|
10760 |
|
|
}
|
10761 |
|
|
|
10762 |
|
|
static int
|
10763 |
|
|
get_some_local_dynamic_name_1 (rtx *px, void *data ATTRIBUTE_UNUSED)
|
10764 |
|
|
{
|
10765 |
|
|
rtx x = *px;
|
10766 |
|
|
|
10767 |
|
|
if (x
|
10768 |
|
|
&& GET_CODE (x) == SYMBOL_REF
|
10769 |
|
|
&& SYMBOL_REF_TLS_MODEL (x) == TLS_MODEL_LOCAL_DYNAMIC)
|
10770 |
|
|
{
|
10771 |
|
|
cfun->machine->some_ld_name = XSTR (x, 0);
|
10772 |
|
|
return 1;
|
10773 |
|
|
}
|
10774 |
|
|
|
10775 |
|
|
return 0;
|
10776 |
|
|
}
|
10777 |
|
|
|
10778 |
|
|
/* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL.
|
10779 |
|
|
We need to emit DTP-relative relocations. */
|
10780 |
|
|
|
10781 |
|
|
static void
|
10782 |
|
|
sparc_output_dwarf_dtprel (FILE *file, int size, rtx x)
|
10783 |
|
|
{
|
10784 |
|
|
switch (size)
|
10785 |
|
|
{
|
10786 |
|
|
case 4:
|
10787 |
|
|
fputs ("\t.word\t%r_tls_dtpoff32(", file);
|
10788 |
|
|
break;
|
10789 |
|
|
case 8:
|
10790 |
|
|
fputs ("\t.xword\t%r_tls_dtpoff64(", file);
|
10791 |
|
|
break;
|
10792 |
|
|
default:
|
10793 |
|
|
gcc_unreachable ();
|
10794 |
|
|
}
|
10795 |
|
|
output_addr_const (file, x);
|
10796 |
|
|
fputs (")", file);
|
10797 |
|
|
}
|
10798 |
|
|
|
10799 |
|
|
/* Do whatever processing is required at the end of a file. */
|
10800 |
|
|
|
10801 |
|
|
static void
|
10802 |
|
|
sparc_file_end (void)
|
10803 |
|
|
{
|
10804 |
|
|
/* If we need to emit the special GOT helper function, do so now. */
|
10805 |
|
|
if (got_helper_rtx)
|
10806 |
|
|
{
|
10807 |
|
|
const char *name = XSTR (got_helper_rtx, 0);
|
10808 |
|
|
const char *reg_name = reg_names[GLOBAL_OFFSET_TABLE_REGNUM];
|
10809 |
|
|
#ifdef DWARF2_UNWIND_INFO
|
10810 |
|
|
bool do_cfi;
|
10811 |
|
|
#endif
|
10812 |
|
|
|
10813 |
|
|
if (USE_HIDDEN_LINKONCE)
|
10814 |
|
|
{
|
10815 |
|
|
tree decl = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
|
10816 |
|
|
get_identifier (name),
|
10817 |
|
|
build_function_type_list (void_type_node,
|
10818 |
|
|
NULL_TREE));
|
10819 |
|
|
DECL_RESULT (decl) = build_decl (BUILTINS_LOCATION, RESULT_DECL,
|
10820 |
|
|
NULL_TREE, void_type_node);
|
10821 |
|
|
TREE_STATIC (decl) = 1;
|
10822 |
|
|
make_decl_one_only (decl, DECL_ASSEMBLER_NAME (decl));
|
10823 |
|
|
DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
|
10824 |
|
|
DECL_VISIBILITY_SPECIFIED (decl) = 1;
|
10825 |
|
|
resolve_unique_section (decl, 0, flag_function_sections);
|
10826 |
|
|
allocate_struct_function (decl, true);
|
10827 |
|
|
cfun->is_thunk = 1;
|
10828 |
|
|
current_function_decl = decl;
|
10829 |
|
|
init_varasm_status ();
|
10830 |
|
|
assemble_start_function (decl, name);
|
10831 |
|
|
}
|
10832 |
|
|
else
|
10833 |
|
|
{
|
10834 |
|
|
const int align = floor_log2 (FUNCTION_BOUNDARY / BITS_PER_UNIT);
|
10835 |
|
|
switch_to_section (text_section);
|
10836 |
|
|
if (align > 0)
|
10837 |
|
|
ASM_OUTPUT_ALIGN (asm_out_file, align);
|
10838 |
|
|
ASM_OUTPUT_LABEL (asm_out_file, name);
|
10839 |
|
|
}
|
10840 |
|
|
|
10841 |
|
|
#ifdef DWARF2_UNWIND_INFO
|
10842 |
|
|
do_cfi = dwarf2out_do_cfi_asm ();
|
10843 |
|
|
if (do_cfi)
|
10844 |
|
|
fprintf (asm_out_file, "\t.cfi_startproc\n");
|
10845 |
|
|
#endif
|
10846 |
|
|
if (flag_delayed_branch)
|
10847 |
|
|
fprintf (asm_out_file, "\tjmp\t%%o7+8\n\t add\t%%o7, %s, %s\n",
|
10848 |
|
|
reg_name, reg_name);
|
10849 |
|
|
else
|
10850 |
|
|
fprintf (asm_out_file, "\tadd\t%%o7, %s, %s\n\tjmp\t%%o7+8\n\t nop\n",
|
10851 |
|
|
reg_name, reg_name);
|
10852 |
|
|
#ifdef DWARF2_UNWIND_INFO
|
10853 |
|
|
if (do_cfi)
|
10854 |
|
|
fprintf (asm_out_file, "\t.cfi_endproc\n");
|
10855 |
|
|
#endif
|
10856 |
|
|
}
|
10857 |
|
|
|
10858 |
|
|
if (NEED_INDICATE_EXEC_STACK)
|
10859 |
|
|
file_end_indicate_exec_stack ();
|
10860 |
|
|
|
10861 |
|
|
#ifdef TARGET_SOLARIS
|
10862 |
|
|
solaris_file_end ();
|
10863 |
|
|
#endif
|
10864 |
|
|
}
|
10865 |
|
|
|
10866 |
|
|
#ifdef TARGET_ALTERNATE_LONG_DOUBLE_MANGLING
|
10867 |
|
|
/* Implement TARGET_MANGLE_TYPE. */
|
10868 |
|
|
|
10869 |
|
|
static const char *
|
10870 |
|
|
sparc_mangle_type (const_tree type)
|
10871 |
|
|
{
|
10872 |
|
|
if (!TARGET_64BIT
|
10873 |
|
|
&& TYPE_MAIN_VARIANT (type) == long_double_type_node
|
10874 |
|
|
&& TARGET_LONG_DOUBLE_128)
|
10875 |
|
|
return "g";
|
10876 |
|
|
|
10877 |
|
|
/* For all other types, use normal C++ mangling. */
|
10878 |
|
|
return NULL;
|
10879 |
|
|
}
|
10880 |
|
|
#endif
|
10881 |
|
|
|
10882 |
|
|
/* Expand a membar instruction for various use cases. Both the LOAD_STORE
|
10883 |
|
|
and BEFORE_AFTER arguments of the form X_Y. They are two-bit masks where
|
10884 |
|
|
bit 0 indicates that X is true, and bit 1 indicates Y is true. */
|
10885 |
|
|
|
10886 |
|
|
void
|
10887 |
|
|
sparc_emit_membar_for_model (enum memmodel model,
|
10888 |
|
|
int load_store, int before_after)
|
10889 |
|
|
{
|
10890 |
|
|
/* Bits for the MEMBAR mmask field. */
|
10891 |
|
|
const int LoadLoad = 1;
|
10892 |
|
|
const int StoreLoad = 2;
|
10893 |
|
|
const int LoadStore = 4;
|
10894 |
|
|
const int StoreStore = 8;
|
10895 |
|
|
|
10896 |
|
|
int mm = 0, implied = 0;
|
10897 |
|
|
|
10898 |
|
|
switch (sparc_memory_model)
|
10899 |
|
|
{
|
10900 |
|
|
case SMM_SC:
|
10901 |
|
|
/* Sequential Consistency. All memory transactions are immediately
|
10902 |
|
|
visible in sequential execution order. No barriers needed. */
|
10903 |
|
|
implied = LoadLoad | StoreLoad | LoadStore | StoreStore;
|
10904 |
|
|
break;
|
10905 |
|
|
|
10906 |
|
|
case SMM_TSO:
|
10907 |
|
|
/* Total Store Ordering: all memory transactions with store semantics
|
10908 |
|
|
are followed by an implied StoreStore. */
|
10909 |
|
|
implied |= StoreStore;
|
10910 |
|
|
/* FALLTHRU */
|
10911 |
|
|
|
10912 |
|
|
case SMM_PSO:
|
10913 |
|
|
/* Partial Store Ordering: all memory transactions with load semantics
|
10914 |
|
|
are followed by an implied LoadLoad | LoadStore. */
|
10915 |
|
|
implied |= LoadLoad | LoadStore;
|
10916 |
|
|
|
10917 |
|
|
/* If we're not looking for a raw barrer (before+after), then atomic
|
10918 |
|
|
operations get the benefit of being both load and store. */
|
10919 |
|
|
if (load_store == 3 && before_after == 2)
|
10920 |
|
|
implied |= StoreLoad | StoreStore;
|
10921 |
|
|
/* FALLTHRU */
|
10922 |
|
|
|
10923 |
|
|
case SMM_RMO:
|
10924 |
|
|
/* Relaxed Memory Ordering: no implicit bits. */
|
10925 |
|
|
break;
|
10926 |
|
|
|
10927 |
|
|
default:
|
10928 |
|
|
gcc_unreachable ();
|
10929 |
|
|
}
|
10930 |
|
|
|
10931 |
|
|
if (before_after & 1)
|
10932 |
|
|
{
|
10933 |
|
|
if (model == MEMMODEL_ACQUIRE
|
10934 |
|
|
|| model == MEMMODEL_ACQ_REL
|
10935 |
|
|
|| model == MEMMODEL_SEQ_CST)
|
10936 |
|
|
{
|
10937 |
|
|
if (load_store & 1)
|
10938 |
|
|
mm |= LoadLoad | LoadStore;
|
10939 |
|
|
if (load_store & 2)
|
10940 |
|
|
mm |= StoreLoad | StoreStore;
|
10941 |
|
|
}
|
10942 |
|
|
}
|
10943 |
|
|
if (before_after & 2)
|
10944 |
|
|
{
|
10945 |
|
|
if (model == MEMMODEL_RELEASE
|
10946 |
|
|
|| model == MEMMODEL_ACQ_REL
|
10947 |
|
|
|| model == MEMMODEL_SEQ_CST)
|
10948 |
|
|
{
|
10949 |
|
|
if (load_store & 1)
|
10950 |
|
|
mm |= LoadLoad | StoreLoad;
|
10951 |
|
|
if (load_store & 2)
|
10952 |
|
|
mm |= LoadStore | StoreStore;
|
10953 |
|
|
}
|
10954 |
|
|
}
|
10955 |
|
|
|
10956 |
|
|
/* Remove the bits implied by the system memory model. */
|
10957 |
|
|
mm &= ~implied;
|
10958 |
|
|
|
10959 |
|
|
/* For raw barriers (before+after), always emit a barrier.
|
10960 |
|
|
This will become a compile-time barrier if needed. */
|
10961 |
|
|
if (mm || before_after == 3)
|
10962 |
|
|
emit_insn (gen_membar (GEN_INT (mm)));
|
10963 |
|
|
}
|
10964 |
|
|
|
10965 |
|
|
/* Expand code to perform a 8 or 16-bit compare and swap by doing 32-bit
|
10966 |
|
|
compare and swap on the word containing the byte or half-word. */
|
10967 |
|
|
|
10968 |
|
|
static void
|
10969 |
|
|
sparc_expand_compare_and_swap_12 (rtx bool_result, rtx result, rtx mem,
|
10970 |
|
|
rtx oldval, rtx newval)
|
10971 |
|
|
{
|
10972 |
|
|
rtx addr1 = force_reg (Pmode, XEXP (mem, 0));
|
10973 |
|
|
rtx addr = gen_reg_rtx (Pmode);
|
10974 |
|
|
rtx off = gen_reg_rtx (SImode);
|
10975 |
|
|
rtx oldv = gen_reg_rtx (SImode);
|
10976 |
|
|
rtx newv = gen_reg_rtx (SImode);
|
10977 |
|
|
rtx oldvalue = gen_reg_rtx (SImode);
|
10978 |
|
|
rtx newvalue = gen_reg_rtx (SImode);
|
10979 |
|
|
rtx res = gen_reg_rtx (SImode);
|
10980 |
|
|
rtx resv = gen_reg_rtx (SImode);
|
10981 |
|
|
rtx memsi, val, mask, end_label, loop_label, cc;
|
10982 |
|
|
|
10983 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, addr,
|
10984 |
|
|
gen_rtx_AND (Pmode, addr1, GEN_INT (-4))));
|
10985 |
|
|
|
10986 |
|
|
if (Pmode != SImode)
|
10987 |
|
|
addr1 = gen_lowpart (SImode, addr1);
|
10988 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, off,
|
10989 |
|
|
gen_rtx_AND (SImode, addr1, GEN_INT (3))));
|
10990 |
|
|
|
10991 |
|
|
memsi = gen_rtx_MEM (SImode, addr);
|
10992 |
|
|
set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
|
10993 |
|
|
MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
|
10994 |
|
|
|
10995 |
|
|
val = copy_to_reg (memsi);
|
10996 |
|
|
|
10997 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, off,
|
10998 |
|
|
gen_rtx_XOR (SImode, off,
|
10999 |
|
|
GEN_INT (GET_MODE (mem) == QImode
|
11000 |
|
|
? 3 : 2))));
|
11001 |
|
|
|
11002 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, off,
|
11003 |
|
|
gen_rtx_ASHIFT (SImode, off, GEN_INT (3))));
|
11004 |
|
|
|
11005 |
|
|
if (GET_MODE (mem) == QImode)
|
11006 |
|
|
mask = force_reg (SImode, GEN_INT (0xff));
|
11007 |
|
|
else
|
11008 |
|
|
mask = force_reg (SImode, GEN_INT (0xffff));
|
11009 |
|
|
|
11010 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, mask,
|
11011 |
|
|
gen_rtx_ASHIFT (SImode, mask, off)));
|
11012 |
|
|
|
11013 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, val,
|
11014 |
|
|
gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
|
11015 |
|
|
val)));
|
11016 |
|
|
|
11017 |
|
|
oldval = gen_lowpart (SImode, oldval);
|
11018 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, oldv,
|
11019 |
|
|
gen_rtx_ASHIFT (SImode, oldval, off)));
|
11020 |
|
|
|
11021 |
|
|
newval = gen_lowpart_common (SImode, newval);
|
11022 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, newv,
|
11023 |
|
|
gen_rtx_ASHIFT (SImode, newval, off)));
|
11024 |
|
|
|
11025 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, oldv,
|
11026 |
|
|
gen_rtx_AND (SImode, oldv, mask)));
|
11027 |
|
|
|
11028 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, newv,
|
11029 |
|
|
gen_rtx_AND (SImode, newv, mask)));
|
11030 |
|
|
|
11031 |
|
|
end_label = gen_label_rtx ();
|
11032 |
|
|
loop_label = gen_label_rtx ();
|
11033 |
|
|
emit_label (loop_label);
|
11034 |
|
|
|
11035 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, oldvalue,
|
11036 |
|
|
gen_rtx_IOR (SImode, oldv, val)));
|
11037 |
|
|
|
11038 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, newvalue,
|
11039 |
|
|
gen_rtx_IOR (SImode, newv, val)));
|
11040 |
|
|
|
11041 |
|
|
emit_move_insn (bool_result, const1_rtx);
|
11042 |
|
|
|
11043 |
|
|
emit_insn (gen_atomic_compare_and_swapsi_1 (res, memsi, oldvalue, newvalue));
|
11044 |
|
|
|
11045 |
|
|
emit_cmp_and_jump_insns (res, oldvalue, EQ, NULL, SImode, 0, end_label);
|
11046 |
|
|
|
11047 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, resv,
|
11048 |
|
|
gen_rtx_AND (SImode, gen_rtx_NOT (SImode, mask),
|
11049 |
|
|
res)));
|
11050 |
|
|
|
11051 |
|
|
emit_move_insn (bool_result, const0_rtx);
|
11052 |
|
|
|
11053 |
|
|
cc = gen_compare_reg_1 (NE, resv, val);
|
11054 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, val, resv));
|
11055 |
|
|
|
11056 |
|
|
/* Use cbranchcc4 to separate the compare and branch! */
|
11057 |
|
|
emit_jump_insn (gen_cbranchcc4 (gen_rtx_NE (VOIDmode, cc, const0_rtx),
|
11058 |
|
|
cc, const0_rtx, loop_label));
|
11059 |
|
|
|
11060 |
|
|
emit_label (end_label);
|
11061 |
|
|
|
11062 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, res,
|
11063 |
|
|
gen_rtx_AND (SImode, res, mask)));
|
11064 |
|
|
|
11065 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, res,
|
11066 |
|
|
gen_rtx_LSHIFTRT (SImode, res, off)));
|
11067 |
|
|
|
11068 |
|
|
emit_move_insn (result, gen_lowpart (GET_MODE (result), res));
|
11069 |
|
|
}
|
11070 |
|
|
|
11071 |
|
|
/* Expand code to perform a compare-and-swap. */
|
11072 |
|
|
|
11073 |
|
|
void
|
11074 |
|
|
sparc_expand_compare_and_swap (rtx operands[])
|
11075 |
|
|
{
|
11076 |
|
|
rtx bval, retval, mem, oldval, newval;
|
11077 |
|
|
enum machine_mode mode;
|
11078 |
|
|
enum memmodel model;
|
11079 |
|
|
|
11080 |
|
|
bval = operands[0];
|
11081 |
|
|
retval = operands[1];
|
11082 |
|
|
mem = operands[2];
|
11083 |
|
|
oldval = operands[3];
|
11084 |
|
|
newval = operands[4];
|
11085 |
|
|
model = (enum memmodel) INTVAL (operands[6]);
|
11086 |
|
|
mode = GET_MODE (mem);
|
11087 |
|
|
|
11088 |
|
|
sparc_emit_membar_for_model (model, 3, 1);
|
11089 |
|
|
|
11090 |
|
|
if (reg_overlap_mentioned_p (retval, oldval))
|
11091 |
|
|
oldval = copy_to_reg (oldval);
|
11092 |
|
|
|
11093 |
|
|
if (mode == QImode || mode == HImode)
|
11094 |
|
|
sparc_expand_compare_and_swap_12 (bval, retval, mem, oldval, newval);
|
11095 |
|
|
else
|
11096 |
|
|
{
|
11097 |
|
|
rtx (*gen) (rtx, rtx, rtx, rtx);
|
11098 |
|
|
rtx x;
|
11099 |
|
|
|
11100 |
|
|
if (mode == SImode)
|
11101 |
|
|
gen = gen_atomic_compare_and_swapsi_1;
|
11102 |
|
|
else
|
11103 |
|
|
gen = gen_atomic_compare_and_swapdi_1;
|
11104 |
|
|
emit_insn (gen (retval, mem, oldval, newval));
|
11105 |
|
|
|
11106 |
|
|
x = emit_store_flag (bval, EQ, retval, oldval, mode, 1, 1);
|
11107 |
|
|
if (x != bval)
|
11108 |
|
|
convert_move (bval, x, 1);
|
11109 |
|
|
}
|
11110 |
|
|
|
11111 |
|
|
sparc_emit_membar_for_model (model, 3, 2);
|
11112 |
|
|
}
|
11113 |
|
|
|
11114 |
|
|
void
|
11115 |
|
|
sparc_expand_vec_perm_bmask (enum machine_mode vmode, rtx sel)
|
11116 |
|
|
{
|
11117 |
|
|
rtx t_1, t_2, t_3;
|
11118 |
|
|
|
11119 |
|
|
sel = gen_lowpart (DImode, sel);
|
11120 |
|
|
switch (vmode)
|
11121 |
|
|
{
|
11122 |
|
|
case V2SImode:
|
11123 |
|
|
/* inp = xxxxxxxAxxxxxxxB */
|
11124 |
|
|
t_1 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (16),
|
11125 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11126 |
|
|
/* t_1 = ....xxxxxxxAxxx. */
|
11127 |
|
|
sel = expand_simple_binop (SImode, AND, gen_lowpart (SImode, sel),
|
11128 |
|
|
GEN_INT (3), NULL_RTX, 1, OPTAB_DIRECT);
|
11129 |
|
|
t_1 = expand_simple_binop (SImode, AND, gen_lowpart (SImode, t_1),
|
11130 |
|
|
GEN_INT (0x30000), NULL_RTX, 1, OPTAB_DIRECT);
|
11131 |
|
|
/* sel = .......B */
|
11132 |
|
|
/* t_1 = ...A.... */
|
11133 |
|
|
sel = expand_simple_binop (SImode, IOR, sel, t_1, sel, 1, OPTAB_DIRECT);
|
11134 |
|
|
/* sel = ...A...B */
|
11135 |
|
|
sel = expand_mult (SImode, sel, GEN_INT (0x4444), sel, 1);
|
11136 |
|
|
/* sel = AAAABBBB * 4 */
|
11137 |
|
|
t_1 = force_reg (SImode, GEN_INT (0x01230123));
|
11138 |
|
|
/* sel = { A*4, A*4+1, A*4+2, ... } */
|
11139 |
|
|
break;
|
11140 |
|
|
|
11141 |
|
|
case V4HImode:
|
11142 |
|
|
/* inp = xxxAxxxBxxxCxxxD */
|
11143 |
|
|
t_1 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (8),
|
11144 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11145 |
|
|
t_2 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (16),
|
11146 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11147 |
|
|
t_3 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (24),
|
11148 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11149 |
|
|
/* t_1 = ..xxxAxxxBxxxCxx */
|
11150 |
|
|
/* t_2 = ....xxxAxxxBxxxC */
|
11151 |
|
|
/* t_3 = ......xxxAxxxBxx */
|
11152 |
|
|
sel = expand_simple_binop (SImode, AND, gen_lowpart (SImode, sel),
|
11153 |
|
|
GEN_INT (0x07),
|
11154 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11155 |
|
|
t_1 = expand_simple_binop (SImode, AND, gen_lowpart (SImode, t_1),
|
11156 |
|
|
GEN_INT (0x0700),
|
11157 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11158 |
|
|
t_2 = expand_simple_binop (SImode, AND, gen_lowpart (SImode, t_2),
|
11159 |
|
|
GEN_INT (0x070000),
|
11160 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11161 |
|
|
t_3 = expand_simple_binop (SImode, AND, gen_lowpart (SImode, t_3),
|
11162 |
|
|
GEN_INT (0x07000000),
|
11163 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11164 |
|
|
/* sel = .......D */
|
11165 |
|
|
/* t_1 = .....C.. */
|
11166 |
|
|
/* t_2 = ...B.... */
|
11167 |
|
|
/* t_3 = .A...... */
|
11168 |
|
|
sel = expand_simple_binop (SImode, IOR, sel, t_1, sel, 1, OPTAB_DIRECT);
|
11169 |
|
|
t_2 = expand_simple_binop (SImode, IOR, t_2, t_3, t_2, 1, OPTAB_DIRECT);
|
11170 |
|
|
sel = expand_simple_binop (SImode, IOR, sel, t_2, sel, 1, OPTAB_DIRECT);
|
11171 |
|
|
/* sel = .A.B.C.D */
|
11172 |
|
|
sel = expand_mult (SImode, sel, GEN_INT (0x22), sel, 1);
|
11173 |
|
|
/* sel = AABBCCDD * 2 */
|
11174 |
|
|
t_1 = force_reg (SImode, GEN_INT (0x01010101));
|
11175 |
|
|
/* sel = { A*2, A*2+1, B*2, B*2+1, ... } */
|
11176 |
|
|
break;
|
11177 |
|
|
|
11178 |
|
|
case V8QImode:
|
11179 |
|
|
/* input = xAxBxCxDxExFxGxH */
|
11180 |
|
|
sel = expand_simple_binop (DImode, AND, sel,
|
11181 |
|
|
GEN_INT ((HOST_WIDE_INT)0x0f0f0f0f << 32
|
11182 |
|
|
| 0x0f0f0f0f),
|
11183 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11184 |
|
|
/* sel = .A.B.C.D.E.F.G.H */
|
11185 |
|
|
t_1 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (4),
|
11186 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11187 |
|
|
/* t_1 = ..A.B.C.D.E.F.G. */
|
11188 |
|
|
sel = expand_simple_binop (DImode, IOR, sel, t_1,
|
11189 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11190 |
|
|
/* sel = .AABBCCDDEEFFGGH */
|
11191 |
|
|
sel = expand_simple_binop (DImode, AND, sel,
|
11192 |
|
|
GEN_INT ((HOST_WIDE_INT)0xff00ff << 32
|
11193 |
|
|
| 0xff00ff),
|
11194 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11195 |
|
|
/* sel = ..AB..CD..EF..GH */
|
11196 |
|
|
t_1 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (8),
|
11197 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11198 |
|
|
/* t_1 = ....AB..CD..EF.. */
|
11199 |
|
|
sel = expand_simple_binop (DImode, IOR, sel, t_1,
|
11200 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11201 |
|
|
/* sel = ..ABABCDCDEFEFGH */
|
11202 |
|
|
sel = expand_simple_binop (DImode, AND, sel,
|
11203 |
|
|
GEN_INT ((HOST_WIDE_INT)0xffff << 32 | 0xffff),
|
11204 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11205 |
|
|
/* sel = ....ABCD....EFGH */
|
11206 |
|
|
t_1 = expand_simple_binop (DImode, LSHIFTRT, sel, GEN_INT (16),
|
11207 |
|
|
NULL_RTX, 1, OPTAB_DIRECT);
|
11208 |
|
|
/* t_1 = ........ABCD.... */
|
11209 |
|
|
sel = gen_lowpart (SImode, sel);
|
11210 |
|
|
t_1 = gen_lowpart (SImode, t_1);
|
11211 |
|
|
break;
|
11212 |
|
|
|
11213 |
|
|
default:
|
11214 |
|
|
gcc_unreachable ();
|
11215 |
|
|
}
|
11216 |
|
|
|
11217 |
|
|
/* Always perform the final addition/merge within the bmask insn. */
|
11218 |
|
|
emit_insn (gen_bmasksi_vis (gen_reg_rtx (SImode), sel, t_1));
|
11219 |
|
|
}
|
11220 |
|
|
|
11221 |
|
|
/* Implement TARGET_FRAME_POINTER_REQUIRED. */
|
11222 |
|
|
|
11223 |
|
|
static bool
|
11224 |
|
|
sparc_frame_pointer_required (void)
|
11225 |
|
|
{
|
11226 |
|
|
/* If the stack pointer is dynamically modified in the function, it cannot
|
11227 |
|
|
serve as the frame pointer. */
|
11228 |
|
|
if (cfun->calls_alloca)
|
11229 |
|
|
return true;
|
11230 |
|
|
|
11231 |
|
|
/* If the function receives nonlocal gotos, it needs to save the frame
|
11232 |
|
|
pointer in the nonlocal_goto_save_area object. */
|
11233 |
|
|
if (cfun->has_nonlocal_label)
|
11234 |
|
|
return true;
|
11235 |
|
|
|
11236 |
|
|
/* In flat mode, that's it. */
|
11237 |
|
|
if (TARGET_FLAT)
|
11238 |
|
|
return false;
|
11239 |
|
|
|
11240 |
|
|
/* Otherwise, the frame pointer is required if the function isn't leaf. */
|
11241 |
|
|
return !(current_function_is_leaf && only_leaf_regs_used ());
|
11242 |
|
|
}
|
11243 |
|
|
|
11244 |
|
|
/* The way this is structured, we can't eliminate SFP in favor of SP
|
11245 |
|
|
if the frame pointer is required: we want to use the SFP->HFP elimination
|
11246 |
|
|
in that case. But the test in update_eliminables doesn't know we are
|
11247 |
|
|
assuming below that we only do the former elimination. */
|
11248 |
|
|
|
11249 |
|
|
static bool
|
11250 |
|
|
sparc_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
|
11251 |
|
|
{
|
11252 |
|
|
return to == HARD_FRAME_POINTER_REGNUM || !sparc_frame_pointer_required ();
|
11253 |
|
|
}
|
11254 |
|
|
|
11255 |
|
|
/* Return the hard frame pointer directly to bypass the stack bias. */
|
11256 |
|
|
|
11257 |
|
|
static rtx
|
11258 |
|
|
sparc_builtin_setjmp_frame_value (void)
|
11259 |
|
|
{
|
11260 |
|
|
return hard_frame_pointer_rtx;
|
11261 |
|
|
}
|
11262 |
|
|
|
11263 |
|
|
/* If !TARGET_FPU, then make the fp registers and fp cc regs fixed so that
|
11264 |
|
|
they won't be allocated. */
|
11265 |
|
|
|
11266 |
|
|
static void
|
11267 |
|
|
sparc_conditional_register_usage (void)
|
11268 |
|
|
{
|
11269 |
|
|
if (PIC_OFFSET_TABLE_REGNUM != INVALID_REGNUM)
|
11270 |
|
|
{
|
11271 |
|
|
fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
|
11272 |
|
|
call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1;
|
11273 |
|
|
}
|
11274 |
|
|
/* If the user has passed -f{fixed,call-{used,saved}}-g5 */
|
11275 |
|
|
/* then honor it. */
|
11276 |
|
|
if (TARGET_ARCH32 && fixed_regs[5])
|
11277 |
|
|
fixed_regs[5] = 1;
|
11278 |
|
|
else if (TARGET_ARCH64 && fixed_regs[5] == 2)
|
11279 |
|
|
fixed_regs[5] = 0;
|
11280 |
|
|
if (! TARGET_V9)
|
11281 |
|
|
{
|
11282 |
|
|
int regno;
|
11283 |
|
|
for (regno = SPARC_FIRST_V9_FP_REG;
|
11284 |
|
|
regno <= SPARC_LAST_V9_FP_REG;
|
11285 |
|
|
regno++)
|
11286 |
|
|
fixed_regs[regno] = 1;
|
11287 |
|
|
/* %fcc0 is used by v8 and v9. */
|
11288 |
|
|
for (regno = SPARC_FIRST_V9_FCC_REG + 1;
|
11289 |
|
|
regno <= SPARC_LAST_V9_FCC_REG;
|
11290 |
|
|
regno++)
|
11291 |
|
|
fixed_regs[regno] = 1;
|
11292 |
|
|
}
|
11293 |
|
|
if (! TARGET_FPU)
|
11294 |
|
|
{
|
11295 |
|
|
int regno;
|
11296 |
|
|
for (regno = 32; regno < SPARC_LAST_V9_FCC_REG; regno++)
|
11297 |
|
|
fixed_regs[regno] = 1;
|
11298 |
|
|
}
|
11299 |
|
|
/* If the user has passed -f{fixed,call-{used,saved}}-g2 */
|
11300 |
|
|
/* then honor it. Likewise with g3 and g4. */
|
11301 |
|
|
if (fixed_regs[2] == 2)
|
11302 |
|
|
fixed_regs[2] = ! TARGET_APP_REGS;
|
11303 |
|
|
if (fixed_regs[3] == 2)
|
11304 |
|
|
fixed_regs[3] = ! TARGET_APP_REGS;
|
11305 |
|
|
if (TARGET_ARCH32 && fixed_regs[4] == 2)
|
11306 |
|
|
fixed_regs[4] = ! TARGET_APP_REGS;
|
11307 |
|
|
else if (TARGET_CM_EMBMEDANY)
|
11308 |
|
|
fixed_regs[4] = 1;
|
11309 |
|
|
else if (fixed_regs[4] == 2)
|
11310 |
|
|
fixed_regs[4] = 0;
|
11311 |
|
|
if (TARGET_FLAT)
|
11312 |
|
|
{
|
11313 |
|
|
int regno;
|
11314 |
|
|
/* Disable leaf functions. */
|
11315 |
|
|
memset (sparc_leaf_regs, 0, FIRST_PSEUDO_REGISTER);
|
11316 |
|
|
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
|
11317 |
|
|
leaf_reg_remap [regno] = regno;
|
11318 |
|
|
}
|
11319 |
|
|
if (TARGET_VIS)
|
11320 |
|
|
global_regs[SPARC_GSR_REG] = 1;
|
11321 |
|
|
}
|
11322 |
|
|
|
11323 |
|
|
/* Implement TARGET_PREFERRED_RELOAD_CLASS:
|
11324 |
|
|
|
11325 |
|
|
- We can't load constants into FP registers.
|
11326 |
|
|
- We can't load FP constants into integer registers when soft-float,
|
11327 |
|
|
because there is no soft-float pattern with a r/F constraint.
|
11328 |
|
|
- We can't load FP constants into integer registers for TFmode unless
|
11329 |
|
|
it is 0.0L, because there is no movtf pattern with a r/F constraint.
|
11330 |
|
|
- Try and reload integer constants (symbolic or otherwise) back into
|
11331 |
|
|
registers directly, rather than having them dumped to memory. */
|
11332 |
|
|
|
11333 |
|
|
static reg_class_t
|
11334 |
|
|
sparc_preferred_reload_class (rtx x, reg_class_t rclass)
|
11335 |
|
|
{
|
11336 |
|
|
enum machine_mode mode = GET_MODE (x);
|
11337 |
|
|
if (CONSTANT_P (x))
|
11338 |
|
|
{
|
11339 |
|
|
if (FP_REG_CLASS_P (rclass)
|
11340 |
|
|
|| rclass == GENERAL_OR_FP_REGS
|
11341 |
|
|
|| rclass == GENERAL_OR_EXTRA_FP_REGS
|
11342 |
|
|
|| (GET_MODE_CLASS (mode) == MODE_FLOAT && ! TARGET_FPU)
|
11343 |
|
|
|| (mode == TFmode && ! const_zero_operand (x, mode)))
|
11344 |
|
|
return NO_REGS;
|
11345 |
|
|
|
11346 |
|
|
if (GET_MODE_CLASS (mode) == MODE_INT)
|
11347 |
|
|
return GENERAL_REGS;
|
11348 |
|
|
|
11349 |
|
|
if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
|
11350 |
|
|
{
|
11351 |
|
|
if (! FP_REG_CLASS_P (rclass)
|
11352 |
|
|
|| !(const_zero_operand (x, mode)
|
11353 |
|
|
|| const_all_ones_operand (x, mode)))
|
11354 |
|
|
return NO_REGS;
|
11355 |
|
|
}
|
11356 |
|
|
}
|
11357 |
|
|
|
11358 |
|
|
if (TARGET_VIS3
|
11359 |
|
|
&& ! TARGET_ARCH64
|
11360 |
|
|
&& (rclass == EXTRA_FP_REGS
|
11361 |
|
|
|| rclass == GENERAL_OR_EXTRA_FP_REGS))
|
11362 |
|
|
{
|
11363 |
|
|
int regno = true_regnum (x);
|
11364 |
|
|
|
11365 |
|
|
if (SPARC_INT_REG_P (regno))
|
11366 |
|
|
return (rclass == EXTRA_FP_REGS
|
11367 |
|
|
? FP_REGS : GENERAL_OR_FP_REGS);
|
11368 |
|
|
}
|
11369 |
|
|
|
11370 |
|
|
return rclass;
|
11371 |
|
|
}
|
11372 |
|
|
|
11373 |
|
|
/* Output a wide multiply instruction in V8+ mode. INSN is the instruction,
|
11374 |
|
|
OPERANDS are its operands and OPCODE is the mnemonic to be used. */
|
11375 |
|
|
|
11376 |
|
|
const char *
|
11377 |
|
|
output_v8plus_mult (rtx insn, rtx *operands, const char *opcode)
|
11378 |
|
|
{
|
11379 |
|
|
char mulstr[32];
|
11380 |
|
|
|
11381 |
|
|
gcc_assert (! TARGET_ARCH64);
|
11382 |
|
|
|
11383 |
|
|
if (sparc_check_64 (operands[1], insn) <= 0)
|
11384 |
|
|
output_asm_insn ("srl\t%L1, 0, %L1", operands);
|
11385 |
|
|
if (which_alternative == 1)
|
11386 |
|
|
output_asm_insn ("sllx\t%H1, 32, %H1", operands);
|
11387 |
|
|
if (GET_CODE (operands[2]) == CONST_INT)
|
11388 |
|
|
{
|
11389 |
|
|
if (which_alternative == 1)
|
11390 |
|
|
{
|
11391 |
|
|
output_asm_insn ("or\t%L1, %H1, %H1", operands);
|
11392 |
|
|
sprintf (mulstr, "%s\t%%H1, %%2, %%L0", opcode);
|
11393 |
|
|
output_asm_insn (mulstr, operands);
|
11394 |
|
|
return "srlx\t%L0, 32, %H0";
|
11395 |
|
|
}
|
11396 |
|
|
else
|
11397 |
|
|
{
|
11398 |
|
|
output_asm_insn ("sllx\t%H1, 32, %3", operands);
|
11399 |
|
|
output_asm_insn ("or\t%L1, %3, %3", operands);
|
11400 |
|
|
sprintf (mulstr, "%s\t%%3, %%2, %%3", opcode);
|
11401 |
|
|
output_asm_insn (mulstr, operands);
|
11402 |
|
|
output_asm_insn ("srlx\t%3, 32, %H0", operands);
|
11403 |
|
|
return "mov\t%3, %L0";
|
11404 |
|
|
}
|
11405 |
|
|
}
|
11406 |
|
|
else if (rtx_equal_p (operands[1], operands[2]))
|
11407 |
|
|
{
|
11408 |
|
|
if (which_alternative == 1)
|
11409 |
|
|
{
|
11410 |
|
|
output_asm_insn ("or\t%L1, %H1, %H1", operands);
|
11411 |
|
|
sprintf (mulstr, "%s\t%%H1, %%H1, %%L0", opcode);
|
11412 |
|
|
output_asm_insn (mulstr, operands);
|
11413 |
|
|
return "srlx\t%L0, 32, %H0";
|
11414 |
|
|
}
|
11415 |
|
|
else
|
11416 |
|
|
{
|
11417 |
|
|
output_asm_insn ("sllx\t%H1, 32, %3", operands);
|
11418 |
|
|
output_asm_insn ("or\t%L1, %3, %3", operands);
|
11419 |
|
|
sprintf (mulstr, "%s\t%%3, %%3, %%3", opcode);
|
11420 |
|
|
output_asm_insn (mulstr, operands);
|
11421 |
|
|
output_asm_insn ("srlx\t%3, 32, %H0", operands);
|
11422 |
|
|
return "mov\t%3, %L0";
|
11423 |
|
|
}
|
11424 |
|
|
}
|
11425 |
|
|
if (sparc_check_64 (operands[2], insn) <= 0)
|
11426 |
|
|
output_asm_insn ("srl\t%L2, 0, %L2", operands);
|
11427 |
|
|
if (which_alternative == 1)
|
11428 |
|
|
{
|
11429 |
|
|
output_asm_insn ("or\t%L1, %H1, %H1", operands);
|
11430 |
|
|
output_asm_insn ("sllx\t%H2, 32, %L1", operands);
|
11431 |
|
|
output_asm_insn ("or\t%L2, %L1, %L1", operands);
|
11432 |
|
|
sprintf (mulstr, "%s\t%%H1, %%L1, %%L0", opcode);
|
11433 |
|
|
output_asm_insn (mulstr, operands);
|
11434 |
|
|
return "srlx\t%L0, 32, %H0";
|
11435 |
|
|
}
|
11436 |
|
|
else
|
11437 |
|
|
{
|
11438 |
|
|
output_asm_insn ("sllx\t%H1, 32, %3", operands);
|
11439 |
|
|
output_asm_insn ("sllx\t%H2, 32, %4", operands);
|
11440 |
|
|
output_asm_insn ("or\t%L1, %3, %3", operands);
|
11441 |
|
|
output_asm_insn ("or\t%L2, %4, %4", operands);
|
11442 |
|
|
sprintf (mulstr, "%s\t%%3, %%4, %%3", opcode);
|
11443 |
|
|
output_asm_insn (mulstr, operands);
|
11444 |
|
|
output_asm_insn ("srlx\t%3, 32, %H0", operands);
|
11445 |
|
|
return "mov\t%3, %L0";
|
11446 |
|
|
}
|
11447 |
|
|
}
|
11448 |
|
|
|
11449 |
|
|
/* Subroutine of sparc_expand_vector_init. Emit code to initialize
|
11450 |
|
|
all fields of TARGET to ELT by means of VIS2 BSHUFFLE insn. MODE
|
11451 |
|
|
and INNER_MODE are the modes describing TARGET. */
|
11452 |
|
|
|
11453 |
|
|
static void
|
11454 |
|
|
vector_init_bshuffle (rtx target, rtx elt, enum machine_mode mode,
|
11455 |
|
|
enum machine_mode inner_mode)
|
11456 |
|
|
{
|
11457 |
|
|
rtx t1, final_insn;
|
11458 |
|
|
int bmask;
|
11459 |
|
|
|
11460 |
|
|
t1 = gen_reg_rtx (mode);
|
11461 |
|
|
|
11462 |
|
|
elt = convert_modes (SImode, inner_mode, elt, true);
|
11463 |
|
|
emit_move_insn (gen_lowpart(SImode, t1), elt);
|
11464 |
|
|
|
11465 |
|
|
switch (mode)
|
11466 |
|
|
{
|
11467 |
|
|
case V2SImode:
|
11468 |
|
|
final_insn = gen_bshufflev2si_vis (target, t1, t1);
|
11469 |
|
|
bmask = 0x45674567;
|
11470 |
|
|
break;
|
11471 |
|
|
case V4HImode:
|
11472 |
|
|
final_insn = gen_bshufflev4hi_vis (target, t1, t1);
|
11473 |
|
|
bmask = 0x67676767;
|
11474 |
|
|
break;
|
11475 |
|
|
case V8QImode:
|
11476 |
|
|
final_insn = gen_bshufflev8qi_vis (target, t1, t1);
|
11477 |
|
|
bmask = 0x77777777;
|
11478 |
|
|
break;
|
11479 |
|
|
default:
|
11480 |
|
|
gcc_unreachable ();
|
11481 |
|
|
}
|
11482 |
|
|
|
11483 |
|
|
emit_insn (gen_bmasksi_vis (gen_reg_rtx (SImode), CONST0_RTX (SImode),
|
11484 |
|
|
force_reg (SImode, GEN_INT (bmask))));
|
11485 |
|
|
emit_insn (final_insn);
|
11486 |
|
|
}
|
11487 |
|
|
|
11488 |
|
|
/* Subroutine of sparc_expand_vector_init. Emit code to initialize
|
11489 |
|
|
all fields of TARGET to ELT in V8QI by means of VIS FPMERGE insn. */
|
11490 |
|
|
|
11491 |
|
|
static void
|
11492 |
|
|
vector_init_fpmerge (rtx target, rtx elt)
|
11493 |
|
|
{
|
11494 |
|
|
rtx t1, t2, t2_low, t3, t3_low;
|
11495 |
|
|
|
11496 |
|
|
t1 = gen_reg_rtx (V4QImode);
|
11497 |
|
|
elt = convert_modes (SImode, QImode, elt, true);
|
11498 |
|
|
emit_move_insn (gen_lowpart (SImode, t1), elt);
|
11499 |
|
|
|
11500 |
|
|
t2 = gen_reg_rtx (V8QImode);
|
11501 |
|
|
t2_low = gen_lowpart (V4QImode, t2);
|
11502 |
|
|
emit_insn (gen_fpmerge_vis (t2, t1, t1));
|
11503 |
|
|
|
11504 |
|
|
t3 = gen_reg_rtx (V8QImode);
|
11505 |
|
|
t3_low = gen_lowpart (V4QImode, t3);
|
11506 |
|
|
emit_insn (gen_fpmerge_vis (t3, t2_low, t2_low));
|
11507 |
|
|
|
11508 |
|
|
emit_insn (gen_fpmerge_vis (target, t3_low, t3_low));
|
11509 |
|
|
}
|
11510 |
|
|
|
11511 |
|
|
/* Subroutine of sparc_expand_vector_init. Emit code to initialize
|
11512 |
|
|
all fields of TARGET to ELT in V4HI by means of VIS FALIGNDATA insn. */
|
11513 |
|
|
|
11514 |
|
|
static void
|
11515 |
|
|
vector_init_faligndata (rtx target, rtx elt)
|
11516 |
|
|
{
|
11517 |
|
|
rtx t1 = gen_reg_rtx (V4HImode);
|
11518 |
|
|
int i;
|
11519 |
|
|
|
11520 |
|
|
elt = convert_modes (SImode, HImode, elt, true);
|
11521 |
|
|
emit_move_insn (gen_lowpart (SImode, t1), elt);
|
11522 |
|
|
|
11523 |
|
|
emit_insn (gen_alignaddrsi_vis (gen_reg_rtx (SImode),
|
11524 |
|
|
force_reg (SImode, GEN_INT (6)),
|
11525 |
|
|
const0_rtx));
|
11526 |
|
|
|
11527 |
|
|
for (i = 0; i < 4; i++)
|
11528 |
|
|
emit_insn (gen_faligndatav4hi_vis (target, t1, target));
|
11529 |
|
|
}
|
11530 |
|
|
|
11531 |
|
|
/* Emit code to initialize TARGET to values for individual fields VALS. */
|
11532 |
|
|
|
11533 |
|
|
void
|
11534 |
|
|
sparc_expand_vector_init (rtx target, rtx vals)
|
11535 |
|
|
{
|
11536 |
|
|
const enum machine_mode mode = GET_MODE (target);
|
11537 |
|
|
const enum machine_mode inner_mode = GET_MODE_INNER (mode);
|
11538 |
|
|
const int n_elts = GET_MODE_NUNITS (mode);
|
11539 |
|
|
int i, n_var = 0;
|
11540 |
|
|
bool all_same;
|
11541 |
|
|
rtx mem;
|
11542 |
|
|
|
11543 |
|
|
all_same = true;
|
11544 |
|
|
for (i = 0; i < n_elts; i++)
|
11545 |
|
|
{
|
11546 |
|
|
rtx x = XVECEXP (vals, 0, i);
|
11547 |
|
|
if (!CONSTANT_P (x))
|
11548 |
|
|
n_var++;
|
11549 |
|
|
|
11550 |
|
|
if (i > 0 && !rtx_equal_p (x, XVECEXP (vals, 0, 0)))
|
11551 |
|
|
all_same = false;
|
11552 |
|
|
}
|
11553 |
|
|
|
11554 |
|
|
if (n_var == 0)
|
11555 |
|
|
{
|
11556 |
|
|
emit_move_insn (target, gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0)));
|
11557 |
|
|
return;
|
11558 |
|
|
}
|
11559 |
|
|
|
11560 |
|
|
if (GET_MODE_SIZE (inner_mode) == GET_MODE_SIZE (mode))
|
11561 |
|
|
{
|
11562 |
|
|
if (GET_MODE_SIZE (inner_mode) == 4)
|
11563 |
|
|
{
|
11564 |
|
|
emit_move_insn (gen_lowpart (SImode, target),
|
11565 |
|
|
gen_lowpart (SImode, XVECEXP (vals, 0, 0)));
|
11566 |
|
|
return;
|
11567 |
|
|
}
|
11568 |
|
|
else if (GET_MODE_SIZE (inner_mode) == 8)
|
11569 |
|
|
{
|
11570 |
|
|
emit_move_insn (gen_lowpart (DImode, target),
|
11571 |
|
|
gen_lowpart (DImode, XVECEXP (vals, 0, 0)));
|
11572 |
|
|
return;
|
11573 |
|
|
}
|
11574 |
|
|
}
|
11575 |
|
|
else if (GET_MODE_SIZE (inner_mode) == GET_MODE_SIZE (word_mode)
|
11576 |
|
|
&& GET_MODE_SIZE (mode) == 2 * GET_MODE_SIZE (word_mode))
|
11577 |
|
|
{
|
11578 |
|
|
emit_move_insn (gen_highpart (word_mode, target),
|
11579 |
|
|
gen_lowpart (word_mode, XVECEXP (vals, 0, 0)));
|
11580 |
|
|
emit_move_insn (gen_lowpart (word_mode, target),
|
11581 |
|
|
gen_lowpart (word_mode, XVECEXP (vals, 0, 1)));
|
11582 |
|
|
return;
|
11583 |
|
|
}
|
11584 |
|
|
|
11585 |
|
|
if (all_same && GET_MODE_SIZE (mode) == 8)
|
11586 |
|
|
{
|
11587 |
|
|
if (TARGET_VIS2)
|
11588 |
|
|
{
|
11589 |
|
|
vector_init_bshuffle (target, XVECEXP (vals, 0, 0), mode, inner_mode);
|
11590 |
|
|
return;
|
11591 |
|
|
}
|
11592 |
|
|
if (mode == V8QImode)
|
11593 |
|
|
{
|
11594 |
|
|
vector_init_fpmerge (target, XVECEXP (vals, 0, 0));
|
11595 |
|
|
return;
|
11596 |
|
|
}
|
11597 |
|
|
if (mode == V4HImode)
|
11598 |
|
|
{
|
11599 |
|
|
vector_init_faligndata (target, XVECEXP (vals, 0, 0));
|
11600 |
|
|
return;
|
11601 |
|
|
}
|
11602 |
|
|
}
|
11603 |
|
|
|
11604 |
|
|
mem = assign_stack_temp (mode, GET_MODE_SIZE (mode), 0);
|
11605 |
|
|
for (i = 0; i < n_elts; i++)
|
11606 |
|
|
emit_move_insn (adjust_address_nv (mem, inner_mode,
|
11607 |
|
|
i * GET_MODE_SIZE (inner_mode)),
|
11608 |
|
|
XVECEXP (vals, 0, i));
|
11609 |
|
|
emit_move_insn (target, mem);
|
11610 |
|
|
}
|
11611 |
|
|
|
11612 |
|
|
/* Implement TARGET_SECONDARY_RELOAD. */
|
11613 |
|
|
|
11614 |
|
|
static reg_class_t
|
11615 |
|
|
sparc_secondary_reload (bool in_p, rtx x, reg_class_t rclass_i,
|
11616 |
|
|
enum machine_mode mode, secondary_reload_info *sri)
|
11617 |
|
|
{
|
11618 |
|
|
enum reg_class rclass = (enum reg_class) rclass_i;
|
11619 |
|
|
|
11620 |
|
|
sri->icode = CODE_FOR_nothing;
|
11621 |
|
|
sri->extra_cost = 0;
|
11622 |
|
|
|
11623 |
|
|
/* We need a temporary when loading/storing a HImode/QImode value
|
11624 |
|
|
between memory and the FPU registers. This can happen when combine puts
|
11625 |
|
|
a paradoxical subreg in a float/fix conversion insn. */
|
11626 |
|
|
if (FP_REG_CLASS_P (rclass)
|
11627 |
|
|
&& (mode == HImode || mode == QImode)
|
11628 |
|
|
&& (GET_CODE (x) == MEM
|
11629 |
|
|
|| ((GET_CODE (x) == REG || GET_CODE (x) == SUBREG)
|
11630 |
|
|
&& true_regnum (x) == -1)))
|
11631 |
|
|
return GENERAL_REGS;
|
11632 |
|
|
|
11633 |
|
|
/* On 32-bit we need a temporary when loading/storing a DFmode value
|
11634 |
|
|
between unaligned memory and the upper FPU registers. */
|
11635 |
|
|
if (TARGET_ARCH32
|
11636 |
|
|
&& rclass == EXTRA_FP_REGS
|
11637 |
|
|
&& mode == DFmode
|
11638 |
|
|
&& GET_CODE (x) == MEM
|
11639 |
|
|
&& ! mem_min_alignment (x, 8))
|
11640 |
|
|
return FP_REGS;
|
11641 |
|
|
|
11642 |
|
|
if (((TARGET_CM_MEDANY
|
11643 |
|
|
&& symbolic_operand (x, mode))
|
11644 |
|
|
|| (TARGET_CM_EMBMEDANY
|
11645 |
|
|
&& text_segment_operand (x, mode)))
|
11646 |
|
|
&& ! flag_pic)
|
11647 |
|
|
{
|
11648 |
|
|
if (in_p)
|
11649 |
|
|
sri->icode = direct_optab_handler (reload_in_optab, mode);
|
11650 |
|
|
else
|
11651 |
|
|
sri->icode = direct_optab_handler (reload_out_optab, mode);
|
11652 |
|
|
return NO_REGS;
|
11653 |
|
|
}
|
11654 |
|
|
|
11655 |
|
|
if (TARGET_VIS3 && TARGET_ARCH32)
|
11656 |
|
|
{
|
11657 |
|
|
int regno = true_regnum (x);
|
11658 |
|
|
|
11659 |
|
|
/* When using VIS3 fp<-->int register moves, on 32-bit we have
|
11660 |
|
|
to move 8-byte values in 4-byte pieces. This only works via
|
11661 |
|
|
FP_REGS, and not via EXTRA_FP_REGS. Therefore if we try to
|
11662 |
|
|
move between EXTRA_FP_REGS and GENERAL_REGS, we will need
|
11663 |
|
|
an FP_REGS intermediate move. */
|
11664 |
|
|
if ((rclass == EXTRA_FP_REGS && SPARC_INT_REG_P (regno))
|
11665 |
|
|
|| ((general_or_i64_p (rclass)
|
11666 |
|
|
|| rclass == GENERAL_OR_FP_REGS)
|
11667 |
|
|
&& SPARC_FP_REG_P (regno)))
|
11668 |
|
|
{
|
11669 |
|
|
sri->extra_cost = 2;
|
11670 |
|
|
return FP_REGS;
|
11671 |
|
|
}
|
11672 |
|
|
}
|
11673 |
|
|
|
11674 |
|
|
return NO_REGS;
|
11675 |
|
|
}
|
11676 |
|
|
|
11677 |
|
|
/* Emit code to conditionally move either OPERANDS[2] or OPERANDS[3] into
|
11678 |
|
|
OPERANDS[0] in MODE. OPERANDS[1] is the operator of the condition. */
|
11679 |
|
|
|
11680 |
|
|
bool
|
11681 |
|
|
sparc_expand_conditional_move (enum machine_mode mode, rtx *operands)
|
11682 |
|
|
{
|
11683 |
|
|
enum rtx_code rc = GET_CODE (operands[1]);
|
11684 |
|
|
enum machine_mode cmp_mode;
|
11685 |
|
|
rtx cc_reg, dst, cmp;
|
11686 |
|
|
|
11687 |
|
|
cmp = operands[1];
|
11688 |
|
|
if (GET_MODE (XEXP (cmp, 0)) == DImode && !TARGET_ARCH64)
|
11689 |
|
|
return false;
|
11690 |
|
|
|
11691 |
|
|
if (GET_MODE (XEXP (cmp, 0)) == TFmode && !TARGET_HARD_QUAD)
|
11692 |
|
|
cmp = sparc_emit_float_lib_cmp (XEXP (cmp, 0), XEXP (cmp, 1), rc);
|
11693 |
|
|
|
11694 |
|
|
cmp_mode = GET_MODE (XEXP (cmp, 0));
|
11695 |
|
|
rc = GET_CODE (cmp);
|
11696 |
|
|
|
11697 |
|
|
dst = operands[0];
|
11698 |
|
|
if (! rtx_equal_p (operands[2], dst)
|
11699 |
|
|
&& ! rtx_equal_p (operands[3], dst))
|
11700 |
|
|
{
|
11701 |
|
|
if (reg_overlap_mentioned_p (dst, cmp))
|
11702 |
|
|
dst = gen_reg_rtx (mode);
|
11703 |
|
|
|
11704 |
|
|
emit_move_insn (dst, operands[3]);
|
11705 |
|
|
}
|
11706 |
|
|
else if (operands[2] == dst)
|
11707 |
|
|
{
|
11708 |
|
|
operands[2] = operands[3];
|
11709 |
|
|
|
11710 |
|
|
if (GET_MODE_CLASS (cmp_mode) == MODE_FLOAT)
|
11711 |
|
|
rc = reverse_condition_maybe_unordered (rc);
|
11712 |
|
|
else
|
11713 |
|
|
rc = reverse_condition (rc);
|
11714 |
|
|
}
|
11715 |
|
|
|
11716 |
|
|
if (XEXP (cmp, 1) == const0_rtx
|
11717 |
|
|
&& GET_CODE (XEXP (cmp, 0)) == REG
|
11718 |
|
|
&& cmp_mode == DImode
|
11719 |
|
|
&& v9_regcmp_p (rc))
|
11720 |
|
|
cc_reg = XEXP (cmp, 0);
|
11721 |
|
|
else
|
11722 |
|
|
cc_reg = gen_compare_reg_1 (rc, XEXP (cmp, 0), XEXP (cmp, 1));
|
11723 |
|
|
|
11724 |
|
|
cmp = gen_rtx_fmt_ee (rc, GET_MODE (cc_reg), cc_reg, const0_rtx);
|
11725 |
|
|
|
11726 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, dst,
|
11727 |
|
|
gen_rtx_IF_THEN_ELSE (mode, cmp, operands[2], dst)));
|
11728 |
|
|
|
11729 |
|
|
if (dst != operands[0])
|
11730 |
|
|
emit_move_insn (operands[0], dst);
|
11731 |
|
|
|
11732 |
|
|
return true;
|
11733 |
|
|
}
|
11734 |
|
|
|
11735 |
|
|
/* Emit code to conditionally move a combination of OPERANDS[1] and OPERANDS[2]
|
11736 |
|
|
into OPERANDS[0] in MODE, depending on the outcome of the comparison of
|
11737 |
|
|
OPERANDS[4] and OPERANDS[5]. OPERANDS[3] is the operator of the condition.
|
11738 |
|
|
FCODE is the machine code to be used for OPERANDS[3] and CCODE the machine
|
11739 |
|
|
code to be used for the condition mask. */
|
11740 |
|
|
|
11741 |
|
|
void
|
11742 |
|
|
sparc_expand_vcond (enum machine_mode mode, rtx *operands, int ccode, int fcode)
|
11743 |
|
|
{
|
11744 |
|
|
rtx mask, cop0, cop1, fcmp, cmask, bshuf, gsr;
|
11745 |
|
|
enum rtx_code code = GET_CODE (operands[3]);
|
11746 |
|
|
|
11747 |
|
|
mask = gen_reg_rtx (Pmode);
|
11748 |
|
|
cop0 = operands[4];
|
11749 |
|
|
cop1 = operands[5];
|
11750 |
|
|
if (code == LT || code == GE)
|
11751 |
|
|
{
|
11752 |
|
|
rtx t;
|
11753 |
|
|
|
11754 |
|
|
code = swap_condition (code);
|
11755 |
|
|
t = cop0; cop0 = cop1; cop1 = t;
|
11756 |
|
|
}
|
11757 |
|
|
|
11758 |
|
|
gsr = gen_rtx_REG (DImode, SPARC_GSR_REG);
|
11759 |
|
|
|
11760 |
|
|
fcmp = gen_rtx_UNSPEC (Pmode,
|
11761 |
|
|
gen_rtvec (1, gen_rtx_fmt_ee (code, mode, cop0, cop1)),
|
11762 |
|
|
fcode);
|
11763 |
|
|
|
11764 |
|
|
cmask = gen_rtx_UNSPEC (DImode,
|
11765 |
|
|
gen_rtvec (2, mask, gsr),
|
11766 |
|
|
ccode);
|
11767 |
|
|
|
11768 |
|
|
bshuf = gen_rtx_UNSPEC (mode,
|
11769 |
|
|
gen_rtvec (3, operands[1], operands[2], gsr),
|
11770 |
|
|
UNSPEC_BSHUFFLE);
|
11771 |
|
|
|
11772 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, mask, fcmp));
|
11773 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, gsr, cmask));
|
11774 |
|
|
|
11775 |
|
|
emit_insn (gen_rtx_SET (VOIDmode, operands[0], bshuf));
|
11776 |
|
|
}
|
11777 |
|
|
|
11778 |
|
|
/* On sparc, any mode which naturally allocates into the float
|
11779 |
|
|
registers should return 4 here. */
|
11780 |
|
|
|
11781 |
|
|
unsigned int
|
11782 |
|
|
sparc_regmode_natural_size (enum machine_mode mode)
|
11783 |
|
|
{
|
11784 |
|
|
int size = UNITS_PER_WORD;
|
11785 |
|
|
|
11786 |
|
|
if (TARGET_ARCH64)
|
11787 |
|
|
{
|
11788 |
|
|
enum mode_class mclass = GET_MODE_CLASS (mode);
|
11789 |
|
|
|
11790 |
|
|
if (mclass == MODE_FLOAT || mclass == MODE_VECTOR_INT)
|
11791 |
|
|
size = 4;
|
11792 |
|
|
}
|
11793 |
|
|
|
11794 |
|
|
return size;
|
11795 |
|
|
}
|
11796 |
|
|
|
11797 |
|
|
/* Return TRUE if it is a good idea to tie two pseudo registers
|
11798 |
|
|
when one has mode MODE1 and one has mode MODE2.
|
11799 |
|
|
If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2,
|
11800 |
|
|
for any hard reg, then this must be FALSE for correct output.
|
11801 |
|
|
|
11802 |
|
|
For V9 we have to deal with the fact that only the lower 32 floating
|
11803 |
|
|
point registers are 32-bit addressable. */
|
11804 |
|
|
|
11805 |
|
|
bool
|
11806 |
|
|
sparc_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
|
11807 |
|
|
{
|
11808 |
|
|
enum mode_class mclass1, mclass2;
|
11809 |
|
|
unsigned short size1, size2;
|
11810 |
|
|
|
11811 |
|
|
if (mode1 == mode2)
|
11812 |
|
|
return true;
|
11813 |
|
|
|
11814 |
|
|
mclass1 = GET_MODE_CLASS (mode1);
|
11815 |
|
|
mclass2 = GET_MODE_CLASS (mode2);
|
11816 |
|
|
if (mclass1 != mclass2)
|
11817 |
|
|
return false;
|
11818 |
|
|
|
11819 |
|
|
if (! TARGET_V9)
|
11820 |
|
|
return true;
|
11821 |
|
|
|
11822 |
|
|
/* Classes are the same and we are V9 so we have to deal with upper
|
11823 |
|
|
vs. lower floating point registers. If one of the modes is a
|
11824 |
|
|
4-byte mode, and the other is not, we have to mark them as not
|
11825 |
|
|
tieable because only the lower 32 floating point register are
|
11826 |
|
|
addressable 32-bits at a time.
|
11827 |
|
|
|
11828 |
|
|
We can't just test explicitly for SFmode, otherwise we won't
|
11829 |
|
|
cover the vector mode cases properly. */
|
11830 |
|
|
|
11831 |
|
|
if (mclass1 != MODE_FLOAT && mclass1 != MODE_VECTOR_INT)
|
11832 |
|
|
return true;
|
11833 |
|
|
|
11834 |
|
|
size1 = GET_MODE_SIZE (mode1);
|
11835 |
|
|
size2 = GET_MODE_SIZE (mode2);
|
11836 |
|
|
if ((size1 > 4 && size2 == 4)
|
11837 |
|
|
|| (size2 > 4 && size1 == 4))
|
11838 |
|
|
return false;
|
11839 |
|
|
|
11840 |
|
|
return true;
|
11841 |
|
|
}
|
11842 |
|
|
|
11843 |
|
|
#include "gt-sparc.h"
|