aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2011-05-31 21:15:13 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2011-05-31 21:15:13 +0200
commitead7c399bc1b0c62bacaf845628ab72024838085 (patch)
treeb2319ac7f65366524c7b8737d47793fce8a175cb
parent509f4495ee4dedc2a27f9f8f749a0507ef3f1938 (diff)
downloadgcc-ead7c399bc1b0c62bacaf845628ab72024838085.zip
gcc-ead7c399bc1b0c62bacaf845628ab72024838085.tar.gz
gcc-ead7c399bc1b0c62bacaf845628ab72024838085.tar.bz2
dwarf2out.c (resolve_addr_in_expr): Optimize away redundant DW_OP_GNU_convert ops.
* dwarf2out.c (resolve_addr_in_expr): Optimize away redundant DW_OP_GNU_convert ops. From-SVN: r174509
-rw-r--r--gcc/ChangeLog3
-rw-r--r--gcc/dwarf2out.c89
2 files changed, 78 insertions, 14 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ed0fb81..8d6dc36a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,8 @@
2011-05-31 Jakub Jelinek <jakub@redhat.com>
+ * dwarf2out.c (resolve_addr_in_expr): Optimize away redundant
+ DW_OP_GNU_convert ops.
+
* cselib.c (promote_debug_loc): Allow l->next non-NULL for
cselib_preserve_constants.
(cselib_lookup_1): If cselib_preserve_constants,
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 58a622c..464de16 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -24100,23 +24100,84 @@ resolve_one_addr (rtx *addr, void *data ATTRIBUTE_UNUSED)
static bool
resolve_addr_in_expr (dw_loc_descr_ref loc)
{
+ dw_loc_descr_ref keep = NULL;
for (; loc; loc = loc->dw_loc_next)
- if (((loc->dw_loc_opc == DW_OP_addr || loc->dtprel)
- && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
- || (loc->dw_loc_opc == DW_OP_implicit_value
- && loc->dw_loc_oprnd2.val_class == dw_val_class_addr
- && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL)))
- return false;
- else if (loc->dw_loc_opc == DW_OP_GNU_implicit_pointer
- && loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
+ switch (loc->dw_loc_opc)
{
- dw_die_ref ref
- = lookup_decl_die (loc->dw_loc_oprnd1.v.val_decl_ref);
- if (ref == NULL)
+ case DW_OP_addr:
+ if (resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
+ return false;
+ break;
+ case DW_OP_const4u:
+ case DW_OP_const8u:
+ if (loc->dtprel
+ && resolve_one_addr (&loc->dw_loc_oprnd1.v.val_addr, NULL))
+ return false;
+ break;
+ case DW_OP_implicit_value:
+ if (loc->dw_loc_oprnd2.val_class == dw_val_class_addr
+ && resolve_one_addr (&loc->dw_loc_oprnd2.v.val_addr, NULL))
return false;
- loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
- loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
- loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
+ break;
+ case DW_OP_GNU_implicit_pointer:
+ if (loc->dw_loc_oprnd1.val_class == dw_val_class_decl_ref)
+ {
+ dw_die_ref ref
+ = lookup_decl_die (loc->dw_loc_oprnd1.v.val_decl_ref);
+ if (ref == NULL)
+ return false;
+ loc->dw_loc_oprnd1.val_class = dw_val_class_die_ref;
+ loc->dw_loc_oprnd1.v.val_die_ref.die = ref;
+ loc->dw_loc_oprnd1.v.val_die_ref.external = 0;
+ }
+ break;
+ case DW_OP_GNU_const_type:
+ case DW_OP_GNU_regval_type:
+ case DW_OP_GNU_deref_type:
+ case DW_OP_GNU_convert:
+ case DW_OP_GNU_reinterpret:
+ while (loc->dw_loc_next
+ && loc->dw_loc_next->dw_loc_opc == DW_OP_GNU_convert)
+ {
+ dw_die_ref base1, base2;
+ unsigned enc1, enc2, size1, size2;
+ if (loc->dw_loc_opc == DW_OP_GNU_regval_type
+ || loc->dw_loc_opc == DW_OP_GNU_deref_type)
+ base1 = loc->dw_loc_oprnd2.v.val_die_ref.die;
+ else
+ base1 = loc->dw_loc_oprnd1.v.val_die_ref.die;
+ base2 = loc->dw_loc_next->dw_loc_oprnd1.v.val_die_ref.die;
+ gcc_assert (base1->die_tag == DW_TAG_base_type
+ && base2->die_tag == DW_TAG_base_type);
+ enc1 = get_AT_unsigned (base1, DW_AT_encoding);
+ enc2 = get_AT_unsigned (base2, DW_AT_encoding);
+ size1 = get_AT_unsigned (base1, DW_AT_byte_size);
+ size2 = get_AT_unsigned (base2, DW_AT_byte_size);
+ if (size1 == size2
+ && (((enc1 == DW_ATE_unsigned || enc1 == DW_ATE_signed)
+ && (enc2 == DW_ATE_unsigned || enc2 == DW_ATE_signed)
+ && loc != keep)
+ || enc1 == enc2))
+ {
+ /* Optimize away next DW_OP_GNU_convert after
+ adjusting LOC's base type die reference. */
+ if (loc->dw_loc_opc == DW_OP_GNU_regval_type
+ || loc->dw_loc_opc == DW_OP_GNU_deref_type)
+ loc->dw_loc_oprnd2.v.val_die_ref.die = base2;
+ else
+ loc->dw_loc_oprnd1.v.val_die_ref.die = base2;
+ loc->dw_loc_next = loc->dw_loc_next->dw_loc_next;
+ continue;
+ }
+ /* Don't change integer DW_OP_GNU_convert after e.g. floating
+ point typed stack entry. */
+ else if (enc1 != DW_ATE_unsigned && enc1 != DW_ATE_signed)
+ keep = loc;
+ break;
+ }
+ break;
+ default:
+ break;
}
return true;
}