mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-05 00:31:30 +08:00
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
This commit is contained in:
parent
4891e8f8cd
commit
e248d83f4b
@ -1,3 +1,14 @@
|
||||
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>
|
||||
|
||||
PR tree-optimization/57000
|
||||
|
@ -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 \
|
||||
$(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) \
|
||||
$(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) \
|
||||
$(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \
|
||||
$(TM_H) coretypes.h $(DUMPFILE_H) $(FLAGS_H) $(CFGLOOP_H) \
|
||||
|
18
gcc/ipa-cp.c
18
gcc/ipa-cp.c
@ -791,20 +791,6 @@ ipa_get_jf_ancestor_result (struct ipa_jump_func *jfunc, tree input)
|
||||
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
|
||||
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
|
||||
@ -816,7 +802,7 @@ ipa_value_from_jfunc (struct ipa_node_params *info, struct ipa_jump_func *jfunc)
|
||||
if (jfunc->type == IPA_JF_CONST)
|
||||
return ipa_get_jf_constant (jfunc);
|
||||
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
|
||||
|| jfunc->type == IPA_JF_ANCESTOR)
|
||||
{
|
||||
@ -1103,7 +1089,7 @@ propagate_scalar_accross_jump_function (struct cgraph_edge *cs,
|
||||
|
||||
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)
|
||||
return set_lattice_contains_variable (dest_lat);
|
||||
}
|
||||
|
@ -356,6 +356,20 @@ ipa_set_ancestor_jf (struct ipa_jump_func *jfunc, HOST_WIDE_INT offset,
|
||||
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
|
||||
check_stmt_for_type_change. */
|
||||
|
||||
@ -1957,6 +1971,30 @@ ipa_analyze_node (struct cgraph_node *node)
|
||||
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
|
||||
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,
|
||||
vec<tree> ,
|
||||
vec<ipa_agg_jump_function_p> );
|
||||
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. */
|
||||
void ipa_analyze_node (struct cgraph_node *);
|
||||
|
@ -1,3 +1,9 @@
|
||||
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>
|
||||
|
||||
PR tree-optimization/57000
|
||||
|
62
gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
Normal file
62
gcc/testsuite/g++.dg/ipa/imm-devirt-1.C
Normal file
@ -0,0 +1,62 @@
|
||||
/* 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" } } */
|
95
gcc/testsuite/g++.dg/ipa/imm-devirt-2.C
Normal file
95
gcc/testsuite/g++.dg/ipa/imm-devirt-2.C
Normal file
@ -0,0 +1,95 @@
|
||||
/* 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
|
||||
#include "params.h"
|
||||
#include "dbgcnt.h"
|
||||
#include "domwalk.h"
|
||||
#include "ipa-prop.h"
|
||||
|
||||
/* TODO:
|
||||
|
||||
@ -4326,7 +4327,15 @@ eliminate_bb (dom_walk_data *, basic_block b)
|
||||
fn = VN_INFO (orig_fn)->valnum;
|
||||
else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
|
||||
&& 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
|
||||
continue;
|
||||
if (gimple_call_addr_fndecl (fn) != NULL_TREE
|
||||
|
Loading…
x
Reference in New Issue
Block a user