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.  */
41static 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
75DEFINE_FPREG (4);
76DEFINE_FPREG (8);
77DEFINE_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.  */
85static const Dwarf_Op loc_aggregate[] =
86  {
87    { .atom = DW_OP_breg8, .number = 0 }
88  };
89#define nloc_aggregate 1
90
91
92static inline int
93compute_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.  */
105static int
106hfa_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
239int
240ia64_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}
367