Home | History | Annotate | Download | only in backends
      1 /* Function return value location for SPARC.
      2    Copyright (C) 2006, 2007 Red Hat, Inc.
      3 
      4    This program is Open Source software; you can redistribute it and/or
      5    modify it under the terms of the Open Software License version 1.0 as
      6    published by the Open Source Initiative.
      7 
      8    You should have received a copy of the Open Software License along
      9    with this program; if not, you may obtain a copy of the Open Software
     10    License version 1.0 from http://www.opensource.org/licenses/osl.php or
     11    by writing the Open Source Initiative c/o Lawrence Rosen, Esq.,
     12    3001 King Ranch Road, Ukiah, CA 95482.   */
     13 
     14 #ifdef HAVE_CONFIG_H
     15 # include <config.h>
     16 #endif
     17 
     18 #include <assert.h>
     19 #include <dwarf.h>
     20 
     21 #define BACKEND sparc_
     22 #include "libebl_CPU.h"
     23 
     24 
     25 /* %o0, or pair %o0, %o1.  */
     26 static const Dwarf_Op loc_intreg[] =
     27   {
     28     { .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 4 },
     29     { .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 4 },
     30   };
     31 #define nloc_intreg	1
     32 #define nloc_intregpair	4
     33 
     34 /* %f0 or pair %f0, %f1, or quad %f0..%f3.  */
     35 static const Dwarf_Op loc_fpreg[] =
     36   {
     37     { .atom = DW_OP_regx, .number = 32 }, { .atom = DW_OP_piece, .number = 4 },
     38     { .atom = DW_OP_regx, .number = 33 }, { .atom = DW_OP_piece, .number = 4 },
     39     { .atom = DW_OP_regx, .number = 34 }, { .atom = DW_OP_piece, .number = 4 },
     40     { .atom = DW_OP_regx, .number = 35 }, { .atom = DW_OP_piece, .number = 4 },
     41   };
     42 #define nloc_fpreg	1
     43 #define nloc_fpregpair	4
     44 #define nloc_fpregquad	8
     45 
     46 /* The return value is a structure and is actually stored in stack space
     47    passed in a hidden argument by the caller.  But, the compiler
     48    helpfully returns the address of that space in %o0.  */
     49 static const Dwarf_Op loc_aggregate[] =
     50   {
     51     { .atom = DW_OP_breg8, .number = 0 }
     52   };
     53 #define nloc_aggregate 1
     54 
     55 int
     56 sparc_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
     57 {
     58   /* Start with the function's type, and get the DW_AT_type attribute,
     59      which is the type of the return value.  */
     60 
     61   Dwarf_Attribute attr_mem;
     62   Dwarf_Attribute *attr = dwarf_attr_integrate (functypedie, DW_AT_type,
     63 						&attr_mem);
     64   if (attr == NULL)
     65     /* The function has no return value, like a `void' function in C.  */
     66     return 0;
     67 
     68   Dwarf_Die die_mem;
     69   Dwarf_Die *typedie = dwarf_formref_die (attr, &die_mem);
     70   int tag = dwarf_tag (typedie);
     71 
     72   /* Follow typedefs and qualifiers to get to the actual type.  */
     73   while (tag == DW_TAG_typedef
     74 	 || tag == DW_TAG_const_type || tag == DW_TAG_volatile_type
     75 	 || tag == DW_TAG_restrict_type || tag == DW_TAG_mutable_type)
     76     {
     77       attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
     78       typedie = dwarf_formref_die (attr, &die_mem);
     79       tag = dwarf_tag (typedie);
     80     }
     81 
     82   Dwarf_Word size;
     83   switch (tag)
     84     {
     85     case -1:
     86       return -1;
     87 
     88     case DW_TAG_subrange_type:
     89       if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
     90 	{
     91 	  attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
     92 	  typedie = dwarf_formref_die (attr, &die_mem);
     93 	  tag = dwarf_tag (typedie);
     94 	}
     95       /* Fall through.  */
     96 
     97     case DW_TAG_base_type:
     98     case DW_TAG_enumeration_type:
     99     case DW_TAG_pointer_type:
    100     case DW_TAG_ptr_to_member_type:
    101       if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
    102 						 &attr_mem), &size) != 0)
    103 	{
    104 	  uint8_t asize;
    105 	  Dwarf_Die cudie;
    106 	  if ((tag == DW_TAG_pointer_type || tag == DW_TAG_ptr_to_member_type)
    107 	      && dwarf_diecu (typedie, &cudie, &asize, NULL) != NULL)
    108 	    size = asize;
    109 	  else
    110 	    return -1;
    111 	}
    112       if (tag == DW_TAG_base_type)
    113 	{
    114 	  Dwarf_Word encoding;
    115 	  if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
    116 						     &attr_mem),
    117 			       &encoding) != 0)
    118 	    return -1;
    119 	  if (encoding == DW_ATE_float)
    120 	    {
    121 	      *locp = loc_fpreg;
    122 	      if (size <= 4)
    123 		return nloc_fpreg;
    124 	      if (size <= 8)
    125 		return nloc_fpregpair;
    126 	      if (size <= 16)
    127 		return nloc_fpregquad;
    128 	    }
    129 	}
    130       if (size <= 8)
    131 	{
    132 	intreg:
    133 	  *locp = loc_intreg;
    134 	  return size <= 4 ? nloc_intreg : nloc_intregpair;
    135 	}
    136 
    137     aggregate:
    138       *locp = loc_aggregate;
    139       return nloc_aggregate;
    140 
    141     case DW_TAG_structure_type:
    142     case DW_TAG_class_type:
    143     case DW_TAG_union_type:
    144     case DW_TAG_array_type:
    145       if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
    146 						 &attr_mem), &size) == 0
    147 	  && size > 0 && size <= 8)
    148 	goto intreg;
    149       goto aggregate;
    150     }
    151 
    152   /* XXX We don't have a good way to return specific errors from ebl calls.
    153      This value means we do not understand the type, but it is well-formed
    154      DWARF and might be valid.  */
    155   return -2;
    156 }
    157