Home | History | Annotate | Download | only in backends
      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 }
    364