Track nondeterminism and interposable calls in ipa-modref

Adds tracking of two new flags in ipa-modref: nondeterministic and
calls_interposable.  First is set when function does something that is not
guaranteed to be the same if run again (volatile memory access, volatile asm or
external function call).  Second is set if function calls something that
does not bind to current def.

nondeterministic enables ipa-modref to discover looping pure/const functions
and it now discovers 138 of them during cc1plus link (which about doubles
number of such functions detected late).  We however can do more

 1) We can extend FRE to eliminate redundant calls.
    I filled a PR103168 for that.
    A common case are inline functions that are not autodetected as ECF_CONST
    just becuase they do not bind to local def and can be easily handled.
    More tricky is to use modref summary to check what memory locations are
    read.
 2) DSE can eliminate redundant stores

The calls_interposable flag currently also improves tree-ssa-structalias
on functions that are not binds_to_current_def since reads_global_memory
is now not cleared by interposable functions.

gcc/ChangeLog:

	* ipa-modref.h (struct modref_summary): Add nondeterministic
	and calls_interposable flags.
	* ipa-modref.c (modref_summary::modref_summary): Initialize new flags.
	(modref_summary::useful_p): Check new flags.
	(struct modref_summary_lto): Add nondeterministic and
	calls_interposable flags.
	(modref_summary_lto::modref_summary_lto): Initialize new flags.
	(modref_summary_lto::useful_p): Check new flags.
	(modref_summary::dump): Dump new flags.
	(modref_summary_lto::dump): Dump new flags.
	(ignore_nondeterminism_p): New function.
	(merge_call_side_effects): Merge new flags.
	(process_fnspec): Likewise.
	(analyze_load): Volatile access is nondeterministic.
	(analyze_store): Liekwise.
	(analyze_stmt): Volatile ASM is nondeterministic.
	(analyze_function): Clear new flags.
	(modref_summaries::duplicate): Duplicate new flags.
	(modref_summaries_lto::duplicate): Duplicate new flags.
	(modref_write): Stream new flags.
	(read_section): Stream new flags.
	(propagate_unknown_call): Update new flags.
	(modref_propagate_in_scc): Propagate new flags.
	* tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Check
	calls_interposable.
	* tree-ssa-structalias.c (determine_global_memory_access):
	Likewise.
This commit is contained in:
Jan Hubicka 2021-11-15 00:10:06 +01:00
parent 3057f1ab73
commit a34edf9a3e
4 changed files with 187 additions and 34 deletions

View file

