8 ms·
A bug story: data alignment on x86 (2016)
- deleted 6y ago[deleted]
- saagarjha 6y agoPreviously: https://news.ycombinator.com/item?id=17910851 https://news.ycombinator.com/item?id=17910851 https://news.ycombinator.com/item?id=12889855 https://news.ycombinator.com/item?id=12889855 Some new developments: > C++ allows us to write the same function in much more readable way by employing some template programming. We’ll introduce a generic type called const_unaligned_pointer. If you support C++20, there's std::bit_cast: https://en.cppreference.com/w/cpp/numeric/bit_cast https://en.cppreference.com/w/cpp/numeric/bit_cast Edit: fixed link. Thanks, nkurz.
- deleted 6y ago[deleted]
- userbinator 6y agoI think something has gone very wrong with the state of programming when the original C version reads extremely straightforwardly, the version that works without UB already looks quite a bit more noisy, and the C++ version is just... yuck! In this case, just writing the appropriate Asm instructions themselves would've been much shorter and simpler, and also worked the first time.
- userbinator 6y ago...and something has certainly gone very wrong when you get downvoted for pointing out the truth! A lot of this idiotic complexity increase would be completely avoided if compiler authors would just exercise some common sense, but unfortunately it's not so common after all.
- nkurz 6y agoSummarizing the conclusion of the article: GCC correctly interprets the spec as saying that all integers reads must be aligned in memory, and when vectorizing the code chooses to use an "aligned" instruction that fails on unaligned data (MOVDQA). On modern x64 processors, the unaligned version of this instruction (MOVDQU) is just as fast on both aligned an unaligned data, and has the advantage of not causing a segfault when run. Is this a bug in GCC that should be fixed, or is GCC justified in its behavior? Or is there another interpretation? Having been bitten by this in the past, my conclusion is that while this is not a bug, it is (slight) evidence that GCC will not act in its users' best interests unless required to do so by the spec. Given the same inputs, Intel's ICC generates working fast code. If both compilers were equally available, I would usually prefer ICC over GCC for code that is going to run on modern Intel processors.
- nly 6y agoGCC is doing its best to give you the best performance on a broad set of CPUs, and its behaviour is 100% correct. Saying you want GCC to not exploit this contract (that the char* actually points to an aligned uint32_t) is asking for inferior performance, which is unacceptable to most people still using C. A warning would be nice though.
- nkurz 6y agoI should add that my comment above is dependent on compiling with options that target a specific processor, when the performance on that processor is equally good with aligned and unaligned data. That is, when compiling with "-march=native" on a modern Intel processor, I strongly prefer a compiler that generates fast and working code over one that segfaults because the spec allows it to. I'm open to arguments that it should behave differently when asked to generate generic code that can work on generic processors. Are there x64 processors in common use today that are significantly slower with MOVDQU than MOVDQA?
- gpderetta 6y agoMovdqu vs movdqa is just one of the possible bad things that can happen when misaligned data is erroneously used. And it will segfault consistently which is a good thing which means that will be caught early in testing. You want compilers to produce binaries that will catch mistakes early in testing, not binaries that work 99.99% of the time and fail in obscure ways.
- nly 6y agoI'm surprised any seasoned C developer would make this mistake. You haven't been able to assume trivial translation of C code to assembly for decades. Casting from a 'pointer to type A' to a 'pointer to type B' is unsafe in all but a handful of circumstances. - B is char or unsigned char. - A is char or unsigned char, and the pointer was previously cast from a pointer to type B. - Where A is a struct (or a standard layout[0] class in C++) and B is the first member of that structure. [0] https://en.cppreference.com/w/cpp/language/data_members#Standard_layout https://en.cppreference.com/w/cpp/language/data_members#Stan...
- deleted 6y ago[deleted]
- catblast 6y ago> I'm surprised any seasoned C developer I'm not too surprised. There is seasoned as in recently experienced (and burned).. and seasoned as outdated. I have come across plenty that don't realize the last 25 years of compiler optimizations have changed the rules of what can be assumed.
- saagarjha 6y ago> I'm surprised any seasoned C developer would make this mistake. Not everyone gets the talk. And even for the ones that do, many consider it to be useless nitpicking until it bites them. (And some who are bitten would prefer to yell at the compiler for “breaking their code”…) > A is char or unsigned char, and the pointer was previously cast from a pointer to type B. And if A is void, of course.
- gpderetta 6y ago> And if A is void, of course To nitpick, casting is rarely the issue. Dereferencing a pointer to the wrong type is the issue. As void can't never be dereferenced nor can be a valid underlying type, void never factors in alias analysis.
- userbinator 6y agoYou haven't been able to assume trivial translation of C code to assembly for decades. Then perhaps everyone should continue to do that, and continue to very strongly complain to the compiler-authors who seem to have become absolutely engrossed in blindly following the standard to the letter and completely ignoring the fact that people are wanting C precisely because it's supposed to be close to Asm. But I guess it satiates their egos more to point and laugh... "we're following the standard, fuck you for thinking we care about anything else."
- pjc50 6y agoChallenge for all the anti-C people here: what other language (a) lets you set up this situation in the first place and (b) avoids the problem "optimally"? That is, generates performant assembler on x86 and doesn't crash on ARM? (a) is a much harder criterion than it sounds!
- benibela 6y agoPascal probably
- peteri 6y agoThis is just expected behaviour isn't it? So many processors require aligned access from the original C target of the pdp-11 onwards. That it happens to work on a x86 is pure chance.
- bcoates 6y agoAm I the only one weirded out that the author didn't even consider writing/benchmarking the obvious byte-at-a-time version (in a loop, and/or unrolled) before resorting to a nonportable/incorrect 'optimized' version? Versions of GCC old enough to drive are pretty good at generating fast code from byte operations and summing up bytes seems like the kind of transparently analyzable case where modern compilers really are sufficiently smart