Message ID | 20101215164916.942314994@virgil.suse.cz |
---|---|
State | New |
Headers | show |
On Wed, 15 Dec 2010, Martin Jambor wrote: > I believe this has been basically already approved by Richi but I'd > like to apply it just before the rest of the series so that we don't > regress in functionality for more time than necessary. The only > important change since the last time is that the hunks pushing and > popping cfun were moved to the subsequent patch where they belong. > > To re-state the general description, this patch removes parts of the > current devirtualization machinery that cannot work because of > potential dynamic type change which might be under way during > sub-object construction and destruction. In the general case we > simply cannot know this about global objects and we do not want to > proceed with the necessary detection when folding. So > devirtualization based on global decls, global IPA-CP constants is > being removed and devirtualization in folding is dumbed down to never > work on sub-objects. > > This patch removes the two testcases that test devirtualization based > on global variables as well as g++.dg/otr-fold-[12].C which are then > however reintroduced in the last patch in the series. Furthermore, > g++.dg/tree-ssa/pr43411.C and g++.dg/tree-ssa/pr45605.C fail which is > expected and also dealt with in the last patch (which removes the > xfail). > > Bootstrapped and tested separately on x86-64-linux, also tested with > make check-c++ on i686. Please apply this patch now. It's already late and this patch fixes bugs. I'm going over the other patches now. Thanks, Richard. > Thanks, > > Martin > > > 2010-12-09 Martin Jambor <mjambor@suse.cz> > > PR tree-optimization/45934 > PR tree-optimization/46302 > * gimple-fold.c (get_base_binfo_for_type): Removed. > (gimple_get_relevant_ref_binfo): Likewise. > (gimple_fold_obj_type_ref_call): Dumb down to 4.5 functionality, > removed parameter inplace, updated the caller. > * gimple.h (gimple_get_relevant_ref_binfo): Remove declaration. > * ipa-cp.c (ipcp_propagate_types): Do not derive types from constants. > (ipcp_discover_new_direct_edges): Do not do devirtualization based on > constants. > * ipa-prop.c (compute_known_type_jump_func): Use > get_ref_base_and_extent and get_binfo_at_offset instead of > gimple_get_relevant_ref_binfo. > (compute_known_type_jump_func): Likewise. > (update_jump_functions_after_inlining): Do not derive types from > constants. > (try_make_edge_direct_virtual_call): Likewise. > * tree.c (get_binfo_at_offset): Get type from non-artificial fields. > * testsuite/g++.dg/ipa/ipcp-ivi-1.C: Removed. > * testsuite/g++.dg/ipa/ivinline-6.C: Likewise. > * testsuite/g++.dg/otr-fold-1.C: Likewise. > * testsuite/g++.dg/otr-fold-2.C: Likewise. > * testsuite/g++.dg/tree-ssa/pr43411.C: Xfail dump scan. > * testsuite/g++.dg/tree-ssa/pr45605.C: Likewise. > > Index: icln/gcc/gimple-fold.c > =================================================================== > --- icln.orig/gcc/gimple-fold.c > +++ icln/gcc/gimple-fold.c > @@ -1364,88 +1364,6 @@ 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; > - 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; > - > - /* Offset 0 indicates the primary base, whose vtable contents are > - represented in the binfo for the derived class. */ > - if (int_bit_position (field) != 0) > - { > - tree d_binfo; > - > - /* Get descendant binfo. */ > - d_binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (ref, 0), > - known_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) == MEM_REF)) > - return known_binfo; > - else > - return NULL_TREE; > - } > -} > - > /* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN > is integer form of OBJ_TYPE_REF_TOKEN of the reference expression. > KNOWN_BINFO carries the binfo describing the true type of > @@ -1529,7 +1447,7 @@ gimple_adjust_this_by_delta (gimple_stmt > INPLACE is false. Return true iff the statement was changed. */ > > static bool > -gimple_fold_obj_type_ref_call (gimple_stmt_iterator *gsi, bool inplace) > +gimple_fold_obj_type_ref_call (gimple_stmt_iterator *gsi) > { > gimple stmt = gsi_stmt (*gsi); > tree ref = gimple_call_fn (stmt); > @@ -1537,27 +1455,21 @@ gimple_fold_obj_type_ref_call (gimple_st > tree binfo, fndecl, delta; > HOST_WIDE_INT token; > > - if (TREE_CODE (obj) == ADDR_EXPR) > - obj = TREE_OPERAND (obj, 0); > - else > + if (TREE_CODE (obj) != ADDR_EXPR) > return false; > - > - binfo = gimple_get_relevant_ref_binfo (obj, NULL_TREE); > + obj = TREE_OPERAND (obj, 0); > + if (!DECL_P (obj) > + || TREE_CODE (TREE_TYPE (obj)) != RECORD_TYPE) > + return false; > + binfo = TYPE_BINFO (TREE_TYPE (obj)); > if (!binfo) > return false; > + > token = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1); > - fndecl = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, > - !DECL_P (obj)); > + fndecl = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, false); > if (!fndecl) > return false; > - > - if (integer_nonzerop (delta)) > - { > - if (inplace) > - return false; > - gimple_adjust_this_by_delta (gsi, delta); > - } > - > + gcc_assert (integer_zerop (delta)); > gimple_call_set_fndecl (stmt, fndecl); > return true; > } > @@ -1595,7 +1507,7 @@ gimple_fold_call (gimple_stmt_iterator * > here where we can just smash the call operand. */ > callee = gimple_call_fn (stmt); > if (TREE_CODE (callee) == OBJ_TYPE_REF) > - return gimple_fold_obj_type_ref_call (gsi, inplace); > + return gimple_fold_obj_type_ref_call (gsi); > } > > return false; > Index: icln/gcc/gimple.h > =================================================================== > --- icln.orig/gcc/gimple.h > +++ icln/gcc/gimple.h > @@ -892,7 +892,6 @@ unsigned get_gimple_rhs_num_ops (enum tr > gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); > const char *gimple_decl_printable_name (tree, int); > bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace); > -tree gimple_get_relevant_ref_binfo (tree ref, tree known_binfo); > tree gimple_get_virt_mehtod_for_binfo (HOST_WIDE_INT, tree, tree *, bool); > void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree); > /* Returns true iff T is a valid GIMPLE statement. */ > Index: icln/gcc/ipa-cp.c > =================================================================== > --- icln.orig/gcc/ipa-cp.c > +++ icln/gcc/ipa-cp.c > @@ -781,26 +781,16 @@ ipcp_propagate_types (struct ipa_node_pa > struct ipa_node_params *callee_info, > struct ipa_jump_func *jf, int i) > { > - tree cst, binfo; > - > switch (jf->type) > { > case IPA_JF_UNKNOWN: > case IPA_JF_CONST_MEMBER_PTR: > + case IPA_JF_CONST: > break; > > case IPA_JF_KNOWN_TYPE: > return ipcp_add_param_type (callee_info, i, jf->value.base_binfo); > > - case IPA_JF_CONST: > - cst = jf->value.constant; > - if (TREE_CODE (cst) != ADDR_EXPR) > - break; > - binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0), NULL_TREE); > - if (!binfo) > - break; > - return ipcp_add_param_type (callee_info, i, binfo); > - > case IPA_JF_PASS_THROUGH: > case IPA_JF_ANCESTOR: > return ipcp_copy_types (caller_info, callee_info, i, jf); > @@ -1292,35 +1282,13 @@ ipcp_discover_new_direct_edges (struct c > for (ie = node->indirect_calls; ie; ie = next_ie) > { > struct cgraph_indirect_call_info *ici = ie->indirect_info; > - tree target, delta = NULL_TREE; > > next_ie = ie->next_callee; > - if (ici->param_index != index) > + if (ici->param_index != index > + || ici->polymorphic) > continue; > > - if (ici->polymorphic) > - { > - tree binfo; > - HOST_WIDE_INT token; > - > - if (TREE_CODE (cst) != ADDR_EXPR) > - continue; > - > - binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0), > - NULL_TREE); > - if (!binfo) > - continue; > - gcc_assert (ie->indirect_info->anc_offset == 0); > - token = ie->indirect_info->otr_token; > - target = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, > - true); > - if (!target) > - continue; > - } > - else > - target = cst; > - > - ipa_make_edge_direct_to_target (ie, target, delta); > + ipa_make_edge_direct_to_target (ie, cst, NULL_TREE); > } > } > > Index: icln/gcc/ipa-prop.c > =================================================================== > --- icln.orig/gcc/ipa-prop.c > +++ icln/gcc/ipa-prop.c > @@ -362,7 +362,7 @@ compute_complex_assign_jump_func (struct > gimple stmt, tree name) > { > HOST_WIDE_INT offset, size, max_size; > - tree op1, op2, type; > + tree op1, op2, base, type; > int index; > > op1 = gimple_assign_rhs1 (stmt); > @@ -404,20 +404,21 @@ compute_complex_assign_jump_func (struct > type = TREE_TYPE (op1); > if (TREE_CODE (type) != RECORD_TYPE) > return; > - op1 = get_ref_base_and_extent (op1, &offset, &size, &max_size); > - if (TREE_CODE (op1) != MEM_REF > + base = get_ref_base_and_extent (op1, &offset, &size, &max_size); > + if (TREE_CODE (base) != MEM_REF > /* If this is a varying address, punt. */ > || max_size == -1 > || max_size != size) > return; > - offset += mem_ref_offset (op1).low * BITS_PER_UNIT; > - op1 = TREE_OPERAND (op1, 0); > - if (TREE_CODE (op1) != SSA_NAME > - || !SSA_NAME_IS_DEFAULT_DEF (op1) > + offset += mem_ref_offset (base).low * BITS_PER_UNIT; > + base = TREE_OPERAND (base, 0); > + if (TREE_CODE (base) != SSA_NAME > + || !SSA_NAME_IS_DEFAULT_DEF (base) > || offset < 0) > return; > > - index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1)); > + /* Dynamic types are changed only in constructors and destructors and */ > + index = ipa_get_param_decl_index (info, SSA_NAME_VAR (base)); > if (index >= 0) > { > jfunc->type = IPA_JF_ANCESTOR; > @@ -534,13 +535,26 @@ compute_complex_ancestor_jump_func (stru > static void > compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc) > { > - tree binfo; > + HOST_WIDE_INT offset, size, max_size; > + tree base, binfo; > > - if (TREE_CODE (op) != ADDR_EXPR) > + if (TREE_CODE (op) != ADDR_EXPR > + || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE) > return; > > op = TREE_OPERAND (op, 0); > - binfo = gimple_get_relevant_ref_binfo (op, NULL_TREE); > + base = get_ref_base_and_extent (op, &offset, &size, &max_size); > + if (!DECL_P (base) > + || max_size == -1 > + || max_size != size > + || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE > + || is_global_var (base)) > + return; > + > + binfo = TYPE_BINFO (TREE_TYPE (base)); > + if (!binfo) > + return; > + binfo = get_binfo_at_offset (binfo, offset, TREE_TYPE (op)); > if (binfo) > { > jfunc->type = IPA_JF_KNOWN_TYPE; > @@ -1420,17 +1434,6 @@ update_jump_functions_after_inlining (st > src = ipa_get_ith_jump_func (top, dst->value.ancestor.formal_id); > if (src->type == IPA_JF_KNOWN_TYPE) > combine_known_type_and_ancestor_jfs (src, dst); > - else if (src->type == IPA_JF_CONST) > - { > - struct ipa_jump_func kt_func; > - > - kt_func.type = IPA_JF_UNKNOWN; > - compute_known_type_jump_func (src->value.constant, &kt_func); > - if (kt_func.type == IPA_JF_KNOWN_TYPE) > - combine_known_type_and_ancestor_jfs (&kt_func, dst); > - else > - dst->type = IPA_JF_UNKNOWN; > - } > else if (src->type == IPA_JF_PASS_THROUGH > && src->value.pass_through.operation == NOP_EXPR) > dst->value.ancestor.formal_id = src->value.pass_through.formal_id; > @@ -1543,15 +1546,6 @@ try_make_edge_direct_virtual_call (struc > > if (jfunc->type == IPA_JF_KNOWN_TYPE) > binfo = jfunc->value.base_binfo; > - else if (jfunc->type == IPA_JF_CONST) > - { > - tree cst = jfunc->value.constant; > - if (TREE_CODE (cst) == ADDR_EXPR) > - binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0), > - NULL_TREE); > - else > - return NULL; > - } > else > return NULL; > > Index: icln/gcc/tree.c > =================================================================== > --- icln.orig/gcc/tree.c > +++ icln/gcc/tree.c > @@ -10945,8 +10945,7 @@ get_binfo_at_offset (tree binfo, HOST_WI > > if (type == expected_type) > return binfo; > - if (TREE_CODE (type) != RECORD_TYPE > - || offset < 0) > + if (offset < 0) > return NULL_TREE; > > for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld)) > @@ -10959,12 +10958,18 @@ get_binfo_at_offset (tree binfo, HOST_WI > if (pos <= offset && (pos + size) > offset) > break; > } > - if (!fld || !DECL_ARTIFICIAL (fld)) > + if (!fld || TREE_CODE (TREE_TYPE (fld)) != RECORD_TYPE) > return NULL_TREE; > > + if (!DECL_ARTIFICIAL (fld)) > + { > + binfo = TYPE_BINFO (TREE_TYPE (fld)); > + if (!binfo) > + return NULL_TREE; > + } > /* Offset 0 indicates the primary base, whose vtable contents are > represented in the binfo for the derived class. */ > - if (offset != 0) > + else if (offset != 0) > { > tree base_binfo, found_binfo = NULL_TREE; > for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) > Index: icln/gcc/testsuite/g++.dg/ipa/ipcp-ivi-1.C > =================================================================== > --- icln.orig/gcc/testsuite/g++.dg/ipa/ipcp-ivi-1.C > +++ /dev/null > @@ -1,65 +0,0 @@ > -/* Verify that simple virtual calls are inlined even without early > - inlining. */ > -/* { dg-do run } */ > -/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */ > - > -extern "C" void abort (void); > - > -class A > -{ > -public: > - int data; > - virtual int foo (int i); > -}; > - > -class B : public A > -{ > -public: > - virtual int foo (int i); > -}; > - > -class C : public A > -{ > -public: > - virtual int foo (int i); > -}; > - > -int A::foo (int i) > -{ > - return i + 1; > -} > - > -int B::foo (int i) > -{ > - return i + 2; > -} > - > -int C::foo (int i) > -{ > - return i + 3; > -} > - > -int __attribute__ ((noinline)) middleman (class A *obj, int i) > -{ > - return obj->foo (i); > -} > - > -int __attribute__ ((noinline,noclone)) get_input(void) > -{ > - return 1; > -} > - > -class B b; > - > -int main (int argc, char *argv[]) > -{ > - int i; > - > - for (i = 0; i < get_input (); i++) > - if (middleman (&b, get_input ()) != 3) > - abort (); > - return 0; > -} > - > -/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int.*middleman" "inline" } } */ > -/* { dg-final { cleanup-ipa-dump "inline" } } */ > Index: icln/gcc/testsuite/g++.dg/ipa/ivinline-6.C > =================================================================== > --- icln.orig/gcc/testsuite/g++.dg/ipa/ivinline-6.C > +++ /dev/null > @@ -1,58 +0,0 @@ > -/* Verify that virtual call inlining works also when it has to get the > - type from an ipa invariant and that even in this case it does not > - pick a wrong method when there is a user defined ancestor in an > - object. */ > -/* { dg-do run } */ > -/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp" } */ > - > -extern "C" void abort (void); > - > -class A > -{ > -public: > - int data; > - virtual int foo (int i); > -}; > - > -class B : public A > -{ > -public: > - class A confusion; > - virtual int foo (int i); > -}; > - > -int A::foo (int i) > -{ > - return i + 1; > -} > - > -int B::foo (int i) > -{ > - return i + 2; > -} > - > -int middleman (class A *obj, int i) > -{ > - return obj->foo (i); > -} > - > -int __attribute__ ((noinline,noclone)) get_input(void) > -{ > - return 1; > -} > - > -class B b; > - > -int main (int argc, char *argv[]) > -{ > - int i, j = get_input (); > - > - for (i = 0; i < j; i++) > - if ((middleman (&b, j) + 100 * middleman (&b.confusion, j)) != 203) > - abort (); > - return 0; > -} > - > -/* { dg-final { scan-ipa-dump "A::foo\[^\\n\]*inline copy in int main" "inline" } } */ > -/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */ > -/* { dg-final { cleanup-ipa-dump "inline" } } */ > Index: icln/gcc/testsuite/g++.dg/tree-ssa/pr43411.C > =================================================================== > --- icln.orig/gcc/testsuite/g++.dg/tree-ssa/pr43411.C > +++ icln/gcc/testsuite/g++.dg/tree-ssa/pr43411.C > @@ -25,5 +25,5 @@ void testInlinePsub() { > sink1 = v(p); > } > > -// { dg-final { scan-tree-dump-not "OBJ_TYPE_REF" "optimized" } } > +// { dg-final { scan-tree-dump-not "OBJ_TYPE_REF" "optimized" { xfail *-*-* } } } > // { dg-final { cleanup-tree-dump "optimized" } } > Index: icln/gcc/testsuite/g++.dg/tree-ssa/pr45605.C > =================================================================== > --- icln.orig/gcc/testsuite/g++.dg/tree-ssa/pr45605.C > +++ icln/gcc/testsuite/g++.dg/tree-ssa/pr45605.C > @@ -33,5 +33,5 @@ int main() { > > > /* We should devirtualize call to D::Run */ > -/* { dg-final { scan-tree-dump-times "D::Run \\(" 1 "ssa"} } */ > +/* { dg-final { scan-tree-dump-times "D::Run \\(" 1 "ssa" { xfail *-*-* } } } */ > /* { dg-final { cleanup-tree-dump "ssa" } } */ > Index: icln/gcc/testsuite/g++.dg/otr-fold-1.C > =================================================================== > --- icln.orig/gcc/testsuite/g++.dg/otr-fold-1.C > +++ /dev/null > @@ -1,76 +0,0 @@ > -/* 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" } } */ > Index: icln/gcc/testsuite/g++.dg/otr-fold-2.C > =================================================================== > --- icln.orig/gcc/testsuite/g++.dg/otr-fold-2.C > +++ /dev/null > @@ -1,88 +0,0 @@ > -/* 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" } } */ > >
Index: icln/gcc/gimple-fold.c =================================================================== --- icln.orig/gcc/gimple-fold.c +++ icln/gcc/gimple-fold.c @@ -1364,88 +1364,6 @@ 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; - 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; - - /* Offset 0 indicates the primary base, whose vtable contents are - represented in the binfo for the derived class. */ - if (int_bit_position (field) != 0) - { - tree d_binfo; - - /* Get descendant binfo. */ - d_binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (ref, 0), - known_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) == MEM_REF)) - return known_binfo; - else - return NULL_TREE; - } -} - /* Return a declaration of a function which an OBJ_TYPE_REF references. TOKEN is integer form of OBJ_TYPE_REF_TOKEN of the reference expression. KNOWN_BINFO carries the binfo describing the true type of @@ -1529,7 +1447,7 @@ gimple_adjust_this_by_delta (gimple_stmt INPLACE is false. Return true iff the statement was changed. */ static bool -gimple_fold_obj_type_ref_call (gimple_stmt_iterator *gsi, bool inplace) +gimple_fold_obj_type_ref_call (gimple_stmt_iterator *gsi) { gimple stmt = gsi_stmt (*gsi); tree ref = gimple_call_fn (stmt); @@ -1537,27 +1455,21 @@ gimple_fold_obj_type_ref_call (gimple_st tree binfo, fndecl, delta; HOST_WIDE_INT token; - if (TREE_CODE (obj) == ADDR_EXPR) - obj = TREE_OPERAND (obj, 0); - else + if (TREE_CODE (obj) != ADDR_EXPR) return false; - - binfo = gimple_get_relevant_ref_binfo (obj, NULL_TREE); + obj = TREE_OPERAND (obj, 0); + if (!DECL_P (obj) + || TREE_CODE (TREE_TYPE (obj)) != RECORD_TYPE) + return false; + binfo = TYPE_BINFO (TREE_TYPE (obj)); if (!binfo) return false; + token = tree_low_cst (OBJ_TYPE_REF_TOKEN (ref), 1); - fndecl = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, - !DECL_P (obj)); + fndecl = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, false); if (!fndecl) return false; - - if (integer_nonzerop (delta)) - { - if (inplace) - return false; - gimple_adjust_this_by_delta (gsi, delta); - } - + gcc_assert (integer_zerop (delta)); gimple_call_set_fndecl (stmt, fndecl); return true; } @@ -1595,7 +1507,7 @@ gimple_fold_call (gimple_stmt_iterator * here where we can just smash the call operand. */ callee = gimple_call_fn (stmt); if (TREE_CODE (callee) == OBJ_TYPE_REF) - return gimple_fold_obj_type_ref_call (gsi, inplace); + return gimple_fold_obj_type_ref_call (gsi); } return false; Index: icln/gcc/gimple.h =================================================================== --- icln.orig/gcc/gimple.h +++ icln/gcc/gimple.h @@ -892,7 +892,6 @@ unsigned get_gimple_rhs_num_ops (enum tr gimple gimple_alloc_stat (enum gimple_code, unsigned MEM_STAT_DECL); const char *gimple_decl_printable_name (tree, int); bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace); -tree gimple_get_relevant_ref_binfo (tree ref, tree known_binfo); tree gimple_get_virt_mehtod_for_binfo (HOST_WIDE_INT, tree, tree *, bool); void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree); /* Returns true iff T is a valid GIMPLE statement. */ Index: icln/gcc/ipa-cp.c =================================================================== --- icln.orig/gcc/ipa-cp.c +++ icln/gcc/ipa-cp.c @@ -781,26 +781,16 @@ ipcp_propagate_types (struct ipa_node_pa struct ipa_node_params *callee_info, struct ipa_jump_func *jf, int i) { - tree cst, binfo; - switch (jf->type) { case IPA_JF_UNKNOWN: case IPA_JF_CONST_MEMBER_PTR: + case IPA_JF_CONST: break; case IPA_JF_KNOWN_TYPE: return ipcp_add_param_type (callee_info, i, jf->value.base_binfo); - case IPA_JF_CONST: - cst = jf->value.constant; - if (TREE_CODE (cst) != ADDR_EXPR) - break; - binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0), NULL_TREE); - if (!binfo) - break; - return ipcp_add_param_type (callee_info, i, binfo); - case IPA_JF_PASS_THROUGH: case IPA_JF_ANCESTOR: return ipcp_copy_types (caller_info, callee_info, i, jf); @@ -1292,35 +1282,13 @@ ipcp_discover_new_direct_edges (struct c for (ie = node->indirect_calls; ie; ie = next_ie) { struct cgraph_indirect_call_info *ici = ie->indirect_info; - tree target, delta = NULL_TREE; next_ie = ie->next_callee; - if (ici->param_index != index) + if (ici->param_index != index + || ici->polymorphic) continue; - if (ici->polymorphic) - { - tree binfo; - HOST_WIDE_INT token; - - if (TREE_CODE (cst) != ADDR_EXPR) - continue; - - binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0), - NULL_TREE); - if (!binfo) - continue; - gcc_assert (ie->indirect_info->anc_offset == 0); - token = ie->indirect_info->otr_token; - target = gimple_get_virt_mehtod_for_binfo (token, binfo, &delta, - true); - if (!target) - continue; - } - else - target = cst; - - ipa_make_edge_direct_to_target (ie, target, delta); + ipa_make_edge_direct_to_target (ie, cst, NULL_TREE); } } Index: icln/gcc/ipa-prop.c =================================================================== --- icln.orig/gcc/ipa-prop.c +++ icln/gcc/ipa-prop.c @@ -362,7 +362,7 @@ compute_complex_assign_jump_func (struct gimple stmt, tree name) { HOST_WIDE_INT offset, size, max_size; - tree op1, op2, type; + tree op1, op2, base, type; int index; op1 = gimple_assign_rhs1 (stmt); @@ -404,20 +404,21 @@ compute_complex_assign_jump_func (struct type = TREE_TYPE (op1); if (TREE_CODE (type) != RECORD_TYPE) return; - op1 = get_ref_base_and_extent (op1, &offset, &size, &max_size); - if (TREE_CODE (op1) != MEM_REF + base = get_ref_base_and_extent (op1, &offset, &size, &max_size); + if (TREE_CODE (base) != MEM_REF /* If this is a varying address, punt. */ || max_size == -1 || max_size != size) return; - offset += mem_ref_offset (op1).low * BITS_PER_UNIT; - op1 = TREE_OPERAND (op1, 0); - if (TREE_CODE (op1) != SSA_NAME - || !SSA_NAME_IS_DEFAULT_DEF (op1) + offset += mem_ref_offset (base).low * BITS_PER_UNIT; + base = TREE_OPERAND (base, 0); + if (TREE_CODE (base) != SSA_NAME + || !SSA_NAME_IS_DEFAULT_DEF (base) || offset < 0) return; - index = ipa_get_param_decl_index (info, SSA_NAME_VAR (op1)); + /* Dynamic types are changed only in constructors and destructors and */ + index = ipa_get_param_decl_index (info, SSA_NAME_VAR (base)); if (index >= 0) { jfunc->type = IPA_JF_ANCESTOR; @@ -534,13 +535,26 @@ compute_complex_ancestor_jump_func (stru static void compute_known_type_jump_func (tree op, struct ipa_jump_func *jfunc) { - tree binfo; + HOST_WIDE_INT offset, size, max_size; + tree base, binfo; - if (TREE_CODE (op) != ADDR_EXPR) + if (TREE_CODE (op) != ADDR_EXPR + || TREE_CODE (TREE_TYPE (TREE_TYPE (op))) != RECORD_TYPE) return; op = TREE_OPERAND (op, 0); - binfo = gimple_get_relevant_ref_binfo (op, NULL_TREE); + base = get_ref_base_and_extent (op, &offset, &size, &max_size); + if (!DECL_P (base) + || max_size == -1 + || max_size != size + || TREE_CODE (TREE_TYPE (base)) != RECORD_TYPE + || is_global_var (base)) + return; + + binfo = TYPE_BINFO (TREE_TYPE (base)); + if (!binfo) + return; + binfo = get_binfo_at_offset (binfo, offset, TREE_TYPE (op)); if (binfo) { jfunc->type = IPA_JF_KNOWN_TYPE; @@ -1420,17 +1434,6 @@ update_jump_functions_after_inlining (st src = ipa_get_ith_jump_func (top, dst->value.ancestor.formal_id); if (src->type == IPA_JF_KNOWN_TYPE) combine_known_type_and_ancestor_jfs (src, dst); - else if (src->type == IPA_JF_CONST) - { - struct ipa_jump_func kt_func; - - kt_func.type = IPA_JF_UNKNOWN; - compute_known_type_jump_func (src->value.constant, &kt_func); - if (kt_func.type == IPA_JF_KNOWN_TYPE) - combine_known_type_and_ancestor_jfs (&kt_func, dst); - else - dst->type = IPA_JF_UNKNOWN; - } else if (src->type == IPA_JF_PASS_THROUGH && src->value.pass_through.operation == NOP_EXPR) dst->value.ancestor.formal_id = src->value.pass_through.formal_id; @@ -1543,15 +1546,6 @@ try_make_edge_direct_virtual_call (struc if (jfunc->type == IPA_JF_KNOWN_TYPE) binfo = jfunc->value.base_binfo; - else if (jfunc->type == IPA_JF_CONST) - { - tree cst = jfunc->value.constant; - if (TREE_CODE (cst) == ADDR_EXPR) - binfo = gimple_get_relevant_ref_binfo (TREE_OPERAND (cst, 0), - NULL_TREE); - else - return NULL; - } else return NULL; Index: icln/gcc/tree.c =================================================================== --- icln.orig/gcc/tree.c +++ icln/gcc/tree.c @@ -10945,8 +10945,7 @@ get_binfo_at_offset (tree binfo, HOST_WI if (type == expected_type) return binfo; - if (TREE_CODE (type) != RECORD_TYPE - || offset < 0) + if (offset < 0) return NULL_TREE; for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld)) @@ -10959,12 +10958,18 @@ get_binfo_at_offset (tree binfo, HOST_WI if (pos <= offset && (pos + size) > offset) break; } - if (!fld || !DECL_ARTIFICIAL (fld)) + if (!fld || TREE_CODE (TREE_TYPE (fld)) != RECORD_TYPE) return NULL_TREE; + if (!DECL_ARTIFICIAL (fld)) + { + binfo = TYPE_BINFO (TREE_TYPE (fld)); + if (!binfo) + return NULL_TREE; + } /* Offset 0 indicates the primary base, whose vtable contents are represented in the binfo for the derived class. */ - if (offset != 0) + else if (offset != 0) { tree base_binfo, found_binfo = NULL_TREE; for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); i++) Index: icln/gcc/testsuite/g++.dg/ipa/ipcp-ivi-1.C =================================================================== --- icln.orig/gcc/testsuite/g++.dg/ipa/ipcp-ivi-1.C +++ /dev/null @@ -1,65 +0,0 @@ -/* Verify that simple virtual calls are inlined even without early - inlining. */ -/* { dg-do run } */ -/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining" } */ - -extern "C" void abort (void); - -class A -{ -public: - int data; - virtual int foo (int i); -}; - -class B : public A -{ -public: - virtual int foo (int i); -}; - -class C : public A -{ -public: - virtual int foo (int i); -}; - -int A::foo (int i) -{ - return i + 1; -} - -int B::foo (int i) -{ - return i + 2; -} - -int C::foo (int i) -{ - return i + 3; -} - -int __attribute__ ((noinline)) middleman (class A *obj, int i) -{ - return obj->foo (i); -} - -int __attribute__ ((noinline,noclone)) get_input(void) -{ - return 1; -} - -class B b; - -int main (int argc, char *argv[]) -{ - int i; - - for (i = 0; i < get_input (); i++) - if (middleman (&b, get_input ()) != 3) - abort (); - return 0; -} - -/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int.*middleman" "inline" } } */ -/* { dg-final { cleanup-ipa-dump "inline" } } */ Index: icln/gcc/testsuite/g++.dg/ipa/ivinline-6.C =================================================================== --- icln.orig/gcc/testsuite/g++.dg/ipa/ivinline-6.C +++ /dev/null @@ -1,58 +0,0 @@ -/* Verify that virtual call inlining works also when it has to get the - type from an ipa invariant and that even in this case it does not - pick a wrong method when there is a user defined ancestor in an - object. */ -/* { dg-do run } */ -/* { dg-options "-O3 -fdump-ipa-inline -fno-early-inlining -fno-ipa-cp" } */ - -extern "C" void abort (void); - -class A -{ -public: - int data; - virtual int foo (int i); -}; - -class B : public A -{ -public: - class A confusion; - virtual int foo (int i); -}; - -int A::foo (int i) -{ - return i + 1; -} - -int B::foo (int i) -{ - return i + 2; -} - -int middleman (class A *obj, int i) -{ - return obj->foo (i); -} - -int __attribute__ ((noinline,noclone)) get_input(void) -{ - return 1; -} - -class B b; - -int main (int argc, char *argv[]) -{ - int i, j = get_input (); - - for (i = 0; i < j; i++) - if ((middleman (&b, j) + 100 * middleman (&b.confusion, j)) != 203) - abort (); - return 0; -} - -/* { dg-final { scan-ipa-dump "A::foo\[^\\n\]*inline copy in int main" "inline" } } */ -/* { dg-final { scan-ipa-dump "B::foo\[^\\n\]*inline copy in int main" "inline" } } */ -/* { dg-final { cleanup-ipa-dump "inline" } } */ Index: icln/gcc/testsuite/g++.dg/tree-ssa/pr43411.C =================================================================== --- icln.orig/gcc/testsuite/g++.dg/tree-ssa/pr43411.C +++ icln/gcc/testsuite/g++.dg/tree-ssa/pr43411.C @@ -25,5 +25,5 @@ void testInlinePsub() { sink1 = v(p); } -// { dg-final { scan-tree-dump-not "OBJ_TYPE_REF" "optimized" } } +// { dg-final { scan-tree-dump-not "OBJ_TYPE_REF" "optimized" { xfail *-*-* } } } // { dg-final { cleanup-tree-dump "optimized" } } Index: icln/gcc/testsuite/g++.dg/tree-ssa/pr45605.C =================================================================== --- icln.orig/gcc/testsuite/g++.dg/tree-ssa/pr45605.C +++ icln/gcc/testsuite/g++.dg/tree-ssa/pr45605.C @@ -33,5 +33,5 @@ int main() { /* We should devirtualize call to D::Run */ -/* { dg-final { scan-tree-dump-times "D::Run \\(" 1 "ssa"} } */ +/* { dg-final { scan-tree-dump-times "D::Run \\(" 1 "ssa" { xfail *-*-* } } } */ /* { dg-final { cleanup-tree-dump "ssa" } } */ Index: icln/gcc/testsuite/g++.dg/otr-fold-1.C =================================================================== --- icln.orig/gcc/testsuite/g++.dg/otr-fold-1.C +++ /dev/null @@ -1,76 +0,0 @@ -/* 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" } } */ Index: icln/gcc/testsuite/g++.dg/otr-fold-2.C =================================================================== --- icln.orig/gcc/testsuite/g++.dg/otr-fold-2.C +++ /dev/null @@ -1,88 +0,0 @@ -/* 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" } } */