Home | History | Annotate | Download | only in backends
      1 /* Function return value location for IA64 ABI.
      2    Copyright (C) 2006, 2007 Red Hat, Inc.
      3    This file is part of Red Hat elfutils.
      4 
      5    Red Hat elfutils is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by the
      7    Free Software Foundation; version 2 of the License.
      8 
      9    Red Hat elfutils is distributed in the hope that it will be useful, but
     10    WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12    General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with Red Hat elfutils; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA.
     17 
     18    Red Hat elfutils is an included package of the Open Invention Network.
     19    An included package of the Open Invention Network is a package for which
     20    Open Invention Network licensees cross-license their patents.  No patent
     21    license is granted, either expressly or impliedly, by designation as an
     22    included package.  Should you wish to participate in the Open Invention
     23    Network licensing program, please visit www.openinventionnetwork.com
     24    <http://www.openinventionnetwork.com>.  */
     25 
     26 #ifdef HAVE_CONFIG_H
     27 # include <config.h>
     28 #endif
     29 
     30 #include <assert.h>
     31 #include <dwarf.h>
     32 
     33 #define BACKEND ia64_
     34 #include "libebl_CPU.h"
     35 
     36 
     37 /* r8, or pair r8, r9, or aggregate up to r8-r11.  */
     38 static const Dwarf_Op loc_intreg[] =
     39   {
     40     { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 },
     41     { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 },
     42     { .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 },
     43     { .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 },
     44   };
     45 #define nloc_intreg	1
     46 #define nloc_intregs(n)	(2 * (n))
     47 
     48 /* f8, or aggregate up to f8-f15.  */
     49 #define DEFINE_FPREG(size) 						      \
     50   static const Dwarf_Op loc_fpreg_##size[] =				      \
     51     {									      \
     52       { .atom = DW_OP_regx, .number = 128 + 8 },			      \
     53       { .atom = DW_OP_piece, .number = size },				      \
     54       { .atom = DW_OP_regx, .number = 128 + 9 },			      \
     55       { .atom = DW_OP_piece, .number = size },				      \
     56       { .atom = DW_OP_regx, .number = 128 + 10 },			      \
     57       { .atom = DW_OP_piece, .number = size },				      \
     58       { .atom = DW_OP_regx, .number = 128 + 11 },			      \
     59       { .atom = DW_OP_piece, .number = size },				      \
     60       { .atom = DW_OP_regx, .number = 128 + 12 },			      \
     61       { .atom = DW_OP_piece, .number = size },				      \
     62       { .atom = DW_OP_regx, .number = 128 + 13 },			      \
     63       { .atom = DW_OP_piece, .number = size },				      \
     64       { .atom = DW_OP_regx, .number = 128 + 14 },			      \
     65       { .atom = DW_OP_piece, .number = size },				      \
     66       { .atom = DW_OP_regx, .number = 128 + 15 },			      \
     67       { .atom = DW_OP_piece, .number = size },				      \
     68     }
     69 #define nloc_fpreg	1
     70 #define nloc_fpregs(n)	(2 * (n))
     71 
     72 DEFINE_FPREG (4);
     73 DEFINE_FPREG (8);
     74 DEFINE_FPREG (10);
     75 
     76 #undef DEFINE_FPREG
     77 
     78 
     79 /* The return value is a structure and is actually stored in stack space
     80    passed in a hidden argument by the caller.  But, the compiler
     81    helpfully returns the address of that space in r8.  */
     82 static const Dwarf_Op loc_aggregate[] =
     83   {
     84     { .atom = DW_OP_breg8, .number = 0 }
     85   };
     86 #define nloc_aggregate 1
     87 
     88 
     89 /* If this type is an HFA small enough to be returned in FP registers,
     90    return the number of registers to use.  Otherwise 9, or -1 for errors.  */
     91 static int
     92 hfa_type (Dwarf_Die *typedie, const Dwarf_Op **locp, int fpregs_used)
     93 {
     94   /* Descend the type structure, counting elements and finding their types.
     95      If we find a datum that's not an FP type (and not quad FP), punt.
     96      If we find a datum that's not the same FP type as the first datum, punt.
     97      If we count more than eight total homogeneous FP data, punt.  */
     98 
     99   inline int hfa (const Dwarf_Op *loc, int nregs)
    100     {
    101       if (fpregs_used == 0)
    102 	*locp = loc;
    103       else if (*locp != loc)
    104 	return 9;
    105       return fpregs_used + nregs;
    106     }
    107 
    108   int tag = dwarf_tag (typedie);
    109   switch (tag)
    110     {
    111       Dwarf_Attribute attr_mem;
    112 
    113     case -1:
    114       return -1;
    115 
    116     case DW_TAG_base_type:;
    117       int size = dwarf_bytesize (typedie);
    118       if (size < 0)
    119 	return -1;
    120 
    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 		if (tag == DW_TAG_union_type)
    182 		  {
    183 		    int used = hfa_type (child_typedie, locp, fpregs_used);
    184 		    if (used < 0 || used > 8)
    185 		      return used;
    186 		    if (used > max_used)
    187 		      max_used = used;
    188 		  }
    189 		else
    190 		  {
    191 		    fpregs_used = hfa_type (child_typedie, locp, fpregs_used);
    192 		    if (fpregs_used < 0 || fpregs_used > 8)
    193 		      return fpregs_used;
    194 		  }
    195 	      }
    196 	  while (dwarf_siblingof (&child_mem, &child_mem) == 0);
    197 	  if (tag == DW_TAG_union_type)
    198 	    fpregs_used = max_used;
    199 	  break;
    200 	}
    201       break;
    202 
    203     case DW_TAG_array_type:;
    204       size = dwarf_bytesize (typedie);
    205       if (size < 0)
    206 	return 9;
    207       if (size == 0)
    208 	break;
    209 
    210       Dwarf_Die base_type_mem;
    211       Dwarf_Die *base_typedie
    212 	= dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
    213 						   &attr_mem),
    214 			     &base_type_mem);
    215 
    216       int used = hfa_type (base_typedie, locp, 0);
    217       if (used < 0 || used > 8)
    218 	return used;
    219       if (size % (*locp)[1].number != 0)
    220 	return 0;
    221       size /= (*locp)[1].number;
    222       fpregs_used += used * size;
    223       break;
    224 
    225     default:
    226       return 9;
    227     }
    228 
    229   return fpregs_used;
    230 }
    231 
    232 int
    233 ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
    234 {
    235   /* Start with the function's type, and get the DW_AT_type attribute,
    236      which is the type of the return value.  */
    237 
    238   Dwarf_Attribute attr_mem;
    239   Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type,
    240 						&attr_mem);
    241   if (attr == NULL)
    242     /* The function has no return value, like a `void' function in C.  */
    243     return 0;
    244 
    245   Dwarf_Die die_mem;
    246   Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
    247   int tag = dwarf_tag (typedie);
    248 
    249   /* Follow typedefs and qualifiers to get to the actual type.  */
    250   while (tag == DW_TAG_typedef
    251 	 || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
    252 	 || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type)
    253     {
    254       attr = dwarf_attr (typedie, DW_AT_type, &attr_mem);
    255       typedie = dwarf_formref_die (attr, &die_mem);
    256       tag = dwarf_tag (typedie);
    257     }
    258 
    259   Dwarf_Word size;
    260   switch (tag)
    261     {
    262     case -1:
    263       return -1;
    264 
    265     case DW_TAG_subrange_type:
    266       if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
    267 	{
    268 	  attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
    269 	  typedie = dwarf_formref_die (attr, &die_mem);
    270 	  tag = dwarf_tag (typedie);
    271 	}
    272       /* Fall through.  */
    273 
    274     case DW_TAG_base_type:
    275     case DW_TAG_enumeration_type:
    276     case DW_TAG_pointer_type:
    277     case DW_TAG_ptr_to_member_type:
    278       if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
    279 						 &attr_mem), &size) != 0)
    280 	{
    281 	  if (tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
    282 	    size = 8;
    283 	  else
    284 	    return -1;
    285 	}
    286       if (tag == DW_TAG_base_type)
    287 	{
    288 	  Dwarf_Word encoding;
    289 	  if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
    290 						     &attr_mem),
    291 			       &encoding) != 0)
    292 	    return -1;
    293 
    294 	  switch (encoding)
    295 	    {
    296 	    case DW_ATE_float:
    297 	      switch (size)
    298 		{
    299 		case 4:		/* float */
    300 		  *locp = loc_fpreg_4;
    301 		  return nloc_fpreg;
    302 		case 8:		/* double */
    303 		  *locp = loc_fpreg_8;
    304 		  return nloc_fpreg;
    305 		case 10:       /* x86-style long double, not really used */
    306 		  *locp = loc_fpreg_10;
    307 		  return nloc_fpreg;
    308 		case 16:	/* long double, IEEE quad format */
    309 		  *locp = loc_intreg;
    310 		  return nloc_intregs (2);
    311 		}
    312 	      return -2;
    313 
    314 	    case DW_ATE_complex_float:
    315 	      switch (size)
    316 		{
    317 		case 4 * 2:	/* complex float */
    318 		  *locp = loc_fpreg_4;
    319 		  return nloc_fpregs (2);
    320 		case 8 * 2:	/* complex double */
    321 		  *locp = loc_fpreg_8;
    322 		  return nloc_fpregs (2);
    323 		case 10 * 2:	/* complex long double (x86-style) */
    324 		  *locp = loc_fpreg_10;
    325 		  return nloc_fpregs (2);
    326 		case 16 * 2:	/* complex long double (IEEE quad) */
    327 		  *locp = loc_intreg;
    328 		  return nloc_intregs (4);
    329 		}
    330 	      return -2;
    331 	    }
    332 	}
    333 
    334     intreg:
    335       *locp = loc_intreg;
    336       if (size <= 8)
    337 	return nloc_intreg;
    338       if (size <= 32)
    339 	return nloc_intregs ((size + 7) / 8);
    340 
    341     large:
    342       *locp = loc_aggregate;
    343       return nloc_aggregate;
    344 
    345     case DW_TAG_structure_type:
    346     case DW_TAG_class_type:
    347     case DW_TAG_union_type:
    348     case DW_TAG_array_type:
    349       if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
    350 						 &attr_mem), &size) != 0)
    351 	return -1;
    352 
    353       /* If this qualifies as an homogeneous floating-point aggregate
    354 	 (HFA), then it should be returned in FP regs. */
    355       int nfpreg = hfa_type (typedie, locp, 0);
    356       if (nfpreg < 0)
    357 	return nfpreg;
    358       else if (nfpreg > 0 && nfpreg <= 8)
    359 	return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
    360 
    361       if (size > 32)
    362 	goto large;
    363 
    364       goto intreg;
    365     }
    366 
    367   /* XXX We don't have a good way to return specific errors from ebl calls.
    368      This value means we do not understand the type, but it is well-formed
    369      DWARF and might be valid.  */
    370   return -2;
    371 }
    372