Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

> 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 and tell me where the ADD instruction shows up in the compiler output. Feel free to pick a different compiler target than Risc-V.



I 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


The parent example can be made clearer like this: https://godbolt.org/z/MKWbz9W16

Dead code elimination only works here because integer overflow is UB.


Take 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.


In 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


`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.


> 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.


C 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

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.


> 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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: