blob: 238cd9efeb2ed068864f71c8c5559866d745bcba [file] [log] [blame]
Ben Chengcc6695e2012-03-07 23:04:02 -08001/* Function return value location for IA64 ABI.
2 Copyright (C) 2006, 2007 Red Hat, Inc.
3 This file is part of Red Hat elfutils.
4
5 Red Hat elfutils is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by the
7 Free Software Foundation; version 2 of the License.
8
9 Red Hat elfutils is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with Red Hat elfutils; if not, write to the Free Software Foundation,
16 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
17
18 Red Hat elfutils is an included package of the Open Invention Network.
19 An included package of the Open Invention Network is a package for which
20 Open Invention Network licensees cross-license their patents. No patent
21 license is granted, either expressly or impliedly, by designation as an
22 included package. Should you wish to participate in the Open Invention
23 Network licensing program, please visit www.openinventionnetwork.com
24 <http://www.openinventionnetwork.com>. */
25
26#ifdef HAVE_CONFIG_H
27# include <config.h>
28#endif
29
30#include <assert.h>
31#include <dwarf.h>
32
33#define BACKEND ia64_
34#include "libebl_CPU.h"
35
36
37/* r8, or pair r8, r9, or aggregate up to r8-r11. */
38static const Dwarf_Op loc_intreg[] =
39 {
40 { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 },
41 { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 },
42 { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 },
43 { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 },
44 };
45#define nloc_intreg 1
46#define nloc_intregs(n) (2 * (n))
47
48/* f8, or aggregate up to f8-f15. */
49#define DEFINE_FPREG(size) \
50 static const Dwarf_Op loc_fpreg_##size[] = \
51 { \
52 { .atom = DW_OP_regx, .number = 128 + 8 }, \
53 { .atom = DW_OP_piece, .number = size }, \
54 { .atom = DW_OP_regx, .number = 128 + 9 }, \
55 { .atom = DW_OP_piece, .number = size }, \
56 { .atom = DW_OP_regx, .number = 128 + 10 }, \
57 { .atom = DW_OP_piece, .number = size }, \
58 { .atom = DW_OP_regx, .number = 128 + 11 }, \
59 { .atom = DW_OP_piece, .number = size }, \
60 { .atom = DW_OP_regx, .number = 128 + 12 }, \
61 { .atom = DW_OP_piece, .number = size }, \
62 { .atom = DW_OP_regx, .number = 128 + 13 }, \
63 { .atom = DW_OP_piece, .number = size }, \
64 { .atom = DW_OP_regx, .number = 128 + 14 }, \
65 { .atom = DW_OP_piece, .number = size }, \
66 { .atom = DW_OP_regx, .number = 128 + 15 }, \
67 { .atom = DW_OP_piece, .number = size }, \
68 }
69#define nloc_fpreg 1
70#define nloc_fpregs(n) (2 * (n))
71
72DEFINE_FPREG (4);
73DEFINE_FPREG (8);
74DEFINE_FPREG (10);
75
76#undef DEFINE_FPREG
77
78
79/* The return value is a structure and is actually stored in stack space
80 passed in a hidden argument by the caller. But, the compiler
81 helpfully returns the address of that space in r8. */
82static const Dwarf_Op loc_aggregate[] =
83 {
84 { .atom = DW_OP_breg8, .number = 0 }
85 };
86#define nloc_aggregate 1
87
88
89/* If this type is an HFA small enough to be returned in FP registers,
90 return the number of registers to use. Otherwise 9, or -1 for errors. */
91static int
92hfa_type (Dwarf_Die *typedie, const Dwarf_Op **locp, int fpregs_used)
93{
94 /* Descend the type structure, counting elements and finding their types.
95 If we find a datum that's not an FP type (and not quad FP), punt.
96 If we find a datum that's not the same FP type as the first datum, punt.
97 If we count more than eight total homogeneous FP data, punt. */
98
99 inline int hfa (const Dwarf_Op *loc, int nregs)
100 {
101 if (fpregs_used == 0)
102 *locp = loc;
103 else if (*locp != loc)
104 return 9;
105 return fpregs_used + nregs;
106 }
107
108 int tag = dwarf_tag (typedie);
109 switch (tag)
110 {
111 Dwarf_Attribute attr_mem;
112
113 case -1:
114 return -1;
115
116 case DW_TAG_base_type:;
117 int size = dwarf_bytesize (typedie);
118 if (size < 0)
119 return -1;
120
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 if (tag == DW_TAG_union_type)
182 {
183 int used = hfa_type (child_typedie, locp, fpregs_used);
184 if (used < 0 || used > 8)
185 return used;
186 if (used > max_used)
187 max_used = used;
188 }
189 else
190 {
191 fpregs_used = hfa_type (child_typedie, locp, fpregs_used);
192 if (fpregs_used < 0 || fpregs_used > 8)
193 return fpregs_used;
194 }
195 }
196 while (dwarf_siblingof (&child_mem, &child_mem) == 0);
197 if (tag == DW_TAG_union_type)
198 fpregs_used = max_used;
199 break;
200 }
201 break;
202
203 case DW_TAG_array_type:;
204 size = dwarf_bytesize (typedie);
205 if (size < 0)
206 return 9;
207 if (size == 0)
208 break;
209
210 Dwarf_Die base_type_mem;
211 Dwarf_Die *base_typedie
212 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
213 &attr_mem),
214 &base_type_mem);
215
216 int used = hfa_type (base_typedie, locp, 0);
217 if (used < 0 || used > 8)
218 return used;
219 if (size % (*locp)[1].number != 0)
220 return 0;
221 size /= (*locp)[1].number;
222 fpregs_used += used * size;
223 break;
224
225 default:
226 return 9;
227 }
228
229 return fpregs_used;
230}
231
232int
233ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
234{
235 /* Start with the function's type, and get the DW_AT_type attribute,
236 which is the type of the return value. */
237
238 Dwarf_Attribute attr_mem;
239 Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type,
240 &attr_mem);
241 if (attr == NULL)
242 /* The function has no return value, like a `void' function in C. */
243 return 0;
244
245 Dwarf_Die die_mem;
246 Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
247 int tag = dwarf_tag (typedie);
248
249 /* Follow typedefs and qualifiers to get to the actual type. */
250 while (tag == DW_TAG_typedef
251 || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
252 || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type)
253 {
254 attr = dwarf_attr (typedie, DW_AT_type, &attr_mem);
255 typedie = dwarf_formref_die (attr, &die_mem);
256 tag = dwarf_tag (typedie);
257 }
258
259 Dwarf_Word size;
260 switch (tag)
261 {
262 case -1:
263 return -1;
264
265 case DW_TAG_subrange_type:
266 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
267 {
268 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
269 typedie = dwarf_formref_die (attr, &die_mem);
270 tag = dwarf_tag (typedie);
271 }
272 /* Fall through. */
273
274 case DW_TAG_base_type:
275 case DW_TAG_enumeration_type:
276 case DW_TAG_pointer_type:
277 case DW_TAG_ptr_to_member_type:
278 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
279 &attr_mem), &size) != 0)
280 {
281 if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
282 size = 8;
283 else
284 return -1;
285 }
286 if (tag == DW_TAG_base_type)
287 {
288 Dwarf_Word encoding;
289 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
290 &attr_mem),
291 &encoding) != 0)
292 return -1;
293
294 switch (encoding)
295 {
296 case DW_ATE_float:
297 switch (size)
298 {
299 case 4: /* float */
300 *locp = loc_fpreg_4;
301 return nloc_fpreg;
302 case 8: /* double */
303 *locp = loc_fpreg_8;
304 return nloc_fpreg;
305 case 10: /* x86-style long double, not really used */
306 *locp = loc_fpreg_10;
307 return nloc_fpreg;
308 case 16: /* long double, IEEE quad format */
309 *locp = loc_intreg;
310 return nloc_intregs (2);
311 }
312 return -2;
313
314 case DW_ATE_complex_float:
315 switch (size)
316 {
317 case 4 * 2: /* complex float */
318 *locp = loc_fpreg_4;
319 return nloc_fpregs (2);
320 case 8 * 2: /* complex double */
321 *locp = loc_fpreg_8;
322 return nloc_fpregs (2);
323 case 10 * 2: /* complex long double (x86-style) */
324 *locp = loc_fpreg_10;
325 return nloc_fpregs (2);
326 case 16 * 2: /* complex long double (IEEE quad) */
327 *locp = loc_intreg;
328 return nloc_intregs (4);
329 }
330 return -2;
331 }
332 }
333
334 intreg:
335 *locp = loc_intreg;
336 if (size <= 8)
337 return nloc_intreg;
338 if (size <= 32)
339 return nloc_intregs ((size + 7) / 8);
340
341 large:
342 *locp = loc_aggregate;
343 return nloc_aggregate;
344
345 case DW_TAG_structure_type:
346 case DW_TAG_class_type:
347 case DW_TAG_union_type:
348 case DW_TAG_array_type:
349 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
350 &attr_mem), &size) != 0)
351 return -1;
352
353 /* If this qualifies as an homogeneous floating-point aggregate
354 (HFA), then it should be returned in FP regs. */
355 int nfpreg = hfa_type (typedie, locp, 0);
356 if (nfpreg < 0)
357 return nfpreg;
358 else if (nfpreg > 0 && nfpreg <= 8)
359 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
360
361 if (size > 32)
362 goto large;
363
364 goto intreg;
365 }
366
367 /* XXX We don't have a good way to return specific errors from ebl calls.
368 This value means we do not understand the type, but it is well-formed
369 DWARF and might be valid. */
370 return -2;
371}