modref_summary::modref_summary ()
: 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)
{
}
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
return true;
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)
return true;
else
kills.release ();
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;
}
auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
eaf_flags_t retslot_flags;
eaf_flags_t static_chain_flags;
- bool writes_errno;
- bool side_effects;
+ unsigned writes_errno : 1;
+ unsigned side_effects : 1;
+ unsigned nondeterministic : 1;
+ unsigned calls_interposable : 1;
modref_summary_lto ();
~modref_summary_lto ();
modref_summary_lto::modref_summary_lto ()
: 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)
{
}
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
return true;
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)
return true;
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;
}
fprintf (out, " Writes errno\n");
if (side_effects)
fprintf (out, " Side effects\n");
+ if (nondeterministic)
+ fprintf (out, " Nondeterministic\n");
+ if (calls_interposable)
+ fprintf (out, " Calls interposable\n");
if (global_memory_read)
fprintf (out, " Global memory read\n");
if (global_memory_written)
fprintf (out, " Writes errno\n");
if (side_effects)
fprintf (out, " Side effects\n");
+ if (nondeterministic)
+ fprintf (out, " Nondeterministic\n");
+ if (calls_interposable)
+ fprintf (out, " Calls interposable\n");
if (arg_flags.length ())
{
for (unsigned int i = 0; i < arg_flags.length (); i++)
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. */
static bool
&& !(flags & ECF_LOOPING_CONST_OR_PURE))
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)
- fprintf (dump_file, " - merging side effects.\n");
- cur_summary->side_effects = true;
- changed = true;
- }
+ if (!cur_summary->side_effects && callee_summary->side_effects)
+ {
+ if (dump_file)
+ 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))
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
&& callee_summary->kills.length ()
&& (!cfun->can_throw_non_call_exceptions
not always bind to current def: it is possible that memory load
was optimized out earlier which may not happen in the interposed
variant. */
- if (!callee_node->binds_to_current_def_p ())
+ if (!callee_node->binds_to_current_def_p ()
+ && !cur_summary->calls_interposable)
{
if (dump_file)
- fprintf (dump_file, " - May be interposed: collapsing loads.\n");
- cur_summary->loads->collapse ();
+ fprintf (dump_file, " - May be interposed.\n");
+ cur_summary->calls_interposable = true;
+ changed = true;
}
if (dump_file)
&& stmt_could_throw_p (cfun, call)))
{
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)
- 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))
return true;
if (dump_file)
fprintf (dump_file, " (volatile or can throw; marking side effects) ");
if (summary)
- summary->side_effects = true;
+ summary->side_effects = summary->nondeterministic = true;
if (summary_lto)
- summary_lto->side_effects = true;
+ summary_lto->side_effects = summary_lto->nondeterministic = true;
}
if (!record_access_p (op))
if (dump_file)
fprintf (dump_file, " (volatile or can throw; marking side effects) ");
if (summary)
- summary->side_effects = true;
+ summary->side_effects = summary->nondeterministic = true;
if (summary_lto)
- summary_lto->side_effects = true;
+ summary_lto->side_effects = summary_lto->nondeterministic = true;
}
if (!record_access_p (op))
switch (gimple_code (stmt))
{
case GIMPLE_ASM:
- if (gimple_asm_volatile_p (as_a <gasm *> (stmt))
- || (cfun->can_throw_non_call_exceptions
- && stmt_could_throw_p (cfun, stmt)))
+ if (gimple_asm_volatile_p (as_a <gasm *> (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)
summary->side_effects = true;
param_modref_max_accesses);
summary->writes_errno = false;
summary->side_effects = false;
+ summary->nondeterministic = false;
+ summary->calls_interposable = false;
}
if (lto)
{
param_modref_max_accesses);
summary_lto->writes_errno = false;
summary_lto->side_effects = false;
+ summary_lto->nondeterministic = false;
+ summary_lto->calls_interposable = false;
}
analyze_parms (summary, summary_lto, ipa,
if (!ipa && flag_ipa_pure_const)
{
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
(cgraph_node::get (current_function_decl),
summary->side_effects, true);
dst_data->kills.splice (src_data->kills);
dst_data->writes_errno = src_data->writes_errno;
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 ())
dst_data->arg_flags = src_data->arg_flags.copy ();
dst_data->retslot_flags = src_data->retslot_flags;
dst_data->loads->copy_from (src_data->loads);
dst_data->writes_errno = src_data->writes_errno;
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 ())
dst_data->arg_flags = src_data->arg_flags.copy ();
dst_data->retslot_flags = src_data->retslot_flags;
struct bitpack_d bp = bitpack_create (ob->main_stream);
bp_pack_value (&bp, r->writes_errno, 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)
{
for (cgraph_edge *e = cnode->indirect_calls;
{
modref_sum->writes_errno = false;
modref_sum->side_effects = false;
+ modref_sum->nondeterministic = false;
+ modref_sum->calls_interposable = false;
}
if (modref_sum_lto)
{
modref_sum_lto->writes_errno = 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
if (modref_sum_lto)
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)
{
for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
cur_summary_lto->side_effects = 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))
return changed;
cur_summary_lto->side_effects = 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))
continue;
the interposed variant. */
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)
fprintf (dump_file, " May not bind local;"
" collapsing loads\n");
? summaries_lto->get (cur)
: NULL;
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
(cur, summary->side_effects, false);
else
(cur, summary->side_effects, false);
}
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
(cur, summary_lto->side_effects, false);
else