packaging: update homepage url
[platform/upstream/elfutils.git] / backends / ia64_retval.c
1 /* Function return value location for IA64 ABI.
2    Copyright (C) 2006-2010, 2014 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 <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.  */
41 static 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
75 DEFINE_FPREG (4);
76 DEFINE_FPREG (8);
77 DEFINE_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.  */
85 static const Dwarf_Op loc_aggregate[] =
86   {
87     { .atom = DW_OP_breg8, .number = 0 }
88   };
89 #define nloc_aggregate 1
90
91
92 static inline int
93 compute_hfa (const Dwarf_Op *loc, int nregs,
94              const Dwarf_Op **locp, int fpregs_used)
95 {
96   if (fpregs_used == 0)
97     *locp = loc;
98   else if (*locp != loc)
99     return 9;
100   return fpregs_used + nregs;
101 }
102
103 /* If this type is an HFA small enough to be returned in FP registers,
104    return the number of registers to use.  Otherwise 9, or -1 for errors.  */
105 static int
106 hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
107           const Dwarf_Op **locp, int fpregs_used)
108 {
109   /* Descend the type structure, counting elements and finding their types.
110      If we find a datum that's not an FP type (and not quad FP), punt.
111      If we find a datum that's not the same FP type as the first datum, punt.
112      If we count more than eight total homogeneous FP data, punt.  */
113
114   int tag = DWARF_TAG_OR_RETURN (typedie);
115   switch (tag)
116     {
117       Dwarf_Attribute attr_mem;
118
119     case -1:
120       return -1;
121
122     case DW_TAG_base_type:;
123       Dwarf_Word encoding;
124       if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
125                                                  &attr_mem), &encoding) != 0)
126         return -1;
127
128 #define hfa(loc, nregs) compute_hfa(loc, nregs, locp, fpregs_used)
129       switch (encoding)
130         {
131         case DW_ATE_float:
132           switch (size)
133             {
134             case 4:             /* float */
135               return hfa (loc_fpreg_4, 1);
136             case 8:             /* double */
137               return hfa (loc_fpreg_8, 1);
138             case 10:       /* x86-style long double, not really used */
139               return hfa (loc_fpreg_10, 1);
140             }
141           break;
142
143         case DW_ATE_complex_float:
144           switch (size)
145             {
146             case 4 * 2: /* complex float */
147               return hfa (loc_fpreg_4, 2);
148             case 8 * 2: /* complex double */
149               return hfa (loc_fpreg_8, 2);
150             case 10 * 2:        /* complex long double (x86-style) */
151               return hfa (loc_fpreg_10, 2);
152             }
153           break;
154         }
155       break;
156
157     case DW_TAG_structure_type:
158     case DW_TAG_class_type:
159     case DW_TAG_union_type:;
160       Dwarf_Die child_mem;
161       switch (dwarf_child (typedie, &child_mem))
162         {
163         default:
164           return -1;
165
166         case 1:                 /* No children: empty struct.  */
167           break;
168
169         case 0:;                /* Look at each element.  */
170           int max_used = fpregs_used;
171           do
172             switch (dwarf_tag (&child_mem))
173               {
174               case -1:
175                 return -1;
176
177               case DW_TAG_member:;
178                 Dwarf_Die child_type_mem;
179                 Dwarf_Die *child_typedie
180                   = dwarf_formref_die (dwarf_attr_integrate (&child_mem,
181                                                              DW_AT_type,
182                                                              &attr_mem),
183                                        &child_type_mem);
184                 Dwarf_Word child_size;
185                 if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
186                   return -1;
187                 if (tag == DW_TAG_union_type)
188                   {
189                     int used = hfa_type (child_typedie, child_size,
190                                          locp, fpregs_used);
191                     if (used < 0 || used > 8)
192                       return used;
193                     if (used > max_used)
194                       max_used = used;
195                   }
196                 else
197                   {
198                     fpregs_used = hfa_type (child_typedie, child_size,
199                                             locp, fpregs_used);
200                     if (fpregs_used < 0 || fpregs_used > 8)
201                       return fpregs_used;
202                   }
203               }
204           while (dwarf_siblingof (&child_mem, &child_mem) == 0);
205           if (tag == DW_TAG_union_type)
206             fpregs_used = max_used;
207           break;
208         }
209       break;
210
211     case DW_TAG_array_type:
212       if (size == 0)
213         break;
214
215       Dwarf_Die base_type_mem;
216       Dwarf_Die *base_typedie
217         = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
218                                                    &attr_mem),
219                              &base_type_mem);
220       Dwarf_Word base_size;
221       if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
222         return -1;
223
224       int used = hfa_type (base_typedie, base_size, locp, 0);
225       if (used < 0 || used > 8)
226         return used;
227       if (size % (*locp)[1].number != 0)
228         return 0;
229       fpregs_used += used * (size / (*locp)[1].number);
230       break;
231
232     default:
233       return 9;
234     }
235
236   return fpregs_used;
237 }
238
239 int
240 ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
241 {
242   /* Start with the function's type, and get the DW_AT_type attribute,
243      which is the type of the return value.  */
244   Dwarf_Die die_mem, *typedie = &die_mem;
245   int tag = dwarf_peeled_die_type (functypedie, typedie);
246   if (tag <= 0)
247     return tag;
248
249   Dwarf_Word size;
250   switch (tag)
251     {
252     case -1:
253       return -1;
254
255     case DW_TAG_subrange_type:
256       if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
257         {
258           Dwarf_Attribute attr_mem, *attr;
259           attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
260           typedie = dwarf_formref_die (attr, &die_mem);
261           tag = DWARF_TAG_OR_RETURN (typedie);
262         }
263       /* Fall through.  */
264
265     case DW_TAG_base_type:
266     case DW_TAG_enumeration_type:
267     case DW_TAG_pointer_type:
268     case DW_TAG_ptr_to_member_type:
269       {
270         Dwarf_Attribute attr_mem;
271         if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
272                                                    &attr_mem), &size) != 0)
273           {
274             if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
275               size = 8;
276             else
277               return -1;
278           }
279       }
280
281       if (tag == DW_TAG_base_type)
282         {
283           Dwarf_Attribute attr_mem;
284           Dwarf_Word encoding;
285           if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
286                                                      &attr_mem),
287                                &encoding) != 0)
288             return -1;
289
290           switch (encoding)
291             {
292             case DW_ATE_float:
293               switch (size)
294                 {
295                 case 4:         /* float */
296                   *locp = loc_fpreg_4;
297                   return nloc_fpreg;
298                 case 8:         /* double */
299                   *locp = loc_fpreg_8;
300                   return nloc_fpreg;
301                 case 10:       /* x86-style long double, not really used */
302                   *locp = loc_fpreg_10;
303                   return nloc_fpreg;
304                 case 16:        /* long double, IEEE quad format */
305                   *locp = loc_intreg;
306                   return nloc_intregs (2);
307                 }
308               return -2;
309
310             case DW_ATE_complex_float:
311               switch (size)
312                 {
313                 case 4 * 2:     /* complex float */
314                   *locp = loc_fpreg_4;
315                   return nloc_fpregs (2);
316                 case 8 * 2:     /* complex double */
317                   *locp = loc_fpreg_8;
318                   return nloc_fpregs (2);
319                 case 10 * 2:    /* complex long double (x86-style) */
320                   *locp = loc_fpreg_10;
321                   return nloc_fpregs (2);
322                 case 16 * 2:    /* complex long double (IEEE quad) */
323                   *locp = loc_intreg;
324                   return nloc_intregs (4);
325                 }
326               return -2;
327             }
328         }
329
330     intreg:
331       *locp = loc_intreg;
332       if (size <= 8)
333         return nloc_intreg;
334       if (size <= 32)
335         return nloc_intregs ((size + 7) / 8);
336
337     large:
338       *locp = loc_aggregate;
339       return nloc_aggregate;
340
341     case DW_TAG_structure_type:
342     case DW_TAG_class_type:
343     case DW_TAG_union_type:
344     case DW_TAG_array_type:
345       if (dwarf_aggregate_size (typedie, &size) != 0)
346         return -1;
347
348       /* If this qualifies as an homogeneous floating-point aggregate
349          (HFA), then it should be returned in FP regs. */
350       int nfpreg = hfa_type (typedie, size, locp, 0);
351       if (nfpreg < 0)
352         return nfpreg;
353       else if (nfpreg > 0 && nfpreg <= 8)
354         return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
355
356       if (size > 32)
357         goto large;
358
359       goto intreg;
360     }
361
362   /* XXX We don't have a good way to return specific errors from ebl calls.
363      This value means we do not understand the type, but it is well-formed
364      DWARF and might be valid.  */
365   return -2;
366 }