4 ms·
> strict aliasing allows for optimizations that are actually worthwhile I don't think there are many sensible, real world examples. A nice explanation of the
by abainbridge 2y ago
> strict aliasing allows for optimizations that are actually worthwhile
I don't think there are many sensible, real world examples.
A nice explanation of the optimizations the strict-aliasing rule allows: https://stackoverflow.com/a/99010/66088 https://stackoverflow.com/a/99010/66088
The example given is:
typedef struct Msg {
unsigned int a;
unsigned int b;
} Msg;
void SendWord(uint32_t);
int main(void) {
// Get a 32-bit buffer from the system
uint32_t* buff = malloc(sizeof(Msg));
// Alias that buffer through message
Msg* msg = (Msg*)(buff);
// Send a bunch of messages
for (int i = 0; i < 10; ++i) {
msg->a = i;
msg->b = i+1;
SendWord(buff[0]);
SendWord(buff[1]);
}
}
The explanation is: with strict aliasing the compiler doesn't have to think about inserting instructions to reload the contents of buff every iteration of the loop.
The problem I have is that when we re-write the example to use a union, the generated code is the same regardless of whether we pass -fno-strict-aliasing or not. So this isn't a working example of an optimization enabled by strict aliasing. It makes no difference whether I build it with clang or gcc, for x86-64 or arm7. I don't think I did it wrong. We still have a memory load instruction in the loop. See https://godbolt.org/z/9xzq87d1r https://godbolt.org/z/9xzq87d1r
Knowing whether a C compiler will make an optimization or not is all but impossible. The simplest and most reliable solution in this case is to do the loop hoisting optimization manually:
uint32_t buff0 = buff[0];
unit32_t buff1 = buff[1];
for (int i = 0; i < 10; ++i) {
msg->a = i;
msg->b = i+1;
SendWord(buff0);
SendWord(buff1);
}
Doing so removes the load instruction from the loop. See https://godbolt.org/z/ecGrvb3se https://godbolt.org/z/ecGrvb3se
Note 1: The first thing that goes wrong for Stackoverflow example is that the compiler spots that malloc returns uninitialized data, so it can omit the reloading of buff in the loop anyway. In fact it removes the malloc too. Here's clang 18 doing that https://godbolt.org/z/97a8K73ss https://godbolt.org/z/97a8K73ss. I had to replace malloc with an undefined GetBuff() function, so the compiler couldn't assume the returned data was unintialized.
Note 2: Once we're calling GetBuff() instead of malloc(), the compiler has to assume that SendWord(buff[0]) could change buff, and therefore it has to reload it in the loop even with strict-aliasing enabled.
- teo_zero 2y agoHow does the version with buf0 and buf1 work? It looks like it sends always the same two values...
- abainbridge 2y agoHmmm, yes. I didn't understand what the code did. Instead of creating those buff0 and buff1 variables before the loop, I should have done: for (int i = 0; i < 10; ++i) { unsigned a = i; unsigned b = i+1; msg->a = a; msg->b = b; SendWord(a); SendWord(b); } That gets rid of the load from the loop. https://godbolt.org/z/xsqWfxKzd https://godbolt.org/z/xsqWfxKzd
- JonChesterfield 2y agoThe strict aliasing stuff allows you to do "optimisations" across translation units that are otherwise unsound. The compiler alias analysis is much more effective than those rules permit within a translation unit because it matters whether int* alias other int*. And then we have link time optimisation, at which point the much better alias analysis runs across the whole program. What remains therefore is a language semantically compromised to help primitive compilers that no longer exist to emit slightly better code. This is a deeply annoying state of affairs.
- saagarjha 2y agoAliasing analysis is quite helpful for sophisticated compilers to generate good code.
- matheusmoreira 2y agoAlias analysis is important. It's the C standard's type-based "strict aliasing" rules which are nonsense and should be disabled by default. This is C. Here in these lands, we do things like cast float* to int* so that we can do evil bit level manipulation. The compiler is just gonna have to put that in its pipeline and compile it.
- 2y ago