From: Jan Hubicka Date: Mon, 8 Nov 2021 06:52:45 +0000 (+0100) Subject: Add loads/stores relative to static chain in ipa-modref X-Git-Tag: upstream/12.2.0~3709 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=1f3a33633dd06a8e4861180ab20c9136361c69e6;p=platform%2Fupstream%2Fgcc.git Add loads/stores relative to static chain in ipa-modref Adds tracking of accesses relative to static chain into modref load/stores analysis. This helps some Fortran benchmarks however it is still quite limited. One problem is that we never discover functions with nested functions as const, pure or not accessing global memory because it contains __builtin_dward_cfa call which we believe to be non-pure. Bootstrapped/regtested x86_64-linux. Plan to commit it tomorrow if there are no complains and once periodic testers picks today modref changes. Honza gcc/ChangeLog: * ipa-modref-tree.h (enum modref_special_parms): New enum. (struct modref_access_node): update for special parms. (struct modref_ref_node): Likewise. (struct modref_parm_map): Likewise. (struct modref_tree): Likewise. * ipa-modref.c (dump_access): Likewise. (get_access): Detect static chain. (parm_map_for_arg): Take tree as arg instead of stmt and index. (merge_call_side_effects): Compute map for static chain. (process_fnspec): Update. (struct escape_point): Remove retslot_arg and static_chain_arg. (analyze_parms): Update. (compute_parm_map): Update. (propagate_unknown_call): Update. (modref_propagate_in_scc): Update. (modref_merge_call_site_flags): Update. (ipa_merge_modref_summary_after_inlining): Update. * tree-ssa-alias.c (modref_may_conflict): Handle static chain. * ipa-modref-tree.c (test_merge): Update. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/modref-12.c: New test. --- diff --git a/gcc/ipa-modref-tree.c b/gcc/ipa-modref-tree.c index 8d147a1..d0ee487 100644 --- a/gcc/ipa-modref-tree.c +++ b/gcc/ipa-modref-tree.c @@ -138,7 +138,7 @@ test_merge () t2->insert (3, 4, a, false); t2->insert (3, 5, a, false); - t1->merge (t2, NULL, false); + t1->merge (t2, NULL, NULL, false); ASSERT_FALSE (t1->every_base); ASSERT_NE (t1->bases, NULL); diff --git a/gcc/ipa-modref-tree.h b/gcc/ipa-modref-tree.h index 54ae9e1..be5efcb 100644 --- a/gcc/ipa-modref-tree.h +++ b/gcc/ipa-modref-tree.h @@ -42,6 +42,18 @@ along with GCC; see the file COPYING3. If not see struct ipa_modref_summary; +/* parm indexes greater than 0 are normal parms. + Some negative values have special meaning. */ +enum modref_special_parms { + MODREF_UNKNOWN_PARM = -1, + MODREF_STATIC_CHAIN_PARM = -2, + MODREF_RETSLOT_PARM = -3, + /* 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 +}; + /* Memory access. */ struct GTY(()) modref_access_node { @@ -65,12 +77,12 @@ struct GTY(()) modref_access_node /* Return true if access node holds no useful info. */ bool useful_p () const { - return parm_index != -1; + return parm_index != MODREF_UNKNOWN_PARM; } /* Return true if range info is useful. */ bool range_info_useful_p () const { - return parm_index != -1 && parm_offset_known + return parm_index != MODREF_UNKNOWN_PARM && parm_offset_known && (known_size_p (size) || known_size_p (max_size) || known_ge (offset, 0)); @@ -80,7 +92,7 @@ struct GTY(()) modref_access_node { if (parm_index != a.parm_index) return false; - if (parm_index >= 0) + if (parm_index != MODREF_UNKNOWN_PARM) { if (parm_offset_known != a.parm_offset_known) return false; @@ -101,7 +113,7 @@ struct GTY(()) modref_access_node bool contains (const modref_access_node &a) const { poly_int64 aoffset_adj = 0; - if (parm_index >= 0) + if (parm_index != MODREF_UNKNOWN_PARM) { if (parm_index != a.parm_index) return false; @@ -211,7 +223,7 @@ struct GTY(()) modref_access_node /* We assume that containment was tested earlier. */ gcc_checking_assert (!contains (a) && !a.contains (*this)); - if (parm_index >= 0) + if (parm_index != MODREF_UNKNOWN_PARM) { if (parm_index != a.parm_index) return false; @@ -350,8 +362,8 @@ struct GTY(()) modref_access_node { if (parm_index != a.parm_index) { - gcc_checking_assert (parm_index != -1); - parm_index = -1; + gcc_checking_assert (parm_index != MODREF_UNKNOWN_PARM); + parm_index = MODREF_UNKNOWN_PARM; return; } @@ -454,7 +466,7 @@ private: /* Access node specifying no useful info. */ const modref_access_node unspecified_modref_access_node - = {0, -1, -1, 0, -1, false, 0}; + = {0, -1, -1, 0, MODREF_UNKNOWN_PARM, false, 0}; template struct GTY((user)) modref_ref_node @@ -506,6 +518,12 @@ struct GTY((user)) modref_ref_node size_t i, j; modref_access_node *a2; + /* Only the following kind of paramters needs to be tracked. + We do not track return slots because they are seen as a direct store + in the caller. */ + gcc_checking_assert (a.parm_index >= 0 + || a.parm_index == MODREF_STATIC_CHAIN_PARM + || a.parm_index == MODREF_UNKNOWN_PARM); if (flag_checking) verify (); @@ -734,9 +752,7 @@ struct GTY((user)) modref_base_node struct modref_parm_map { /* Index of parameter we translate to. - -1 indicates that parameter is unknown - -2 indicates that parameter points to local memory and access can be - discarded. */ + Values from special_params enum are permitted too. */ int parm_index; bool parm_offset_known; poly_int64 parm_offset; @@ -946,10 +962,11 @@ struct GTY((user)) modref_tree } /* Merge OTHER into the tree. - PARM_MAP, if non-NULL, maps parm indexes of callee to caller. -2 is used - to signalize that parameter is local and does not need to be tracked. + PARM_MAP, if non-NULL, maps parm indexes of callee to caller. + Similar CHAIN_MAP, if non-NULL, maps static chain of callee to caller. Return true if something has changed. */ bool merge (modref_tree *other, vec *parm_map, + modref_parm_map *static_chain_map, bool record_accesses) { if (!other || every_base) @@ -1003,21 +1020,21 @@ struct GTY((user)) modref_tree { modref_access_node a = *access_node; - if (a.parm_index != -1 && parm_map) + if (a.parm_index != MODREF_UNKNOWN_PARM && parm_map) { if (a.parm_index >= (int)parm_map->length ()) - a.parm_index = -1; - else if ((*parm_map) [a.parm_index].parm_index == -2) - continue; + a.parm_index = MODREF_UNKNOWN_PARM; else { - a.parm_offset - += (*parm_map) [a.parm_index].parm_offset; - a.parm_offset_known - &= (*parm_map) - [a.parm_index].parm_offset_known; - a.parm_index - = (*parm_map) [a.parm_index].parm_index; + modref_parm_map &m + = a.parm_index == MODREF_STATIC_CHAIN_PARM + ? *static_chain_map + : (*parm_map) [a.parm_index]; + if (m.parm_index == MODREF_LOCAL_MEMORY_PARM) + continue; + a.parm_offset += m.parm_offset; + a.parm_offset_known &= m.parm_offset_known; + a.parm_index = m.parm_index; } } changed |= insert (base_node->base, ref_node->ref, a, @@ -1033,7 +1050,7 @@ struct GTY((user)) modref_tree /* Copy OTHER to THIS. */ void copy_from (modref_tree *other) { - merge (other, NULL, false); + merge (other, NULL, NULL, false); } /* Search BASE in tree; return NULL if failed. */ @@ -1065,7 +1082,7 @@ 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 < 0) + if (access_node->parm_index == MODREF_UNKNOWN_PARM) return true; } } @@ -1127,7 +1144,7 @@ struct GTY((user)) modref_tree if (access_node->parm_index < (int)map->length ()) access_node->parm_index = (*map)[access_node->parm_index]; else - access_node->parm_index = -1; + access_node->parm_index = MODREF_UNKNOWN_PARM; } } } diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c index 4e64ee5..4429bce 100644 --- a/gcc/ipa-modref.c +++ b/gcc/ipa-modref.c @@ -426,9 +426,14 @@ static void dump_access (modref_access_node *a, FILE *out) { fprintf (out, " access:"); - if (a->parm_index != -1) + if (a->parm_index != MODREF_UNKNOWN_PARM) { - fprintf (out, " Parm %i", a->parm_index); + if (a->parm_index >= 0) + fprintf (out, " Parm %i", a->parm_index); + else if (a->parm_index == MODREF_STATIC_CHAIN_PARM) + fprintf (out, " Static chain"); + else + gcc_unreachable (); if (a->parm_offset_known) { fprintf (out, " param offset:"); @@ -697,40 +702,40 @@ get_access (ao_ref *ref) base = ao_ref_base (ref); modref_access_node a = {ref->offset, ref->size, ref->max_size, - 0, -1, false, 0}; + 0, MODREF_UNKNOWN_PARM, false, 0}; if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF) { tree memref = base; base = TREE_OPERAND (base, 0); + if (TREE_CODE (base) == SSA_NAME && SSA_NAME_IS_DEFAULT_DEF (base) && TREE_CODE (SSA_NAME_VAR (base)) == PARM_DECL) { a.parm_index = 0; - for (tree t = DECL_ARGUMENTS (current_function_decl); - t != SSA_NAME_VAR (base); t = DECL_CHAIN (t)) - { - if (!t) - { - a.parm_index = -1; - break; - } - a.parm_index++; - } - if (TREE_CODE (memref) == MEM_REF) - { - a.parm_offset_known - = wi::to_poly_wide (TREE_OPERAND - (memref, 1)).to_shwi (&a.parm_offset); - } + if (cfun->static_chain_decl + && base == ssa_default_def (cfun, cfun->static_chain_decl)) + a.parm_index = MODREF_STATIC_CHAIN_PARM; else - a.parm_offset_known = false; + for (tree t = DECL_ARGUMENTS (current_function_decl); + t != SSA_NAME_VAR (base); t = DECL_CHAIN (t)) + a.parm_index++; + } + else + a.parm_index = MODREF_UNKNOWN_PARM; + + if (a.parm_index != MODREF_UNKNOWN_PARM + && TREE_CODE (memref) == MEM_REF) + { + a.parm_offset_known + = wi::to_poly_wide (TREE_OPERAND + (memref, 1)).to_shwi (&a.parm_offset); } else - a.parm_index = -1; + a.parm_offset_known = false; } else - a.parm_index = -1; + a.parm_index = MODREF_UNKNOWN_PARM; return a; } @@ -858,12 +863,11 @@ ignore_stores_p (tree caller, int flags) return false; } -/* Determine parm_map for argument I of STMT. */ +/* Determine parm_map for argument OP. */ modref_parm_map -parm_map_for_arg (gimple *stmt, int i) +parm_map_for_arg (tree op) { - tree op = gimple_call_arg (stmt, i); bool offset_known; poly_int64 offset; struct modref_parm_map parm_map; @@ -882,7 +886,7 @@ parm_map_for_arg (gimple *stmt, int i) { if (!t) { - index = -1; + index = MODREF_UNKNOWN_PARM; break; } index++; @@ -892,9 +896,9 @@ parm_map_for_arg (gimple *stmt, int i) parm_map.parm_offset = offset; } else if (points_to_local_or_readonly_memory_p (op)) - parm_map.parm_index = -2; + parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM; else - parm_map.parm_index = -1; + parm_map.parm_index = MODREF_UNKNOWN_PARM; return parm_map; } @@ -911,6 +915,7 @@ merge_call_side_effects (modref_summary *cur_summary, bool record_adjustments) { auto_vec parm_map; + modref_parm_map chain_map; bool changed = false; /* We can not safely optimize based on summary of callee if it does @@ -931,7 +936,7 @@ merge_call_side_effects (modref_summary *cur_summary, parm_map.safe_grow_cleared (gimple_call_num_args (stmt), true); for (unsigned i = 0; i < gimple_call_num_args (stmt); i++) { - parm_map[i] = parm_map_for_arg (stmt, i); + parm_map[i] = parm_map_for_arg (gimple_call_arg (stmt, i)); if (dump_file) { fprintf (dump_file, " %i", parm_map[i].parm_index); @@ -943,16 +948,30 @@ merge_call_side_effects (modref_summary *cur_summary, } } } + if (gimple_call_chain (stmt)) + { + chain_map = parm_map_for_arg (gimple_call_chain (stmt)); + if (dump_file) + { + fprintf (dump_file, "static chain %i", chain_map.parm_index); + if (chain_map.parm_offset_known) + { + fprintf (dump_file, " offset:"); + print_dec ((poly_int64_pod)chain_map.parm_offset, + dump_file, SIGNED); + } + } + } if (dump_file) fprintf (dump_file, "\n"); /* Merge with callee's summary. */ changed |= cur_summary->loads->merge (callee_summary->loads, &parm_map, - record_adjustments); + &chain_map, record_adjustments); if (!ignore_stores) { changed |= cur_summary->stores->merge (callee_summary->stores, - &parm_map, + &parm_map, &chain_map, record_adjustments); if (!cur_summary->writes_errno && callee_summary->writes_errno) @@ -1078,11 +1097,12 @@ process_fnspec (modref_summary *cur_summary, else if (!fnspec.arg_specified_p (i) || fnspec.arg_maybe_read_p (i)) { - modref_parm_map map = parm_map_for_arg (call, i); + modref_parm_map map = parm_map_for_arg + (gimple_call_arg (call, i)); - if (map.parm_index == -2) + if (map.parm_index == MODREF_LOCAL_MEMORY_PARM) continue; - if (map.parm_index == -1) + if (map.parm_index == MODREF_UNKNOWN_PARM) { collapse_loads (cur_summary, cur_summary_lto); break; @@ -1113,11 +1133,12 @@ process_fnspec (modref_summary *cur_summary, else if (!fnspec.arg_specified_p (i) || fnspec.arg_maybe_written_p (i)) { - modref_parm_map map = parm_map_for_arg (call, i); + modref_parm_map map = parm_map_for_arg + (gimple_call_arg (call, i)); - if (map.parm_index == -2) + if (map.parm_index == MODREF_LOCAL_MEMORY_PARM) continue; - if (map.parm_index == -1) + if (map.parm_index == MODREF_UNKNOWN_PARM) { collapse_stores (cur_summary, cur_summary_lto); break; @@ -1429,12 +1450,6 @@ deref_flags (int flags, bool ignore_stores) struct escape_point { - /* Extra hidden args we keep track of. */ - enum hidden_args - { - retslot_arg = -1, - static_chain_arg = -2 - }; /* Value escapes to this call. */ gcall *call; /* Argument it escapes to. */ @@ -2410,7 +2425,7 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto, if (summary_lto) summary_lto->retslot_flags = flags; eaf_analysis.record_escape_points (retslot, - escape_point::retslot_arg, flags); + MODREF_RETSLOT_PARM, flags); } } if (static_chain) @@ -2425,7 +2440,7 @@ analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto, if (summary_lto) summary_lto->static_chain_flags = flags; eaf_analysis.record_escape_points (static_chain, - escape_point::static_chain_arg, + MODREF_STATIC_CHAIN_PARM, flags); } } @@ -3586,7 +3601,7 @@ compute_parm_map (cgraph_edge *callee_edge, vec *parm_map) { if (es && es->param[i].points_to_local_or_readonly_memory) { - (*parm_map)[i].parm_index = -2; + (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM; continue; } @@ -3600,7 +3615,7 @@ compute_parm_map (cgraph_edge *callee_edge, vec *parm_map) (callee_pi, i)); if (cst && points_to_local_or_readonly_memory_p (cst)) { - (*parm_map)[i].parm_index = -2; + (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM; continue; } } @@ -3798,9 +3813,9 @@ propagate_unknown_call (cgraph_node *node, || fnspec.arg_maybe_read_p (i)) { modref_parm_map map = parm_map[i]; - if (map.parm_index == -2) + if (map.parm_index == MODREF_LOCAL_MEMORY_PARM) continue; - if (map.parm_index == -1) + if (map.parm_index == MODREF_UNKNOWN_PARM) { collapse_loads (cur_summary, cur_summary_lto); break; @@ -3828,9 +3843,9 @@ propagate_unknown_call (cgraph_node *node, || fnspec.arg_maybe_written_p (i)) { modref_parm_map map = parm_map[i]; - if (map.parm_index == -2) + if (map.parm_index == MODREF_LOCAL_MEMORY_PARM) continue; - if (map.parm_index == -1) + if (map.parm_index == MODREF_UNKNOWN_PARM) { collapse_stores (cur_summary, cur_summary_lto); break; @@ -4030,6 +4045,10 @@ modref_propagate_in_scc (cgraph_node *component_node) auto_vec parm_map; + modref_parm_map chain_map; + /* TODO: Once we get jump functions for static chains we could + compute this. */ + chain_map.parm_index = MODREF_UNKNOWN_PARM; compute_parm_map (callee_edge, &parm_map); @@ -4037,12 +4056,13 @@ modref_propagate_in_scc (cgraph_node *component_node) if (callee_summary) { changed |= cur_summary->loads->merge - (callee_summary->loads, &parm_map, !first); + (callee_summary->loads, &parm_map, + &chain_map, !first); if (!ignore_stores) { changed |= cur_summary->stores->merge (callee_summary->stores, &parm_map, - !first); + &chain_map, !first); if (!cur_summary->writes_errno && callee_summary->writes_errno) { @@ -4055,12 +4075,12 @@ modref_propagate_in_scc (cgraph_node *component_node) { changed |= cur_summary_lto->loads->merge (callee_summary_lto->loads, &parm_map, - !first); + &chain_map, !first); if (!ignore_stores) { changed |= cur_summary_lto->stores->merge (callee_summary_lto->stores, &parm_map, - !first); + &chain_map, !first); if (!cur_summary_lto->writes_errno && callee_summary_lto->writes_errno) { @@ -4223,9 +4243,9 @@ modref_merge_call_site_flags (escape_summary *sum, if (!(flags & EAF_UNUSED) && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ()) { - eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg + eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM ? cur_summary->retslot_flags - : ee->parm_index == escape_point::static_chain_arg + : ee->parm_index == MODREF_STATIC_CHAIN_PARM ? cur_summary->static_chain_flags : cur_summary->arg_flags[ee->parm_index]; if ((f & flags) != f) @@ -4240,9 +4260,9 @@ modref_merge_call_site_flags (escape_summary *sum, && cur_summary_lto && ee->parm_index < (int)cur_summary_lto->arg_flags.length ()) { - eaf_flags_t &f = ee->parm_index == escape_point::retslot_arg + eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM ? cur_summary_lto->retslot_flags - : ee->parm_index == escape_point::static_chain_arg + : ee->parm_index == MODREF_STATIC_CHAIN_PARM ? cur_summary_lto->static_chain_flags : cur_summary_lto->arg_flags[ee->parm_index]; if ((f & flags_lto) != f) @@ -4428,24 +4448,30 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge) if (callee_info || callee_info_lto) { auto_vec parm_map; + modref_parm_map chain_map; + /* TODO: Once we get jump functions for static chains we could + compute this. */ + chain_map.parm_index = MODREF_UNKNOWN_PARM; compute_parm_map (edge, &parm_map); if (!ignore_stores) { if (to_info && callee_info) - to_info->stores->merge (callee_info->stores, &parm_map, false); + to_info->stores->merge (callee_info->stores, &parm_map, + &chain_map, false); if (to_info_lto && callee_info_lto) to_info_lto->stores->merge (callee_info_lto->stores, &parm_map, - false); + &chain_map, false); } if (!(flags & (ECF_CONST | ECF_NOVOPS))) { if (to_info && callee_info) - to_info->loads->merge (callee_info->loads, &parm_map, false); + to_info->loads->merge (callee_info->loads, &parm_map, + &chain_map, false); if (to_info_lto && callee_info_lto) to_info_lto->loads->merge (callee_info_lto->loads, &parm_map, - false); + &chain_map, false); } } diff --git a/gcc/testsuite/gcc.dg/tree-ssa/modref-12.c b/gcc/testsuite/gcc.dg/tree-ssa/modref-12.c new file mode 100644 index 0000000..f8ce047 --- /dev/null +++ b/gcc/testsuite/gcc.dg/tree-ssa/modref-12.c @@ -0,0 +1,16 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-optimized" } */ +void foo (); +int +test() +{ + struct {int a,b;} a = {0,0}; + __attribute__ ((noinline)) + void nested () + { + a.b++; + } + nested (); + return a.a; +} +/* { dg-final { scan-tree-dump "return 0" "optimized"} } */ diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c index ce667ff..eabf680 100644 --- a/gcc/tree-ssa-alias.c +++ b/gcc/tree-ssa-alias.c @@ -2594,14 +2594,18 @@ modref_may_conflict (const gimple *stmt, if (num_tests >= max_tests) return true; - if (access_node->parm_index == -1 - || (unsigned)access_node->parm_index - >= gimple_call_num_args (stmt)) + if (access_node->parm_index == MODREF_UNKNOWN_PARM + || access_node->parm_index + >= (int)gimple_call_num_args (stmt)) return true; alias_stats.modref_baseptr_tests++; + tree arg; - tree arg = gimple_call_arg (stmt, access_node->parm_index); + if (access_node->parm_index == MODREF_STATIC_CHAIN_PARM) + arg = gimple_call_chain (stmt); + else + arg = gimple_call_arg (stmt, access_node->parm_index); if (integer_zerop (arg) && flag_delete_null_pointer_checks) continue;