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?
CodePudding user response:
Am I using
restrictwrong 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 without restrict. 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:
Let
Dbe a declaration of an ordinary identifier that provides a means of designating an objectPas arestrict-qualified pointer to typeT.
D is int *restrict bp = &b[0];.
P is bp.
T is int.
[...] let
Bdenote the block.
B is the whole body of function possibleOverlapOn2ndInt_().
In what follows, a pointer expression
Eis said to be based on objectPif (at some sequence point in the execution ofBprior to the evaluation ofE) modifyingPto point to a copy of the array object into which it formerly pointed would change the value of E.
No such expressions E appear in possibleOverlapOn2ndInt_(), other than bp itself. In particular, neither a nor b is such an expression.
During each execution of
B, letLbe any lvalue that has&Lbased onP.
Neither a[0] nor b[0] nor b[1] satisfies that description. The only such lvalue appearing in possibleOverlapOn2ndInt_() is bp[0].
If
Lis used to access the value of the objectXthat it designates,
bp[0] is used to access the object it designates.
and
Xis also modified (by any means),
The object designated by bp[0] is modified (via bp[0] itself).
then the following requirements apply: [...] Every other lvalue used to access the value of
Xshall also have its address based onP.
This would be violated if a[0] aliased bp[0] (and therefore also b[0]) in any execution of possibleOverlapOn2ndInt_().
[...] If these requirements are not met, then the behavior is undefined.
If the compiler assumed that the behavior of every execution of possibleOverlapOn2ndInt_() has defined behavior, including with respect to restrict qualification, then it could generate code as if the function were written like so:
int possibleOverlapOn2ndInt_2(int a[1], int b[2]) {
b[0] = 0xbb;
b[1] = 0xba; // cannot alias b[0]
a[0] = 0xaa; // must not alias b[0], may alias b[1]
return 0xbb b[1];
}
The compiler is by no means required to make use of that freedom, however.
CodePudding user response:
Use it in the parameter list. bp is not restricted as it holds reference from the not-restricted pointer.
int possibleOverlapOn2ndInt_(int * restrict a, int *b){ //<=> (int *a, int *b)
b[0] = 0xbb; //unaliased
b[1] = 0xba; //may alias a[0]
a[0] = 0xaa; //may alias b[1]
return b[0] /*0xbb?*/ b[1];
https://godbolt.org/z/89jb5hd4c
Maybe I misunderstood the question.
