gimple.c (gimple_fold_obj_type_ref): Removed (a replacement moved to gimple-fold.c).
2010-05-13 Martin Jambor <mjambor@suse.cz> * gimple.c (gimple_fold_obj_type_ref): Removed (a replacement moved to gimple-fold.c). * gimple-fold.c (get_base_binfo_for_type): New function. (gimple_get_relevant_ref_binfo): Likewise. (gimple_fold_obj_type_ref_known_binfo): Likewise. (gimple_fold_obj_type_ref): Likewise. (fold_gimple_call): Simplify condition for folding virtual calls and call gimple_fold_obj_type_ref. * gimple.h (gimple_get_relevant_ref_binfo): Declare. (gimple_fold_obj_type_ref_known_binfo): Likewise. * testsuite/g++.dg/otr-fold-1.C: New test. * testsuite/g++.dg/otr-fold-2.C: New test. From-SVN: r159362
This commit is contained in:
parent
2b45bf2152
commit
1ae6fe9be5
@ -1,3 +1,16 @@
|
||||
2010-05-13 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* gimple.c (gimple_fold_obj_type_ref): Removed (a replacement moved to
|
||||
gimple-fold.c).
|
||||
* gimple-fold.c (get_base_binfo_for_type): New function.
|
||||
(gimple_get_relevant_ref_binfo): Likewise.
|
||||
(gimple_fold_obj_type_ref_known_binfo): Likewise.
|
||||
(gimple_fold_obj_type_ref): Likewise.
|
||||
(fold_gimple_call): Simplify condition for folding virtual calls
|
||||
and call gimple_fold_obj_type_ref.
|
||||
* gimple.h (gimple_get_relevant_ref_binfo): Declare.
|
||||
(gimple_fold_obj_type_ref_known_binfo): Likewise.
|
||||
|
||||
2010-05-13 Andreas Schwab <schwab@linux-m68k.org>
|
||||
|
||||
* config/rs6000/rs6000-protos.h
|
||||
|
@ -1401,6 +1401,137 @@ gimple_fold_builtin (gimple stmt)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Search for a base binfo of BINFO that corresponds to TYPE and return it if
|
||||
it is found or NULL_TREE if it is not. */
|
||||
|
||||
static tree
|
||||
get_base_binfo_for_type (tree binfo, tree type)
|
||||
{
|
||||
int i;
|
||||
tree base_binfo;
|
||||
tree res = NULL_TREE;
|
||||
|
||||
for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++)
|
||||
if (TREE_TYPE (base_binfo) == type)
|
||||
{
|
||||
gcc_assert (!res);
|
||||
res = base_binfo;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Return a binfo describing the part of object referenced by expression REF.
|
||||
Return NULL_TREE if it cannot be determined. REF can consist of a series of
|
||||
COMPONENT_REFs of a declaration or of an INDIRECT_REF or it can also be just
|
||||
a simple declaration, indirect reference or an SSA_NAME. If the function
|
||||
discovers an INDIRECT_REF or an SSA_NAME, it will assume that the
|
||||
encapsulating type is described by KNOWN_BINFO, if it is not NULL_TREE.
|
||||
Otherwise the first non-artificial field declaration or the base declaration
|
||||
will be examined to get the encapsulating type. */
|
||||
|
||||
tree
|
||||
gimple_get_relevant_ref_binfo (tree ref, tree known_binfo)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
if (TREE_CODE (ref) == COMPONENT_REF)
|
||||
{
|
||||
tree par_type;
|
||||
tree binfo, base_binfo;
|
||||
tree field = TREE_OPERAND (ref, 1);
|
||||
|
||||
if (!DECL_ARTIFICIAL (field))
|
||||
{
|
||||
tree type = TREE_TYPE (field);
|
||||
if (TREE_CODE (type) == RECORD_TYPE)
|
||||
return TYPE_BINFO (type);
|
||||
else
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
par_type = TREE_TYPE (TREE_OPERAND (ref, 0));
|
||||
binfo = TYPE_BINFO (par_type);
|
||||
if (!binfo
|
||||
|| BINFO_N_BASE_BINFOS (binfo) == 0)
|
||||
return NULL_TREE;
|
||||
|
||||
base_binfo = BINFO_BASE_BINFO (binfo, 0);
|
||||
if (BINFO_TYPE (base_binfo) != TREE_TYPE (field))
|
||||
{
|
||||
tree d_binfo;
|
||||
|
||||
d_binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (ref, 0),
|
||||
known_binfo);
|
||||
/* Get descendant binfo. */
|
||||
if (!d_binfo)
|
||||
return NULL_TREE;
|
||||
return get_base_binfo_for_type (d_binfo, TREE_TYPE (field));
|
||||
}
|
||||
|
||||
ref = TREE_OPERAND (ref, 0);
|
||||
}
|
||||
else if (DECL_P (ref) && TREE_CODE (TREE_TYPE (ref)) == RECORD_TYPE)
|
||||
return TYPE_BINFO (TREE_TYPE (ref));
|
||||
else if (known_binfo
|
||||
&& (TREE_CODE (ref) == SSA_NAME
|
||||
|| TREE_CODE (ref) == INDIRECT_REF))
|
||||
return known_binfo;
|
||||
else
|
||||
return NULL_TREE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Fold a OBJ_TYPE_REF expression to the address of a function. TOKEN is
|
||||
integer form of OBJ_TYPE_REF_TOKEN of the reference expression. KNOWN_BINFO
|
||||
carries the binfo describing the true type of OBJ_TYPE_REF_OBJECT(REF). */
|
||||
|
||||
tree
|
||||
gimple_fold_obj_type_ref_known_binfo (HOST_WIDE_INT token, tree known_binfo)
|
||||
{
|
||||
HOST_WIDE_INT i;
|
||||
tree v, fndecl;
|
||||
|
||||
v = BINFO_VIRTUALS (known_binfo);
|
||||
i = 0;
|
||||
while (i != token)
|
||||
{
|
||||
i += (TARGET_VTABLE_USES_DESCRIPTORS
|
||||
? TARGET_VTABLE_USES_DESCRIPTORS : 1);
|
||||
v = TREE_CHAIN (v);
|
||||
}
|
||||
|
||||
fndecl = TREE_VALUE (v);
|
||||
return build_fold_addr_expr (fndecl);
|
||||
}
|
||||
|
||||
|
||||
/* Fold a OBJ_TYPE_REF expression to the address of a function. If KNOWN_TYPE
|
||||
is not NULL_TREE, it is the true type of the outmost encapsulating object if
|
||||
that comes from a pointer SSA_NAME. If the true outmost encapsulating type
|
||||
can be determined from a declaration OBJ_TYPE_REF_OBJECT(REF), it is used
|
||||
regardless of KNOWN_TYPE (which thus can be NULL_TREE). */
|
||||
|
||||
tree
|
||||
gimple_fold_obj_type_ref (tree ref, tree known_type)
|
||||
{
|
||||
tree obj = OBJ_TYPE_REF_OBJECT (ref);
|
||||
tree known_binfo = known_type ? TYPE_BINFO (known_type) : NULL_TREE;
|
||||
tree binfo;
|
||||
|
||||
if (TREE_CODE (obj) == ADDR_EXPR)
|
||||
obj = TREE_OPERAND (obj, 0);
|
||||
|
||||
binfo = gimple_get_relevant_ref_binfo (obj, known_binfo);
|
||||
if (binfo)
|
||||
{
|
||||
HOST_WIDE_INT token = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1);
|
||||
return gimple_fold_obj_type_ref_known_binfo (token, binfo);
|
||||
}
|
||||
else
|
||||
return NULL_TREE;
|
||||
}
|
||||
|
||||
/* Attempt to fold a call statement referenced by the statement iterator GSI.
|
||||
The statement may be replaced by another statement, e.g., if the call
|
||||
simplifies to a constant value. Return true if any changes were made.
|
||||
@ -1428,9 +1559,6 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Check for resolvable OBJ_TYPE_REF. The only sorts we can resolve
|
||||
here are when we've propagated the address of a decl into the
|
||||
object slot. */
|
||||
/* ??? Should perhaps do this in fold proper. However, doing it
|
||||
there requires that we create a new CALL_EXPR, and that requires
|
||||
copying EH region info to the new node. Easier to just do it
|
||||
@ -1438,19 +1566,11 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
|
||||
/* ??? Is there a good reason not to do this in fold_stmt_inplace? */
|
||||
callee = gimple_call_fn (stmt);
|
||||
if (TREE_CODE (callee) == OBJ_TYPE_REF
|
||||
&& lang_hooks.fold_obj_type_ref
|
||||
&& TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR
|
||||
&& DECL_P (TREE_OPERAND
|
||||
(OBJ_TYPE_REF_OBJECT (callee), 0)))
|
||||
&& TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR)
|
||||
{
|
||||
tree t;
|
||||
|
||||
/* ??? Caution: Broken ADDR_EXPR semantics means that
|
||||
looking at the type of the operand of the addr_expr
|
||||
can yield an array type. See silly exception in
|
||||
check_pointer_types_r. */
|
||||
t = TREE_TYPE (TREE_TYPE (OBJ_TYPE_REF_OBJECT (callee)));
|
||||
t = lang_hooks.fold_obj_type_ref (callee, t);
|
||||
t = gimple_fold_obj_type_ref (callee, NULL_TREE);
|
||||
if (t)
|
||||
{
|
||||
gimple_call_set_fn (stmt, t);
|
||||
|
39
gcc/gimple.c
39
gcc/gimple.c
@ -4685,43 +4685,4 @@ gimple_decl_printable_name (tree decl, int verbosity)
|
||||
return IDENTIFIER_POINTER (DECL_NAME (decl));
|
||||
}
|
||||
|
||||
|
||||
/* Fold a OBJ_TYPE_REF expression to the address of a function.
|
||||
KNOWN_TYPE carries the true type of OBJ_TYPE_REF_OBJECT(REF). Adapted
|
||||
from cp_fold_obj_type_ref, but it tolerates types with no binfo
|
||||
data. */
|
||||
|
||||
tree
|
||||
gimple_fold_obj_type_ref (tree ref, tree known_type)
|
||||
{
|
||||
HOST_WIDE_INT index;
|
||||
HOST_WIDE_INT i;
|
||||
tree v;
|
||||
tree fndecl;
|
||||
|
||||
if (TYPE_BINFO (known_type) == NULL_TREE)
|
||||
return NULL_TREE;
|
||||
|
||||
v = BINFO_VIRTUALS (TYPE_BINFO (known_type));
|
||||
index = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1);
|
||||
i = 0;
|
||||
while (i != index)
|
||||
{
|
||||
i += (TARGET_VTABLE_USES_DESCRIPTORS
|
||||
? TARGET_VTABLE_USES_DESCRIPTORS : 1);
|
||||
v = TREE_CHAIN (v);
|
||||
}
|
||||
|
||||
fndecl = TREE_VALUE (v);
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
gcc_assert (tree_int_cst_equal (OBJ_TYPE_REF_TOKEN (ref),
|
||||
DECL_VINDEX (fndecl)));
|
||||
#endif
|
||||
|
||||
cgraph_node (fndecl)->local.vtable_method = true;
|
||||
|
||||
return build_fold_addr_expr (fndecl);
|
||||
}
|
||||
|
||||
#include "gt-gimple.h"
|
||||
|
@ -888,6 +888,8 @@ unsigned get_gimple_rhs_num_ops (enum tree_code);
|
||||
gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
|
||||
const char *gimple_decl_printable_name (tree, int);
|
||||
tree gimple_fold_obj_type_ref (tree, tree);
|
||||
tree gimple_get_relevant_ref_binfo (tree ref, tree known_binfo);
|
||||
tree gimple_fold_obj_type_ref_known_binfo (HOST_WIDE_INT, tree);
|
||||
|
||||
/* Returns true iff T is a valid GIMPLE statement. */
|
||||
extern bool is_gimple_stmt (tree);
|
||||
|
@ -1,3 +1,8 @@
|
||||
2010-05-13 Martin Jambor <mjambor@suse.cz>
|
||||
|
||||
* g++.dg/otr-fold-1.C: New test.
|
||||
* g++.dg/otr-fold-2.C: New test.
|
||||
|
||||
2010-05-13 Jakub Jelinek <jakub@redhat.com>
|
||||
|
||||
PR fortran/44036
|
||||
|
76
gcc/testsuite/g++.dg/otr-fold-1.C
Normal file
76
gcc/testsuite/g++.dg/otr-fold-1.C
Normal file
@ -0,0 +1,76 @@
|
||||
/* Verify that virtual calls are folded even when a typecast to an
|
||||
ancestor is involved along the way. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O -fdump-tree-optimized-slim" } */
|
||||
|
||||
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 Distraction, public A
|
||||
{
|
||||
public:
|
||||
virtual int foo (int i);
|
||||
};
|
||||
|
||||
float Distraction::bar (float z)
|
||||
{
|
||||
f += z;
|
||||
return f/2;
|
||||
}
|
||||
|
||||
int A::foo (int i)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
int B::foo (int i)
|
||||
{
|
||||
return i + 2;
|
||||
}
|
||||
|
||||
int __attribute__ ((noinline,noclone)) get_input(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
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 "= B::foo" "optimized" } } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
88
gcc/testsuite/g++.dg/otr-fold-2.C
Normal file
88
gcc/testsuite/g++.dg/otr-fold-2.C
Normal file
@ -0,0 +1,88 @@
|
||||
/* Verify that virtual calls are folded even when a typecast to an
|
||||
ancestor is involved along the way. */
|
||||
/* { dg-do run } */
|
||||
/* { dg-options "-O -fdump-tree-optimized-slim" } */
|
||||
|
||||
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 A_2 : public A
|
||||
{
|
||||
public:
|
||||
int data_2;
|
||||
virtual int baz (int i);
|
||||
};
|
||||
|
||||
|
||||
class B : public Distraction, public A_2
|
||||
{
|
||||
public:
|
||||
virtual int foo (int i);
|
||||
};
|
||||
|
||||
float Distraction::bar (float z)
|
||||
{
|
||||
f += z;
|
||||
return f/2;
|
||||
}
|
||||
|
||||
int A::foo (int i)
|
||||
{
|
||||
return i + 1;
|
||||
}
|
||||
|
||||
int A_2::baz (int i)
|
||||
{
|
||||
return i * 15;
|
||||
}
|
||||
|
||||
int B::foo (int i)
|
||||
{
|
||||
return i + 2;
|
||||
}
|
||||
|
||||
int __attribute__ ((noinline,noclone)) get_input(void)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline int middleman_1 (class A *obj, int i)
|
||||
{
|
||||
return obj->foo (i);
|
||||
}
|
||||
|
||||
static inline int middleman_2 (class A *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 "= B::foo" "optimized" } } */
|
||||
/* { dg-final { cleanup-tree-dump "optimized" } } */
|
Loading…
Reference in New Issue
Block a user