diff --git a/gcc/ChangeLog b/gcc/ChangeLog index a77d7c7670f..b38c84bc57d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2013-09-23 Jan Hubicka + + * ipa-cp.c (ipa_get_indirect_edge_target_1): Add sanity check + for ipa-devirt. + * ipa-utils.h (possible_polymorphic_call_target_p): New function. + * ipa-devirt.c (possible_polymorphic_call_target_p): Be tolerant + of external calls + * gimple-fold.c: Include ipa-utils.h and gimple-pretty-print.h + (gimple_fold_call): Dump inconsistent devirtualizations; add + sanity check for type based devirtualizations. + * ipa-prop.c: Include ipa-utils.h + (ipa_intraprocedural_devirtualization): Add sanity check. + (try_make_edge_direct_virtual_call): Likewise. + 2013-09-23 Eric Botcazou * tree-ssa-ccp.c (insert_clobber_before_stack_restore): Recurse on copy diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c index 51713e64655..c77d00bca01 100644 --- a/gcc/gimple-fold.c +++ b/gcc/gimple-fold.c @@ -30,6 +30,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa-propagate.h" #include "target.h" #include "gimple-fold.h" +#include "ipa-utils.h" +#include "gimple-pretty-print.h" /* Return true when DECL can be referenced from current unit. FROM_DECL (if non-null) specify constructor of variable DECL was taken from. @@ -1116,6 +1118,19 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) { if (gimple_call_addr_fndecl (OBJ_TYPE_REF_EXPR (callee)) != NULL_TREE) { + if (dump_file && virtual_method_call_p (callee) + && !possible_polymorphic_call_target_p + (callee, cgraph_get_node (gimple_call_addr_fndecl + (OBJ_TYPE_REF_EXPR (callee))))) + { + fprintf (dump_file, + "Type inheritnace inconsistent devirtualization of "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + fprintf (dump_file, " to "); + print_generic_expr (dump_file, callee, TDF_SLIM); + fprintf (dump_file, "\n"); + } + gimple_call_set_fn (stmt, OBJ_TYPE_REF_EXPR (callee)); changed = true; } @@ -1131,6 +1146,11 @@ gimple_fold_call (gimple_stmt_iterator *gsi, bool inplace) tree fndecl = gimple_get_virt_method_for_binfo (token, binfo); if (fndecl) { +#ifdef ENABLE_CHECKING + gcc_assert (possible_polymorphic_call_target_p + (callee, cgraph_get_node (fndecl))); + +#endif gimple_call_set_fndecl (stmt, fndecl); changed = true; } diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c index 56b27b257b4..86f5501c388 100644 --- a/gcc/ipa-cp.c +++ b/gcc/ipa-cp.c @@ -1484,6 +1484,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, HOST_WIDE_INT token, anc_offset; tree otr_type; tree t; + tree target; if (param_index == -1 || known_vals.length () <= (unsigned int) param_index) @@ -1552,7 +1553,7 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, binfo = get_binfo_at_offset (binfo, anc_offset, otr_type); if (!binfo) return NULL_TREE; - return gimple_get_virt_method_for_binfo (token, binfo); + target = gimple_get_virt_method_for_binfo (token, binfo); } else { @@ -1561,8 +1562,15 @@ ipa_get_indirect_edge_target_1 (struct cgraph_edge *ie, binfo = get_binfo_at_offset (t, anc_offset, otr_type); if (!binfo) return NULL_TREE; - return gimple_get_virt_method_for_binfo (token, binfo); + target = gimple_get_virt_method_for_binfo (token, binfo); } +#ifdef ENABLE_CHECKING + if (target) + gcc_assert (possible_polymorphic_call_target_p + (ie, cgraph_get_node (target))); +#endif + + return target; } diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c index 85bc5b0652b..c610e7bd14d 100644 --- a/gcc/ipa-devirt.c +++ b/gcc/ipa-devirt.c @@ -905,13 +905,19 @@ possible_polymorphic_call_target_p (tree otr_type, { vec targets; unsigned int i; + bool final; if (!odr_hash.is_created ()) return true; - targets = possible_polymorphic_call_targets (otr_type, otr_token); + targets = possible_polymorphic_call_targets (otr_type, otr_token, &final); for (i = 0; i < targets.length (); i++) if (n == targets[i]) return true; + + /* At a moment we allow middle end to dig out new external declarations + as a targets of polymorphic calls. */ + if (!final && !n->symbol.definition) + return true; return false; } diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c index c09ec2f0166..2fbc9d41541 100644 --- a/gcc/ipa-prop.c +++ b/gcc/ipa-prop.c @@ -38,6 +38,7 @@ along with GCC; see the file COPYING3. If not see #include "data-streamer.h" #include "tree-streamer.h" #include "params.h" +#include "ipa-utils.h" /* Intermediate information about a parameter that is only useful during the run of ipa_analyze_node and is not kept afterwards. */ @@ -2196,6 +2197,11 @@ ipa_intraprocedural_devirtualization (gimple call) token = OBJ_TYPE_REF_TOKEN (otr); fndecl = gimple_get_virt_method_for_binfo (tree_low_cst (token, 1), binfo); +#ifdef ENABLE_CHECKING + if (fndecl) + gcc_assert (possible_polymorphic_call_target_p + (otr, cgraph_get_node (fndecl))); +#endif return fndecl; } @@ -2651,7 +2657,13 @@ try_make_edge_direct_virtual_call (struct cgraph_edge *ie, return NULL; if (target) - return ipa_make_edge_direct_to_target (ie, target); + { +#ifdef ENABLE_CHECKING + gcc_assert (possible_polymorphic_call_target_p + (ie, cgraph_get_node (target))); +#endif + return ipa_make_edge_direct_to_target (ie, target); + } else return NULL; } diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h index d6f390daf15..27949e19270 100644 --- a/gcc/ipa-utils.h +++ b/gcc/ipa-utils.h @@ -108,6 +108,19 @@ possible_polymorphic_call_target_p (struct cgraph_edge *e, return possible_polymorphic_call_target_p (e->indirect_info->otr_type, e->indirect_info->otr_token, n); } + +/* Return true if N can be possibly target of a polymorphic call of + OBJ_TYPE_REF expression CALL. */ + +inline bool +possible_polymorphic_call_target_p (tree call, + struct cgraph_node *n) +{ + return possible_polymorphic_call_target_p (obj_type_ref_class (call), + tree_low_cst + (OBJ_TYPE_REF_TOKEN (call), 1), + n); +} #endif /* GCC_IPA_UTILS_H */