Branch data Line data Source code
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
93 : 0 : compute_hfa (const Dwarf_Op *loc, int nregs,
94 : : const Dwarf_Op **locp, int fpregs_used)
95 : : {
96 : 0 : if (fpregs_used == 0)
97 : 0 : *locp = loc;
98 [ # # # # : 0 : else if (*locp != loc)
# # # # #
# # # ]
99 : : return 9;
100 : 0 : 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
106 : 0 : 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 [ # # ]: 0 : int tag = DWARF_TAG_OR_RETURN (typedie);
115 [ # # # # : 0 : switch (tag)
# ]
116 : : {
117 : : Dwarf_Attribute attr_mem;
118 : :
119 : : case -1:
120 : 0 : return -1;
121 : :
122 : 0 : case DW_TAG_base_type:;
123 : 0 : Dwarf_Word encoding;
124 [ # # ]: 0 : 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 [ # # # ]: 0 : switch (encoding)
130 : : {
131 : 0 : case DW_ATE_float:
132 [ # # # # ]: 0 : switch (size)
133 : : {
134 : : case 4: /* float */
135 [ # # ]: 0 : return hfa (loc_fpreg_4, 1);
136 : : case 8: /* double */
137 [ # # ]: 0 : return hfa (loc_fpreg_8, 1);
138 : : case 10: /* x86-style long double, not really used */
139 [ # # ]: 0 : return hfa (loc_fpreg_10, 1);
140 : : }
141 : : break;
142 : :
143 : 0 : case DW_ATE_complex_float:
144 [ # # # # ]: 0 : switch (size)
145 : : {
146 : : case 4 * 2: /* complex float */
147 [ # # ]: 0 : return hfa (loc_fpreg_4, 2);
148 : : case 8 * 2: /* complex double */
149 [ # # ]: 0 : return hfa (loc_fpreg_8, 2);
150 : : case 10 * 2: /* complex long double (x86-style) */
151 [ # # ]: 0 : return hfa (loc_fpreg_10, 2);
152 : : }
153 : : break;
154 : : }
155 : 0 : break;
156 : :
157 : 0 : case DW_TAG_structure_type:
158 : : case DW_TAG_class_type:
159 : 0 : case DW_TAG_union_type:;
160 : 0 : Dwarf_Die child_mem;
161 : 0 : 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 : 0 : do
172 : 0 : switch (dwarf_tag (&child_mem))
173 : : {
174 : : case -1:
175 : 0 : return -1;
176 : :
177 : 0 : case DW_TAG_member:;
178 : 0 : Dwarf_Die child_type_mem;
179 : 0 : Dwarf_Die *child_typedie
180 : 0 : = dwarf_formref_die (dwarf_attr_integrate (&child_mem,
181 : : DW_AT_type,
182 : : &attr_mem),
183 : : &child_type_mem);
184 : 0 : Dwarf_Word child_size;
185 [ # # ]: 0 : if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
186 : : return -1;
187 [ # # ]: 0 : if (tag == DW_TAG_union_type)
188 : : {
189 : 0 : int used = hfa_type (child_typedie, child_size,
190 : : locp, fpregs_used);
191 [ # # ]: 0 : if (used < 0 || used > 8)
192 : 0 : return used;
193 : 0 : if (used > max_used)
194 : : max_used = used;
195 : : }
196 : : else
197 : : {
198 : 0 : fpregs_used = hfa_type (child_typedie, child_size,
199 : : locp, fpregs_used);
200 [ # # ]: 0 : if (fpregs_used < 0 || fpregs_used > 8)
201 : 0 : return fpregs_used;
202 : : }
203 : : }
204 [ # # ]: 0 : while (dwarf_siblingof (&child_mem, &child_mem) == 0);
205 [ # # ]: 0 : if (tag == DW_TAG_union_type)
206 : 0 : fpregs_used = max_used;
207 : : break;
208 : : }
209 : : break;
210 : :
211 : 0 : case DW_TAG_array_type:
212 [ # # ]: 0 : if (size == 0)
213 : : break;
214 : :
215 : 0 : Dwarf_Die base_type_mem;
216 : 0 : Dwarf_Die *base_typedie
217 : 0 : = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
218 : : &attr_mem),
219 : : &base_type_mem);
220 : 0 : Dwarf_Word base_size;
221 [ # # ]: 0 : if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
222 : : return -1;
223 : :
224 : 0 : int used = hfa_type (base_typedie, base_size, locp, 0);
225 [ # # ]: 0 : if (used < 0 || used > 8)
226 : : return used;
227 [ # # ]: 0 : if (size % (*locp)[1].number != 0)
228 : : return 0;
229 : 0 : fpregs_used += used * (size / (*locp)[1].number);
230 : 0 : break;
231 : :
232 : 0 : default:
233 : 0 : return 9;
234 : : }
235 : :
236 : 0 : return fpregs_used;
237 : : }
238 : :
239 : : int
240 : 0 : 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 : 0 : Dwarf_Die die_mem, *typedie = &die_mem;
245 : 0 : int tag = dwarf_peeled_die_type (functypedie, typedie);
246 [ # # ]: 0 : if (tag <= 0)
247 : : return tag;
248 : :
249 : 0 : Dwarf_Word size;
250 [ # # # # ]: 0 : switch (tag)
251 : : {
252 : : case -1:
253 : : return -1;
254 : :
255 : 0 : case DW_TAG_subrange_type:
256 [ # # ]: 0 : if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
257 : : {
258 : 0 : Dwarf_Attribute attr_mem, *attr;
259 : 0 : attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
260 : 0 : typedie = dwarf_formref_die (attr, &die_mem);
261 [ # # ]: 0 : tag = DWARF_TAG_OR_RETURN (typedie);
262 : : }
263 : 0 : FALLTHROUGH;
264 : :
265 : : case DW_TAG_base_type:
266 : : case DW_TAG_enumeration_type:
267 : : CASE_POINTER:
268 : : {
269 : 0 : Dwarf_Attribute attr_mem;
270 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
271 : : &attr_mem), &size) != 0)
272 : : {
273 [ # # ]: 0 : if (dwarf_is_pointer (tag))
274 : 0 : size = 8;
275 : : else
276 : 0 : return -1;
277 : : }
278 : : }
279 : :
280 [ # # ]: 0 : if (tag == DW_TAG_base_type)
281 : : {
282 : 0 : Dwarf_Attribute attr_mem;
283 : 0 : Dwarf_Word encoding;
284 [ # # ]: 0 : if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
285 : : &attr_mem),
286 : : &encoding) != 0)
287 : 0 : return -1;
288 : :
289 [ # # # ]: 0 : switch (encoding)
290 : : {
291 : 0 : case DW_ATE_float:
292 [ # # # # : 0 : switch (size)
# ]
293 : : {
294 : 0 : case 4: /* float */
295 : 0 : *locp = loc_fpreg_4;
296 : 0 : return nloc_fpreg;
297 : 0 : case 8: /* double */
298 : 0 : *locp = loc_fpreg_8;
299 : 0 : return nloc_fpreg;
300 : 0 : case 10: /* x86-style long double, not really used */
301 : 0 : *locp = loc_fpreg_10;
302 : 0 : return nloc_fpreg;
303 : 0 : case 16: /* long double, IEEE quad format */
304 : 0 : *locp = loc_intreg;
305 : 0 : return nloc_intregs (2);
306 : : }
307 : : return -2;
308 : :
309 : 0 : case DW_ATE_complex_float:
310 [ # # # # : 0 : switch (size)
# ]
311 : : {
312 : 0 : case 4 * 2: /* complex float */
313 : 0 : *locp = loc_fpreg_4;
314 : 0 : return nloc_fpregs (2);
315 : 0 : case 8 * 2: /* complex double */
316 : 0 : *locp = loc_fpreg_8;
317 : 0 : return nloc_fpregs (2);
318 : 0 : case 10 * 2: /* complex long double (x86-style) */
319 : 0 : *locp = loc_fpreg_10;
320 : 0 : return nloc_fpregs (2);
321 : 0 : case 16 * 2: /* complex long double (IEEE quad) */
322 : 0 : *locp = loc_intreg;
323 : 0 : return nloc_intregs (4);
324 : : }
325 : : return -2;
326 : : }
327 : : }
328 : :
329 : 0 : intreg:
330 : 0 : *locp = loc_intreg;
331 [ # # ]: 0 : if (size <= 8)
332 : : return nloc_intreg;
333 [ # # ]: 0 : if (size <= 32)
334 : 0 : return nloc_intregs ((size + 7) / 8);
335 : :
336 : 0 : large:
337 : 0 : *locp = loc_aggregate;
338 : 0 : return nloc_aggregate;
339 : :
340 : 0 : case DW_TAG_structure_type:
341 : : case DW_TAG_class_type:
342 : : case DW_TAG_union_type:
343 : : case DW_TAG_array_type:
344 [ # # ]: 0 : 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 : 0 : int nfpreg = hfa_type (typedie, size, locp, 0);
350 [ # # ]: 0 : if (nfpreg < 0)
351 : : return nfpreg;
352 [ # # ]: 0 : else if (nfpreg > 0 && nfpreg <= 8)
353 [ # # ]: 0 : return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
354 : :
355 [ # # ]: 0 : if (size > 32)
356 : 0 : goto large;
357 : :
358 : 0 : 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 : : }
|