On Mon, Mar 09, 2026 at 09:21:13AM +0100, Josef Melcr wrote:
> On 3/5/26 2:08 PM, Jakub Jelinek wrote:
> > Thanks for working on this. I'll defer the IPA review to Martin/Honza,
> > my knowledge of the IPA passes is limited, I'll just note that this is
> > highly desirable (maybe not just IPA-SRA for it but other IPA optimizations,
> > perhaps IPA-CP, IPA-VRP etc.)
> I actually managed to get ipa-cp working, but I had trouble finding
> testcases where the propagation made an impact, i.e. where it enabled an
> optimization that couldn't be done before. I want to implement it, but I'd
> save it for subsequent patches. With this committed, adding additional
> passes shouldn't be an issue.
E.g.
inline bool
bar (int x, int y)
{
return x < y;
}
bool
foo (int x)
{
int a = 42;
[[assume (bar (x, a))]];
return x < 42;
}
Here it is important to constant propagate 42 to the second argument of
_Z3fooi._assume.0, otherwise it will not figure out that the assumption
is actually x < 42.
> > and just want to note that due to inlining
> > and unrolling and other code copying one can end up with multiple
> > .ASSUME ifn calls for the same *.assume_fn, and if that happens one needs
> > to be careful (similarly to other IPA optimizations with static function
> > and multiple callers in the TU) to optimize it with all callers (in this
> > case "callers") in mind and adjust them all, rather than just assuming
> > there must be exactly one. But if all corresponding .ASSUME calls for
> > a particular *.assume_fn can be changed, changing arguments the normal
> > IPA way is fine and desirable, except normal calls look like
> > foo (arg1, arg2, arg3) but in this case it is
> > .ASSUME (&foo.assume_fn, arg1, arg2, arg3).
> If the function gets copied, the corresponding edge should be copied as
> well. I'll prepare testcases for it, but I don't think that's going to be
> an issue :)
I meant e.g.
struct S { int x, y; };
inline bool
baz (S x)
{
return x.x < 42;
}
inline bool
qux (S x)
{
[[assume (baz (x))]];
return x.x < 42 && x.y > 52;
}
void
corge (S x, S y, S z, bool *p)
{
p[0] = qux (x);
p[1] = qux (y);
p[2] = qux (z);
}
After einline, there is a single _Z3qux1S._assume.0 magic
function but 4 separate "callers" of it:
.ASSUME (_Z3qux1S._assume.0, x);
.ASSUME (_Z3qux1S._assume.0, x);
.ASSUME (_Z3qux1S._assume.0, y);
.ASSUME (_Z3qux1S._assume.0, z);
Jakub