blob: b5928c587b71d0f401264bc738adb75772bf456b [file] [log] [blame]
Ben Cheng25b3c042013-11-20 14:45:36 -08001/* Function return value location for IA64 ABI.
Elliott Hughes03333822015-02-18 22:19:45 -08002 Copyright (C) 2006-2010, 2014 Red Hat, Inc.
3 This file is part of elfutils.
Ben Cheng25b3c042013-11-20 14:45:36 -08004
Elliott Hughes03333822015-02-18 22:19:45 -08005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Ben Cheng25b3c042013-11-20 14:45:36 -08007
Elliott Hughes03333822015-02-18 22:19:45 -08008 * 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
Ben Cheng25b3c042013-11-20 14:45:36 -080021 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
Elliott Hughes03333822015-02-18 22:19:45 -080025 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/>. */
Ben Cheng25b3c042013-11-20 14:45:36 -080028
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. */
41static 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
75DEFINE_FPREG (4);
76DEFINE_FPREG (8);
77DEFINE_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. */
85static const Dwarf_Op loc_aggregate[] =
86 {
87 { .atom = DW_OP_breg8, .number = 0 }
88 };
89#define nloc_aggregate 1
90
91
92/* If this type is an HFA small enough to be returned in FP registers,
93 return the number of registers to use. Otherwise 9, or -1 for errors. */
94static int
95hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
96 const Dwarf_Op **locp, int fpregs_used)
97{
98 /* Descend the type structure, counting elements and finding their types.
99 If we find a datum that's not an FP type (and not quad FP), punt.
100 If we find a datum that's not the same FP type as the first datum, punt.
101 If we count more than eight total homogeneous FP data, punt. */
102
103 inline int hfa (const Dwarf_Op *loc, int nregs)
104 {
105 if (fpregs_used == 0)
106 *locp = loc;
107 else if (*locp != loc)
108 return 9;
109 return fpregs_used + nregs;
110 }
111
Elliott Hughes03333822015-02-18 22:19:45 -0800112 int tag = DWARF_TAG_OR_RETURN (typedie);
Ben Cheng25b3c042013-11-20 14:45:36 -0800113 switch (tag)
114 {
115 Dwarf_Attribute attr_mem;
116
117 case -1:
118 return -1;
119
120 case DW_TAG_base_type:;
121 Dwarf_Word encoding;
122 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
123 &attr_mem), &encoding) != 0)
124 return -1;
125
126 switch (encoding)
127 {
128 case DW_ATE_float:
129 switch (size)
130 {
131 case 4: /* float */
132 return hfa (loc_fpreg_4, 1);
133 case 8: /* double */
134 return hfa (loc_fpreg_8, 1);
135 case 10: /* x86-style long double, not really used */
136 return hfa (loc_fpreg_10, 1);
137 }
138 break;
139
140 case DW_ATE_complex_float:
141 switch (size)
142 {
143 case 4 * 2: /* complex float */
144 return hfa (loc_fpreg_4, 2);
145 case 8 * 2: /* complex double */
146 return hfa (loc_fpreg_8, 2);
147 case 10 * 2: /* complex long double (x86-style) */
148 return hfa (loc_fpreg_10, 2);
149 }
150 break;
151 }
152 break;
153
154 case DW_TAG_structure_type:
155 case DW_TAG_class_type:
156 case DW_TAG_union_type:;
157 Dwarf_Die child_mem;
158 switch (dwarf_child (typedie, &child_mem))
159 {
160 default:
161 return -1;
162
163 case 1: /* No children: empty struct. */
164 break;
165
166 case 0:; /* Look at each element. */
167 int max_used = fpregs_used;
168 do
169 switch (dwarf_tag (&child_mem))
170 {
171 case -1:
172 return -1;
173
174 case DW_TAG_member:;
175 Dwarf_Die child_type_mem;
176 Dwarf_Die *child_typedie
177 = dwarf_formref_die (dwarf_attr_integrate (&child_mem,
178 DW_AT_type,
179 &attr_mem),
180 &child_type_mem);
181 Dwarf_Word child_size;
182 if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
183 return -1;
184 if (tag == DW_TAG_union_type)
185 {
186 int used = hfa_type (child_typedie, child_size,
187 locp, fpregs_used);
188 if (used < 0 || used > 8)
189 return used;
190 if (used > max_used)
191 max_used = used;
192 }
193 else
194 {
195 fpregs_used = hfa_type (child_typedie, child_size,
196 locp, fpregs_used);
197 if (fpregs_used < 0 || fpregs_used > 8)
198 return fpregs_used;
199 }
200 }
201 while (dwarf_siblingof (&child_mem, &child_mem) == 0);
202 if (tag == DW_TAG_union_type)
203 fpregs_used = max_used;
204 break;
205 }
206 break;
207
208 case DW_TAG_array_type:
209 if (size == 0)
210 break;
211
212 Dwarf_Die base_type_mem;
213 Dwarf_Die *base_typedie
214 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
215 &attr_mem),
216 &base_type_mem);
217 Dwarf_Word base_size;
218 if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
219 return -1;
220
221 int used = hfa_type (base_typedie, base_size, locp, 0);
222 if (used < 0 || used > 8)
223 return used;
224 if (size % (*locp)[1].number != 0)
225 return 0;
226 fpregs_used += used * (size / (*locp)[1].number);
227 break;
228
229 default:
230 return 9;
231 }
232
233 return fpregs_used;
234}
235
236int
237ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
238{
239 /* Start with the function's type, and get the DW_AT_type attribute,
240 which is the type of the return value. */
Elliott Hughes03333822015-02-18 22:19:45 -0800241 Dwarf_Die die_mem, *typedie = &die_mem;
242 int tag = dwarf_peeled_die_type (functypedie, typedie);
243 if (tag <= 0)
244 return tag;
Ben Cheng25b3c042013-11-20 14:45:36 -0800245
246 Dwarf_Word size;
247 switch (tag)
248 {
249 case -1:
250 return -1;
251
252 case DW_TAG_subrange_type:
253 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
254 {
Elliott Hughes03333822015-02-18 22:19:45 -0800255 Dwarf_Attribute attr_mem, *attr;
Ben Cheng25b3c042013-11-20 14:45:36 -0800256 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
257 typedie = dwarf_formref_die (attr, &die_mem);
Elliott Hughes03333822015-02-18 22:19:45 -0800258 tag = DWARF_TAG_OR_RETURN (typedie);
Ben Cheng25b3c042013-11-20 14:45:36 -0800259 }
260 /* Fall through. */
261
262 case DW_TAG_base_type:
263 case DW_TAG_enumeration_type:
264 case DW_TAG_pointer_type:
265 case DW_TAG_ptr_to_member_type:
Elliott Hughes03333822015-02-18 22:19:45 -0800266 {
267 Dwarf_Attribute attr_mem;
268 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
269 &attr_mem), &size) != 0)
270 {
271 if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
272 size = 8;
273 else
274 return -1;
275 }
276 }
277
Ben Cheng25b3c042013-11-20 14:45:36 -0800278 if (tag == DW_TAG_base_type)
279 {
Elliott Hughes03333822015-02-18 22:19:45 -0800280 Dwarf_Attribute attr_mem;
Ben Cheng25b3c042013-11-20 14:45:36 -0800281 Dwarf_Word encoding;
282 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
283 &attr_mem),
284 &encoding) != 0)
285 return -1;
286
287 switch (encoding)
288 {
289 case DW_ATE_float:
290 switch (size)
291 {
292 case 4: /* float */
293 *locp = loc_fpreg_4;
294 return nloc_fpreg;
295 case 8: /* double */
296 *locp = loc_fpreg_8;
297 return nloc_fpreg;
298 case 10: /* x86-style long double, not really used */
299 *locp = loc_fpreg_10;
300 return nloc_fpreg;
301 case 16: /* long double, IEEE quad format */
302 *locp = loc_intreg;
303 return nloc_intregs (2);
304 }
305 return -2;
306
307 case DW_ATE_complex_float:
308 switch (size)
309 {
310 case 4 * 2: /* complex float */
311 *locp = loc_fpreg_4;
312 return nloc_fpregs (2);
313 case 8 * 2: /* complex double */
314 *locp = loc_fpreg_8;
315 return nloc_fpregs (2);
316 case 10 * 2: /* complex long double (x86-style) */
317 *locp = loc_fpreg_10;
318 return nloc_fpregs (2);
319 case 16 * 2: /* complex long double (IEEE quad) */
320 *locp = loc_intreg;
321 return nloc_intregs (4);
322 }
323 return -2;
324 }
325 }
326
327 intreg:
328 *locp = loc_intreg;
329 if (size <= 8)
330 return nloc_intreg;
331 if (size <= 32)
332 return nloc_intregs ((size + 7) / 8);
333
334 large:
335 *locp = loc_aggregate;
336 return nloc_aggregate;
337
338 case DW_TAG_structure_type:
339 case DW_TAG_class_type:
340 case DW_TAG_union_type:
341 case DW_TAG_array_type:
342 if (dwarf_aggregate_size (typedie, &size) != 0)
343 return -1;
344
345 /* If this qualifies as an homogeneous floating-point aggregate
346 (HFA), then it should be returned in FP regs. */
347 int nfpreg = hfa_type (typedie, size, locp, 0);
348 if (nfpreg < 0)
349 return nfpreg;
350 else if (nfpreg > 0 && nfpreg <= 8)
351 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
352
353 if (size > 32)
354 goto large;
355
356 goto intreg;
357 }
358
359 /* XXX We don't have a good way to return specific errors from ebl calls.
360 This value means we do not understand the type, but it is well-formed
361 DWARF and might be valid. */
362 return -2;
363}