Given type definitions
struct a { int a; };
struct b { int b; struct a ba;};
and a function taking struct a* a and struct b* b, the type information expresses possible overlap between a->a and b->ba.a but no overlap on b->b.
Therefore in a function such as:
int possibleOverlapOn2ndInt(struct a *a, struct b *b){
b->b = 0xbb; //unaliased
b->ba.a = 0xba; //may alias a->a
a->a = 0xaa; //may alias b->ba.a;
return b->b /*0xbb*/ + b->ba.a;
}
compilers need not reload b->b in the return line and instead they may substitute the stored constant. Gcc and clang indeed do this.
I am curious if this case of possible partial overlap could be expressed without via restrict without using structs.
I've tried:
int possibleOverlapOn2ndInt_(int a[1], int b[2]){ //<=> (int *a, int *b)
int *restrict bp = &b[0];
bp[0] = 0xbb; //unaliased
b[1] = 0xba; //may alias a[0]
a[0] = 0xaa; //may alias b[1]
return bp[0] /*0xbb?*/ + b[1];
}
but got no effect from having the restricted pointer there. https://godbolt.org/z/9Y7zz37rs
Am I using restrict wrong here is it the compilers not optimizing as well as they could?
restrict-qualification puts constraints on program behavior intended to allow optimizations that otherwise might be assumed unsafe on the basis of possible aliasing. In any particular case, however, that does not imply that the compiler has missed an optimization opportunity if it generates the same code both with and withoutrestrict. Therefore, I'll focus mainly on the first part of the question.These are the constraints associated with use of
restrict, from C17 6.7.3.1, somewhat contextualized to your example:Disint *restrict bp = &b[0];.Pisbp.Tisint.Bis the whole body of functionpossibleOverlapOn2ndInt_().No such expressions
Eappear inpossibleOverlapOn2ndInt_(), other thanbpitself. In particular, neitheranorbis such an expression.Neither
a[0]norb[0]norb[1]satisfies that description. The only such lvalue appearing inpossibleOverlapOn2ndInt_()isbp[0].bp[0]is used to access the object it designates.The object designated by
bp[0]is modified (viabp[0]itself).This would be violated if
a[0]aliasedbp[0](and therefore alsob[0]) in any execution ofpossibleOverlapOn2ndInt_().If the compiler assumed that the behavior of every execution of
possibleOverlapOn2ndInt_()has defined behavior, including with respect torestrictqualification, then it could generate code as if the function were written like so:The compiler is by no means required to make use of that freedom, however.