1 /* Function return value location for IA64 ABI.
2 Copyright (C) 2006-2010, 2014 Red Hat, Inc.
3 This file is part of elfutils.
4
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
7
8 * the GNU Lesser General Public License as published by the Free
9 Software Foundation; either version 3 of the License, or (at
10 your option) any later version
11
12 or
13
14 * the GNU General Public License as published by the Free
15 Software Foundation; either version 2 of the License, or (at
16 your option) any later version
17
18 or both in parallel, as here.
19
20 elfutils is distributed in the hope that it will be useful, but
21 WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
23 General Public License for more details.
24
25 You should have received copies of the GNU General Public License and
26 the GNU Lesser General Public License along with this program. If
27 not, see <http://www.gnu.org/licenses/>. */
28
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32
33 #include <assert.h>
34 #include <dwarf.h>
35
36 #define BACKEND ia64_
37 #include "libebl_CPU.h"
38
39
40 /* r8, or pair r8, r9, or aggregate up to r8-r11. */
41 static const Dwarf_Op loc_intreg[] =
42 {
43 { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 },
44 { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 },
45 { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 },
46 { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 },
47 };
48 #define nloc_intreg 1
49 #define nloc_intregs(n) (2 * (n))
50
51 /* f8, or aggregate up to f8-f15. */
52 #define DEFINE_FPREG(size) \
53 static const Dwarf_Op loc_fpreg_##size[] = \
54 { \
55 { .atom = DW_OP_regx, .number = 128 + 8 }, \
56 { .atom = DW_OP_piece, .number = size }, \
57 { .atom = DW_OP_regx, .number = 128 + 9 }, \
58 { .atom = DW_OP_piece, .number = size }, \
59 { .atom = DW_OP_regx, .number = 128 + 10 }, \
60 { .atom = DW_OP_piece, .number = size }, \
61 { .atom = DW_OP_regx, .number = 128 + 11 }, \
62 { .atom = DW_OP_piece, .number = size }, \
63 { .atom = DW_OP_regx, .number = 128 + 12 }, \
64 { .atom = DW_OP_piece, .number = size }, \
65 { .atom = DW_OP_regx, .number = 128 + 13 }, \
66 { .atom = DW_OP_piece, .number = size }, \
67 { .atom = DW_OP_regx, .number = 128 + 14 }, \
68 { .atom = DW_OP_piece, .number = size }, \
69 { .atom = DW_OP_regx, .number = 128 + 15 }, \
70 { .atom = DW_OP_piece, .number = size }, \
71 }
72 #define nloc_fpreg 1
73 #define nloc_fpregs(n) (2 * (n))
74
75 DEFINE_FPREG (4);
76 DEFINE_FPREG (8);
77 DEFINE_FPREG (10);
78
79 #undef DEFINE_FPREG
80
81
82 /* The return value is a structure and is actually stored in stack space
83 passed in a hidden argument by the caller. But, the compiler
84 helpfully returns the address of that space in r8. */
85 static const Dwarf_Op loc_aggregate[] =
86 {
87 { .atom = DW_OP_breg8, .number = 0 }
88 };
89 #define nloc_aggregate 1
90
91
92 static inline int
compute_hfa(const Dwarf_Op * loc,int nregs,const Dwarf_Op ** locp,int fpregs_used)93 compute_hfa (const Dwarf_Op *loc, int nregs,
94 const Dwarf_Op **locp, int fpregs_used)
95 {
96 if (fpregs_used == 0)
97 *locp = loc;
98 else if (*locp != loc)
99 return 9;
100 return fpregs_used + nregs;
101 }
102
103 /* If this type is an HFA small enough to be returned in FP registers,
104 return the number of registers to use. Otherwise 9, or -1 for errors. */
105 static int
hfa_type(Dwarf_Die * typedie,Dwarf_Word size,const Dwarf_Op ** locp,int fpregs_used)106 hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
107 const Dwarf_Op **locp, int fpregs_used)
108 {
109 /* Descend the type structure, counting elements and finding their types.
110 If we find a datum that's not an FP type (and not quad FP), punt.
111 If we find a datum that's not the same FP type as the first datum, punt.
112 If we count more than eight total homogeneous FP data, punt. */
113
114 int tag = DWARF_TAG_OR_RETURN (typedie);
115 switch (tag)
116 {
117 Dwarf_Attribute attr_mem;
118
119 case -1:
120 return -1;
121
122 case DW_TAG_base_type:;
123 Dwarf_Word encoding;
124 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
125 &attr_mem), &encoding) != 0)
126 return -1;
127
128 #define hfa(loc, nregs) compute_hfa(loc, nregs, locp, fpregs_used)
129 switch (encoding)
130 {
131 case DW_ATE_float:
132 switch (size)
133 {
134 case 4: /* float */
135 return hfa (loc_fpreg_4, 1);
136 case 8: /* double */
137 return hfa (loc_fpreg_8, 1);
138 case 10: /* x86-style long double, not really used */
139 return hfa (loc_fpreg_10, 1);
140 }
141 break;
142
143 case DW_ATE_complex_float:
144 switch (size)
145 {
146 case 4 * 2: /* complex float */
147 return hfa (loc_fpreg_4, 2);
148 case 8 * 2: /* complex double */
149 return hfa (loc_fpreg_8, 2);
150 case 10 * 2: /* complex long double (x86-style) */
151 return hfa (loc_fpreg_10, 2);
152 }
153 break;
154 }
155 break;
156
157 case DW_TAG_structure_type:
158 case DW_TAG_class_type:
159 case DW_TAG_union_type:;
160 Dwarf_Die child_mem;
161 switch (dwarf_child (typedie, &child_mem))
162 {
163 default:
164 return -1;
165
166 case 1: /* No children: empty struct. */
167 break;
168
169 case 0:; /* Look at each element. */
170 int max_used = fpregs_used;
171 do
172 switch (dwarf_tag (&child_mem))
173 {
174 case -1:
175 return -1;
176
177 case DW_TAG_member:;
178 Dwarf_Die child_type_mem;
179 Dwarf_Die *child_typedie
180 = dwarf_formref_die (dwarf_attr_integrate (&child_mem,
181 DW_AT_type,
182 &attr_mem),
183 &child_type_mem);
184 Dwarf_Word child_size;
185 if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
186 return -1;
187 if (tag == DW_TAG_union_type)
188 {
189 int used = hfa_type (child_typedie, child_size,
190 locp, fpregs_used);
191 if (used < 0 || used > 8)
192 return used;
193 if (used > max_used)
194 max_used = used;
195 }
196 else
197 {
198 fpregs_used = hfa_type (child_typedie, child_size,
199 locp, fpregs_used);
200 if (fpregs_used < 0 || fpregs_used > 8)
201 return fpregs_used;
202 }
203 }
204 while (dwarf_siblingof (&child_mem, &child_mem) == 0);
205 if (tag == DW_TAG_union_type)
206 fpregs_used = max_used;
207 break;
208 }
209 break;
210
211 case DW_TAG_array_type:
212 if (size == 0)
213 break;
214
215 Dwarf_Die base_type_mem;
216 Dwarf_Die *base_typedie
217 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
218 &attr_mem),
219 &base_type_mem);
220 Dwarf_Word base_size;
221 if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
222 return -1;
223
224 int used = hfa_type (base_typedie, base_size, locp, 0);
225 if (used < 0 || used > 8)
226 return used;
227 if (size % (*locp)[1].number != 0)
228 return 0;
229 fpregs_used += used * (size / (*locp)[1].number);
230 break;
231
232 default:
233 return 9;
234 }
235
236 return fpregs_used;
237 }
238
239 int
ia64_return_value_location(Dwarf_Die * functypedie,const Dwarf_Op ** locp)240 ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
241 {
242 /* Start with the function's type, and get the DW_AT_type attribute,
243 which is the type of the return value. */
244 Dwarf_Die die_mem, *typedie = &die_mem;
245 int tag = dwarf_peeled_die_type (functypedie, typedie);
246 if (tag <= 0)
247 return tag;
248
249 Dwarf_Word size;
250 switch (tag)
251 {
252 case -1:
253 return -1;
254
255 case DW_TAG_subrange_type:
256 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
257 {
258 Dwarf_Attribute attr_mem, *attr;
259 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
260 typedie = dwarf_formref_die (attr, &die_mem);
261 tag = DWARF_TAG_OR_RETURN (typedie);
262 }
263 FALLTHROUGH;
264
265 case DW_TAG_base_type:
266 case DW_TAG_enumeration_type:
267 CASE_POINTER:
268 {
269 Dwarf_Attribute attr_mem;
270 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
271 &attr_mem), &size) != 0)
272 {
273 if (dwarf_is_pointer (tag))
274 size = 8;
275 else
276 return -1;
277 }
278 }
279
280 if (tag == DW_TAG_base_type)
281 {
282 Dwarf_Attribute attr_mem;
283 Dwarf_Word encoding;
284 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
285 &attr_mem),
286 &encoding) != 0)
287 return -1;
288
289 switch (encoding)
290 {
291 case DW_ATE_float:
292 switch (size)
293 {
294 case 4: /* float */
295 *locp = loc_fpreg_4;
296 return nloc_fpreg;
297 case 8: /* double */
298 *locp = loc_fpreg_8;
299 return nloc_fpreg;
300 case 10: /* x86-style long double, not really used */
301 *locp = loc_fpreg_10;
302 return nloc_fpreg;
303 case 16: /* long double, IEEE quad format */
304 *locp = loc_intreg;
305 return nloc_intregs (2);
306 }
307 return -2;
308
309 case DW_ATE_complex_float:
310 switch (size)
311 {
312 case 4 * 2: /* complex float */
313 *locp = loc_fpreg_4;
314 return nloc_fpregs (2);
315 case 8 * 2: /* complex double */
316 *locp = loc_fpreg_8;
317 return nloc_fpregs (2);
318 case 10 * 2: /* complex long double (x86-style) */
319 *locp = loc_fpreg_10;
320 return nloc_fpregs (2);
321 case 16 * 2: /* complex long double (IEEE quad) */
322 *locp = loc_intreg;
323 return nloc_intregs (4);
324 }
325 return -2;
326 }
327 }
328
329 intreg:
330 *locp = loc_intreg;
331 if (size <= 8)
332 return nloc_intreg;
333 if (size <= 32)
334 return nloc_intregs ((size + 7) / 8);
335
336 large:
337 *locp = loc_aggregate;
338 return nloc_aggregate;
339
340 case DW_TAG_structure_type:
341 case DW_TAG_class_type:
342 case DW_TAG_union_type:
343 case DW_TAG_array_type:
344 if (dwarf_aggregate_size (typedie, &size) != 0)
345 return -1;
346
347 /* If this qualifies as an homogeneous floating-point aggregate
348 (HFA), then it should be returned in FP regs. */
349 int nfpreg = hfa_type (typedie, size, locp, 0);
350 if (nfpreg < 0)
351 return nfpreg;
352 else if (nfpreg > 0 && nfpreg <= 8)
353 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
354
355 if (size > 32)
356 goto large;
357
358 goto intreg;
359 }
360
361 /* XXX We don't have a good way to return specific errors from ebl calls.
362 This value means we do not understand the type, but it is well-formed
363 DWARF and might be valid. */
364 return -2;
365 }
366