0

If you write statements like:

a[i] = b[i] + c[i];

...you might want to indicate to the compiler that a[i], b[i] and c[i] point to different places in memory, thus enabling various optimizations (e.g. vectorization). This can be done by adding a special keyword in their declaration:

float * __restrict__ a; // same for b and c

However, what do you do if instead of float you are using a more complex object, say:

struct item {
    float foo, bar;
};

Consider the following code:

float *a, *b;
item *c;
// ...
for (int i = 0; i < 42; ++i) {
    a[i] = b[i] * c[i].foo + c[i].bar;
}

In the loop, the compiler does not care about c[i] but rather about c[i].foo and c[i].bar. How can an equivalent assertion about pointer independence be declared in this case with respect to individual fields of the structure?

Petr Mánek
  • 1,046
  • 1
  • 9
  • 24
  • Hmm, you skipped the important part, the assignment of the pointers. That's how the optimizer knows that there is no aliasing danger. Is this academic or do you have a concrete example where the optimizer got it wrong? – Hans Passant Sep 22 '18 at 22:28
  • The `__restrict__` keyword is a vendor extension. It's not part of C++. – doug Sep 22 '18 at 22:32
  • @HansPassant: I do have a concrete example, but it is much more complicated. I need to subtract constant offset from one value, then divide it by another constant, and store the result in memory. Since I'm using array-of-structs storage layout, the constants are stored together in memory and I'm positive that no aliasing can occur between them and the rest of the data. – Petr Mánek Sep 22 '18 at 22:34
  • @doug: I'm aware of that, perhaps I should add the `gcc` tag. – Petr Mánek Sep 22 '18 at 22:35
  • I’m not sure if your second example is relevant. The compiler should already know that `c[i].foo` and `c[i].bar` already point to different locations. I think the compiler needs help if you had e.g. `c[i].foo+d[i].foo` – vdavid Sep 22 '18 at 22:46
  • @vdavid: That's possible. But I believe that the premise of my question is still valid. Do you write something like: `(float * __restrict__) &d[i].foo` and then dereference? That looks a bit fishy to me. – Petr Mánek Sep 22 '18 at 22:50
  • @PetrMánek Are you even sure `__restrict__` makes a difference in your first example? I can’t see any using the C compiler of GCC 8.2 https://godbolt.org/z/EO_bGw nor with the C++ compiler https://godbolt.org/z/TTxTKD – vdavid Sep 22 '18 at 23:06
  • It [looks like](https://godbolt.org/z/pL2sAK) adding `__restrict__` to the pointer to the struct does the same thing as adding it directly to a pointer to `float`. – Miles Budnek Sep 22 '18 at 23:17
  • @vdavid: I would not expect this to work in your setup. Have a look here: https://godbolt.org/z/tIzVQH Using compiler flags, I have enabled optimization, chose the AVX2 vector instruction set and extracted the contents of the loop into a separate function. Note that `__restrict__` is now placed rather in the argument list of this function. – Petr Mánek Sep 23 '18 at 08:53

3 Answers3

1

For now, I have managed to solve the problem using:

#pragma GCC ivdep

However, this turns off the dependency checking completely. I would still be interested in more selective solution.

Petr Mánek
  • 1,046
  • 1
  • 9
  • 24
1

The Standard does not require compilers to accommodate the possibility that a[anything] and b[anything] might be used to access any part of a struct item. It lists the types of lvalues that implementations must always allow to be used to access a structure such as struct item, and non-character member types such as int are not among them. No special permission would be required to let a compiler assume that neither a nor b will alias a struct item.

Of course, it would be rather unhelpful for a compiler to allow code to take the address of a struct or union member of non-character type, but never actually allow the resulting pointer to be used to access the member even in cases that don't involve aliasing(*). The Standard makes no distinction between cases that involve aliasing and those that don't, however, and leaves the question of when to allow structures to be accessed using member-type lvalues entirely up to implementers' judgment. The authors of gcc and clang may have decided that the easiest way to support the use of pointers to struct members in non-aliasing scenarios was to support them in all scenarios, but the Standard hardly requires such treatment, and I don't think the authors wanted it to.

The Standard gives implementations room to benefit from an assumption that neither a not b will alias c, and yet still support most programs that would need to work with pointers to structure or union members. While there are some cases where more qualifiers similar to __restrict would be helpful, I'm not sure what additional permission you would think an implementation would need in cases like the one you show.

(*) i.e. situations where no operations accesses a region of storage, or derive a pointer/reference that will be used to do so, at times when there exists a newer pointer/reference that will also be used to access or address the same storage in conflicting fashion.

supercat
  • 77,689
  • 9
  • 166
  • 211
0

There's no need to do that.

Either a compiler is smart enough to know that these struct members cannot alias, or it's not smart enough to do anything useful with that information.

The reason you have the __restrict__ and C99 restrict keywords is because unlike structs, arrays might alias. Therefore the keywords provide real and useful information to the compiler.

MSalters
  • 173,980
  • 10
  • 155
  • 350