mirror of
https://github.com/gcc-mirror/gcc.git
synced 2024-11-21 13:40:47 +00:00
ipa-modref bits for unsequenced and reproducible
C attributes reproducible and unsequenced implies that calling function twice leads to same effect if parameters are otherwise unchanged (function call itself does not count). This is bit bit stronger that modref's notion of nondeterminism that says that same inputs will yield same outputs (function call itself does count). This patch makes reproducible/unsequenced imply determinism and cleans up determinism handling. By itself it is not useful, since we can not make use of it unless we know what are the inputs/outputs of the function which I plan to handle by the "fn spec" attribute. gcc/ChangeLog: * ipa-modref.cc (modref_summary::useful_p): const/pure implies determinism. (modref_summary_lto::useful_p): Likewise. (ignore_nondeterminism_p): Add CALLEE_FNTYPE parameter; check for reproducible/unsequenced (modref_access_analysis::record_access_p): Use ignore_nondeterminism_p when handling volatile accesses. (modref_access_analysis::get_access_for_fnspec): Update. (modref_access_analysis::process_fnspec): Cleanup handling of NOVOPS. (modref_access_analysis::analyze_call): Use ignore_nondeterminism_p when handling asm statements. (modref_access_analysis::analyze_stmt): Update. (propagate_unknown_call): Update. (modref_propagate_in_scc): Update. (ipa_merge_modref_summary_after_inlining): Update.
This commit is contained in:
parent
aac5c57ee1
commit
addf022820
@ -336,15 +336,13 @@ modref_summary::useful_p (int ecf_flags, bool check_flags)
|
||||
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
|
||||
return true;
|
||||
if (ecf_flags & ECF_CONST)
|
||||
return ((!side_effects || !nondeterministic)
|
||||
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
|
||||
return (!side_effects && (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 || !nondeterministic)
|
||||
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
|
||||
return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
|
||||
return stores && !stores->every_base;
|
||||
}
|
||||
|
||||
@ -409,15 +407,13 @@ modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
|
||||
&& remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
|
||||
return true;
|
||||
if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
|
||||
return ((!side_effects || !nondeterministic)
|
||||
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
|
||||
return (!side_effects && (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 || !nondeterministic)
|
||||
&& (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
|
||||
return (!side_effects && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
|
||||
return stores && !stores->every_base;
|
||||
}
|
||||
|
||||
@ -794,13 +790,25 @@ namespace {
|
||||
/* Return true if ECF flags says that nondeterminism can be ignored. */
|
||||
|
||||
static bool
|
||||
ignore_nondeterminism_p (tree caller, int flags)
|
||||
ignore_nondeterminism_p (tree caller, int flags, tree callee_fntype)
|
||||
{
|
||||
if (flags & (ECF_CONST | ECF_PURE))
|
||||
int caller_flags = flags_from_decl_or_type (caller);
|
||||
if ((flags | caller_flags) & (ECF_CONST | ECF_PURE))
|
||||
return true;
|
||||
if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
|
||||
|| (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
|
||||
return true;
|
||||
/* C language defines unsequenced and reproducible functions
|
||||
to be deterministic. */
|
||||
if (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (TREE_TYPE (caller)))
|
||||
|| lookup_attribute ("reproducible",
|
||||
TYPE_ATTRIBUTES (TREE_TYPE (caller))))
|
||||
return true;
|
||||
if (callee_fntype
|
||||
&& (lookup_attribute ("unsequenced", TYPE_ATTRIBUTES (callee_fntype))
|
||||
|| lookup_attribute ("reproducible",
|
||||
TYPE_ATTRIBUTES (callee_fntype))))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1151,7 +1159,8 @@ modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref,
|
||||
bool
|
||||
modref_access_analysis::record_access_p (tree expr)
|
||||
{
|
||||
if (TREE_THIS_VOLATILE (expr))
|
||||
if (TREE_THIS_VOLATILE (expr)
|
||||
&& !ignore_nondeterminism_p (current_function_decl, 0, NULL))
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " (volatile; marking nondeterministic) ");
|
||||
@ -1288,7 +1297,8 @@ modref_access_analysis::merge_call_side_effects
|
||||
changed = true;
|
||||
}
|
||||
if (!m_summary->nondeterministic && callee_summary->nondeterministic
|
||||
&& !ignore_nondeterminism_p (current_function_decl, flags))
|
||||
&& !ignore_nondeterminism_p (current_function_decl, flags,
|
||||
gimple_call_fntype (call)))
|
||||
{
|
||||
if (dump_file)
|
||||
fprintf (dump_file, " - merging nondeterministic.\n");
|
||||
@ -1455,6 +1465,7 @@ 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. */
|
||||
@ -1472,7 +1483,8 @@ modref_access_analysis::process_fnspec (gcall *call)
|
||||
&& stmt_could_throw_p (cfun, call)))
|
||||
{
|
||||
set_side_effects ();
|
||||
if (!ignore_nondeterminism_p (current_function_decl, flags))
|
||||
if (!ignore_nondeterminism_p (current_function_decl, flags,
|
||||
gimple_call_fntype (call)))
|
||||
set_nondeterministic ();
|
||||
}
|
||||
|
||||
@ -1625,13 +1637,7 @@ modref_access_analysis::analyze_call (gcall *stmt)
|
||||
if (dump_file)
|
||||
fprintf (dump_file, gimple_call_internal_p (stmt)
|
||||
? " - Internal call" : " - Indirect call.\n");
|
||||
if (flags & ECF_NOVOPS)
|
||||
{
|
||||
set_side_effects ();
|
||||
set_nondeterministic ();
|
||||
}
|
||||
else
|
||||
process_fnspec (stmt);
|
||||
process_fnspec (stmt);
|
||||
return;
|
||||
}
|
||||
/* We only need to handle internal calls in IPA mode. */
|
||||
@ -1800,7 +1806,8 @@ modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
|
||||
switch (gimple_code (stmt))
|
||||
{
|
||||
case GIMPLE_ASM:
|
||||
if (gimple_asm_volatile_p (as_a <gasm *> (stmt)))
|
||||
if (gimple_asm_volatile_p (as_a <gasm *> (stmt))
|
||||
&& !ignore_nondeterminism_p (current_function_decl, 0, NULL))
|
||||
set_nondeterministic ();
|
||||
if (cfun->can_throw_non_call_exceptions
|
||||
&& stmt_could_throw_p (cfun, stmt))
|
||||
@ -4592,17 +4599,20 @@ propagate_unknown_call (cgraph_node *node,
|
||||
cur_summary_lto->side_effects = true;
|
||||
changed = true;
|
||||
}
|
||||
if (cur_summary && !cur_summary->nondeterministic
|
||||
&& !ignore_nondeterminism_p (node->decl, ecf_flags))
|
||||
if (!ignore_nondeterminism_p (node->decl, ecf_flags,
|
||||
e->callee ? TREE_TYPE (e->callee->decl)
|
||||
: NULL_TREE))
|
||||
{
|
||||
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 (cur_summary && !cur_summary->nondeterministic)
|
||||
{
|
||||
cur_summary->nondeterministic = true;
|
||||
changed = true;
|
||||
}
|
||||
if (cur_summary_lto && !cur_summary_lto->nondeterministic)
|
||||
{
|
||||
cur_summary_lto->nondeterministic = true;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
|
||||
@ -4869,14 +4879,18 @@ modref_propagate_in_scc (cgraph_node *component_node)
|
||||
}
|
||||
if (callee_summary && !cur_summary->nondeterministic
|
||||
&& callee_summary->nondeterministic
|
||||
&& !ignore_nondeterminism_p (cur->decl, flags))
|
||||
&& !ignore_nondeterminism_p
|
||||
(cur->decl, flags,
|
||||
TREE_TYPE (callee_edge->callee->decl)))
|
||||
{
|
||||
cur_summary->nondeterministic = true;
|
||||
changed = true;
|
||||
}
|
||||
if (callee_summary_lto && !cur_summary_lto->nondeterministic
|
||||
&& callee_summary_lto->nondeterministic
|
||||
&& !ignore_nondeterminism_p (cur->decl, flags))
|
||||
&& !ignore_nondeterminism_p
|
||||
(cur->decl, flags,
|
||||
TREE_TYPE (callee_edge->callee->decl)))
|
||||
{
|
||||
cur_summary_lto->nondeterministic = true;
|
||||
changed = true;
|
||||
@ -5358,20 +5372,22 @@ ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
|
||||
if (!(flags & (ECF_CONST | ECF_PURE))
|
||||
|| (flags & ECF_LOOPING_CONST_OR_PURE))
|
||||
{
|
||||
bool set_nondeterministic
|
||||
= !ignore_nondeterminism_p
|
||||
(edge->caller->decl, flags,
|
||||
TREE_TYPE (edge->callee->decl));
|
||||
if (to_info)
|
||||
{
|
||||
if (!callee_info || callee_info->side_effects)
|
||||
to_info->side_effects = true;
|
||||
if ((!callee_info || callee_info->nondeterministic)
|
||||
&& !ignore_nondeterminism_p (edge->caller->decl, flags))
|
||||
if (set_nondeterministic)
|
||||
to_info->nondeterministic = true;
|
||||
}
|
||||
if (to_info_lto)
|
||||
{
|
||||
if (!callee_info_lto || callee_info_lto->side_effects)
|
||||
to_info_lto->side_effects = true;
|
||||
if ((!callee_info_lto || callee_info_lto->nondeterministic)
|
||||
&& !ignore_nondeterminism_p (edge->caller->decl, flags))
|
||||
if (set_nondeterministic)
|
||||
to_info_lto->nondeterministic = true;
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user