aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorJan Hubicka <hubicka@ucw.cz>2014-08-21 15:49:07 +0200
committerJan Hubicka <hubicka@gcc.gnu.org>2014-08-21 13:49:07 +0000
commita336b719a34c07effb7e1ba9e72f8c270ea362ee (patch)
tree28584c8124114195615453c501e911bdccec1199 /gcc
parent2903befbec9fb56ce7883952bf040daa80041ae8 (diff)
downloadgcc-a336b719a34c07effb7e1ba9e72f8c270ea362ee.zip
gcc-a336b719a34c07effb7e1ba9e72f8c270ea362ee.tar.gz
gcc-a336b719a34c07effb7e1ba9e72f8c270ea362ee.tar.bz2
re PR tree-optimization/62091 (ice in before_dom_children)
PR tree-optimization/62091 * g++.dg/ipa/devirt-37.C: Update template. * g++.dg/ipa/devirt-40.C: New testcase. * ipa-devirt.c (ipa_polymorphic_call_context::restrict_to_inner_type): handle correctly arrays. (extr_type_from_vtbl_ptr_store): Add debug output; handle multiple inheritance binfos. (record_known_type): Walk into inner type. (ipa_polymorphic_call_context::get_dynamic_type): Likewise; strenghten condition on no type changes. From-SVN: r214271
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog11
-rw-r--r--gcc/ipa-devirt.c164
-rw-r--r--gcc/lto/lto.c5
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-37.C2
-rw-r--r--gcc/testsuite/g++.dg/ipa/devirt-40.C23
6 files changed, 175 insertions, 36 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index b7b4f10..6a366d3 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,14 @@
+2014-08-21 Jan Hubicka <hubicka@ucw.cz>
+
+ PR tree-optimization/62091
+ * ipa-devirt.c (ipa_polymorphic_call_context::restrict_to_inner_type):
+ handle correctly arrays.
+ (extr_type_from_vtbl_ptr_store): Add debug output; handle multiple
+ inheritance binfos.
+ (record_known_type): Walk into inner type.
+ (ipa_polymorphic_call_context::get_dynamic_type): Likewise; strenghten
+ condition on no type changes.
+
2014-08-21 David Malcolm <dmalcolm@redhat.com>
* genattrtab.c (write_attr_get): Within the generated get_attr_
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index ba57b86..2e74ca6 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -2015,8 +2015,10 @@ ipa_polymorphic_call_context::restrict_to_inner_class (tree expected_type)
tree subtype = TYPE_MAIN_VARIANT (TREE_TYPE (type));
/* Give up if we don't know array size. */
- if (!tree_fits_shwi_p (TYPE_SIZE (subtype))
- || !tree_to_shwi (TYPE_SIZE (subtype)) <= 0)
+ if (!TYPE_SIZE (subtype)
+ || !tree_fits_shwi_p (TYPE_SIZE (subtype))
+ || tree_to_shwi (TYPE_SIZE (subtype)) <= 0
+ || !contains_polymorphic_type_p (subtype))
goto give_up;
cur_offset = cur_offset % tree_to_shwi (TYPE_SIZE (subtype));
type = subtype;
@@ -2630,7 +2632,7 @@ extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci,
HOST_WIDE_INT *type_offset)
{
HOST_WIDE_INT offset, size, max_size;
- tree lhs, rhs, base, binfo;
+ tree lhs, rhs, base;
if (!gimple_assign_single_p (stmt))
return NULL_TREE;
@@ -2639,7 +2641,11 @@ extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci,
rhs = gimple_assign_rhs1 (stmt);
if (TREE_CODE (lhs) != COMPONENT_REF
|| !DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
- return NULL_TREE;
+ {
+ if (dump_file)
+ fprintf (dump_file, " LHS is not virtual table.\n");
+ return NULL_TREE;
+ }
if (tci->vtbl_ptr_ref && operand_equal_p (lhs, tci->vtbl_ptr_ref, 0))
;
@@ -2649,33 +2655,80 @@ extr_type_from_vtbl_ptr_store (gimple stmt, struct type_change_info *tci,
if (offset != tci->offset
|| size != POINTER_SIZE
|| max_size != POINTER_SIZE)
- return NULL_TREE;
+ {
+ if (dump_file)
+ fprintf (dump_file, " wrong offset %i!=%i or size %i\n",
+ (int)offset, (int)tci->offset, (int)size);
+ return NULL_TREE;
+ }
if (DECL_P (tci->instance))
{
if (base != tci->instance)
- return NULL_TREE;
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, " base:");
+ print_generic_expr (dump_file, base, TDF_SLIM);
+ fprintf (dump_file, " does not match instance:");
+ print_generic_expr (dump_file, tci->instance, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
}
else if (TREE_CODE (base) == MEM_REF)
{
if (!operand_equal_p (tci->instance, TREE_OPERAND (base, 0), 0)
|| !integer_zerop (TREE_OPERAND (base, 1)))
- return NULL_TREE;
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, " base mem ref:");
+ print_generic_expr (dump_file, base, TDF_SLIM);
+ fprintf (dump_file, " has nonzero offset or does not match instance:");
+ print_generic_expr (dump_file, tci->instance, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+ return NULL_TREE;
+ }
}
else if (!operand_equal_p (tci->instance, base, 0)
|| tci->offset)
- return NULL_TREE;
+ {
+ if (dump_file)
+ {
+ fprintf (dump_file, " base:");
+ print_generic_expr (dump_file, base, TDF_SLIM);
+ fprintf (dump_file, " does not match instance:");
+ print_generic_expr (dump_file, tci->instance, TDF_SLIM);
+ fprintf (dump_file, " with offset %i\n", (int)tci->offset);
+ }
+ return NULL_TREE;
+ }
}
- binfo = vtable_pointer_value_to_binfo (rhs);
+ tree vtable;
+ unsigned HOST_WIDE_INT offset2;
+ if (!vtable_pointer_value_to_vtable (rhs, &vtable, &offset2))
+ {
+ if (dump_file)
+ fprintf (dump_file, " Failed to lookup binfo\n");
+ return NULL;
+ }
+
+ tree binfo = subbinfo_with_vtable_at_offset (TYPE_BINFO (DECL_CONTEXT (vtable)),
+ offset2, vtable);
if (!binfo)
- return NULL;
+ {
+ if (dump_file)
+ fprintf (dump_file, " Construction vtable used\n");
+ /* FIXME: We should suport construction contextes. */
+ return NULL;
+ }
+
*type_offset = tree_to_shwi (BINFO_OFFSET (binfo)) * BITS_PER_UNIT;
- if (TYPE_BINFO (BINFO_TYPE (binfo)) == binfo)
- return BINFO_TYPE (binfo);
-
- /* TODO: Figure out the type containing BINFO. */
- return NULL;
+ return DECL_CONTEXT (vtable);
}
/* Record dynamic type change of TCI to TYPE. */
@@ -2694,11 +2747,43 @@ record_known_type (struct type_change_info *tci, tree type, HOST_WIDE_INT offset
else
fprintf (dump_file, " Recording unknown type\n");
}
+
+ /* If we found a constructor of type that is not polymorphic or
+ that may contain the type in question as a field (not as base),
+ restrict to the inner class first to make type matching bellow
+ happier. */
+ if (type
+ && (offset
+ || (TREE_CODE (type) != RECORD_TYPE
+ || !polymorphic_type_binfo_p (TYPE_BINFO (type)))))
+ {
+ ipa_polymorphic_call_context context;
+
+ context.offset = offset;
+ context.outer_type = type;
+ context.maybe_in_construction = false;
+ context.maybe_derived_type = false;
+ /* If we failed to find the inner type, we know that the call
+ would be undefined for type produced here. */
+ if (!context.restrict_to_inner_class (tci->otr_type))
+ {
+ if (dump_file)
+ fprintf (dump_file, " Ignoring; does not contain otr_type\n");
+ return;
+ }
+ /* Watch for case we reached an POD type and anticipate placement
+ new. */
+ if (!context.maybe_derived_type)
+ {
+ type = context.outer_type;
+ offset = context.offset;
+ }
+ }
if (tci->type_maybe_changed
- && (type != tci->known_current_type
+ && (!types_same_for_odr (type, tci->known_current_type)
|| offset != tci->known_current_offset))
tci->multiple_types_encountered = true;
- tci->known_current_type = type;
+ tci->known_current_type = TYPE_MAIN_VARIANT (type);
tci->known_current_offset = offset;
tci->type_maybe_changed = true;
}
@@ -2846,6 +2931,20 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
bool function_entry_reached = false;
tree instance_ref = NULL;
gimple stmt = call;
+ /* Remember OFFSET before it is modified by restrict_to_inner_class.
+ This is because we do not update INSTANCE when walking inwards. */
+ HOST_WIDE_INT instance_offset = offset;
+
+ otr_type = TYPE_MAIN_VARIANT (otr_type);
+
+ /* Walk into inner type. This may clear maybe_derived_type and save us
+ from useless work. It also makes later comparsions with static type
+ easier. */
+ if (outer_type)
+ {
+ if (!restrict_to_inner_class (otr_type))
+ return false;
+ }
if (!maybe_in_construction && !maybe_derived_type)
return false;
@@ -2900,11 +2999,11 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
or from INSTANCE with offset OFFSET. */
if (base_ref
&& ((TREE_CODE (base_ref) == MEM_REF
- && ((offset2 == offset
+ && ((offset2 == instance_offset
&& TREE_OPERAND (base_ref, 0) == instance)
|| (!offset2 && TREE_OPERAND (base_ref, 0) == otr_object)))
|| (DECL_P (instance) && base_ref == instance
- && offset2 == offset)))
+ && offset2 == instance_offset)))
{
stmt = SSA_NAME_DEF_STMT (ref);
instance_ref = ref_exp;
@@ -3010,7 +3109,13 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
only if there was dyanmic type store that may affect given variable
(seen_unanalyzed_store) */
- if (!tci.type_maybe_changed)
+ if (!tci.type_maybe_changed
+ || (outer_type
+ && !tci.seen_unanalyzed_store
+ && !tci.multiple_types_encountered
+ && offset == tci.offset
+ && types_same_for_odr (tci.known_current_type,
+ outer_type)))
{
if (!outer_type || tci.seen_unanalyzed_store)
return false;
@@ -3025,16 +3130,9 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
&& !function_entry_reached
&& !tci.multiple_types_encountered)
{
- if (!tci.speculative
- /* Again in instances located in static storage we are interested only
- in constructor stores. */
- || (outer_type
- && !tci.seen_unanalyzed_store
- && offset == tci.offset
- && types_same_for_odr (tci.known_current_type,
- outer_type)))
+ if (!tci.speculative)
{
- outer_type = tci.known_current_type;
+ outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
offset = tci.known_current_offset;
maybe_in_construction = false;
maybe_derived_type = false;
@@ -3044,7 +3142,7 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
else if (!speculative_outer_type
|| speculative_maybe_derived_type)
{
- speculative_outer_type = tci.known_current_type;
+ speculative_outer_type = TYPE_MAIN_VARIANT (tci.known_current_type);
speculative_offset = tci.known_current_offset;
speculative_maybe_derived_type = false;
if (dump_file)
@@ -3052,7 +3150,11 @@ ipa_polymorphic_call_context::get_dynamic_type (tree instance,
}
}
else if (dump_file)
- fprintf (dump_file, " Found multiple types.\n");
+ {
+ fprintf (dump_file, " Found multiple types%s%s\n",
+ function_entry_reached ? " (function entry reached)" : "",
+ function_entry_reached ? " (multiple types encountered)" : "");
+ }
return true;
}
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index f0e3261..62444ed 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -3244,10 +3244,7 @@ do_whole_program_analysis (void)
cgraph_state = CGRAPH_STATE_IPA_SSA;
execute_ipa_pass_list (g->get_passes ()->all_regular_ipa_passes);
-#ifdef ENABLE_CHECKING
- /* Verify that IPA passes cleans up after themselves. */
- gcc_assert (!symtab_remove_unreachable_nodes (false, dump_file));
-#endif
+ symtab_remove_unreachable_nodes (false, dump_file);
if (cgraph_dump_file)
{
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 681733b..72a1fee 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2014-08-21 Jan Hubicka <hubicka@ucw.cz>
+
+ PR tree-optimization/62091
+ * g++.dg/ipa/devirt-37.C: Update template.
+ * g++.dg/ipa/devirt-40.C: New testcase.
+
2014-08-21 Marc Glisse <marc.glisse@inria.fr>
PR tree-optimization/62112
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-37.C b/gcc/testsuite/g++.dg/ipa/devirt-37.C
index 6f7fb09..0dc4d27 100644
--- a/gcc/testsuite/g++.dg/ipa/devirt-37.C
+++ b/gcc/testsuite/g++.dg/ipa/devirt-37.C
@@ -30,7 +30,7 @@ t()
/* After inlining the call within constructor needs to be checked to not go into a basetype.
We should see the vtbl store and we should notice extcall as possibly clobbering the
type but ignore it because b is in static storage. */
-/* { dg-final { scan-tree-dump "Determined dynamic type." "fre2" } } */
+/* { dg-final { scan-tree-dump "No dynamic type change found." "fre2" } } */
/* { dg-final { scan-tree-dump "Checking vtbl store:" "fre2" } } */
/* { dg-final { scan-tree-dump "Function call may change dynamic type:extcall" "fre2" } } */
/* { dg-final { scan-tree-dump "converting indirect call to function virtual void" "fre2" } } */
diff --git a/gcc/testsuite/g++.dg/ipa/devirt-40.C b/gcc/testsuite/g++.dg/ipa/devirt-40.C
new file mode 100644
index 0000000..852e369
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ipa/devirt-40.C
@@ -0,0 +1,23 @@
+/* { dg-options "-O2 -fdump-tree-fre2-details" } */
+typedef enum
+{
+} UErrorCode;
+class UnicodeString
+{
+public:
+ UnicodeString ();
+ virtual ~UnicodeString ();
+};
+class A
+{
+ UnicodeString &m_fn1 (UnicodeString &, int &p2, UErrorCode &) const;
+};
+UnicodeString::UnicodeString () {}
+UnicodeString &
+A::m_fn1 (UnicodeString &, int &p2, UErrorCode &) const
+{
+ UnicodeString a[2];
+}
+
+/* { dg-final { scan-tree-dump "converting indirect call to function virtual UnicodeString" "fre2" } } */
+/* { dg-final { cleanup-tree-dump "fre2" } } */