On 10/13/22 05:53, Jakub Jelinek wrote:
On Thu, Oct 13, 2022 at 08:11:53AM +0000, Richard Biener wrote:
On Wed, 12 Oct 2022, Andrew MacLeod wrote:
On 10/12/22 10:39, Jakub Jelinek wrote:
On Wed, Oct 12, 2022 at 10:31:00AM -0400, Andrew MacLeod wrote:
I presume you are looking to get this working for this release, making the
priority high? :-)
Yes. So that we can claim we actually support C++23 Portable Assumptions
and OpenMP assume directive's hold clauses for something non-trivial so
people won't be afraid to actually use it.
Of course, first the posted patch needs to be reviewed and only once it gets
in, the ranger/GORI part can follow. As the latter is only an optimization,
it can be done incrementally.
I will start poking at something to find ranges for parameters from the return
backwards.
If the return were
if (return_val)
return return_val;
you could use path-ranger with the parameter SSA default defs as
"interesting". So you "only" need to somehow interpret the return
statement as such and do path rangers compute_ranges ()
If it was easier for handling, another possible representation of the
assume_function could be not that it returns a bool where [1,1] returned
means defined behavior, otherwise UB, but that the function returns void
and the assumption is that it returns, the other paths would be
__builtin_unreachable (). But still in both cases it needs a specialized
backwards walk from the assumption that either it returns [1,1] or that it
returns through GIMPLE_RETURN to be defined behavior. In either case,
external exceptions, or infinite loops or other reasons why the function
might not return normally (exit/abort/longjmp/non-local goto etc.) are still
UB for assumptions.
Say normally, if we have:
extern void foo (int);
bool
assume1 (int x)
{
foo (x);
if (x != 42)
__builtin_unreachable ();
return true;
}
we can't through backwards ranger walk determine that x_1(D) at the start of
the function has [42,42] range, we can just say it is true at the end of the
function, because foo could do if (x != 42) exit (0); or if (x != 42) throw
1; or if (x != 42) longjmp (buf, 1); or while (x != 42) ; or if (x != 42)
abort ();
But with assumption functions we actually can and stick [42, 42] on the
parameters even when we know nothing about foo function.
Of course, perhaps initially, we can choose to ignore those extra
guarantees.
I dont think we need to change anything. All I intend to do is provide
something that looks for the returns, wire GORI in, and reuse a global
range table in to a reverse dependency walk to starting with a range of
[1,1] for whatever is on the return stmt.
From GORIs point of view, thats all outgoing_edge_range_p () does,
except it picks up the initial value of [0,0] or [1,1] from the
specified edge instead.
Initially It'll stop at the top of the block, but I don't think its too
much work beyond that provide "simple" processing of PHIs and edges
coming into the block.. In the absence of loops it should be pretty
straightforward. "All" you do is feed the value of the phi argument to
the previous block. Of course it'll probably be a little more
complicated than that, but the basic premise seems pretty straightforward.
The result produced would be vector over the ssa-names in the function
with any ranges that were determined. You could use that to more
efficiently store just the values of the parameters somewhere and
somehow associate them with the assume function decl.
I'll try to get to this shortly.
Andrew