diff options
author | Roland McGrath <roland@redhat.com> | 2006-07-21 11:26:51 +0000 |
---|---|---|
committer | Roland McGrath <roland@redhat.com> | 2006-07-21 11:26:51 +0000 |
commit | 22d02c2021e91f9b03cf5f897a64ae34477da0f4 (patch) | |
tree | 054bbccac5124eade2e13a4d7db0c798552304a0 | |
parent | 950246297c03f9ce25f645470250619e40d71018 (diff) | |
download | elfutils-22d02c2021e91f9b03cf5f897a64ae34477da0f4.tar.gz |
Take a crack at HFA recognition too.
-rw-r--r-- | backends/ia64_retval.c | 157 |
1 files changed, 151 insertions, 6 deletions
diff --git a/backends/ia64_retval.c b/backends/ia64_retval.c index b66fe5c2..4100328c 100644 --- a/backends/ia64_retval.c +++ b/backends/ia64_retval.c @@ -86,6 +86,148 @@ static const Dwarf_Op loc_aggregate[] = #define nloc_aggregate 1 +/* If this type is an HFA small enough to be returned in FP registers, + return the number of registers to use. Otherwise 9, or -1 for errors. */ +static int +hfa_type (Dwarf_Die *typedie, const Dwarf_Op **locp, int fpregs_used) +{ + /* Descend the type structure, counting elements and finding their types. + If we find a datum that's not an FP type (and not quad FP), punt. + If we find a datum that's not the same FP type as the first datum, punt. + If we count more than eight total homogeneous FP data, punt. */ + + inline int hfa (const Dwarf_Op *loc, int nregs) + { + if (fpregs_used == 0) + *locp = loc; + else if (*locp != loc) + return 9; + return fpregs_used + nregs; + } + + int tag = dwarf_tag (typedie); + switch (tag) + { + Dwarf_Attribute attr_mem; + + case -1: + return -1; + + case DW_TAG_base_type:; + int size = dwarf_bytesize (typedie); + if (size < 0) + return -1; + + Dwarf_Word encoding; + if (dwarf_formudata (dwarf_attr (typedie, DW_AT_encoding, + &attr_mem), &encoding) != 0) + return -1; + + switch (encoding) + { + case DW_ATE_float: + switch (size) + { + case 4: /* float */ + return hfa (loc_fpreg_4, 1); + case 8: /* double */ + return hfa (loc_fpreg_8, 1); + case 10: /* x86-style long double, not really used */ + return hfa (loc_fpreg_10, 1); + } + break; + + case DW_ATE_complex_float: + switch (size) + { + case 4 * 2: /* complex float */ + return hfa (loc_fpreg_4, 2); + case 8 * 2: /* complex double */ + return hfa (loc_fpreg_8, 2); + case 10 * 2: /* complex long double (x86-style) */ + 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: /* No children: empty struct. */ + break; + + case 0:; /* Look at each element. */ + 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 (&child_mem, DW_AT_type, + &attr_mem), + &child_type_mem); + if (tag == DW_TAG_union_type) + { + int used = hfa_type (child_typedie, locp, fpregs_used); + if (used < 0 || used > 8) + return used; + if (used > max_used) + max_used = used; + } + else + { + fpregs_used = hfa_type (child_typedie, 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:; + size = dwarf_bytesize (typedie); + if (size < 0) + return 9; + if (size == 0) + break; + + Dwarf_Die base_type_mem; + Dwarf_Die *base_typedie = dwarf_formref_die (dwarf_attr (typedie, + DW_AT_type, + &attr_mem), + &base_type_mem); + + int used = hfa_type (base_typedie, locp, 0); + if (used < 0 || used > 8) + return used; + if (size % (*locp)[1].number != 0) + return 0; + size /= (*locp)[1].number; + fpregs_used += used * size; + break; + + default: + return 9; + } + + return fpregs_used; +} + int ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) { @@ -204,15 +346,18 @@ ia64_return_value_location (Dwarf_Die *functypedie, const Dwarf_Op **locp) if (dwarf_formudata (dwarf_attr (typedie, DW_AT_byte_size, &attr_mem), &size) != 0) return -1; + + /* If this qualifies as an homogeneous floating-point aggregate + (HFA), then it should be returned in FP regs. */ + int nfpreg = hfa_type (typedie, 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; - /* XXX - Must examine the fields in picayune ways to determine the - actual answer. If it qualifies as an HFA (all floats) - then it should be returned in fp regs. - */ - goto intreg; } |