From: Martin Jambor Date: Tue, 19 Apr 2011 16:35:33 +0000 (+0200) Subject: ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize also according... X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=49c471e3d8e5a505b20672f7029d07bb828cbe1b;p=gcc.git ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize also according to actual contants. 2011-04-19 Martin Jambor * ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize also according to actual contants. * gimple-fold.c (gimple_extract_devirt_binfo_from_cst): New function. (gimple_fold_call): Use it. * gimple.h (gimple_extract_devirt_binfo_from_cst): Declare. * testsuite/g++.dg/opt/devirt1.C: Bump to -O2, remove XFAIL. * testsuite/g++.dg/opt/devirt2.C: New test. * testsuite/g++.dg/ipa/devirt-g-1.C: Likewise. From-SVN: r172719 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 785980d91d1..5c44ebda4f4 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,11 @@ +2011-04-19 Martin Jambor + + * ipa-cp.c (ipcp_process_devirtualization_opportunities): Devirtualize + also according to actual contants. + * gimple-fold.c (gimple_extract_devirt_binfo_from_cst): New function. + (gimple_fold_call): Use it. + * gimple.h (gimple_extract_devirt_binfo_from_cst): Declare. + 2011-04-19 Martin Jambor * ipa-prop.c (stmt_may_be_vtbl_ptr_store): Return false for scalar diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index a6e326bdd1d..8d3ab6eb1ff 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -1445,6 +1445,74 @@ gimple_adjust_this_by_delta (gimple_stmt_iterator *gsi, tree delta) gimple_call_set_arg (call_stmt, 0, tmp); } +/* Return a binfo to be used for devirtualization of calls based on an object + represented by a declaration (i.e. a global or automatically allocated one) + or NULL if it cannot be found or is not safe. CST is expected to be an + ADDR_EXPR of such object or the function will return NULL. Currently it is + safe to use such binfo only if it has no base binfo (i.e. no ancestors). */ + +tree +gimple_extract_devirt_binfo_from_cst (tree cst) +{ + HOST_WIDE_INT offset, size, max_size; + tree base, type, expected_type, binfo; + bool last_artificial = false; + + if (!flag_devirtualize + || TREE_CODE (cst) != ADDR_EXPR + || TREE_CODE (TREE_TYPE (TREE_TYPE (cst))) != RECORD_TYPE) + return NULL_TREE; + + cst = TREE_OPERAND (cst, 0); + expected_type = TREE_TYPE (cst); + base = get_ref_base_and_extent (cst, &offset, &size, &max_size); + type = TREE_TYPE (base); + if (!DECL_P (base) + || max_size == -1 + || max_size != size + || TREE_CODE (type) != RECORD_TYPE) + return NULL_TREE; + + /* Find the sub-object the constant actually refers to and mark whether it is + an artificial one (as opposed to a user-defined one). */ + while (true) + { + HOST_WIDE_INT pos, size; + tree fld; + + if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (expected_type)) + break; + if (offset < 0) + return NULL_TREE; + + for (fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld)) + { + if (TREE_CODE (fld) != FIELD_DECL) + continue; + + pos = int_bit_position (fld); + size = tree_low_cst (DECL_SIZE (fld), 1); + if (pos <= offset && (pos + size) > offset) + break; + } + if (!fld || TREE_CODE (TREE_TYPE (fld)) != RECORD_TYPE) + return NULL_TREE; + + last_artificial = DECL_ARTIFICIAL (fld); + type = TREE_TYPE (fld); + offset -= pos; + } + /* Artifical sub-objects are ancestors, we do not want to use them for + devirtualization, at least not here. */ + if (last_artificial) + return NULL_TREE; + binfo = TYPE_BINFO (type); + if (!binfo || BINFO_N_BASE_BINFOS (binfo) > 0) + return NULL_TREE; + else + return binfo; +} + /* 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. @@ -1473,10 +1541,27 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) /* Check for virtual calls that became direct calls. */ callee = gimple_call_fn (stmt); - if (TREE_CODE (callee) == OBJ_TYPE_REF - && gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE) + if (TREE_CODE (callee) == OBJ_TYPE_REF) { - gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee)); + tree binfo, fndecl, delta, obj; + HOST_WIDE_INT token; + + if (gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE) + { + gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee)); + return true; + } + + obj = OBJ_TYPE_REF_OBJECT (callee); + binfo = gimple_extract_devirt_binfo_from_cst (obj); + if (!binfo) + return false; + token = TREE_INT_CST_LOW (OBJ_TYPE_REF_TOKEN (callee)); + fndecl = gimple_get_virt_method_for_binfo (token, binfo, &delta, false); + if (!fndecl) + return false; + gcc_assert (integer_zerop (delta)); + gimple_call_set_fndecl (stmt, fndecl); return true; } diff --git a/gcc/gimple.h b/gcc/gimple.h index 9ae29c4697d..322ce99eb5c 100644 --- a/gcc/gimple.h +++ b/gcc/gimple.h @@ -898,6 +898,7 @@ const char *gimple_decl_printable_name (tree, int); bool gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace); tree gimple_get_virt_method_for_binfo (HOST_WIDE_INT, tree, tree *, bool); void gimple_adjust_this_by_delta (gimple_stmt_iterator *, tree); +tree gimple_extract_devirt_binfo_from_cst (tree); /* Returns true iff T is a valid GIMPLE statement. */ extern bool is_gimple_stmt (tree); diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index f7413f22a51..270e58a95d5 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -1246,51 +1246,71 @@ ipcp_process_devirtualization_opportunities (struct cgraph_node *node) for (ie = node->indirect_calls; ie; ie = next_ie) { - int param_index, types_count, j; + int param_index; HOST_WIDE_INT token, anc_offset; tree target, delta, otr_type; + struct ipcp_lattice *lat; next_ie = ie->next_callee; if (!ie->indirect_info->polymorphic) continue; param_index = ie->indirect_info->param_index; - if (param_index == -1 - || ipa_param_cannot_devirtualize_p (info, param_index) - || ipa_param_types_vec_empty (info, param_index)) + if (param_index == -1) continue; + lat = ipcp_get_lattice (info, param_index); token = ie->indirect_info->otr_token; anc_offset = ie->indirect_info->anc_offset; otr_type = ie->indirect_info->otr_type; target = NULL_TREE; - types_count = VEC_length (tree, info->params[param_index].types); - for (j = 0; j < types_count; j++) + if (lat->type == IPA_CONST_VALUE) { - tree binfo = VEC_index (tree, info->params[param_index].types, j); - tree d, t; - + tree binfo = gimple_extract_devirt_binfo_from_cst (lat->constant); + if (!binfo) + continue; binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); if (!binfo) - { - target = NULL_TREE; - break; - } + continue; + target = gimple_get_virt_method_for_binfo (token, binfo, &delta, + false); + } + else + { + int types_count, j; - t = gimple_get_virt_method_for_binfo (token, binfo, &d, true); - if (!t) - { - target = NULL_TREE; - break; - } - else if (!target) - { - target = t; - delta = d; - } - else if (target != t || !tree_int_cst_equal (delta, d)) + if (ipa_param_cannot_devirtualize_p (info, param_index) + || ipa_param_types_vec_empty (info, param_index)) + continue; + + types_count = VEC_length (tree, info->params[param_index].types); + for (j = 0; j < types_count; j++) { - target = NULL_TREE; - break; + tree binfo = VEC_index (tree, info->params[param_index].types, j); + tree d, t; + + binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); + if (!binfo) + { + target = NULL_TREE; + break; + } + + t = gimple_get_virt_method_for_binfo (token, binfo, &d, true); + if (!t) + { + target = NULL_TREE; + break; + } + else if (!target) + { + target = t; + delta = d; + } + else if (target != t || !tree_int_cst_equal (delta, d)) + { + target = NULL_TREE; + break; + } } } diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index bc66cbb3d4d..71c4556ea0e 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2011-04-19 Martin Jambor + + * g++.dg/opt/devirt1.C: Bump to -O2, remove XFAIL. + * g++.dg/opt/devirt2.C: New test. + * g++.dg/ipa/devirt-g-1.C: Likewise. + 2011-04-19 Tobias Burnus PR fortran/48588 diff --git a/gcc/testsuite/g++.dg/ipa/devirt-g-1.C b/gcc/testsuite/g++.dg/ipa/devirt-g-1.C new file mode 100644 index 00000000000..175f24efbbd --- /dev/null +++ b/gcc/testsuite/g++.dg/ipa/devirt-g-1.C @@ -0,0 +1,24 @@ +// { dg-do compile } +// { dg-options "-O2 -fdump-ipa-cp -fdump-tree-optimized" } + +struct S { S(); virtual void xyzzy(); void otherstuff(); }; +struct R { int a; S s; R(); }; +S s; +R r; + +void S::xyzzy () +{ + otherstuff (); + otherstuff (); +} + +static void __attribute__ ((noinline)) foo(S *p) { p->xyzzy(); } +void bar() {foo(&s); } + +static void __attribute__ ((noinline)) foh(S *p) { p->xyzzy(); } +void bah() {foh(&r.s); } + +/* { dg-final { scan-ipa-dump "Discovered a virtual call to a known target.*S::xyzzy" "cp" } } */ +/* { dg-final { scan-tree-dump-times "OBJ_TYPE_REF" 0 "optimized"} } */ +/* { dg-final { cleanup-ipa-dump "cp" } } */ +/* { dg-final { cleanup-tree-dump "optimized" } } */ diff --git a/gcc/testsuite/g++.dg/opt/devirt1.C b/gcc/testsuite/g++.dg/opt/devirt1.C index 0a825c2a590..f9b4dc2fc31 100644 --- a/gcc/testsuite/g++.dg/opt/devirt1.C +++ b/gcc/testsuite/g++.dg/opt/devirt1.C @@ -1,6 +1,6 @@ // { dg-do compile } -// { dg-options "-O" } -// { dg-final { scan-assembler "xyzzy" { xfail *-*-* } } } +// { dg-options "-O2" } +// { dg-final { scan-assembler "xyzzy" } } struct S { S(); virtual void xyzzy(); }; inline void foo(S *s) { s->xyzzy(); } diff --git a/gcc/testsuite/g++.dg/opt/devirt2.C b/gcc/testsuite/g++.dg/opt/devirt2.C new file mode 100644 index 00000000000..087dd179115 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/devirt2.C @@ -0,0 +1,11 @@ +// { dg-do compile } +// { dg-options "-O2" } +// { dg-final { scan-assembler-times "xyzzy" 2 } } + +struct S { S(); virtual void xyzzy(); }; +struct R { int a; S s; R(); }; +S s; +R r; +inline void foo(S *p) { p->xyzzy(); } +void bar() {foo(&s);} +void bah() {foo(&r.s);}