Hacker News new | past | comments | ask | show | jobs | submit login

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




Join us for AI Startup School this June 16-17 in San Francisco!

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

Search: