1 /* Function return value location for IA64 ABI.
2 Copyright (C) 2006-2010 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 (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. */
242 Dwarf_Attribute attr_mem;
243 Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type,
246 /* The function has no return value, like a `void' function in C. */
250 Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
251 int tag = dwarf_tag (typedie);
253 /* Follow typedefs and qualifiers to get to the actual type. */
254 while (tag == DW_TAG_typedef
255 || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
256 || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type)
258 attr = dwarf_attr (typedie, DW_AT_type, &attr_mem);
259 typedie = dwarf_formref_die (attr, &die_mem);
260 tag = dwarf_tag (typedie);
269 case DW_TAG_subrange_type:
270 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
272 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
273 typedie = dwarf_formref_die (attr, &die_mem);
274 tag = dwarf_tag (typedie);
278 case DW_TAG_base_type:
279 case DW_TAG_enumeration_type:
280 case DW_TAG_pointer_type:
281 case DW_TAG_ptr_to_member_type:
282 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
283 &attr_mem), &size) != 0)
285 if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
290 if (tag == DW_TAG_base_type)
293 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
309 case 10: /* x86-style long double, not really used */
310 *locp = loc_fpreg_10;
312 case 16: /* long double, IEEE quad format */
314 return nloc_intregs (2);
318 case DW_ATE_complex_float:
321 case 4 * 2: /* complex float */
323 return nloc_fpregs (2);
324 case 8 * 2: /* complex double */
326 return nloc_fpregs (2);
327 case 10 * 2: /* complex long double (x86-style) */
328 *locp = loc_fpreg_10;
329 return nloc_fpregs (2);
330 case 16 * 2: /* complex long double (IEEE quad) */
332 return nloc_intregs (4);
343 return nloc_intregs ((size + 7) / 8);
346 *locp = loc_aggregate;
347 return nloc_aggregate;
349 case DW_TAG_structure_type:
350 case DW_TAG_class_type:
351 case DW_TAG_union_type:
352 case DW_TAG_array_type:
353 if (dwarf_aggregate_size (typedie, &size) != 0)
356 /* If this qualifies as an homogeneous floating-point aggregate
357 (HFA), then it should be returned in FP regs. */
358 int nfpreg = hfa_type (typedie, size, locp, 0);
361 else if (nfpreg > 0 && nfpreg <= 8)
362 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
370 /* XXX We don't have a good way to return specific errors from ebl calls.
371 This value means we do not understand the type, but it is well-formed
372 DWARF and might be valid. */