3 ms·
It's valuable for compilers to be able to choose the instruction scheduling order. Standards authors try not to unnecessarily bind implementors. If post increme
by AlotOfReading 5mo ago
It's valuable for compilers to be able to choose the instruction scheduling order. Standards authors try not to unnecessarily bind implementors. If post increment happened after the full statement is finished, then the original value has to be maintained until the next sequence point. Maybe the compiler will be smart enough to elide that, maybe not, but it's a lot more difficult to fix those kinds of edge cases than to say sequencing is undefined.
- Aardwolf 5mo agoBut this is not valuable if doing so results in different numerical results, and I think that will always happen if ++ is executed at different times, there's no point in a compiler optimizing pointless code that can silently give different results elsewhere
- AlotOfReading 5mo agoYour compiler does many optimizations that break numerical reproducibility, especially in floats. I reviewed a PR the other day that wrote X=AB+(CD)+E; And when I checked 3 different compilers, each of them chose a different way to use FMAs. Even with integer math, you can get different numerical results via UB (e.g. expressions with signed overflow one way and not another).
- daemin 5mo agoFloating point reproducibility and cross platform determinism requires strict adherence to the IEEE standard and disabling of fused instructions.
- AlotOfReading 5mo agoThe point being that there are many other places where reproducibility fails to hold, especially when optimizations are involved. The standard doesn't mandate a way to disable contraction, nor the existence (or absence) of -ffast-math and others. They're simply different, legal compilations within the broad scope allowed under the standard.
- deleted 5mo ago[deleted]
- Karliss 5mo agoThe same rule which makes the evaluation order of a++ + ++a unsequenced also applies to (x+y+z+a+b+c) where x,y,z could be any expression (in a sane case on separate variables and without mix of pre/post increments). Breaking questionable code and introducing UB where reordering changes result is just a side effect of this. Just switching between left to right or right to left wouldn't be that useful but it also permits to interleave the subexpression evaluation. Grouping memory fetches/writes, taking into account how many execution units and registers of different kinds a CPU has can have some performance benefits. For example if you have something like `++a[0] + ++a[1] + ++a[2] + ++a[3]` instead of evaluating each increment one by one both GCC and Clang will vectorize it loading all 4 values from memory using single simd instruction, incrementing and then writing result back to memory. And if you add fifth one (but not 8) which needs to be handled using regular instruction, that will be done after the first 4. If standard defined that left subexpression of addition is fully evaluated before the right expression that wouldn't be allowed.
- jcparkyn 5mo ago> If standard defined that left subexpression of addition is fully evaluated before the right expression that wouldn't be allowed. I'm no expert, but surely this would still be allowed so long as the compiler can prove that incrementing a[0] has no effect on the value of a[1]?
- xigoi 5mo agoIt would only make a difference in cases that are currently UB, so there is no program valid under current C that would be pessimized by this change.
- AlotOfReading 5mo agoIt's a language feature that was in K&R, and the rules around sequencing were introduced in C89. There were good reasons to believe it would pessimize code in the following decades. Dennis Richie himself pointed out that Thompson probably added the operators because compilers of the time were able to generate better code that way.