Branch data Line data Source code
1 : : /* Function return value location for Linux/AArch64 ABI.
2 : : Copyright (C) 2013 Red Hat, Inc.
3 : : This file is part of elfutils.
4 : :
5 : : This file is free software; you can redistribute it and/or modify
6 : : it under the terms of either
7 : :
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
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
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.
24 : :
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/>. */
28 : :
29 : : #ifdef HAVE_CONFIG_H
30 : : # include <config.h>
31 : : #endif
32 : :
33 : : #include <stdio.h>
34 : : #include <inttypes.h>
35 : :
36 : : #include <assert.h>
37 : : #include <dwarf.h>
38 : :
39 : : #define BACKEND aarch64_
40 : : #include "libebl_CPU.h"
41 : :
42 : : static int
43 : 206 : skip_until (Dwarf_Die *child, int tag)
44 : : {
45 : 206 : int i;
46 [ + - - + ]: 206 : while (DWARF_TAG_OR_RETURN (child) != tag)
47 [ # # ]: 0 : if ((i = dwarf_siblingof (child, child)) != 0)
48 : : /* If there are no members, then this is not a HFA. Errors
49 : : are propagated. */
50 : 0 : return i;
51 : : return 0;
52 : : }
53 : :
54 : : static int
55 : 86 : dwarf_bytesize_aux (Dwarf_Die *die, Dwarf_Word *sizep)
56 : : {
57 : 86 : int bits;
58 [ - + ]: 86 : if (((bits = 8 * dwarf_bytesize (die)) < 0
59 [ # # ]: 0 : && (bits = dwarf_bitsize (die)) < 0)
60 [ - + ]: 86 : || bits % 8 != 0)
61 : 0 : return -1;
62 : :
63 : 86 : *sizep = bits / 8;
64 : 86 : return 0;
65 : : }
66 : :
67 : : /* HFA (Homogeneous Floating-point Aggregate) is an aggregate type
68 : : whose members are all of the same floating-point type, which is
69 : : then base type of this HFA. Instead of being floating-point types
70 : : directly, members can instead themselves be HFA. Such HFA fields
71 : : are handled as if their type were HFA base type.
72 : :
73 : : This function returns 0 if TYPEDIE is HFA, 1 if it is not, or -1 if
74 : : there were errors. In the former case, *SIZEP contains byte size
75 : : of the base type (e.g. 8 for IEEE double). *COUNT is set to the
76 : : number of leaf members of the HFA. */
77 : : static int hfa_type (Dwarf_Die *ftypedie, int tag,
78 : : Dwarf_Word *sizep, Dwarf_Word *countp);
79 : :
80 : : /* Return 0 if MEMBDIE refers to a member with a floating-point or HFA
81 : : type, or 1 if it's not. Return -1 for errors. The meaning of the
82 : : remaining arguments is as documented at hfa_type. */
83 : : static int
84 : 222 : member_is_fp (Dwarf_Die *membdie, Dwarf_Word *sizep, Dwarf_Word *countp)
85 : : {
86 : 222 : Dwarf_Die typedie;
87 : 222 : int tag = dwarf_peeled_die_type (membdie, &typedie);
88 [ + + - ]: 222 : switch (tag)
89 : : {
90 : 74 : case DW_TAG_base_type:;
91 : 74 : Dwarf_Word encoding;
92 : 74 : Dwarf_Attribute attr_mem;
93 [ + - ]: 74 : if (dwarf_attr_integrate (&typedie, DW_AT_encoding, &attr_mem) == NULL
94 [ - + ]: 74 : || dwarf_formudata (&attr_mem, &encoding) != 0)
95 : 0 : return -1;
96 : :
97 [ + + + ]: 74 : switch (encoding)
98 : : {
99 : 6 : case DW_ATE_complex_float:
100 : 6 : *countp = 2;
101 : 6 : break;
102 : :
103 : 66 : case DW_ATE_float:
104 : 66 : *countp = 1;
105 : 66 : break;
106 : :
107 : : default:
108 : : return 1;
109 : : }
110 : :
111 [ + - ]: 72 : if (dwarf_bytesize_aux (&typedie, sizep) < 0)
112 : : return -1;
113 : :
114 : 72 : *sizep /= *countp;
115 : 72 : return 0;
116 : :
117 : 148 : case DW_TAG_structure_type:
118 : : case DW_TAG_union_type:
119 : : case DW_TAG_array_type:
120 : 148 : return hfa_type (&typedie, tag, sizep, countp);
121 : : }
122 : :
123 : : return 1;
124 : : }
125 : :
126 : : static int
127 : 251 : hfa_type (Dwarf_Die *ftypedie, int tag, Dwarf_Word *sizep, Dwarf_Word *countp)
128 : : {
129 [ + + - + ]: 251 : assert (tag == DW_TAG_structure_type || tag == DW_TAG_class_type
130 : : || tag == DW_TAG_union_type || tag == DW_TAG_array_type);
131 : :
132 : 251 : int i;
133 [ + + ]: 251 : if (tag == DW_TAG_array_type)
134 : : {
135 : 160 : Dwarf_Word tot_size;
136 [ + - ]: 160 : if (dwarf_aggregate_size (ftypedie, &tot_size) < 0)
137 : : return -1;
138 : :
139 : : /* For vector types, we don't care about the underlying
140 : : type, but only about the vector type itself. */
141 : 160 : bool vec;
142 : 160 : Dwarf_Attribute attr_mem;
143 [ + + ]: 160 : if (dwarf_formflag (dwarf_attr_integrate (ftypedie, DW_AT_GNU_vector,
144 : : &attr_mem), &vec) == 0
145 [ + - ]: 144 : && vec)
146 : : {
147 : 144 : *sizep = tot_size;
148 : 144 : *countp = 1;
149 : :
150 : 144 : return 0;
151 : : }
152 : :
153 [ + + ]: 16 : if ((i = member_is_fp (ftypedie, sizep, countp)) == 0)
154 : : {
155 : 15 : *countp = tot_size / *sizep;
156 : 15 : return 0;
157 : : }
158 : :
159 : : return i;
160 : : }
161 : :
162 : : /* Find first DW_TAG_member and determine its type. */
163 : 91 : Dwarf_Die member;
164 [ + - ]: 91 : if ((i = dwarf_child (ftypedie, &member) != 0))
165 : : return i;
166 : :
167 [ + - ]: 91 : if ((i = skip_until (&member, DW_TAG_member)) != 0)
168 : : return i;
169 : :
170 : 91 : *countp = 0;
171 [ + + ]: 91 : if ((i = member_is_fp (&member, sizep, countp)) != 0)
172 : : return i;
173 : :
174 [ + + ]: 204 : while ((i = dwarf_siblingof (&member, &member)) == 0
175 [ + - ]: 115 : && (i = skip_until (&member, DW_TAG_member)) == 0)
176 : : {
177 : 115 : Dwarf_Word size, count;
178 [ - + ]: 115 : if ((i = member_is_fp (&member, &size, &count)) != 0)
179 : 0 : return i;
180 : :
181 [ + - ]: 115 : if (*sizep != size)
182 : : return 1;
183 : :
184 : 115 : *countp += count;
185 : : }
186 : :
187 : : /* At this point we already have at least one FP member, which means
188 : : FTYPEDIE is an HFA. So either return 0, or propagate error. */
189 : 89 : return i < 0 ? i : 0;
190 : : }
191 : :
192 : : static int
193 : 8 : pass_in_gpr (const Dwarf_Op **locp, Dwarf_Word size)
194 : : {
195 : 8 : static const Dwarf_Op loc[] =
196 : : {
197 : : { .atom = DW_OP_reg0 }, { .atom = DW_OP_piece, .number = 8 },
198 : : { .atom = DW_OP_reg1 }, { .atom = DW_OP_piece, .number = 8 }
199 : : };
200 : :
201 : 8 : *locp = loc;
202 : 8 : return size <= 8 ? 1 : 4;
203 : : }
204 : :
205 : : static int
206 : 8 : pass_by_ref (const Dwarf_Op **locp)
207 : : {
208 : 8 : static const Dwarf_Op loc[] = { { .atom = DW_OP_breg0 } };
209 : :
210 : 8 : *locp = loc;
211 : 8 : return 1;
212 : : }
213 : :
214 : : static int
215 : 101 : pass_hfa (const Dwarf_Op **locp, Dwarf_Word size, Dwarf_Word count)
216 : : {
217 [ - + ]: 98 : assert (count >= 1 && count <= 4);
218 [ + + - + ]: 98 : assert (size == 2 || size == 4 || size == 8 || size == 16);
219 : :
220 : : #define DEFINE_FPREG(NAME, SIZE) \
221 : : static const Dwarf_Op NAME[] = { \
222 : : { .atom = DW_OP_regx, .number = 64 }, \
223 : : { .atom = DW_OP_piece, .number = SIZE }, \
224 : : { .atom = DW_OP_regx, .number = 65 }, \
225 : : { .atom = DW_OP_piece, .number = SIZE }, \
226 : : { .atom = DW_OP_regx, .number = 66 }, \
227 : : { .atom = DW_OP_piece, .number = SIZE }, \
228 : : { .atom = DW_OP_regx, .number = 67 }, \
229 : : { .atom = DW_OP_piece, .number = SIZE } \
230 : : }
231 : :
232 [ - + + + : 98 : switch (size)
- ]
233 : : {
234 : 0 : case 2:;
235 : 0 : DEFINE_FPREG (loc_hfa_2, 2);
236 : 0 : *locp = loc_hfa_2;
237 : 0 : break;
238 : :
239 : 11 : case 4:;
240 : 11 : DEFINE_FPREG (loc_hfa_4, 4);
241 : 11 : *locp = loc_hfa_4;
242 : 11 : break;
243 : :
244 : 44 : case 8:;
245 : 44 : DEFINE_FPREG (loc_hfa_8, 8);
246 : 44 : *locp = loc_hfa_8;
247 : 41 : break;
248 : :
249 : 46 : case 16:;
250 : 46 : DEFINE_FPREG (loc_hfa_16, 16);
251 : 46 : *locp = loc_hfa_16;
252 : 46 : break;
253 : : }
254 : : #undef DEFINE_FPREG
255 : :
256 [ + + ]: 98 : return count == 1 ? 1 : 2 * count;
257 : : }
258 : :
259 : : static int
260 : 3 : pass_in_simd (const Dwarf_Op **locp)
261 : : {
262 : : /* This is like passing single-element HFA. Size doesn't matter, so
263 : : pretend it's for example double. */
264 : 3 : return pass_hfa (locp, 8, 1);
265 : : }
266 : :
267 : : int
268 : 117 : aarch64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
269 : : {
270 : : /* Start with the function's type, and get the DW_AT_type attribute,
271 : : which is the type of the return value. */
272 : 117 : Dwarf_Die typedie;
273 : 117 : int tag = dwarf_peeled_die_type (functypedie, &typedie);
274 [ + - ]: 117 : if (tag <= 0)
275 : : return tag;
276 : :
277 : 117 : Dwarf_Word size = (Dwarf_Word)-1;
278 : :
279 : : /* If the argument type is a Composite Type that is larger than 16
280 : : bytes, then the argument is copied to memory allocated by the
281 : : caller and the argument is replaced by a pointer to the copy. */
282 [ + + ]: 117 : if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type
283 [ + + ]: 26 : || tag == DW_TAG_class_type || tag == DW_TAG_array_type)
284 : : {
285 : 103 : Dwarf_Word base_size, count;
286 [ + + - ]: 103 : switch (hfa_type (&typedie, tag, &base_size, &count))
287 : : {
288 : : default:
289 : 103 : return -1;
290 : :
291 : 101 : case 0:
292 [ - + ]: 101 : assert (count > 0);
293 [ + + ]: 101 : if (count <= 4)
294 : 95 : return pass_hfa (locp, base_size, count);
295 : 8 : FALLTHROUGH;
296 : :
297 : : case 1:
298 : : /* Not a HFA. */
299 [ + - ]: 8 : if (dwarf_aggregate_size (&typedie, &size) < 0)
300 : : return -1;
301 [ + - ]: 8 : if (size > 16)
302 : 8 : return pass_by_ref (locp);
303 : : }
304 : : }
305 : :
306 [ + + + - ]: 14 : if (tag == DW_TAG_base_type || dwarf_is_pointer (tag))
307 : : {
308 [ - + ]: 14 : if (dwarf_bytesize_aux (&typedie, &size) < 0)
309 : : {
310 [ # # ]: 0 : if (dwarf_is_pointer (tag))
311 : 0 : size = 8;
312 : : else
313 : : return -1;
314 : : }
315 : :
316 : 14 : Dwarf_Attribute attr_mem;
317 [ + + ]: 14 : if (tag == DW_TAG_base_type)
318 : : {
319 : 13 : Dwarf_Word encoding;
320 [ + - ]: 13 : if (dwarf_formudata (dwarf_attr_integrate (&typedie, DW_AT_encoding,
321 : : &attr_mem),
322 : : &encoding) != 0)
323 : : return -1;
324 : :
325 [ + + + - ]: 13 : switch (encoding)
326 : : {
327 : : /* If the argument is a Half-, Single-, Double- or Quad-
328 : : precision Floating-point [...] the argument is allocated
329 : : to the least significant bits of register v[NSRN]. */
330 : 3 : case DW_ATE_float:
331 [ + - ]: 3 : switch (size)
332 : : {
333 : : case 2: /* half */
334 : : case 4: /* single */
335 : : case 8: /* double */
336 : : case 16: /* quad */
337 : 3 : return pass_in_simd (locp);
338 : :
339 : : default:
340 : : return -2;
341 : : }
342 : :
343 : 3 : case DW_ATE_complex_float:
344 [ + - ]: 3 : switch (size)
345 : : {
346 : 3 : case 8: /* float _Complex */
347 : : case 16: /* double _Complex */
348 : : case 32: /* long double _Complex */
349 : 3 : return pass_hfa (locp, size / 2, 2);
350 : :
351 : : default:
352 : : return -2;
353 : : }
354 : :
355 : : /* If the argument is an Integral or Pointer Type, the
356 : : size of the argument is less than or equal to 8 bytes
357 : : [...] the argument is copied to the least significant
358 : : bits in x[NGRN]. */
359 : 7 : case DW_ATE_boolean:
360 : : case DW_ATE_signed:
361 : : case DW_ATE_unsigned:
362 : : case DW_ATE_unsigned_char:
363 : : case DW_ATE_signed_char:
364 [ + + ]: 8 : return pass_in_gpr (locp, size);
365 : : }
366 : :
367 : : return -2;
368 : : }
369 : : else
370 [ - + ]: 1 : return pass_in_gpr (locp, size);
371 : : }
372 : :
373 : 0 : *locp = NULL;
374 : 0 : return 0;
375 : : }
|