blob: b5928c587b71d0f401264bc738adb75772bf456b [file] [log] [blame]
Roland McGrath95024622006-07-21 10:06:31 +00001/* Function return value location for IA64 ABI.
Petr Machataba9e5152014-06-20 22:59:43 +02002 Copyright (C) 2006-2010, 2014 Red Hat, Inc.
Mark Wielaardde2ed972012-06-05 17:15:16 +02003 This file is part of elfutils.
Roland McGrath95024622006-07-21 10:06:31 +00004
Mark Wielaardde2ed972012-06-05 17:15:16 +02005 This file is free software; you can redistribute it and/or modify
6 it under the terms of either
Roland McGrath95024622006-07-21 10:06:31 +00007
Mark Wielaardde2ed972012-06-05 17:15:16 +02008 * 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
Roland McGrath95024622006-07-21 10:06:31 +000021 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
Mark Wielaardde2ed972012-06-05 17:15:16 +020025 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/>. */
Roland McGrath95024622006-07-21 10:06:31 +000028
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
Roland McGrath22d02c22006-07-21 11:26:51 +000092/* 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
Roland McGrath0c16c582010-01-05 22:59:32 -080095hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
96 const Dwarf_Op **locp, int fpregs_used)
Roland McGrath22d02c22006-07-21 11:26:51 +000097{
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
Mark Wielaard1d5037f2013-02-06 13:15:10 +0100112 int tag = DWARF_TAG_OR_RETURN (typedie);
Roland McGrath22d02c22006-07-21 11:26:51 +0000113 switch (tag)
114 {
115 Dwarf_Attribute attr_mem;
116
117 case -1:
118 return -1;
119
120 case DW_TAG_base_type:;
Roland McGrath22d02c22006-07-21 11:26:51 +0000121 Dwarf_Word encoding;
Roland McGrathc76f0b02007-09-27 07:31:33 +0000122 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
123 &attr_mem), &encoding) != 0)
Roland McGrath22d02c22006-07-21 11:26:51 +0000124 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
Roland McGrathc76f0b02007-09-27 07:31:33 +0000177 = dwarf_formref_die (dwarf_attr_integrate (&child_mem,
178 DW_AT_type,
179 &attr_mem),
Roland McGrath22d02c22006-07-21 11:26:51 +0000180 &child_type_mem);
Roland McGrath0c16c582010-01-05 22:59:32 -0800181 Dwarf_Word child_size;
182 if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
183 return -1;
Roland McGrath22d02c22006-07-21 11:26:51 +0000184 if (tag == DW_TAG_union_type)
185 {
Roland McGrath0c16c582010-01-05 22:59:32 -0800186 int used = hfa_type (child_typedie, child_size,
187 locp, fpregs_used);
Roland McGrath22d02c22006-07-21 11:26:51 +0000188 if (used < 0 || used > 8)
189 return used;
190 if (used > max_used)
191 max_used = used;
192 }
193 else
194 {
Roland McGrath0c16c582010-01-05 22:59:32 -0800195 fpregs_used = hfa_type (child_typedie, child_size,
196 locp, fpregs_used);
Roland McGrath22d02c22006-07-21 11:26:51 +0000197 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
Roland McGrath0c16c582010-01-05 22:59:32 -0800208 case DW_TAG_array_type:
Roland McGrath22d02c22006-07-21 11:26:51 +0000209 if (size == 0)
210 break;
211
212 Dwarf_Die base_type_mem;
Roland McGrathc76f0b02007-09-27 07:31:33 +0000213 Dwarf_Die *base_typedie
214 = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
215 &attr_mem),
216 &base_type_mem);
Roland McGrath0c16c582010-01-05 22:59:32 -0800217 Dwarf_Word base_size;
218 if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
219 return -1;
Roland McGrath22d02c22006-07-21 11:26:51 +0000220
Roland McGrath0c16c582010-01-05 22:59:32 -0800221 int used = hfa_type (base_typedie, base_size, locp, 0);
Roland McGrath22d02c22006-07-21 11:26:51 +0000222 if (used < 0 || used > 8)
223 return used;
224 if (size % (*locp)[1].number != 0)
225 return 0;
Roland McGrath0c16c582010-01-05 22:59:32 -0800226 fpregs_used += used * (size / (*locp)[1].number);
Roland McGrath22d02c22006-07-21 11:26:51 +0000227 break;
228
229 default:
230 return 9;
231 }
232
233 return fpregs_used;
234}
235
Roland McGrath95024622006-07-21 10:06:31 +0000236int
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. */
Petr Machataba9e5152014-06-20 22:59:43 +0200241 Dwarf_Die die_mem, *typedie = &die_mem;
242 int tag = dwarf_peeled_die_type (functypedie, typedie);
243 if (tag <= 0)
244 return tag;
Roland McGrath95024622006-07-21 10:06:31 +0000245
246 Dwarf_Word size;
247 switch (tag)
248 {
249 case -1:
250 return -1;
251
252 case DW_TAG_subrange_type:
Roland McGrathc76f0b02007-09-27 07:31:33 +0000253 if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
Roland McGrath95024622006-07-21 10:06:31 +0000254 {
Petr Machataba9e5152014-06-20 22:59:43 +0200255 Dwarf_Attribute attr_mem, *attr;
Roland McGrathc76f0b02007-09-27 07:31:33 +0000256 attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
Roland McGrath95024622006-07-21 10:06:31 +0000257 typedie = dwarf_formref_die (attr, &die_mem);
Mark Wielaard1d5037f2013-02-06 13:15:10 +0100258 tag = DWARF_TAG_OR_RETURN (typedie);
Roland McGrath95024622006-07-21 10:06:31 +0000259 }
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:
Petr Machataba9e5152014-06-20 22:59:43 +0200266 {
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
Roland McGrath95024622006-07-21 10:06:31 +0000278 if (tag == DW_TAG_base_type)
279 {
Petr Machataba9e5152014-06-20 22:59:43 +0200280 Dwarf_Attribute attr_mem;
Roland McGrath95024622006-07-21 10:06:31 +0000281 Dwarf_Word encoding;
Roland McGrathc76f0b02007-09-27 07:31:33 +0000282 if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
283 &attr_mem),
284 &encoding) != 0)
Roland McGrath95024622006-07-21 10:06:31 +0000285 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:
Roland McGrath0c16c582010-01-05 22:59:32 -0800342 if (dwarf_aggregate_size (typedie, &size) != 0)
Roland McGrath95024622006-07-21 10:06:31 +0000343 return -1;
Roland McGrath22d02c22006-07-21 11:26:51 +0000344
345 /* If this qualifies as an homogeneous floating-point aggregate
346 (HFA), then it should be returned in FP regs. */
Roland McGrath0c16c582010-01-05 22:59:32 -0800347 int nfpreg = hfa_type (typedie, size, locp, 0);
Roland McGrath22d02c22006-07-21 11:26:51 +0000348 if (nfpreg < 0)
349 return nfpreg;
350 else if (nfpreg > 0 && nfpreg <= 8)
351 return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
352
Roland McGrath95024622006-07-21 10:06:31 +0000353 if (size > 32)
354 goto large;
355
Roland McGrath95024622006-07-21 10:06:31 +0000356 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}