Commit e248d83f by Martin Jambor Committed by Martin Jambor

re PR tree-optimization/56718 (Early inlining prevents type based devirtualization)

2013-04-19  Martin Jambor  <mjambor@suse.cz>

	PR tree-optimization/56718
	* ipa-cp.c (ipa_value_from_known_type_jfunc): Moved...
	* ipa-prop.c (ipa_binfo_from_known_type_jfunc): ...here, renamed
	and made public.  Adjusted all callers.
	(ipa_intraprocedural_devirtualization): New function.
	* ipa-prop.h (ipa_binfo_from_known_type_jfunc): Declare.
	(ipa_intraprocedural_devirtualization): Likewise.
	* Makefile.in (tree-ssa-pre.o): Add ipa-prop.h to dependencies.

testsuite/
	* g++.dg/ipa/imm-devirt-1.C: New test.
	* g++.dg/ipa/imm-devirt-2.C: Likewise.

From-SVN: r198088
parent 4891e8f8
2013-04-19 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/56718
* ipa-cp.c (ipa_value_from_known_type_jfunc): Moved...
* ipa-prop.c (ipa_binfo_from_known_type_jfunc): ...here, renamed
and made public. Adjusted all callers.
(ipa_intraprocedural_devirtualization): New function.
* ipa-prop.h (ipa_binfo_from_known_type_jfunc): Declare.
(ipa_intraprocedural_devirtualization): Likewise.
* Makefile.in (tree-ssa-pre.o): Add ipa-prop.h to dependencies.
2013-04-19 Richard Biener <rguenther@suse.de> 2013-04-19 Richard Biener <rguenther@suse.de>
PR tree-optimization/57000 PR tree-optimization/57000
......
...@@ -2369,7 +2369,8 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \ ...@@ -2369,7 +2369,8 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \
$(TM_H) coretypes.h $(TREE_PASS_H) $(FLAGS_H) langhooks.h \ $(TM_H) coretypes.h $(TREE_PASS_H) $(FLAGS_H) langhooks.h \
$(CFGLOOP_H) alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) $(HASH_TABLE_H) \ $(CFGLOOP_H) alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) $(HASH_TABLE_H) \
$(GIMPLE_H) $(TREE_INLINE_H) tree-iterator.h tree-ssa-sccvn.h $(PARAMS_H) \ $(GIMPLE_H) $(TREE_INLINE_H) tree-iterator.h tree-ssa-sccvn.h $(PARAMS_H) \
$(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H) domwalk.h $(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H) domwalk.h \
$(IPA_PROP_H)
tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \ tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \ $(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \
$(TM_H) coretypes.h $(DUMPFILE_H) $(FLAGS_H) $(CFGLOOP_H) \ $(TM_H) coretypes.h $(DUMPFILE_H) $(FLAGS_H) $(CFGLOOP_H) \
......
...@@ -791,20 +791,6 @@ ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input) ...@@ -791,20 +791,6 @@ ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
return NULL_TREE; return NULL_TREE;
} }
/* Extract the acual BINFO being described by JFUNC which must be a known type
jump function. */
static tree
ipa_value_from_known_type_jfunc (struct ipa_jump_func *jfunc)
{
tree base_binfo = TYPE_BINFO (ipa_get_jf_known_type_base_type (jfunc));
if (!base_binfo)
return NULL_TREE;
return get_binfo_at_offset (base_binfo,
ipa_get_jf_known_type_offset (jfunc),
ipa_get_jf_known_type_component_type (jfunc));
}
/* Determine whether JFUNC evaluates to a known value (that is either a /* Determine whether JFUNC evaluates to a known value (that is either a
constant or a binfo) and if so, return it. Otherwise return NULL. INFO constant or a binfo) and if so, return it. Otherwise return NULL. INFO
describes the caller node so that pass-through jump functions can be describes the caller node so that pass-through jump functions can be
...@@ -816,7 +802,7 @@ ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc) ...@@ -816,7 +802,7 @@ ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc)
if (jfunc->type == IPA_JF_CONST) if (jfunc->type == IPA_JF_CONST)
return ipa_get_jf_constant (jfunc); return ipa_get_jf_constant (jfunc);
else if (jfunc->type == IPA_JF_KNOWN_TYPE) else if (jfunc->type == IPA_JF_KNOWN_TYPE)
return ipa_value_from_known_type_jfunc (jfunc); return ipa_binfo_from_known_type_jfunc (jfunc);
else if (jfunc->type == IPA_JF_PASS_THROUGH else if (jfunc->type == IPA_JF_PASS_THROUGH
|| jfunc->type == IPA_JF_ANCESTOR) || jfunc->type == IPA_JF_ANCESTOR)
{ {
...@@ -1103,7 +1089,7 @@ propagate_scalar_accross_jump_function (struct cgraph_edge *cs, ...@@ -1103,7 +1089,7 @@ propagate_scalar_accross_jump_function (struct cgraph_edge *cs,
if (jfunc->type == IPA_JF_KNOWN_TYPE) if (jfunc->type == IPA_JF_KNOWN_TYPE)
{ {
val = ipa_value_from_known_type_jfunc (jfunc); val = ipa_binfo_from_known_type_jfunc (jfunc);
if (!val) if (!val)
return set_lattice_contains_variable (dest_lat); return set_lattice_contains_variable (dest_lat);
} }
......
...@@ -356,6 +356,20 @@ ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset, ...@@ -356,6 +356,20 @@ ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
jfunc->value.ancestor.agg_preserved = agg_preserved; jfunc->value.ancestor.agg_preserved = agg_preserved;
} }
/* Extract the acual BINFO being described by JFUNC which must be a known type
jump function. */
tree
ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *jfunc)
{
tree base_binfo = TYPE_BINFO (jfunc->value.known_type.base_type);
if (!base_binfo)
return NULL_TREE;
return get_binfo_at_offset (base_binfo,
jfunc->value.known_type.offset,
jfunc->value.known_type.component_type);
}
/* Structure to be passed in between detect_type_change and /* Structure to be passed in between detect_type_change and
check_stmt_for_type_change. */ check_stmt_for_type_change. */
...@@ -1957,6 +1971,30 @@ ipa_analyze_node (struct cgraph_node *node) ...@@ -1957,6 +1971,30 @@ ipa_analyze_node (struct cgraph_node *node)
pop_cfun (); pop_cfun ();
} }
/* Given a statement CALL which must be a GIMPLE_CALL calling an OBJ_TYPE_REF
attempt a type-based devirtualization. If successful, return the
target function declaration, otherwise return NULL. */
tree
ipa_intraprocedural_devirtualization (gimple call)
{
tree binfo, token, fndecl;
struct ipa_jump_func jfunc;
tree otr = gimple_call_fn (call);
jfunc.type = IPA_JF_UNKNOWN;
compute_known_type_jump_func (OBJ_TYPE_REF_OBJECT (otr), &jfunc,
call);
if (jfunc.type != IPA_JF_KNOWN_TYPE)
return NULL_TREE;
binfo = ipa_binfo_from_known_type_jfunc (&jfunc);
if (!binfo)
return NULL_TREE;
token = OBJ_TYPE_REF_TOKEN (otr);
fndecl = gimple_get_virt_method_for_binfo (tree_low_cst (token, 1),
binfo);
return fndecl;
}
/* Update the jump function DST when the call graph edge corresponding to SRC is /* Update the jump function DST when the call graph edge corresponding to SRC is
is being inlined, knowing that DST is of type ancestor and src of known is being inlined, knowing that DST is of type ancestor and src of known
......
...@@ -507,6 +507,8 @@ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie, ...@@ -507,6 +507,8 @@ tree ipa_get_indirect_edge_target (struct cgraph_edge *ie,
vec<tree> , vec<tree> ,
vec<ipa_agg_jump_function_p> ); vec<ipa_agg_jump_function_p> );
struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree); struct cgraph_edge *ipa_make_edge_direct_to_target (struct cgraph_edge *, tree);
tree ipa_binfo_from_known_type_jfunc (struct ipa_jump_func *);
tree ipa_intraprocedural_devirtualization (gimple);
/* Functions related to both. */ /* Functions related to both. */
void ipa_analyze_node (struct cgraph_node *); void ipa_analyze_node (struct cgraph_node *);
......
2013-04-19 Martin Jambor <mjambor@suse.cz>
PR tree-optimization/56718
* g++.dg/ipa/imm-devirt-1.C: New test.
* g++.dg/ipa/imm-devirt-2.C: Likewise.
2013-04-19 Richard Biener <rguenther@suse.de> 2013-04-19 Richard Biener <rguenther@suse.de>
PR tree-optimization/57000 PR tree-optimization/57000
......
/* Verify that virtual calls are folded even early inlining puts them into one
function with the definition. */
/* { dg-do run } */
/* { dg-options "-O2 -fdump-tree-fre1-details" } */
extern "C" void abort (void);
class A
{
public:
int data;
virtual int foo (int i);
};
class B : public A
{
public:
__attribute__ ((noinline)) B();
virtual int foo (int i);
};
int __attribute__ ((noinline)) A::foo (int i)
{
return i + 1;
}
int __attribute__ ((noinline)) B::foo (int i)
{
return i + 2;
}
int __attribute__ ((noinline,noclone)) get_input(void)
{
return 1;
}
__attribute__ ((noinline)) B::B()
{
}
static inline int middleman_1 (class A *obj, int i)
{
return obj->foo (i);
}
static inline int middleman_2 (class B *obj, int i)
{
return middleman_1 (obj, i);
}
int main (int argc, char *argv[])
{
class B b;
if (middleman_2 (&b, get_input ()) != 3)
abort ();
return 0;
}
/* { dg-final { scan-tree-dump "Replacing call target with foo" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
/* Verify that virtual calls are folded even early inlining puts them into one
function with the definition. */
/* { dg-do run } */
/* { dg-options "-O2 -fdump-tree-fre1-details" } */
extern "C" void abort (void);
class Distraction
{
public:
float f;
double d;
Distraction ()
{
f = 8.3;
d = 10.2;
}
virtual float bar (float z);
};
class A
{
public:
int data;
virtual int foo (int i);
};
class B : public A
{
public:
int data_2;
virtual int foo (int i);
virtual int baz (int i);
};
class C : public Distraction, public B
{
public:
__attribute__ ((noinline)) C();
virtual int foo (int i);
};
float __attribute__ ((noinline)) Distraction::bar (float z)
{
f += z;
return f/2;
}
int __attribute__ ((noinline)) A::foo (int i)
{
return i + 1;
}
int __attribute__ ((noinline)) B::foo (int i)
{
return i + 2;
}
int __attribute__ ((noinline)) B::baz (int i)
{
return i * 15;
}
int __attribute__ ((noinline)) C::foo (int i)
{
return i + 3;
}
int __attribute__ ((noinline,noclone)) get_input(void)
{
return 1;
}
static inline int middleman (class A *obj, int i)
{
return obj->foo (i);
}
__attribute__ ((noinline)) C::C()
{
}
int main (int argc, char *argv[])
{
class C c;
if (middleman (&c, get_input ()) != 4)
abort ();
return 0;
}
/* { dg-final { scan-tree-dump "Replacing call target" "fre1" } } */
/* { dg-final { cleanup-tree-dump "fre1" } } */
...@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see ...@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "params.h" #include "params.h"
#include "dbgcnt.h" #include "dbgcnt.h"
#include "domwalk.h" #include "domwalk.h"
#include "ipa-prop.h"
/* TODO: /* TODO:
...@@ -4326,7 +4327,15 @@ eliminate_bb (dom_walk_data *, basic_block b) ...@@ -4326,7 +4327,15 @@ eliminate_bb (dom_walk_data *, basic_block b)
fn = VN_INFO (orig_fn)->valnum; fn = VN_INFO (orig_fn)->valnum;
else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
&& TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME) && TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
{
fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum; fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
if (!gimple_call_addr_fndecl (fn))
{
fn = ipa_intraprocedural_devirtualization (stmt);
if (fn)
fn = build_fold_addr_expr (fn);
}
}
else else
continue; continue;
if (gimple_call_addr_fndecl (fn) != NULL_TREE if (gimple_call_addr_fndecl (fn) != NULL_TREE
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment