Imported Upstream version 0.160
[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 /* 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.  */
94 static int
95 hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
96           const Dwarf_Op **locp, int fpregs_used)
97 {
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
112   int tag = DWARF_TAG_OR_RETURN (typedie);
113   switch (tag)
114     {
115       Dwarf_Attribute attr_mem;
116
117     case -1:
118       return -1;
119
120     case DW_TAG_base_type:;
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                 Dwarf_Word child_size;
182                 if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
183                   return -1;
184                 if (tag == DW_TAG_union_type)
185                   {
186                     int used = hfa_type (child_typedie, child_size,
187                                          locp, fpregs_used);
188                     if (used < 0 || used > 8)
189                       return used;
190                     if (used > max_used)
191                       max_used = used;
192                   }
193                 else
194                   {
195                     fpregs_used = hfa_type (child_typedie, child_size,
196                                             locp, fpregs_used);
197                     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
208     case DW_TAG_array_type:
209       if (size == 0)
210         break;
211
212       Dwarf_Die base_type_mem;
213       Dwarf_Die *base_typedie
214         = dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
215                                                    &attr_mem),
216                              &base_type_mem);
217       Dwarf_Word base_size;
218       if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
219         return -1;
220
221       int used = hfa_type (base_typedie, base_size, locp, 0);
222       if (used < 0 || used > 8)
223         return used;
224       if (size % (*locp)[1].number != 0)
225         return 0;
226       fpregs_used += used * (size / (*locp)[1].number);
227       break;
228
229     default:
230       return 9;
231     }
232
233   return fpregs_used;
234 }
235
236 int
237 ia64_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.  */
241   Dwarf_Die die_mem, *typedie = &die_mem;
242   int tag = dwarf_peeled_die_type (functypedie, typedie);
243   if (tag <= 0)
244     return tag;
245
246   Dwarf_Word size;
247   switch (tag)
248     {
249     case -1:
250       return -1;
251
252     case DW_TAG_subrange_type:
253       if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
254         {
255           Dwarf_Attribute attr_mem, *attr;
256           attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
257           typedie = dwarf_formref_die (attr, &die_mem);
258           tag = DWARF_TAG_OR_RETURN (typedie);
259         }
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:
266       {
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
278       if (tag == DW_TAG_base_type)
279         {
280           Dwarf_Attribute attr_mem;
281           Dwarf_Word encoding;
282           if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
283                                                      &attr_mem),
284                                &encoding) != 0)
285             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:
342       if (dwarf_aggregate_size (typedie, &size) != 0)
343         return -1;
344
345       /* If this qualifies as an homogeneous floating-point aggregate
346          (HFA), then it should be returned in FP regs. */
347       int nfpreg = hfa_type (typedie, size, locp, 0);
348       if (nfpreg < 0)
349         return nfpreg;
350       else if (nfpreg > 0 && nfpreg <= 8)
351         return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
352
353       if (size > 32)
354         goto large;
355
356       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 }