#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <assert.h>
#include <dwarf.h>
#define BACKEND ia64_
#include "libebl_CPU.h"
static const Dwarf_Op loc_intreg[] =
{
{ .atom = DW_OP_reg8 }, { .atom = DW_OP_piece, .number = 8 },
{ .atom = DW_OP_reg9 }, { .atom = DW_OP_piece, .number = 8 },
{ .atom = DW_OP_reg10 }, { .atom = DW_OP_piece, .number = 8 },
{ .atom = DW_OP_reg11 }, { .atom = DW_OP_piece, .number = 8 },
};
#define nloc_intreg 1
#define nloc_intregs(n) (2 * (n))
#define DEFINE_FPREG(size) \
static const Dwarf_Op loc_fpreg_##size[] = \
{ \
{ .atom = DW_OP_regx, .number = 128 + 8 }, \
{ .atom = DW_OP_piece, .number = size }, \
{ .atom = DW_OP_regx, .number = 128 + 9 }, \
{ .atom = DW_OP_piece, .number = size }, \
{ .atom = DW_OP_regx, .number = 128 + 10 }, \
{ .atom = DW_OP_piece, .number = size }, \
{ .atom = DW_OP_regx, .number = 128 + 11 }, \
{ .atom = DW_OP_piece, .number = size }, \
{ .atom = DW_OP_regx, .number = 128 + 12 }, \
{ .atom = DW_OP_piece, .number = size }, \
{ .atom = DW_OP_regx, .number = 128 + 13 }, \
{ .atom = DW_OP_piece, .number = size }, \
{ .atom = DW_OP_regx, .number = 128 + 14 }, \
{ .atom = DW_OP_piece, .number = size }, \
{ .atom = DW_OP_regx, .number = 128 + 15 }, \
{ .atom = DW_OP_piece, .number = size }, \
}
#define nloc_fpreg 1
#define nloc_fpregs(n) (2 * (n))
DEFINE_FPREG (4);
DEFINE_FPREG (8);
DEFINE_FPREG (10);
#undef DEFINE_FPREG
static const Dwarf_Op loc_aggregate[] =
{
{ .atom = DW_OP_breg8, .number = 0 }
};
#define nloc_aggregate 1
static inline int
compute_hfa (const Dwarf_Op *loc, int nregs,
const Dwarf_Op **locp, int fpregs_used)
{
if (fpregs_used == 0)
*locp = loc;
else if (*locp != loc)
return 9;
return fpregs_used + nregs;
}
static int
hfa_type (Dwarf_Die *typedie, Dwarf_Word size,
const Dwarf_Op **locp, int fpregs_used)
{
int tag = DWARF_TAG_OR_RETURN (typedie);
switch (tag)
{
Dwarf_Attribute attr_mem;
case -1:
return -1;
case DW_TAG_base_type:;
Dwarf_Word encoding;
if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
&attr_mem), &encoding) != 0)
return -1;
#define hfa(loc, nregs) compute_hfa(loc, nregs, locp, fpregs_used)
switch (encoding)
{
case DW_ATE_float:
switch (size)
{
case 4:
return hfa (loc_fpreg_4, 1);
case 8:
return hfa (loc_fpreg_8, 1);
case 10:
return hfa (loc_fpreg_10, 1);
}
break;
case DW_ATE_complex_float:
switch (size)
{
case 4 * 2:
return hfa (loc_fpreg_4, 2);
case 8 * 2:
return hfa (loc_fpreg_8, 2);
case 10 * 2:
return hfa (loc_fpreg_10, 2);
}
break;
}
break;
case DW_TAG_structure_type:
case DW_TAG_class_type:
case DW_TAG_union_type:;
Dwarf_Die child_mem;
switch (dwarf_child (typedie, &child_mem))
{
default:
return -1;
case 1:
break;
case 0:;
int max_used = fpregs_used;
do
switch (dwarf_tag (&child_mem))
{
case -1:
return -1;
case DW_TAG_member:;
Dwarf_Die child_type_mem;
Dwarf_Die *child_typedie
= dwarf_formref_die (dwarf_attr_integrate (&child_mem,
DW_AT_type,
&attr_mem),
&child_type_mem);
Dwarf_Word child_size;
if (dwarf_aggregate_size (child_typedie, &child_size) != 0)
return -1;
if (tag == DW_TAG_union_type)
{
int used = hfa_type (child_typedie, child_size,
locp, fpregs_used);
if (used < 0 || used > 8)
return used;
if (used > max_used)
max_used = used;
}
else
{
fpregs_used = hfa_type (child_typedie, child_size,
locp, fpregs_used);
if (fpregs_used < 0 || fpregs_used > 8)
return fpregs_used;
}
}
while (dwarf_siblingof (&child_mem, &child_mem) == 0);
if (tag == DW_TAG_union_type)
fpregs_used = max_used;
break;
}
break;
case DW_TAG_array_type:
if (size == 0)
break;
Dwarf_Die base_type_mem;
Dwarf_Die *base_typedie
= dwarf_formref_die (dwarf_attr_integrate (typedie, DW_AT_type,
&attr_mem),
&base_type_mem);
Dwarf_Word base_size;
if (dwarf_aggregate_size (base_typedie, &base_size) != 0)
return -1;
int used = hfa_type (base_typedie, base_size, locp, 0);
if (used < 0 || used > 8)
return used;
if (size % (*locp)[1].number != 0)
return 0;
fpregs_used += used * (size / (*locp)[1].number);
break;
default:
return 9;
}
return fpregs_used;
}
int
ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp)
{
Dwarf_Die die_mem, *typedie = &die_mem;
int tag = dwarf_peeled_die_type (functypedie, typedie);
if (tag <= 0)
return tag;
Dwarf_Word size;
switch (tag)
{
case -1:
return -1;
case DW_TAG_subrange_type:
if (! dwarf_hasattr_integrate (typedie, DW_AT_byte_size))
{
Dwarf_Attribute attr_mem, *attr;
attr = dwarf_attr_integrate (typedie, DW_AT_type, &attr_mem);
typedie = dwarf_formref_die (attr, &die_mem);
tag = DWARF_TAG_OR_RETURN (typedie);
}
FALLTHROUGH;
case DW_TAG_base_type:
case DW_TAG_enumeration_type:
CASE_POINTER:
{
Dwarf_Attribute attr_mem;
if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_byte_size,
&attr_mem), &size) != 0)
{
if (dwarf_is_pointer (tag))
size = 8;
else
return -1;
}
}
if (tag == DW_TAG_base_type)
{
Dwarf_Attribute attr_mem;
Dwarf_Word encoding;
if (dwarf_formudata (dwarf_attr_integrate (typedie, DW_AT_encoding,
&attr_mem),
&encoding) != 0)
return -1;
switch (encoding)
{
case DW_ATE_float:
switch (size)
{
case 4:
*locp = loc_fpreg_4;
return nloc_fpreg;
case 8:
*locp = loc_fpreg_8;
return nloc_fpreg;
case 10:
*locp = loc_fpreg_10;
return nloc_fpreg;
case 16:
*locp = loc_intreg;
return nloc_intregs (2);
}
return -2;
case DW_ATE_complex_float:
switch (size)
{
case 4 * 2:
*locp = loc_fpreg_4;
return nloc_fpregs (2);
case 8 * 2:
*locp = loc_fpreg_8;
return nloc_fpregs (2);
case 10 * 2:
*locp = loc_fpreg_10;
return nloc_fpregs (2);
case 16 * 2:
*locp = loc_intreg;
return nloc_intregs (4);
}
return -2;
}
}
intreg:
*locp = loc_intreg;
if (size <= 8)
return nloc_intreg;
if (size <= 32)
return nloc_intregs ((size + 7) / 8);
large:
*locp = loc_aggregate;
return nloc_aggregate;
case DW_TAG_structure_type:
case DW_TAG_class_type:
case DW_TAG_union_type:
case DW_TAG_array_type:
if (dwarf_aggregate_size (typedie, &size) != 0)
return -1;
int nfpreg = hfa_type (typedie, size, locp, 0);
if (nfpreg < 0)
return nfpreg;
else if (nfpreg > 0 && nfpreg <= 8)
return nfpreg == 1 ? nloc_fpreg : nloc_fpregs (nfpreg);
if (size > 32)
goto large;
goto intreg;
}
return -2;
}