int **restrict
only asserts that the memory addressed by Out, A and B don't overlap (except that A and B can overlap, assuming your function doesn't modify either of them). This means the arrays of pointers. It doesn't assert anything about the contents of the memory pointed to by Out, A, and B. Footnote 117 in n1124 says:
if identifier p has type (int
**restrict), then the pointer expressions p and p+1 are based on the
restricted pointer object designated
by p, but the pointer expressions *p
and p[1] are not.
By analogy with const
, I suspect that qualifying with restrict
twice will assert what you want, which is that none of the values in the array points to overlapping memory. But reading the standard, I can't prove to myself that it actually does. I reckon that "Let D be a declaration of an ordinary identifier that provides a means of designating an object P as a restrict-qualified pointer to type T" does indeed mean that for int *restrict *restrict A
, then A[0] and A[1] are objects designated as a restrict-qualified pointer to int. But it's pretty heavy legalese.
I have no idea whether your compiler will actually do anything with that knowledge, mind you. Clearly it could, it's a question of whether it's implemented.
So I don't really know what you've gained over a conventional C 2-D array, where you just allocate rows * cols * sizeof(int)
, and index with A[cols*row + col]
. Then you clearly only need one use of restrict, and any compiler that does anything with restrict
will be able to re-order reads from A and B across writes to Out. Without restrict
, of course, it can't, so by doing what you're doing, you're throwing yourself on your compiler's mercy. If it can't cope with double-restrict, only the single restrict case, then your double-indirection has cost you the optimization.
At first guess, multiplication is likely to be faster than an additional pointer indirection anyway. You obviously care about performance or you wouldn't be using restrict at all, so I'd test performance fairly carefully (on all compilers you care about) before making this change for the sake of slightly nicer syntax and not having to remember how many columns there are in your array every time you access it.
is accessing elements through A[0][col*nrows + row] undefined?
Yes, if the element is modified by one of the accesses, because this makes A[0] an alias for memory also accessed via A[col]. That'd be fine if only A and B were restrict-qualified pointers, but not if A[0] and A[col] are.
I assume that you don't modify A in this function, so actually that alias is fine. If you did the same thing with Out, though, behavior would be undefined.