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
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. */
95 hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
96 const Dwarf_Op **locp, int fpregs_used)
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. */
103 inline int hfa (const Dwarf_Op *loc, int nregs)
105 if (fpregs_used == 0)
107 else if (*locp != loc)
109 return fpregs_used + nregs;
112 int tag = DWARF_TAG_OR_RETURN (typedie);
115 Dwarf_Attribute attr_mem;
120 case DW_TAG_base_type:;
122 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
123 &attr_mem), &encoding) != 0)
132 return hfa (loc_fpreg_4, 1);
134 return hfa (loc_fpreg_8, 1);
135 case 10: /* x86-style long double, not really used */
136 return hfa (loc_fpreg_10, 1);
140 case DW_ATE_complex_float:
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);
154 case DW_TAG_structure_type:
155 case DW_TAG_class_type:
156 case DW_TAG_union_type:;
158 switch (dwarf_child (typedie, &child_mem))
163 case 1: /* No children: empty struct. */
166 case 0:; /* Look at each element. */
167 int max_used = fpregs_used;
169 switch (dwarf_tag (&child_mem))
175 Dwarf_Die child_type_mem;
176 Dwarf_Die *child_typedie
177 = dwarf_formref_die (dwarf_attr_integrate (&child_mem,
181 Dwarf_Word child_size;
182 if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
184 if (tag == DW_TAG_union_type)
186 int used = hfa_type (child_typedie, child_size,
188 if (used < 0 || used > 8)
195 fpregs_used = hfa_type (child_typedie, child_size,
197 if (fpregs_used < 0 || fpregs_used > 8)
201 while (dwarf_siblingof (&child_mem, &child_mem) == 0);
202 if (tag == DW_TAG_union_type)
203 fpregs_used = max_used;
208 case DW_TAG_array_type:
212 Dwarf_Die base_type_mem;
213 Dwarf_Die *base_typedie
214 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
217 Dwarf_Word base_size;
218 if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
221 int used = hfa_type (base_typedie, base_size, locp, 0);
222 if (used < 0 || used > 8)
224 if (size % (*locp)[1].number != 0)
226 fpregs_used += used * (size / (*locp)[1].number);
237 ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
239 /* Start with the function's type, and get the DW_AT_type attribute,
240 which is the type of the return value. */
241 Dwarf_Die die_mem, *typedie = &die_mem;
242 int tag = dwarf_peeled_die_type (functypedie, typedie);
252 case DW_TAG_subrange_type:
253 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
255 Dwarf_Attribute attr_mem, *attr;
256 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
257 typedie = dwarf_formref_die (attr, &die_mem);
258 tag = DWARF_TAG_OR_RETURN (typedie);
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:
267 Dwarf_Attribute attr_mem;
268 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
269 &attr_mem), &size) != 0)
271 if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
278 if (tag == DW_TAG_base_type)
280 Dwarf_Attribute attr_mem;
282 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
298 case 10: /* x86-style long double, not really used */
299 *locp = loc_fpreg_10;
301 case 16: /* long double, IEEE quad format */
303 return nloc_intregs (2);
307 case DW_ATE_complex_float:
310 case 4 * 2: /* complex float */
312 return nloc_fpregs (2);
313 case 8 * 2: /* complex double */
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) */
321 return nloc_intregs (4);
332 return nloc_intregs ((size + 7) / 8);
335 *locp = loc_aggregate;
336 return nloc_aggregate;
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)
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);
350 else if (nfpreg > 0 && nfpreg <= 8)
351 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
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. */