https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109112

--- Comment #8 from Jakub Jelinek <jakub at gcc dot gnu.org> ---
(In reply to Jason Merrill from comment #7)
> Why don't the existing optimizations work on the artificial function the
> same as any other function?  i.e. like
> 
> struct S { bool x; };
> void do_something();
> inline void assumption_1 (const S& s) noexcept {
>   if (s.x) __builtin_unreachable ();
> }
> void fn(S s) {
>   assumption_1 (s);
>   if (s.x) do_something();
> }
> 
> which is also optimized as expected.

Because the assumptions have different representation in the IL.
While normal calls look like:
  ret = foo (arg1, arg2, arg3);
and we can inline those etc., because the assumptions potentially contain
side-effects which shouldn't be evaluated and therefore should e.g. not be
inlined nor assumed that they are actually called, the representation is like:
  .ASSUME (&foo, arg1, arg2, arg3);
where foo is that artificial assumption function which takes arg1, arg2, arg3.
The above behaves like if (!foo (arg1, arg2, arg3)) __builtin_unreachable ();
except that the function actually isn't called (nor emitted into assembly
etc.).
The assumption is if this function would be called and returned false at this
spot,
it would be UB.
So, VRP walks the assumption function (after optimizations are performed on it,
e.g. inlining into those and various other optimizations) backwards from the
return value starting with [1, 1] and from that derives ranges for the
arguments.

Similarly to how for functions which aren't inlined but can be e.g. cloned it
is essential to get IPA SRA and IPA CP etc. optimizations to tweak the
arguments of functions (scalarize them, remove unneeded ones, replace others),
it is needed
that we optimize the assumptions similarly.  The assumption functions should be
always static and often will have a single reference (unless inlined multiple
times / loop unrolled), so it is just fine to tweak them, just those
optimizations will need
to special case the IFN_ASSUME internal calls and treat
.ASSUME (&foo, arg1, arg2, arg3);
more like
foo (arg1, arg2, arg3);
(i.e. off by one argument and treat it as if there was a call edge from the
.ASSUME
caller to foo.

Reply via email to