diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ipa-modref-tree.c | 14 | ||||
-rw-r--r-- | gcc/ipa-modref-tree.h | 25 | ||||
-rw-r--r-- | gcc/ipa-modref.c | 160 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/data-model-1.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/uninit-38.c | 2 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/uninit-pr98578.c | 2 | ||||
-rw-r--r-- | gcc/tree-ssa-alias.c | 36 |
7 files changed, 214 insertions, 26 deletions
diff --git a/gcc/ipa-modref-tree.c b/gcc/ipa-modref-tree.c index a868e3e..64ef077 100644 --- a/gcc/ipa-modref-tree.c +++ b/gcc/ipa-modref-tree.c @@ -36,7 +36,8 @@ modref_access_node::operator == (modref_access_node &a) const { if (parm_index != a.parm_index) return false; - if (parm_index != MODREF_UNKNOWN_PARM) + if (parm_index != MODREF_UNKNOWN_PARM + && parm_index != MODREF_GLOBAL_MEMORY_PARM) { if (parm_offset_known != a.parm_offset_known) return false; @@ -613,7 +614,9 @@ modref_access_node::insert (vec <modref_access_node, va_gc> *&accesses, bool modref_access_node::range_info_useful_p () const { - return parm_index != MODREF_UNKNOWN_PARM && parm_offset_known + return parm_index != MODREF_UNKNOWN_PARM + && parm_index != MODREF_GLOBAL_MEMORY_PARM + && parm_offset_known && (known_size_p (size) || known_size_p (max_size) || known_ge (offset, 0)); @@ -625,7 +628,9 @@ modref_access_node::dump (FILE *out) { if (parm_index != MODREF_UNKNOWN_PARM) { - if (parm_index >= 0) + if (parm_index == MODREF_GLOBAL_MEMORY_PARM) + fprintf (out, " Base in global memory"); + else if (parm_index >= 0) fprintf (out, " Parm %i", parm_index); else if (parm_index == MODREF_STATIC_CHAIN_PARM) fprintf (out, " Static chain"); @@ -655,7 +660,8 @@ modref_access_node::dump (FILE *out) tree modref_access_node::get_call_arg (const gcall *stmt) const { - if (parm_index == MODREF_UNKNOWN_PARM) + if (parm_index == MODREF_UNKNOWN_PARM + || parm_index == MODREF_GLOBAL_MEMORY_PARM) return NULL; if (parm_index == MODREF_STATIC_CHAIN_PARM) return gimple_call_chain (stmt); diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h index 4ad556f..94fcebd 100644 --- a/gcc/ipa-modref-tree.h +++ b/gcc/ipa-modref-tree.h @@ -48,10 +48,12 @@ enum modref_special_parms { MODREF_UNKNOWN_PARM = -1, MODREF_STATIC_CHAIN_PARM = -2, MODREF_RETSLOT_PARM = -3, + /* Used for bases that points to memory that escapes from function. */ + MODREF_GLOBAL_MEMORY_PARM = -4, /* Used in modref_parm_map to tak references which can be removed from the summary during summary update since they now points to loca memory. */ - MODREF_LOCAL_MEMORY_PARM = -4 + MODREF_LOCAL_MEMORY_PARM = -5 }; /* Modref record accesses relative to function parameters. @@ -86,6 +88,7 @@ struct GTY(()) modref_access_node bool useful_for_kill_p () const { return parm_offset_known && parm_index != MODREF_UNKNOWN_PARM + && parm_index != MODREF_GLOBAL_MEMORY_PARM && parm_index != MODREF_RETSLOT_PARM && known_size_p (size) && known_eq (max_size, size) && known_gt (size, 0); @@ -175,6 +178,7 @@ struct GTY((user)) modref_ref_node in the caller. */ gcc_checking_assert (a.parm_index >= 0 || a.parm_index == MODREF_STATIC_CHAIN_PARM + || a.parm_index == MODREF_GLOBAL_MEMORY_PARM || a.parm_index == MODREF_UNKNOWN_PARM); if (!a.useful_p ()) @@ -524,7 +528,8 @@ struct GTY((user)) modref_tree unsigned int max_accesses, modref_tree <T> *other, vec <modref_parm_map> *parm_map, modref_parm_map *static_chain_map, - bool record_accesses) + bool record_accesses, + bool promote_unknown_to_global = false) { if (!other || every_base) return false; @@ -579,7 +584,9 @@ struct GTY((user)) modref_tree { modref_access_node a = *access_node; - if (a.parm_index != MODREF_UNKNOWN_PARM && parm_map) + if (a.parm_index != MODREF_UNKNOWN_PARM + && a.parm_index != MODREF_GLOBAL_MEMORY_PARM + && parm_map) { if (a.parm_index >= (int)parm_map->length ()) a.parm_index = MODREF_UNKNOWN_PARM; @@ -596,6 +603,9 @@ struct GTY((user)) modref_tree a.parm_index = m.parm_index; } } + if (a.parm_index == MODREF_UNKNOWN_PARM + && promote_unknown_to_global) + a.parm_index = MODREF_GLOBAL_MEMORY_PARM; changed |= insert (max_bases, max_refs, max_accesses, base_node->base, ref_node->ref, a, record_accesses); @@ -614,12 +624,14 @@ struct GTY((user)) modref_tree bool merge (tree fndecl, modref_tree <T> *other, vec <modref_parm_map> *parm_map, modref_parm_map *static_chain_map, - bool record_accesses) + bool record_accesses, + bool promote_unknown_to_global = false) { return merge (opt_for_fn (fndecl, param_modref_max_bases), opt_for_fn (fndecl, param_modref_max_refs), opt_for_fn (fndecl, param_modref_max_accesses), - other, parm_map, static_chain_map, record_accesses); + other, parm_map, static_chain_map, record_accesses, + promote_unknown_to_global); } /* Copy OTHER to THIS. */ @@ -657,7 +669,8 @@ struct GTY((user)) modref_tree if (ref_node->every_access) return true; FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node) - if (access_node->parm_index == MODREF_UNKNOWN_PARM) + if (access_node->parm_index == MODREF_UNKNOWN_PARM + || access_node->parm_index == MODREF_GLOBAL_MEMORY_PARM) return true; } } diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index d6bd9d3..d3590f0 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -869,6 +869,66 @@ parm_map_for_ptr (tree op) return parm_map; } +/* Return true if ARG with EAF flags FLAGS can not make any caller's parameter + used (if LOAD is true we check loads, otherwise stores). */ + +static bool +verify_arg (tree arg, int flags, bool load) +{ + if (flags & EAF_UNUSED) + return true; + if (load && (flags & EAF_NO_DIRECT_READ)) + return true; + if (!load + && (flags & (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER)) + == (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER)) + return true; + if (is_gimple_constant (arg)) + return true; + if (DECL_P (arg) && TREE_READONLY (arg)) + return true; + if (TREE_CODE (arg) == ADDR_EXPR) + { + tree t = get_base_address (TREE_OPERAND (arg, 0)); + if (is_gimple_constant (t)) + return true; + if (DECL_P (t) + && (TREE_READONLY (t) || TREE_CODE (t) == FUNCTION_DECL)) + return true; + } + return false; +} + +/* Return true if STMT may access memory that is pointed to by parameters + of caller and which is not seen as an escape by PTA. + CALLEE_ECF_FLAGS are ECF flags of callee. If LOAD is true then by access + we mean load, otherwise we mean store. */ + +static bool +may_access_nonescaping_parm_p (gcall *call, int callee_ecf_flags, bool load) +{ + int implicit_flags = 0; + + if (ignore_stores_p (current_function_decl, callee_ecf_flags)) + implicit_flags |= ignore_stores_eaf_flags; + if (callee_ecf_flags & ECF_PURE) + implicit_flags |= implicit_pure_eaf_flags; + if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS)) + implicit_flags |= implicit_const_eaf_flags; + if (gimple_call_chain (call) + && !verify_arg (gimple_call_chain (call), + gimple_call_static_chain_flags (call) | implicit_flags, + load)) + return true; + for (unsigned int i = 0; i < gimple_call_num_args (call); i++) + if (!verify_arg (gimple_call_arg (call, i), + gimple_call_arg_flags (call, i) | implicit_flags, + load)) + return true; + return false; +} + + /* Analyze memory accesses (loads, stores and kills) performed by the function. Set also side_effects, calls_interposable and nondeterminism flags. */ @@ -892,6 +952,8 @@ private: bool record_access_p (tree); bool record_unknown_load (); bool record_unknown_store (); + bool record_global_memory_load (); + bool record_global_memory_store (); bool merge_call_side_effects (gimple *, modref_summary *, cgraph_node *, bool); modref_access_node get_access_for_fnspec (gcall *, attr_fnspec &, @@ -1149,6 +1211,41 @@ modref_access_analysis::record_unknown_store () return changed; } +/* Record unknown load from gloal memory. */ + +bool +modref_access_analysis::record_global_memory_load () +{ + bool changed = false; + modref_access_node a = {0, -1, -1, + 0, MODREF_GLOBAL_MEMORY_PARM, false, 0}; + + if (m_summary && !m_summary->loads->every_base) + changed |= m_summary->loads->insert (current_function_decl, 0, 0, a, false); + if (m_summary_lto && !m_summary_lto->loads->every_base) + changed |= m_summary_lto->loads->insert (current_function_decl, + 0, 0, a, false); + return changed; +} + +/* Record unknown store from gloal memory. */ + +bool +modref_access_analysis::record_global_memory_store () +{ + bool changed = false; + modref_access_node a = {0, -1, -1, + 0, MODREF_GLOBAL_MEMORY_PARM, false, 0}; + + if (m_summary && !m_summary->stores->every_base) + changed |= m_summary->stores->insert (current_function_decl, + 0, 0, a, false); + if (m_summary_lto && !m_summary_lto->stores->every_base) + changed |= m_summary_lto->stores->insert (current_function_decl, + 0, 0, a, false); + return changed; +} + /* Merge side effects of call STMT to function with CALLEE_SUMMARY. Return true if something changed. If IGNORE_STORES is true, do not merge stores. @@ -1160,7 +1257,8 @@ modref_access_analysis::merge_call_side_effects (gimple *stmt, modref_summary *callee_summary, cgraph_node *callee_node, bool record_adjustments) { - int flags = gimple_call_flags (stmt); + gcall *call = as_a <gcall *> (stmt); + int flags = gimple_call_flags (call); /* Nothing to do for non-looping cont functions. */ if ((flags & (ECF_CONST | ECF_NOVOPS)) @@ -1223,10 +1321,10 @@ modref_access_analysis::merge_call_side_effects fprintf (dump_file, " Parm map:"); auto_vec <modref_parm_map, 32> parm_map; - parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true); - for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) + parm_map.safe_grow_cleared (gimple_call_num_args (call), true); + for (unsigned i = 0; i < gimple_call_num_args (call); i++) { - parm_map[i] = parm_map_for_ptr (gimple_call_arg (stmt, i)); + parm_map[i] = parm_map_for_ptr (gimple_call_arg (call, i)); if (dump_file) { fprintf (dump_file, " %i", parm_map[i].parm_index); @@ -1240,9 +1338,9 @@ modref_access_analysis::merge_call_side_effects } modref_parm_map chain_map; - if (gimple_call_chain (stmt)) + if (gimple_call_chain (call)) { - chain_map = parm_map_for_ptr (gimple_call_chain (stmt)); + chain_map = parm_map_for_ptr (gimple_call_chain (call)); if (dump_file) { fprintf (dump_file, "static chain %i", chain_map.parm_index); @@ -1262,7 +1360,7 @@ modref_access_analysis::merge_call_side_effects if (m_always_executed && callee_summary->kills.length () && (!cfun->can_throw_non_call_exceptions - || !stmt_could_throw_p (cfun, stmt))) + || !stmt_could_throw_p (cfun, call))) { /* Watch for self recursive updates. */ auto_vec<modref_access_node, 32> saved_kills; @@ -1295,14 +1393,18 @@ modref_access_analysis::merge_call_side_effects changed |= m_summary->loads->merge (current_function_decl, callee_summary->loads, &parm_map, &chain_map, - record_adjustments); + record_adjustments, + !may_access_nonescaping_parm_p + (call, flags, true)); /* Merge in stores. */ if (!ignore_stores_p (current_function_decl, flags)) { changed |= m_summary->stores->merge (current_function_decl, callee_summary->stores, &parm_map, &chain_map, - record_adjustments); + record_adjustments, + !may_access_nonescaping_parm_p + (call, flags, false)); if (!m_summary->writes_errno && callee_summary->writes_errno) { @@ -1350,7 +1452,6 @@ modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec, } return a; } - /* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC. If IGNORE_STORES is true ignore them. Return false if no useful summary can be produced. */ @@ -1383,14 +1484,34 @@ modref_access_analysis::process_fnspec (gcall *call) if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL)) fprintf (dump_file, " Builtin with no fnspec: %s\n", IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call)))); - record_unknown_load (); if (!ignore_stores_p (current_function_decl, flags)) - record_unknown_store (); + { + if (!may_access_nonescaping_parm_p (call, flags, false)) + record_global_memory_store (); + else + record_unknown_store (); + if (!may_access_nonescaping_parm_p (call, flags, true)) + record_global_memory_load (); + else + record_unknown_load (); + } + else + { + if (!may_access_nonescaping_parm_p (call, flags, true)) + record_global_memory_load (); + else + record_unknown_load (); + } return; } /* Process fnspec. */ if (fnspec.global_memory_read_p ()) - record_unknown_load (); + { + if (may_access_nonescaping_parm_p (call, flags, true)) + record_unknown_load (); + else + record_global_memory_load (); + } else { for (unsigned int i = 0; i < gimple_call_num_args (call); i++) @@ -1422,7 +1543,12 @@ modref_access_analysis::process_fnspec (gcall *call) if (ignore_stores_p (current_function_decl, flags)) return; if (fnspec.global_memory_written_p ()) - record_unknown_store (); + { + if (may_access_nonescaping_parm_p (call, flags, false)) + record_unknown_store (); + else + record_global_memory_store (); + } else { for (unsigned int i = 0; i < gimple_call_num_args (call); i++) @@ -1470,6 +1596,12 @@ modref_access_analysis::analyze_call (gcall *stmt) simplified. */ int flags = gimple_call_flags (stmt); + if (dump_file) + { + fprintf (dump_file, " - Analyzing call:"); + print_gimple_stmt (dump_file, stmt, 0); + } + if ((flags & (ECF_CONST | ECF_NOVOPS)) && !(flags & ECF_LOOPING_CONST_OR_PURE)) { diff --git a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c index 908d999..511ed4b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/data-model-1.c +++ b/gcc/testsuite/gcc.dg/analyzer/data-model-1.c @@ -1,4 +1,5 @@ /* { dg-require-effective-target alloca } */ +/* { dg-additional-options "-fno-ipa-modref" } */ #include <stdlib.h> #include <string.h> diff --git a/gcc/testsuite/gcc.dg/uninit-38.c b/gcc/testsuite/gcc.dg/uninit-38.c index 0d70bcd..ff2aee6 100644 --- a/gcc/testsuite/gcc.dg/uninit-38.c +++ b/gcc/testsuite/gcc.dg/uninit-38.c @@ -6,7 +6,7 @@ be adjusted. Ditto if -Wuninitialized output changes for some other reason. { dg-do compile { target { { lp64 || ilp32 } || llp64 } } } - { dg-options "-O2 -Wall -ftrack-macro-expansion=0" } */ + { dg-options "-O2 -Wall -ftrack-macro-expansion=0 -fno-ipa-modref" } */ #define CONCAT(x, y) x ## y #define CAT(x, y) CONCAT(x, y) diff --git a/gcc/testsuite/gcc.dg/uninit-pr98578.c b/gcc/testsuite/gcc.dg/uninit-pr98578.c index 98d6117..745328b 100644 --- a/gcc/testsuite/gcc.dg/uninit-pr98578.c +++ b/gcc/testsuite/gcc.dg/uninit-pr98578.c @@ -1,6 +1,6 @@ /* PR middle-end/98578 - ICE warning on uninitialized VLA access { dg-do compile } - { dg-options "-O2 -Wall" } */ + { dg-options "-O2 -Wall -fno-ipa-modref" } */ void* malloc (__SIZE_TYPE__); diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index 88fd782..0112989 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2544,6 +2544,30 @@ refs_output_dependent_p (tree store1, tree store2) return refs_may_alias_p_1 (&r1, &r2, false); } +/* Return ture if REF may access global memory. */ + +bool +ref_may_access_global_memory_p (ao_ref *ref) +{ + if (!ref->ref) + return true; + tree base = ao_ref_base (ref); + if (TREE_CODE (base) == MEM_REF + || TREE_CODE (base) == TARGET_MEM_REF) + { + if (ptr_deref_may_alias_global_p (TREE_OPERAND (base, 0))) + return true; + } + else + { + if (!auto_var_in_fn_p (base, current_function_decl) + || pt_solution_includes (&cfun->gimple_df->escaped, + base)) + return true; + } + return false; +} + /* Returns true if and only if REF may alias any access stored in TT. IF TBAA_P is true, use TBAA oracle. */ @@ -2552,6 +2576,7 @@ modref_may_conflict (const gcall *stmt, modref_tree <alias_set_type> *tt, ao_ref *ref, bool tbaa_p) { alias_set_type base_set, ref_set; + bool global_memory_ok = false; if (tt->every_base) return true; @@ -2602,6 +2627,17 @@ modref_may_conflict (const gcall *stmt, if (num_tests >= max_tests) return true; + if (access_node.parm_index == MODREF_GLOBAL_MEMORY_PARM) + { + if (global_memory_ok) + continue; + if (ref_may_access_global_memory_p (ref)) + return true; + global_memory_ok = true; + num_tests++; + continue; + } + tree arg = access_node.get_call_arg (stmt); if (!arg) return true; |