1 /* Function return value location for IA64 ABI.
2 Copyright (C) 2006-2010, 2014 Red Hat, Inc.
3 This file is part of elfutils.
5 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
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
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
18 or both in parallel, as here.
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.
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/>. */
37 #include "libebl_CPU.h"
40 /* r8, or pair r8, r9, or aggregate up to r8-r11. */
41 static const Dwarf_Op loc_intreg[] =
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 },
49 #define nloc_intregs(n) (2 * (n))
51 /* f8, or aggregate up to f8-f15. */
52 #define DEFINE_FPREG(size) \
53 static const Dwarf_Op loc_fpreg_##size[] = \
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 }, \
73 #define nloc_fpregs(n) (2 * (n))
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[] =
87 { .atom = DW_OP_breg8, .number = 0 }
89 #define nloc_aggregate 1
93 compute_hfa (const Dwarf_Op *loc, int nregs,
94 const Dwarf_Op **locp, int fpregs_used)
98 else if (*locp != loc)
100 return fpregs_used + nregs;
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. */
106 hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
107 const Dwarf_Op **locp, int fpregs_used)
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. */
114 int tag = DWARF_TAG_OR_RETURN (typedie);
117 Dwarf_Attribute attr_mem;
122 case DW_TAG_base_type:;
124 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
125 &attr_mem), &encoding) != 0)
128 #define hfa(loc, nregs) compute_hfa(loc, nregs, locp, fpregs_used)
135 return hfa (loc_fpreg_4, 1);
137 return hfa (loc_fpreg_8, 1);
138 case 10: /* x86-style long double, not really used */
139 return hfa (loc_fpreg_10, 1);
143 case DW_ATE_complex_float:
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);
157 case DW_TAG_structure_type:
158 case DW_TAG_class_type:
159 case DW_TAG_union_type:;
161 switch (dwarf_child (typedie, &child_mem))
166 case 1: /* No children: empty struct. */
169 case 0:; /* Look at each element. */
170 int max_used = fpregs_used;
172 switch (dwarf_tag (&child_mem))
178 Dwarf_Die child_type_mem;
179 Dwarf_Die *child_typedie
180 = dwarf_formref_die (dwarf_attr_integrate (&child_mem,
184 Dwarf_Word child_size;
185 if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
187 if (tag == DW_TAG_union_type)
189 int used = hfa_type (child_typedie, child_size,
191 if (used < 0 || used > 8)
198 fpregs_used = hfa_type (child_typedie, child_size,
200 if (fpregs_used < 0 || fpregs_used > 8)
204 while (dwarf_siblingof (&child_mem, &child_mem) == 0);
205 if (tag == DW_TAG_union_type)
206 fpregs_used = max_used;
211 case DW_TAG_array_type:
215 Dwarf_Die base_type_mem;
216 Dwarf_Die *base_typedie
217 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
220 Dwarf_Word base_size;
221 if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
224 int used = hfa_type (base_typedie, base_size, locp, 0);
225 if (used < 0 || used > 8)
227 if (size % (*locp)[1].number != 0)
229 fpregs_used += used * (size / (*locp)[1].number);
240 ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
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);
255 case DW_TAG_subrange_type:
256 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
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);
265 case DW_TAG_base_type:
266 case DW_TAG_enumeration_type:
267 case DW_TAG_pointer_type:
268 case DW_TAG_ptr_to_member_type:
270 Dwarf_Attribute attr_mem;
271 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
272 &attr_mem), &size) != 0)
274 if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
281 if (tag == DW_TAG_base_type)
283 Dwarf_Attribute attr_mem;
285 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
301 case 10: /* x86-style long double, not really used */
302 *locp = loc_fpreg_10;
304 case 16: /* long double, IEEE quad format */
306 return nloc_intregs (2);
310 case DW_ATE_complex_float:
313 case 4 * 2: /* complex float */
315 return nloc_fpregs (2);
316 case 8 * 2: /* complex double */
318 return nloc_fpregs (2);
319 case 10 * 2: /* complex long double (x86-style) */
320 *locp = loc_fpreg_10;
321 return nloc_fpregs (2);
322 case 16 * 2: /* complex long double (IEEE quad) */
324 return nloc_intregs (4);
335 return nloc_intregs ((size + 7) / 8);
338 *locp = loc_aggregate;
339 return nloc_aggregate;
341 case DW_TAG_structure_type:
342 case DW_TAG_class_type:
343 case DW_TAG_union_type:
344 case DW_TAG_array_type:
345 if (dwarf_aggregate_size (typedie, &size) != 0)
348 /* If this qualifies as an homogeneous floating-point aggregate
349 (HFA), then it should be returned in FP regs. */
350 int nfpreg = hfa_type (typedie, size, locp, 0);
353 else if (nfpreg > 0 && nfpreg <= 8)
354 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
362 /* XXX We don't have a good way to return specific errors from ebl calls.
363 This value means we do not understand the type, but it is well-formed
364 DWARF and might be valid. */