@ -276,7 +276,8 @@ static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
modref_summary::modref_summary () modref_summary::modref_summary ()
: loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0), : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
writes_errno (false), side_effects (false), global_memory_read (false), writes_errno (false), side_effects (false), nondeterministic (false),
calls_interposable (false), global_memory_read (false),
global_memory_written (false), try_dse (false) global_memory_written (false), try_dse (false)
{ {
} }
@ -332,13 +333,15 @@ modref_summary::useful_p (int ecf_flags, bool check_flags)
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false)) && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
return true; return true;
if (ecf_flags & (ECF_CONST | ECF_NOVOPS)) if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE)); return ((!side_effects || !nondeterministic)
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
if (loads && !loads->every_base) if (loads && !loads->every_base)
return true; return true;
else else
kills.release (); kills.release ();
if (ecf_flags & ECF_PURE) if (ecf_flags & ECF_PURE)
return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE)); return ((!side_effects || !nondeterministic)
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
return stores && !stores->every_base; return stores && !stores->every_base;
} }
@ -357,8 +360,10 @@ struct GTY(()) modref_summary_lto
auto_vec<eaf_flags_t> GTY((skip)) arg_flags; auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
eaf_flags_t retslot_flags; eaf_flags_t retslot_flags;
eaf_flags_t static_chain_flags; eaf_flags_t static_chain_flags;
bool writes_errno; unsigned writes_errno : 1;
bool side_effects; unsigned side_effects : 1;
unsigned nondeterministic : 1;
unsigned calls_interposable : 1;
modref_summary_lto (); modref_summary_lto ();
~modref_summary_lto (); ~modref_summary_lto ();
@ -370,7 +375,8 @@ struct GTY(()) modref_summary_lto
modref_summary_lto::modref_summary_lto () modref_summary_lto::modref_summary_lto ()
: loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0), : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
writes_errno (false), side_effects (false) writes_errno (false), side_effects (false), nondeterministic (false),
calls_interposable (false)
{ {
} }
@ -400,11 +406,13 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false)) && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
return true; return true;
if (ecf_flags & (ECF_CONST | ECF_NOVOPS)) if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE)); return ((!side_effects || !nondeterministic)
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
if (loads && !loads->every_base) if (loads && !loads->every_base)
return true; return true;
if (ecf_flags & ECF_PURE) if (ecf_flags & ECF_PURE)
return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE)); return ((!side_effects || !nondeterministic)
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
return stores && !stores->every_base; return stores && !stores->every_base;
} }
@ -586,6 +594,10 @@ modref_summary::dump (FILE *out)
fprintf (out, " Writes errno\n"); fprintf (out, " Writes errno\n");
if (side_effects) if (side_effects)
fprintf (out, " Side effects\n"); fprintf (out, " Side effects\n");
if (nondeterministic)
fprintf (out, " Nondeterministic\n");
if (calls_interposable)
fprintf (out, " Calls interposable\n");
if (global_memory_read) if (global_memory_read)
fprintf (out, " Global memory read\n"); fprintf (out, " Global memory read\n");
if (global_memory_written) if (global_memory_written)
@ -626,6 +638,10 @@ modref_summary_lto::dump (FILE *out)
fprintf (out, " Writes errno\n"); fprintf (out, " Writes errno\n");
if (side_effects) if (side_effects)
fprintf (out, " Side effects\n"); fprintf (out, " Side effects\n");
if (nondeterministic)
fprintf (out, " Nondeterministic\n");
if (calls_interposable)
fprintf (out, " Calls interposable\n");
if (arg_flags.length ()) if (arg_flags.length ())
{ {
for (unsigned int i = 0; i < arg_flags.length (); i++) for (unsigned int i = 0; i < arg_flags.length (); i++)
@ -869,6 +885,20 @@ record_access_p (tree expr)
return true; return true;
} }
/* Return true if ECF flags says that nondeterminsm can be ignored. */
static bool
ignore_nondeterminism_p (tree caller, int flags)
{
if ((flags & (ECF_CONST | ECF_PURE))
&& !(flags & ECF_LOOPING_CONST_OR_PURE))
return true;
if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
|| (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
return true;
return false;
}
/* Return true if ECF flags says that return value can be ignored. */ /* Return true if ECF flags says that return value can be ignored. */
static bool static bool
@ -953,17 +983,37 @@ merge_call_side_effects (modref_summary *cur_summary,
&& !(flags & ECF_LOOPING_CONST_OR_PURE)) && !(flags & ECF_LOOPING_CONST_OR_PURE))
return changed; return changed;
if (!cur_summary->side_effects && callee_summary->side_effects) if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
|| (flags & ECF_LOOPING_CONST_OR_PURE))
{ {
if (dump_file) if (!cur_summary->side_effects && callee_summary->side_effects)
fprintf (dump_file, " - merging side effects.\n"); {
cur_summary->side_effects = true; if (dump_file)
changed = true; fprintf (dump_file, " - merging side effects.\n");
} cur_summary->side_effects = true;
changed = true;
}
if (!cur_summary->nondeterministic && callee_summary->nondeterministic
&& !ignore_nondeterminism_p (current_function_decl, flags))
{
if (dump_file)
fprintf (dump_file, " - merging nondeterministic.\n");
cur_summary->nondeterministic = true;
changed = true;
}
}
if (flags & (ECF_CONST | ECF_NOVOPS)) if (flags & (ECF_CONST | ECF_NOVOPS))
return changed; return changed;
if (!cur_summary->calls_interposable && callee_summary->calls_interposable)
{
if (dump_file)
fprintf (dump_file, " - merging calls interposable.\n");
cur_summary->calls_interposable = true;
changed = true;
}
if (always_executed if (always_executed
&& callee_summary->kills.length () && callee_summary->kills.length ()
&& (!cfun->can_throw_non_call_exceptions && (!cfun->can_throw_non_call_exceptions
@ -1000,11 +1050,13 @@ merge_call_side_effects (modref_summary *cur_summary,
not always bind to current def: it is possible that memory load not always bind to current def: it is possible that memory load
was optimized out earlier which may not happen in the interposed was optimized out earlier which may not happen in the interposed
variant. */ variant. */
if (!callee_node->binds_to_current_def_p ()) if (!callee_node->binds_to_current_def_p ()
&& !cur_summary->calls_interposable)
{ {
if (dump_file) if (dump_file)
fprintf (dump_file, " - May be interposed: collapsing loads.\n"); fprintf (dump_file, " - May be interposed.\n");
cur_summary->loads->collapse (); cur_summary->calls_interposable = true;
changed = true;
} }
if (dump_file) if (dump_file)
@ -1161,9 +1213,17 @@ process_fnspec (modref_summary *cur_summary,
&& stmt_could_throw_p (cfun, call))) && stmt_could_throw_p (cfun, call)))
{ {
if (cur_summary) if (cur_summary)
cur_summary->side_effects = true; {
cur_summary->side_effects = true;
if (!ignore_nondeterminism_p (current_function_decl, flags))
cur_summary->nondeterministic = true;
}
if (cur_summary_lto) if (cur_summary_lto)
cur_summary_lto->side_effects = true; {
cur_summary_lto->side_effects = true;
if (!ignore_nondeterminism_p (current_function_decl, flags))
cur_summary_lto->nondeterministic = true;
}
} }
if (flags & (ECF_CONST | ECF_NOVOPS)) if (flags & (ECF_CONST | ECF_NOVOPS))
return true; return true;
@ -1388,9 +1448,9 @@ analyze_load (gimple *, tree, tree op, void *data)
if (dump_file) if (dump_file)
fprintf (dump_file, " (volatile or can throw; marking side effects) "); fprintf (dump_file, " (volatile or can throw; marking side effects) ");
if (summary) if (summary)
summary->side_effects = true; summary->side_effects = summary->nondeterministic = true;
if (summary_lto) if (summary_lto)
summary_lto->side_effects = true; summary_lto->side_effects = summary_lto->nondeterministic = true;
} }
if (!record_access_p (op)) if (!record_access_p (op))
@ -1429,9 +1489,9 @@ analyze_store (gimple *stmt, tree, tree op, void *data)
if (dump_file) if (dump_file)
fprintf (dump_file, " (volatile or can throw; marking side effects) "); fprintf (dump_file, " (volatile or can throw; marking side effects) ");
if (summary) if (summary)
summary->side_effects = true; summary->side_effects = summary->nondeterministic = true;
if (summary_lto) if (summary_lto)
summary_lto->side_effects = true; summary_lto->side_effects = summary_lto->nondeterministic = true;
} }
if (!record_access_p (op)) if (!record_access_p (op))
@ -1497,9 +1557,15 @@ analyze_stmt (modref_summary *summary, modref_summary_lto *summary_lto,
switch (gimple_code (stmt)) switch (gimple_code (stmt))
{ {
case GIMPLE_ASM: case GIMPLE_ASM:
if (gimple_asm_volatile_p (as_a <gasm *> (stmt)) if (gimple_asm_volatile_p (as_a <gasm *> (stmt)))
|| (cfun->can_throw_non_call_exceptions {
&& stmt_could_throw_p (cfun, stmt))) if (summary)
summary->side_effects = summary->nondeterministic = true;
if (summary_lto)
summary_lto->side_effects = summary_lto->nondeterministic = true;
}
if (cfun->can_throw_non_call_exceptions
&& stmt_could_throw_p (cfun, stmt))
{ {
if (summary) if (summary)
summary->side_effects = true; summary->side_effects = true;
@ -2826,6 +2892,8 @@ analyze_function (function *f, bool ipa)
param_modref_max_accesses); param_modref_max_accesses);
summary->writes_errno = false; summary->writes_errno = false;
summary->side_effects = false; summary->side_effects = false;
summary->nondeterministic = false;
summary->calls_interposable = false;
} }
if (lto) if (lto)
{ {
@ -2841,6 +2909,8 @@ analyze_function (function *f, bool ipa)
param_modref_max_accesses); param_modref_max_accesses);
summary_lto->writes_errno = false; summary_lto->writes_errno = false;
summary_lto->side_effects = false; summary_lto->side_effects = false;
summary_lto->nondeterministic = false;
summary_lto->calls_interposable = false;
} }
analyze_parms (summary, summary_lto, ipa, analyze_parms (summary, summary_lto, ipa,
@ -2913,9 +2983,10 @@ analyze_function (function *f, bool ipa)
if (!ipa && flag_ipa_pure_const) if (!ipa && flag_ipa_pure_const)
{ {
if (!summary->stores->every_base && !summary->stores->bases if (!summary->stores->every_base && !summary->stores->bases
&& !summary->side_effects) && !summary->nondeterministic)
{ {
if (!summary->loads->every_base && !summary->loads->bases) if (!summary->loads->every_base && !summary->loads->bases
&& !summary->calls_interposable)
fixup_cfg = ipa_make_function_const fixup_cfg = ipa_make_function_const
(cgraph_node::get (current_function_decl), (cgraph_node::get (current_function_decl),
summary->side_effects, true); summary->side_effects, true);
@ -3149,6 +3220,8 @@ modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
dst_data->kills.splice (src_data->kills); dst_data->kills.splice (src_data->kills);
dst_data->writes_errno = src_data->writes_errno; dst_data->writes_errno = src_data->writes_errno;
dst_data->side_effects = src_data->side_effects; dst_data->side_effects = src_data->side_effects;
dst_data->nondeterministic = src_data->nondeterministic;
dst_data->calls_interposable = src_data->calls_interposable;
if (src_data->arg_flags.length ()) if (src_data->arg_flags.length ())
dst_data->arg_flags = src_data->arg_flags.copy (); dst_data->arg_flags = src_data->arg_flags.copy ();
dst_data->retslot_flags = src_data->retslot_flags; dst_data->retslot_flags = src_data->retslot_flags;
@ -3177,6 +3250,8 @@ modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
dst_data->loads->copy_from (src_data->loads); dst_data->loads->copy_from (src_data->loads);
dst_data->writes_errno = src_data->writes_errno; dst_data->writes_errno = src_data->writes_errno;
dst_data->side_effects = src_data->side_effects; dst_data->side_effects = src_data->side_effects;
dst_data->nondeterministic = src_data->nondeterministic;
dst_data->calls_interposable = src_data->calls_interposable;
if (src_data->arg_flags.length ()) if (src_data->arg_flags.length ())
dst_data->arg_flags = src_data->arg_flags.copy (); dst_data->arg_flags = src_data->arg_flags.copy ();
dst_data->retslot_flags = src_data->retslot_flags; dst_data->retslot_flags = src_data->retslot_flags;
@ -3506,6 +3581,8 @@ modref_write ()
struct bitpack_d bp = bitpack_create (ob->main_stream); struct bitpack_d bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, r->writes_errno, 1); bp_pack_value (&bp, r->writes_errno, 1);
bp_pack_value (&bp, r->side_effects, 1); bp_pack_value (&bp, r->side_effects, 1);
bp_pack_value (&bp, r->nondeterministic, 1);
bp_pack_value (&bp, r->calls_interposable, 1);
if (!flag_wpa) if (!flag_wpa)
{ {
for (cgraph_edge *e = cnode->indirect_calls; for (cgraph_edge *e = cnode->indirect_calls;
@ -3578,11 +3655,15 @@ read_section (struct lto_file_decl_data *file_data, const char *data,
{ {
modref_sum->writes_errno = false; modref_sum->writes_errno = false;
modref_sum->side_effects = false; modref_sum->side_effects = false;
modref_sum->nondeterministic = false;
modref_sum->calls_interposable = false;
} }
if (modref_sum_lto) if (modref_sum_lto)
{ {
modref_sum_lto->writes_errno = false; modref_sum_lto->writes_errno = false;
modref_sum_lto->side_effects = false; modref_sum_lto->side_effects = false;
modref_sum_lto->nondeterministic = false;
modref_sum_lto->calls_interposable = false;
} }
gcc_assert (!modref_sum || (!modref_sum->loads gcc_assert (!modref_sum || (!modref_sum->loads
@ -3635,6 +3716,20 @@ read_section (struct lto_file_decl_data *file_data, const char *data,
if (modref_sum_lto) if (modref_sum_lto)
modref_sum_lto->side_effects = true; modref_sum_lto->side_effects = true;
} }
if (bp_unpack_value (&bp, 1))
{
if (modref_sum)
modref_sum->nondeterministic = true;
if (modref_sum_lto)
modref_sum_lto->nondeterministic = true;
}
if (bp_unpack_value (&bp, 1))
{
if (modref_sum)
modref_sum->calls_interposable = true;
if (modref_sum_lto)
modref_sum_lto->calls_interposable = true;
}
if (!flag_ltrans) if (!flag_ltrans)
{ {
for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee) for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
@ -4162,6 +4257,18 @@ propagate_unknown_call (cgraph_node *node,
cur_summary_lto->side_effects = true; cur_summary_lto->side_effects = true;
changed = true; changed = true;
} }
if (cur_summary && !cur_summary->nondeterministic
&& !ignore_nondeterminism_p (node->decl, ecf_flags))
{
cur_summary->nondeterministic = true;
changed = true;
}
if (cur_summary_lto && !cur_summary_lto->nondeterministic
&& !ignore_nondeterminism_p (node->decl, ecf_flags))
{
cur_summary_lto->nondeterministic = true;
changed = true;
}
} }
if (ecf_flags & (ECF_CONST | ECF_NOVOPS)) if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
return changed; return changed;
@ -4421,6 +4528,20 @@ modref_propagate_in_scc (cgraph_node *component_node)
cur_summary_lto->side_effects = true; cur_summary_lto->side_effects = true;
changed = true; changed = true;
} }
if (callee_summary && !cur_summary->nondeterministic
&& callee_summary->nondeterministic
&& !ignore_nondeterminism_p (cur->decl, flags))
{
cur_summary->nondeterministic = true;
changed = true;
}
if (callee_summary_lto && !cur_summary_lto->nondeterministic
&& callee_summary_lto->nondeterministic
&& !ignore_nondeterminism_p (cur->decl, flags))
{
cur_summary_lto->nondeterministic = true;
changed = true;
}
if (flags & (ECF_CONST | ECF_NOVOPS)) if (flags & (ECF_CONST | ECF_NOVOPS))
continue; continue;
@ -4430,7 +4551,16 @@ modref_propagate_in_scc (cgraph_node *component_node)
the interposed variant. */ the interposed variant. */
if (!callee_edge->binds_to_current_def_p ()) if (!callee_edge->binds_to_current_def_p ())
{ {
changed |= collapse_loads (cur_summary, cur_summary_lto); if (cur_summary && !cur_summary->calls_interposable)
{
cur_summary->calls_interposable = true;
changed = true;
}
if (cur_summary_lto && !cur_summary_lto->calls_interposable)
{
cur_summary_lto->calls_interposable = true;
changed = true;
}
if (dump_file) if (dump_file)
fprintf (dump_file, " May not bind local;" fprintf (dump_file, " May not bind local;"
" collapsing loads\n"); " collapsing loads\n");
@ -4516,9 +4646,10 @@ modref_propagate_in_scc (cgraph_node *component_node)
? summaries_lto->get (cur) ? summaries_lto->get (cur)
: NULL; : NULL;
if (summary && !summary->stores->every_base && !summary->stores->bases if (summary && !summary->stores->every_base && !summary->stores->bases
&& !summary->side_effects) && !summary->nondeterministic)
{ {
if (!summary->loads->every_base && !summary->loads->bases) if (!summary->loads->every_base && !summary->loads->bases
&& !summary->calls_interposable)
pureconst |= ipa_make_function_const pureconst |= ipa_make_function_const
(cur, summary->side_effects, false); (cur, summary->side_effects, false);
else else
@ -4526,9 +4657,10 @@ modref_propagate_in_scc (cgraph_node *component_node)
(cur, summary->side_effects, false); (cur, summary->side_effects, false);
} }
if (summary_lto && !summary_lto->stores->every_base if (summary_lto && !summary_lto->stores->every_base
&& !summary_lto->stores->bases && !summary_lto->side_effects) && !summary_lto->stores->bases && !summary_lto->nondeterministic)
{ {
if (!summary_lto->loads->every_base && !summary_lto->loads->bases) if (!summary_lto->loads->every_base && !summary_lto->loads->bases
&& !summary_lto->calls_interposable)
pureconst |= ipa_make_function_const pureconst |= ipa_make_function_const
(cur, summary_lto->side_effects, false); (cur, summary_lto->side_effects, false);
else else

View file

@ -32,11 +32,31 @@ struct GTY(()) modref_summary
modref_records *stores; modref_records *stores;
auto_vec<modref_access_node> GTY((skip)) kills; auto_vec<modref_access_node> GTY((skip)) kills;
auto_vec<eaf_flags_t> GTY((skip)) arg_flags; auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
eaf_flags_t retslot_flags; eaf_flags_t retslot_flags;
eaf_flags_t static_chain_flags; eaf_flags_t static_chain_flags;
unsigned writes_errno : 1; unsigned writes_errno : 1;
/* Side effects does not include memory loads and stores which are
expressed using loads, stores and calls_interposable fields. */
unsigned side_effects : 1; unsigned side_effects : 1;
/* If true function can not be CSE optimized because it may behave
differently even if invoked with same inputs. */
unsigned nondeterministic : 1;
/* IF true the function may read any reachable memory but not use
it for anything useful. This may happen i.e. when interposing
function with optimized out conditional with unoptimized one.
In this situation the loads summary is not useful for DSE but
it is still useful for CSE. */
unsigned calls_interposable : 1;
/* Flags coputed by finalize method. */ /* Flags coputed by finalize method. */
/* global_memory_read is not set for functions calling functions
with !binds_to_current_def which, after interposition, may read global
memory but do nothing useful with it (except for crashing if some
stores are optimized out. */
unsigned global_memory_read : 1; unsigned global_memory_read : 1;
unsigned global_memory_written : 1; unsigned global_memory_written : 1;
unsigned try_dse : 1; unsigned try_dse : 1;

View file

@ -2765,7 +2765,7 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref, bool tbaa_p)
if (node && node->binds_to_current_def_p ()) if (node && node->binds_to_current_def_p ())
{ {
modref_summary *summary = get_modref_function_summary (node); modref_summary *summary = get_modref_function_summary (node);
if (summary) if (summary && !summary->calls_interposable)
{ {
if (!modref_may_conflict (call, summary->loads, ref, tbaa_p)) if (!modref_may_conflict (call, summary->loads, ref, tbaa_p))
{ {

View file

@ -4266,6 +4266,7 @@ determine_global_memory_access (gcall *stmt,
if (reads_global_memory && *reads_global_memory) if (reads_global_memory && *reads_global_memory)
*reads_global_memory = summary->global_memory_read; *reads_global_memory = summary->global_memory_read;
if (reads_global_memory && uses_global_memory if (reads_global_memory && uses_global_memory
&& !summary->calls_interposable
&& !*reads_global_memory && node->binds_to_current_def_p ()) && !*reads_global_memory && node->binds_to_current_def_p ())
*uses_global_memory = false; *uses_global_memory = false;
} }