Commit 1ae6fe9b by Martin Jambor Committed by Martin Jambor

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
parent 2b45bf21
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> 2010-05-13 Andreas Schwab <schwab@linux-m68k.org>
* config/rs6000/rs6000-protos.h * config/rs6000/rs6000-protos.h
......
...@@ -1401,6 +1401,137 @@ gimple_fold_builtin (gimple stmt) ...@@ -1401,6 +1401,137 @@ gimple_fold_builtin (gimple stmt)
return result; 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. /* 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 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. simplifies to a constant value. Return true if any changes were made.
...@@ -1428,9 +1559,6 @@ fold_gimple_call (gimple_stmt_iterator *gsi) ...@@ -1428,9 +1559,6 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
} }
else 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 /* ??? Should perhaps do this in fold proper. However, doing it
there requires that we create a new CALL_EXPR, and that requires 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 copying EH region info to the new node. Easier to just do it
...@@ -1438,19 +1566,11 @@ fold_gimple_call (gimple_stmt_iterator *gsi) ...@@ -1438,19 +1566,11 @@ fold_gimple_call (gimple_stmt_iterator *gsi)
/* ??? Is there a good reason not to do this in fold_stmt_inplace? */ /* ??? Is there a good reason not to do this in fold_stmt_inplace? */
callee = gimple_call_fn (stmt); callee = gimple_call_fn (stmt);
if (TREE_CODE (callee) == OBJ_TYPE_REF if (TREE_CODE (callee) == OBJ_TYPE_REF
&& lang_hooks.fold_obj_type_ref && TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR)
&& TREE_CODE (OBJ_TYPE_REF_OBJECT (callee)) == ADDR_EXPR
&& DECL_P (TREE_OPERAND
(OBJ_TYPE_REF_OBJECT (callee), 0)))
{ {
tree t; tree t;
/* ??? Caution: Broken ADDR_EXPR semantics means that t = gimple_fold_obj_type_ref (callee, NULL_TREE);
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);
if (t) if (t)
{ {
gimple_call_set_fn (stmt, t); gimple_call_set_fn (stmt, t);
......
...@@ -4685,43 +4685,4 @@ gimple_decl_printable_name (tree decl, int verbosity) ...@@ -4685,43 +4685,4 @@ gimple_decl_printable_name (tree decl, int verbosity)
return IDENTIFIER_POINTER (DECL_NAME (decl)); 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" #include "gt-gimple.h"
...@@ -888,6 +888,8 @@ unsigned get_gimple_rhs_num_ops (enum tree_code); ...@@ -888,6 +888,8 @@ unsigned get_gimple_rhs_num_ops (enum tree_code);
gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL);
const char *gimple_decl_printable_name (tree, int); const char *gimple_decl_printable_name (tree, int);
tree gimple_fold_obj_type_ref (tree, tree); 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. */ /* Returns true iff T is a valid GIMPLE statement. */
extern bool is_gimple_stmt (tree); extern bool is_gimple_stmt (tree);
......
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> 2010-05-13 Jakub Jelinek <jakub@redhat.com>
PR fortran/44036 PR fortran/44036
......
/* 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" } } */
/* 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" } } */
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