Imported Upstream version 0.155
[platform/upstream/elfutils.git] / backends / ia64_retval.c
1 /* Function return value location for IA64 ABI.
2    Copyright (C) 2006-2010 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 (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
242   Dwarf_Attribute attr_mem;
243   Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type,
244                                                 &attr_mem);
245   if (attr == NULL)
246     /* The function has no return value, like a `void' function in C.  */
247     return 0;
248
249   Dwarf_Die die_mem;
250   Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
251   int tag = dwarf_tag (typedie);
252
253   /* Follow typedefs and qualifiers to get to the actual type.  */
254   while (tag == DW_TAG_typedef
255          || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
256          || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type)
257     {
258       attr = dwarf_attr (typedie, DW_AT_type, &attr_mem);
259       typedie = dwarf_formref_die (attr, &die_mem);
260       tag = dwarf_tag (typedie);
261     }
262
263   Dwarf_Word size;
264   switch (tag)
265     {
266     case -1:
267       return -1;
268
269     case DW_TAG_subrange_type:
270       if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
271         {
272           attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
273           typedie = dwarf_formref_die (attr, &die_mem);
274           tag = dwarf_tag (typedie);
275         }
276       /* Fall through.  */
277
278     case DW_TAG_base_type:
279     case DW_TAG_enumeration_type:
280     case DW_TAG_pointer_type:
281     case DW_TAG_ptr_to_member_type:
282       if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
283                                                  &attr_mem), &size) != 0)
284         {
285           if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
286             size = 8;
287           else
288             return -1;
289         }
290       if (tag == DW_TAG_base_type)
291         {
292           Dwarf_Word encoding;
293           if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
294                                                      &attr_mem),
295                                &encoding) != 0)
296             return -1;
297
298           switch (encoding)
299             {
300             case DW_ATE_float:
301               switch (size)
302                 {
303                 case 4:         /* float */
304                   *locp = loc_fpreg_4;
305                   return nloc_fpreg;
306                 case 8:         /* double */
307                   *locp = loc_fpreg_8;
308                   return nloc_fpreg;
309                 case 10:       /* x86-style long double, not really used */
310                   *locp = loc_fpreg_10;
311                   return nloc_fpreg;
312                 case 16:        /* long double, IEEE quad format */
313                   *locp = loc_intreg;
314                   return nloc_intregs (2);
315                 }
316               return -2;
317
318             case DW_ATE_complex_float:
319               switch (size)
320                 {
321                 case 4 * 2:     /* complex float */
322                   *locp = loc_fpreg_4;
323                   return nloc_fpregs (2);
324                 case 8 * 2:     /* complex double */
325                   *locp = loc_fpreg_8;
326                   return nloc_fpregs (2);
327                 case 10 * 2:    /* complex long double (x86-style) */
328                   *locp = loc_fpreg_10;
329                   return nloc_fpregs (2);
330                 case 16 * 2:    /* complex long double (IEEE quad) */
331                   *locp = loc_intreg;
332                   return nloc_intregs (4);
333                 }
334               return -2;
335             }
336         }
337
338     intreg:
339       *locp = loc_intreg;
340       if (size <= 8)
341         return nloc_intreg;
342       if (size <= 32)
343         return nloc_intregs ((size + 7) / 8);
344
345     large:
346       *locp = loc_aggregate;
347       return nloc_aggregate;
348
349     case DW_TAG_structure_type:
350     case DW_TAG_class_type:
351     case DW_TAG_union_type:
352     case DW_TAG_array_type:
353       if (dwarf_aggregate_size (typedie, &size) != 0)
354         return -1;
355
356       /* If this qualifies as an homogeneous floating-point aggregate
357          (HFA), then it should be returned in FP regs. */
358       int nfpreg = hfa_type (typedie, size, locp, 0);
359       if (nfpreg < 0)
360         return nfpreg;
361       else if (nfpreg > 0 && nfpreg <= 8)
362         return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
363
364       if (size > 32)
365         goto large;
366
367       goto intreg;
368     }
369
370   /* XXX We don't have a good way to return specific errors from ebl calls.
371      This value means we do not understand the type, but it is well-formed
372      DWARF and might be valid.  */
373   return -2;
374 }