last day (15 days later) » 

09:35
15
Q: When did type punning through violating the strict aliasing rule become disallowed?

Adam HylandLooking at the C code from the Fast Inverse Square Root, the casting of a float to a long is done via pointer arithmetic: i = * ( long * ) &y; // evil floating point bit level hacking The hacking in question isn't of immediate interest to me. The method, using pointer arithmetic to access the ...

There were tags in the tag list such as programming-practices and compilers but the UI would not let me add them. Thanks to anyone who can categorize this more appropriately.
But if I read the K&R right, it is allowed to change pointer type with a cast. And the code does take a pointer to float, casts it to pointer to long, and assigns the integer value fetched from that pointer to long variable i. So the code does it by the book, according to K&R.
The C99 and C90 specs are widely available (maybe not the official ANSI/ISO versions, but the final working drafts that are identical), so surely you can answer #2 for yourself?
While this question targets a possible historical development, It seems as it would be a better fit at Computer Science. Wouldn't it?
As for (3), I’m not sure you could actually convince a typical programmer of the time that strict aliasing violations are wrong, even if you pointed at standards documents. I think they’d just shrug and say ‘well, it works on my compiler’. The DeathStation 9000 was considered a silly thought experiment without any practical implications; it is only when compilers with sophisticated optimisations became widely adopted that the language lawyers started being taken seriously. Pervasive ‘it-works-on-my-machine-ism’ is something that is yet to be rooted out of the common programmer’s mindset.
09:35
how might a C programmer learn that this was behavior to be avoided - on the PDP-11, on entry to the odd-address trap handler!
On (1), if you explicitly cast an expression, compilers are supposed to accept this without warning or error.
There isn't any pointer arithmetic in the fast inverse square root algorithm. The pointer casts are only there so the algorithm can access the bits of a float directly.
I should say that my C compiler (clang) does not emit any errors or warnings for the algorithm even with -Wall.
@JeremyP Try GCC with -O2 -Wall.
@user3840170: I don't think many people would have opposed application of the rules in situations like the one used to justify them. The problem is that the claimed purpose of the rules was to avoid requiring that compilers accommodate the possibility that seemingly-unrelated pointers might alias even in the absence of any evidence that they would do so, but the maintainers of gcc decided to abuse the rule as inviting compilers to assume, given T1 *p;, that a construct like *(T2*)p wouldn't be used to access the storage associated with a T1, *even in the places where the type of p...
...and the fact that the resulting pointer was formed from it would be readily apparent to any compiler that made any effort whatsoever to notice such things, or to justify an assumption that no storage which has ever be written with one type will, within its lifetime, be read using another, even after the storage has been rewritten using the latter type.
@supercat The compiler either is allowed to assume there are no strict aliasing violations anywhere, or not. If not, you give up TBAA (which you may be fine with; not saying you have to like it). If it is, you shouldn’t be surprised at the consequences of the principle of explosion that follow when that assumption is wrong. Absence of evidence of violations is not evidence of absence, so either strict aliasing is guaranteed everywhere (even where the compiler can’t see) or it might as well be ignored. There is no third possibility. Your rants are just wishful thinking.
09:35
@user3840170: The aliasing logic of clang and gcc is designed in a way that is incapable of accommodating any alternatives between those two extremes, but somehow other compilers like icc seem to find a way. See gcc.godbolt.org/z/fPPTYTfdj for a simple example. Notice that in the first function, there is no evidence of a relationship between the pointers used for floating-point and integer access, and thus icc assumes they will not alias, but in the second example the presence of a float* to unsigned* conversion between the floating-point operations prevents the latter...
...operations from being consolidated. If gcc and clang had a mode where every pointer type conversion or volatile-qualified access would artificially generate a memory clobber, the combination of that mode with LTO would be compatible with many programs that would otherwise be incompatible with LTO, and for many tasks the cost of the memory clobbers would be less than the cost of disabling LTO. Another useful mode with even less performance downside would be to trigger a memory clobber on cross-module entry/exit of any function which performs any pointer casts or volatile accesses.
With -Wall, GCC 12.2 does give a warning for the Quake fast square root code, but the warning is incorrect. It claims that y is being used uninitialized, but it is not. Clang 15 and MSVC 19 both accept it even with all warnings enabled.
@supercat Someone can still invoke test1((void *)&x, (void *)&x) from another translation unit. Linked dynamically. So really, LTO has nothing to do with it. TBAA relies on no strict aliasing violations anywhere ever. ‘TBAA with exceptions’ is wishful thinking.
@user3840170: Under a sensible TBAA model, any function which accesses the same storage using two different types would be required to contain within it something tying the pointers used for the accesses to a common type. Nothing within the test1() function would suggest any relationship between the pointers of different types, and a compiler would not be required to account for the possibility that the function might be invoked as you show. Why is it "impossible" for compilers which use TBAA to process code as exemplified by test2(), observing that both recieved pointers share type...
...float even though one is cast to unsigned immediately before access?
@user3840170 that would mean installing gcc.

last day (15 days later) »