dwarf2out.c (resolve_addr_in_expr): Optimize away redundant DW_OP_GNU_convert ops.
authorJakub Jelinek <jakub@redhat.com>
Tue, 31 May 2011 19:15:13 +0000 (21:15 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Tue, 31 May 2011 19:15:13 +0000 (21:15 +0200)
* dwarf2out.c (resolve_addr_in_expr): Optimize away redundant
DW_OP_GNU_convert ops.

From-SVN: r174509

gcc/ChangeLog
gcc/dwarf2out.c

index ed0fb816550fcc8d972fa8f402bd867b386f0e15..8d6dc36ab657354e5e7927dac8aeebfebe29f3ae 100644 (file)
@@ -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,
index 58a622cca1e00504ec3a4c9e2807680023d66c31..464de166f37ec9e15f52851961b65c4d43985e13 100644 (file)
@@ -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;
 }