===================================================================
@@ -355,6 +355,12 @@ ipa_print_all_jump_functions (FILE *f)
struct type_change_info
{
+ /* The declaration or SSA_NAME pointer of the base that we are checking for
+ type change. */
+ tree object;
+ /* If we actually can tell the type that the object has changed to, it is
+ stored in this field. Otherwise it remains NULL_TREE. */
+ tree known_current_type;
/* Set to true if dynamic type change has been detected. */
bool type_maybe_changed;
};
@@ -387,6 +393,49 @@ stmt_may_be_vtbl_ptr_store (gimple stmt)
return true;
}
+/* If STMT can be proved to be an assignment to the virtual method table
+ pointer of ANALYZED_OBJ and the type associated witht the new table
+ identified, return the type. Otherwise return NULL_TREE. */
+
+static tree
+extr_type_from_vtbl_ptr_store (gimple stmt, tree analyzed_obj)
+{
+ tree lhs, t, obj;
+
+ if (!is_gimple_assign (stmt))
+ return NULL_TREE;
+
+ lhs = gimple_assign_lhs (stmt);
+
+ if (TREE_CODE (lhs) != COMPONENT_REF)
+ return NULL_TREE;
+ obj = lhs;
+
+ if (!DECL_VIRTUAL_P (TREE_OPERAND (lhs, 1)))
+ return NULL_TREE;
+
+ do
+ {
+ obj = TREE_OPERAND (obj, 0);
+ } while (TREE_CODE (obj) == COMPONENT_REF);
+ if (TREE_CODE (obj) == MEM_REF)
+ obj = TREE_OPERAND (obj, 0);
+ if (TREE_CODE (obj) == ADDR_EXPR)
+ obj = TREE_OPERAND (obj, 0);
+ if (obj != analyzed_obj)
+ return NULL_TREE;
+
+
+ t = gimple_assign_rhs1 (stmt);
+ if (TREE_CODE (t) != ADDR_EXPR)
+ return NULL_TREE;
+ t = get_base_address (TREE_OPERAND (t, 0));
+ if (!t || TREE_CODE (t) != VAR_DECL || !DECL_VIRTUAL_P (t))
+ return NULL_TREE;
+
+ return DECL_CONTEXT (t);
+}
+
/* Callbeck of walk_aliased_vdefs and a helper function for
detect_type_change_anc to check whether a particular statement may modify
the virtual table pointer, and if possible also determine the new type of
@@ -402,6 +451,8 @@ check_stmt_for_type_change (ao_ref *ao A
if (stmt_may_be_vtbl_ptr_store (stmt))
{
tci->type_maybe_changed = true;
+ tci->known_current_type = extr_type_from_vtbl_ptr_store (stmt,
+ tci->object);
return true;
}
else
@@ -417,9 +468,10 @@ check_stmt_for_type_change (ao_ref *ao A
static bool
detect_type_change_anc (tree arg, gimple call, struct ipa_jump_func *jfunc,
- HOST_WIDE_INT anc_offset ATTRIBUTE_UNUSED)
+ HOST_WIDE_INT anc_offset)
{
struct type_change_info tci;
+ tree obj;
ao_ref ar;
/* Const calls cannot call virtual methods through VMT and so type changes do
@@ -427,6 +479,15 @@ detect_type_change_anc (tree arg, gimple
if (!gimple_vuse (call))
return false;
+ obj = arg;
+ while (handled_component_p (obj))
+ obj = TREE_OPERAND (obj, 0);
+ if (TREE_CODE (obj) == MEM_REF)
+ obj = TREE_OPERAND (obj, 0);
+ if (TREE_CODE (obj) == ADDR_EXPR)
+ obj = TREE_OPERAND (obj, 0);
+ tci.object = obj;
+ tci.known_current_type = NULL_TREE;
tci.type_maybe_changed = false;
ao_ref_init (&ar, arg);
@@ -435,7 +496,31 @@ detect_type_change_anc (tree arg, gimple
if (!tci.type_maybe_changed)
return false;
- jfunc->type = IPA_JF_UNKNOWN;
+ if (!tci.known_current_type)
+ jfunc->type = IPA_JF_UNKNOWN;
+ else if (anc_offset != 0)
+ {
+ tree new_binfo = get_binfo_at_offset (TYPE_BINFO (tci.known_current_type),
+ anc_offset, TREE_TYPE (arg));
+
+ if (new_binfo)
+ {
+ jfunc->type = IPA_JF_KNOWN_TYPE;
+ jfunc->value.base_binfo = new_binfo;
+ }
+ else
+ jfunc->type = IPA_JF_UNKNOWN;
+ }
+ else
+ {
+ /* If an offset of a searched-for sub-object actually happens to be zero,
+ we do not have to worry about non-artificialness. Either there are no
+ virtual methods anyway or there is a VMT pointer at offset zero and so
+ artificial sub-objects start at higher offsets. */
+ jfunc->type = IPA_JF_KNOWN_TYPE;
+ jfunc->value.base_binfo = TYPE_BINFO (tci.known_current_type);
+ }
+
return true;
}
===================================================================
@@ -1,7 +1,7 @@
/* Verify that ipa-cp correctly detects the dynamic type of an object
under construction when doing devirtualization. */
/* { dg-do run } */
-/* { dg-options "-O3 -fno-early-inlining -fno-inline" } */
+/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
extern "C" void abort (void);
@@ -69,3 +69,8 @@ int main (int argc, char *argv[])
bah ();
return 0;
}
+
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo" "cp" } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
===================================================================
@@ -1,7 +1,7 @@
/* Verify that ipa-cp correctly detects the dynamic type of an object
under construction when doing devirtualization. */
/* { dg-do run } */
-/* { dg-options "-O3 -fno-early-inlining -fno-inline" } */
+/* { dg-options "-O3 -fno-early-inlining -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
extern "C" void abort (void);
@@ -77,3 +77,8 @@ int main (int argc, char *argv[])
bah ();
return 0;
}
+
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo" "cp" } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
===================================================================
@@ -1,7 +1,7 @@
/* Verify that ipa-cp correctly detects the dynamic type of an object
under construction when doing devirtualization. */
/* { dg-do run } */
-/* { dg-options "-O3 -fno-inline" } */
+/* { dg-options "-O3 -fno-inline -fdump-ipa-cp -fdump-tree-optimized" } */
extern "C" void abort (void);
@@ -78,3 +78,8 @@ int main (int argc, char *argv[])
bah ();
return 0;
}
+
+/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*A::foo" "cp" } } */
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-ipa-dump "cp" } } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */
===================================================================
@@ -1,7 +1,7 @@
/* Verify that ipa-cp correctly detects the dynamic type of an object
under construction when doing devirtualization. */
/* { dg-do run } */
-/* { dg-options "-O3 -fno-inline" } */
+/* { dg-options "-O3 -fno-inline -fdump-tree-optimized" } */
extern "C" void abort (void);
@@ -108,3 +108,6 @@ int main (int argc, char *argv[])
bah ();
return 0;
}
+
+/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */
+/* { dg-final { cleanup-tree-dump "optimized" } } */