4 ms·
a+=1 will not produce any surprising results, signed integer overflow is well defined on all platforms that matter. And we all know about the looping behavior,
by TinkersW 2y ago
a+=1 will not produce any surprising results, signed integer overflow is well defined on all platforms that matter.
And we all know about the looping behavior, it isn't surprising.
The only surprising part would be if the compiler decides to use inc vs add, not that it really matters to the result.
- eru 2y ago> a+=1 will not produce any surprising results, signed integer overflow is well defined on all platforms that matter. I'm not sure what you are talking about? There's a difference between how your processor behaves when given some specific instructions, and what shenanigans your C compiler gets up to. See eg https://godbolt.org/z/YY69Ezxnv https://godbolt.org/z/YY69Ezxnv and tell me where the ADD instruction shows up in the compiler output. Feel free to pick a different compiler target than Risc-V.
- jmillikin 2y agoI don't think "dead-code elimination removes dead code" adds much to the discussion. If you change the code so that the value of `a` is used, then the output is as expected: https://godbolt.org/z/78eYx37WG https://godbolt.org/z/78eYx37WG
- xmcqdpt2 2y agoThe parent example can be made clearer like this: https://godbolt.org/z/MKWbz9W16 https://godbolt.org/z/MKWbz9W16 Dead code elimination only works here because integer overflow is UB.
- jmillikin 2y agoTake a closer look at 'eru's example and my follow-up. He wrote an example where the result of `a+1` isn't necessary, so the compiler doesn't emit an ADDI even though the literal text of the C source contains the substring "a += 1". Your version has the same issue: unsigned int square2(unsigned int num) { unsigned int a = num; a += 1; if (num < a) return num * num; return num; } The return value doesn't depend on `a+1`, so the compiler can optimize it to just a comparison. If you change it to this: unsigned int square2(unsigned int num) { unsigned int a = num; a += 1; if (num < a) return num * a; return num; } then the result of `a+1` is required to compute the result in the first branch, and therefore the ADDI instruction is emitted. The (implied) disagreement is whether a language can be considered to be "portable assembly" if its compiler elides unnecessary operations from the output. I think that sort of optimization is allowed, but 'eru (presumably) thinks that it's diverging too far from the C source code.
- gpderetta 2y agoIn what world the return value doesn't depends on 'a' in this code? if (num < a) return num * num; /*else*/ return num; A control dependency is still a dependency
- jmillikin 2y ago`a = num; a += 1; if (num < a)` is the same as `if (num < (num + 1))`, which for unsigned integer addition can be rewritten as `if (num != UINT_MAX)`. So there's no need to actually compute `a+1`, the comparison is against a constant. If the code returns `num * a` then the value of `a` is now necessary, and must be computed before the function returns. For signed integer addition the compiler is allowed to assume that `(num < (num + 1))` is true, so the comparison can be removed entirely.
- eru 2y ago> For signed integer addition the compiler is allowed to assume that `(num < (num + 1))` is true, so the comparison can be removed entirely. That's not directly what the compiler assumes. The direct problem is in 'a + 1' having undefined behaviour, and that transitively allows the assumption on the comparison that you mentioned. This was an example where 'a + 1' doesn't compile to an add instruction.
- xmcqdpt2 2y agoC compilers are just too smart IMO to make C portable assembly. Your example doesn’t always ADDI either, for example if it is inlined https://godbolt.org/z/vv9rvKsxn https://godbolt.org/z/vv9rvKsxn This isn’t qualitatively different from what the JVM JIT would do, but Java isn’t considered portable assembly. I guess if you compile with optimizations completely off, you get something that is assembly-like, but I’ve never seen that in prod code.
- eru 2y ago> He wrote an example where the result of `a+1` isn't necessary, so the compiler doesn't emit an ADDI even though the literal text of the C source contains the substring "a += 1". No, the result of the 'a+1' is necessary in my version. And if you change the type from 'int' to 'unsigned' you will see that the compiler no longer just omits the addition.