diff options
Diffstat (limited to 'gcc/tree-ssa-alias.c')
-rw-r--r-- | gcc/tree-ssa-alias.c | 207 |
1 files changed, 146 insertions, 61 deletions
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 29be1f8..093d65c 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -116,10 +116,14 @@ static struct { unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_may_alias; unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_must_overlap; unsigned HOST_WIDE_INT nonoverlapping_refs_since_match_p_no_alias; + unsigned HOST_WIDE_INT stmt_kills_ref_p_no; + unsigned HOST_WIDE_INT stmt_kills_ref_p_yes; unsigned HOST_WIDE_INT modref_use_may_alias; unsigned HOST_WIDE_INT modref_use_no_alias; unsigned HOST_WIDE_INT modref_clobber_may_alias; unsigned HOST_WIDE_INT modref_clobber_no_alias; + unsigned HOST_WIDE_INT modref_kill_no; + unsigned HOST_WIDE_INT modref_kill_yes; unsigned HOST_WIDE_INT modref_tests; unsigned HOST_WIDE_INT modref_baseptr_tests; } alias_stats; @@ -146,6 +150,12 @@ dump_alias_stats (FILE *s) alias_stats.call_may_clobber_ref_p_no_alias, alias_stats.call_may_clobber_ref_p_no_alias + alias_stats.call_may_clobber_ref_p_may_alias); + fprintf (s, " stmt_kills_ref_p: " + HOST_WIDE_INT_PRINT_DEC" kills, " + HOST_WIDE_INT_PRINT_DEC" queries\n", + alias_stats.stmt_kills_ref_p_yes + alias_stats.modref_kill_yes, + alias_stats.stmt_kills_ref_p_yes + alias_stats.modref_kill_yes + + alias_stats.stmt_kills_ref_p_no + alias_stats.modref_kill_no); fprintf (s, " nonoverlapping_component_refs_p: " HOST_WIDE_INT_PRINT_DEC" disambiguations, " HOST_WIDE_INT_PRINT_DEC" queries\n", @@ -169,6 +179,12 @@ dump_alias_stats (FILE *s) + alias_stats.aliasing_component_refs_p_may_alias); dump_alias_stats_in_alias_c (s); fprintf (s, "\nModref stats:\n"); + fprintf (s, " modref kill: " + HOST_WIDE_INT_PRINT_DEC" kills, " + HOST_WIDE_INT_PRINT_DEC" queries\n", + alias_stats.modref_kill_yes, + alias_stats.modref_kill_yes + + alias_stats.modref_kill_no); fprintf (s, " modref use: " HOST_WIDE_INT_PRINT_DEC" disambiguations, " HOST_WIDE_INT_PRINT_DEC" queries\n", @@ -3220,6 +3236,51 @@ same_addr_size_stores_p (tree base1, poly_int64 offset1, poly_int64 size1, && known_eq (wi::to_poly_offset (DECL_SIZE (obj)), size1)); } +/* Return true if REF is killed by an store described by + BASE, OFFSET, SIZE and MAX_SIZE. */ + +static bool +store_kills_ref_p (tree base, poly_int64 offset, poly_int64 size, + poly_int64 max_size, ao_ref *ref) +{ + poly_int64 ref_offset = ref->offset; + /* We can get MEM[symbol: sZ, index: D.8862_1] here, + so base == ref->base does not always hold. */ + if (base != ref->base) + { + /* Try using points-to info. */ + if (same_addr_size_stores_p (base, offset, size, max_size, ref->base, + ref->offset, ref->size, ref->max_size)) + return true; + + /* If both base and ref->base are MEM_REFs, only compare the + first operand, and if the second operand isn't equal constant, + try to add the offsets into offset and ref_offset. */ + if (TREE_CODE (base) == MEM_REF && TREE_CODE (ref->base) == MEM_REF + && TREE_OPERAND (base, 0) == TREE_OPERAND (ref->base, 0)) + { + if (!tree_int_cst_equal (TREE_OPERAND (base, 1), + TREE_OPERAND (ref->base, 1))) + { + poly_offset_int off1 = mem_ref_offset (base); + off1 <<= LOG2_BITS_PER_UNIT; + off1 += offset; + poly_offset_int off2 = mem_ref_offset (ref->base); + off2 <<= LOG2_BITS_PER_UNIT; + off2 += ref_offset; + if (!off1.to_shwi (&offset) || !off2.to_shwi (&ref_offset)) + size = -1; + } + } + else + size = -1; + } + /* For a must-alias check we need to be able to constrain + the access properly. */ + return (known_eq (size, max_size) + && known_subrange_p (ref_offset, ref->max_size, offset, size)); +} + /* If STMT kills the memory reference REF return true, otherwise return false. */ @@ -3293,7 +3354,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) && operand_equal_p (lhs, base, OEP_ADDRESS_OF | OEP_MATCH_SIDE_EFFECTS)))) - return true; + { + ++alias_stats.stmt_kills_ref_p_yes; + return true; + } } /* Now look for non-literal equal bases with the restriction of @@ -3301,52 +3365,72 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) /* For a must-alias check we need to be able to constrain the access properly. */ if (!ref->max_size_known_p ()) - return false; - poly_int64 size, offset, max_size, ref_offset = ref->offset; + { + ++alias_stats.stmt_kills_ref_p_no; + return false; + } + poly_int64 size, offset, max_size; bool reverse; tree base = get_ref_base_and_extent (lhs, &offset, &size, &max_size, &reverse); - /* We can get MEM[symbol: sZ, index: D.8862_1] here, - so base == ref->base does not always hold. */ - if (base != ref->base) + if (store_kills_ref_p (base, offset, size, max_size, ref)) { - /* Try using points-to info. */ - if (same_addr_size_stores_p (base, offset, size, max_size, ref->base, - ref->offset, ref->size, ref->max_size)) - return true; - - /* If both base and ref->base are MEM_REFs, only compare the - first operand, and if the second operand isn't equal constant, - try to add the offsets into offset and ref_offset. */ - if (TREE_CODE (base) == MEM_REF && TREE_CODE (ref->base) == MEM_REF - && TREE_OPERAND (base, 0) == TREE_OPERAND (ref->base, 0)) - { - if (!tree_int_cst_equal (TREE_OPERAND (base, 1), - TREE_OPERAND (ref->base, 1))) - { - poly_offset_int off1 = mem_ref_offset (base); - off1 <<= LOG2_BITS_PER_UNIT; - off1 += offset; - poly_offset_int off2 = mem_ref_offset (ref->base); - off2 <<= LOG2_BITS_PER_UNIT; - off2 += ref_offset; - if (!off1.to_shwi (&offset) || !off2.to_shwi (&ref_offset)) - size = -1; - } - } - else - size = -1; + ++alias_stats.stmt_kills_ref_p_yes; + return true; } - /* For a must-alias check we need to be able to constrain - the access properly. */ - if (known_eq (size, max_size) - && known_subrange_p (ref_offset, ref->max_size, offset, size)) - return true; } if (is_gimple_call (stmt)) { tree callee = gimple_call_fndecl (stmt); + struct cgraph_node *node; + modref_summary *summary; + + /* Try to disambiguate using modref summary. Modref records a vector + of stores with known offsets relative to function parameters that must + happen every execution of function. Find if we have a matching + store and verify that function can not use the value. */ + if (callee != NULL_TREE + && (node = cgraph_node::get (callee)) != NULL + && node->binds_to_current_def_p () + && (summary = get_modref_function_summary (node)) != NULL + && summary->kills.length () + && (!cfun->can_throw_non_call_exceptions + || !stmt_can_throw_internal (cfun, stmt))) + { + for (auto kill : summary->kills) + { + ao_ref dref; + + /* We only can do useful compares if we know the access range + precisely. */ + if (!kill.get_ao_ref (as_a <gcall *> (stmt), &dref)) + continue; + if (store_kills_ref_p (ao_ref_base (&dref), dref.offset, + dref.size, dref.max_size, ref)) + { + /* For store to be killed it needs to not be used + earlier. */ + if (ref_maybe_used_by_call_p_1 (as_a <gcall *> (stmt), ref, + true) + || !dbg_cnt (ipa_mod_ref)) + break; + if (dump_file && (dump_flags & TDF_DETAILS)) + { + fprintf (dump_file, + "ipa-modref: call stmt "); + print_gimple_stmt (dump_file, stmt, 0); + fprintf (dump_file, + "ipa-modref: call to %s kills ", + node->dump_name ()); + print_generic_expr (dump_file, ref->base); + } + ++alias_stats.modref_kill_yes; + return true; + } + } + ++alias_stats.modref_kill_no; + } if (callee != NULL_TREE && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) switch (DECL_FUNCTION_CODE (callee)) @@ -3357,7 +3441,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) tree base = ao_ref_base (ref); if (base && TREE_CODE (base) == MEM_REF && TREE_OPERAND (base, 0) == ptr) - return true; + { + ++alias_stats.stmt_kills_ref_p_yes; + return true; + } break; } @@ -3376,7 +3463,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) /* For a must-alias check we need to be able to constrain the access properly. */ if (!ref->max_size_known_p ()) - return false; + { + ++alias_stats.stmt_kills_ref_p_no; + return false; + } tree dest; tree len; @@ -3391,11 +3481,17 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) tree arg1 = gimple_call_arg (stmt, 1); if (TREE_CODE (arg0) != INTEGER_CST || TREE_CODE (arg1) != INTEGER_CST) - return false; + { + ++alias_stats.stmt_kills_ref_p_no; + return false; + } dest = gimple_call_lhs (stmt); if (!dest) - return false; + { + ++alias_stats.stmt_kills_ref_p_no; + return false; + } len = fold_build2 (MULT_EXPR, TREE_TYPE (arg0), arg0, arg1); } else @@ -3405,29 +3501,14 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) } if (!poly_int_tree_p (len)) return false; - tree rbase = ref->base; - poly_offset_int roffset = ref->offset; ao_ref dref; ao_ref_init_from_ptr_and_size (&dref, dest, len); - tree base = ao_ref_base (&dref); - poly_offset_int offset = dref.offset; - if (!base || !known_size_p (dref.size)) - return false; - if (TREE_CODE (base) == MEM_REF) + if (store_kills_ref_p (ao_ref_base (&dref), dref.offset, + dref.size, dref.max_size, ref)) { - if (TREE_CODE (rbase) != MEM_REF) - return false; - // Compare pointers. - offset += mem_ref_offset (base) << LOG2_BITS_PER_UNIT; - roffset += mem_ref_offset (rbase) << LOG2_BITS_PER_UNIT; - base = TREE_OPERAND (base, 0); - rbase = TREE_OPERAND (rbase, 0); + ++alias_stats.stmt_kills_ref_p_yes; + return true; } - if (base == rbase - && known_subrange_p (roffset, ref->max_size, offset, - wi::to_poly_offset (len) - << LOG2_BITS_PER_UNIT)) - return true; break; } @@ -3438,7 +3519,10 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) { tree base = ao_ref_base (ref); if (TREE_OPERAND (ptr, 0) == base) - return true; + { + ++alias_stats.stmt_kills_ref_p_yes; + return true; + } } break; } @@ -3446,6 +3530,7 @@ stmt_kills_ref_p (gimple *stmt, ao_ref *ref) default:; } } + ++alias_stats.stmt_kills_ref_p_no; return false; } |