3 ms·
> if you know enough to know whether you need standard floating-point calculations, you probably know about the -ffast-math flag. If you just want physics engi
by mananaysiempre 4y ago
> if you know enough to know whether you need standard floating-point calculations, you probably know about the -ffast-math flag.
If you just want physics engine go brr and a small binary, though, maybe you don’t.
I find the FP advice suspect for a different reason: I’ve seen some no good, very bad, seriously terrible, really horrifyingly awful codegen from Clang for x86-64 things involving `long double`, and without checking first I wouldn’t assume that it doesn’t extend to all x87 stuff in general.
(Clang’s preferred optimized way to copy a naturally-aligned 16-byte union with a `long double` being the longest member is... to copy the first ten bytes with FLD/FSTP, then the following two bytes of padding by a word-sized MOV, then the final four bytes, also of padding, by a doubleword-sized MOV. Apparently it forgot its MOVAPS at home.
When it spills onto the stack a `long double` temporary it itself invented to implement an atomic operation’s inner loop, though, it first clears the padding using a bleeding XORPS+MOVAPS pair before FSTPing it there—inside the loop, twice, to two identical temporaries, because apparently it belongs to the offshore oil rig school of register spilling.
And so on. I lack the words to describe how bad Clang’s codegen is for anything that might have ever briefly brushed against a `long double`.)
Also take care with -Os; while clang’s -Os is generally sane, gcc -Os will e.g. implement division by a constant with IDIV instead of magic multiplication, giving you code that’s maybe three times shorter and easily a dozen or two dozen times slower. (I think I remember Torvalds saying years ago that he gave up on gcc -Os.)
- josephg 4y ago> (Clang’s preferred optimized way to copy a naturally-aligned 16-byte union with a `long double` being the longest member is... to copy the first ten bytes with FLD/FSTP, then the following two bytes of padding by a word-sized MOV, then the final four bytes, also of padding, by a doubleword-sized MOV. Apparently it forgot its MOVAPS at home. Is that still true? Might warrant a bug filed on clang/llvm.
- mananaysiempre 4y agoOn second glance, surprisingly (or maybe not), this is not as easy to trigger as I thought. The somewhat messy interpreter loop I’m using still exhibits the problem on Clang 14 today (and I mean, I wrote a workaround for that a month ago, how much could it have changed in the meantime). Yet if I just write out the same union (every scalar type in C, basically) and make a function that assigns some things of that union type to some other things, I can’t get the bad codegen to manifest even on Clang 9. So I’d need to do some work to make a small reproducer; then I’d have to figure out how to get access to their bug tracker, because apparently letting people register their own accounts is too easy, let alone just send mail to an address. I don’t know if I have that in me. (On a more positive note, do you know that sometimes, if you add `default: __builtin_unreachable();` to your switch-threaded interpreter loop, Clang will look at it and replicate the dispatch at the end of each bytecode instruction, like in the standard technique for better branch prediction in handwritten assembly-language interpreters? When I noticed that I couldn’t stop imagining it going “It looks you’re writing an interpreter. Would you like some help?”.)