• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
compute_hfa(const Dwarf_Op * loc,int nregs,const Dwarf_Op ** locp,int fpregs_used)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
hfa_type(Dwarf_Die * typedie,Dwarf_Word size,const Dwarf_Op ** locp,int fpregs_used)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
ia64_return_value_location(Dwarf_Die * functypedie,const Dwarf_Op ** locp)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       FALLTHROUGH;
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 }
367