1

Compiling the following code with clang 14.0.0 (x86-64, -O3)

double f (double x)
{
    return x + 5.0 + 0;
}

results in

.LCPI0_0:
  .quad 0x4014000000000000 # double 5
f(double): # @f(double)
  addsd xmm0, qword ptr [rip + .LCPI0_0]
  xorpd xmm1, xmm1
  addsd xmm0, xmm1
  ret

(Godbolt).

In which situation does the sequence

  xorpd xmm1, xmm1
  addsd xmm0, xmm1

make any difference?

While I am aware that float constant folding without -ffast-math is no possible in general, I cannot see any reason why the xord/addsd sequence is needed: It does not change the bit pattern in xmm0, I cannot see how it could trigger an exception or have any other side effect.

Edit: clang's default is -fno-rounding-math (see manual). So it is safe to assume x + 5.0 never results in -0.0 and thus +0.0 can be considered a no-op.

FPK
  • 2,008
  • 13
  • 19
  • 1
    Adding `+0.0` is not always a no-op for strict FP math, due to signed-zero semantics (`-0.0`). IIRC, subtracting `0.0` is a no-op, and indeed, clang *does* optimize `x + 5.0 - 0` down to just an add. https://godbolt.org/z/zEdbvdv6e – Peter Cordes Jun 18 '22 at 09:15
  • 1
    Ah, it covers the case ```x=-5.0;``` in case of rounding towards negative because in this case ```5.0 - 5.0```results in ```-0.0``` .... – FPK Jun 18 '22 at 09:32
  • 1
    Or maybe it's a missed optimization; if we change the source to do `x=-5.0` first, it turns into a `return +0.0;` with or without adding zero. https://godbolt.org/z/TsG5E7ec9. And `nextafter(-5.0, -Inf) + 5.0` wouldn't underflow to `-0.0`, so I'm not sure there's a way for `x + 5.0` to actually produce `-0.0`. Perhaps with the rounding mode set to round towards -Inf? (floor)? I forget if clang assumes the current rounding mode is the default round to nearest unless told otherwise. But anyway, if so this is clearly still the reason for that missed optimization. – Peter Cordes Jun 18 '22 at 09:35
  • Yeah, I checked on real hardware, and the `addsd` produces a `0.0`, integer zero bit-pattern. This is a missed optimization at least for the default rounding mode, because the value we're adding 0 to can't be `-0.0`. IDK if it's worth reporting this; seems like a serious corner case for LLVM to look for, most source code doesn't add a zero after another constant. – Peter Cordes Jun 18 '22 at 09:48
  • No, it is unlikely that somebody writes such code. But it could be the result of some automatically generated code or the output of macros or templates. – FPK Jun 18 '22 at 10:00
  • Yes, it could be, it has non-zero value, but it also costs compile-time to look for it. I guess only in a case where you're already adding `+0`, though, which is already a special case. So there's hopefully be no slowdown for the common case. – Peter Cordes Jun 18 '22 at 10:03
  • 1
    [Why does Clang optimize away x \* 1.0 but NOT x + 0.0?](https://stackoverflow.com/q/33272994) confirms that `-5 + 5` should produce `-0.0` in roundTowardNegative mode. So the optimization is only allowed if clang can assume the default rounding mode. (Or with `-fno-signed-zeros` to forget about those semantics: https://godbolt.org/z/KdeYqej3b) – Peter Cordes Jun 18 '22 at 10:07
  • 1
    But https://clang.llvm.org/docs/UsersManual.html says ```-fno-rounding-math```is the default. So clang could assume there is no round to negative. So ```5.0 - 5.0``` cannot be ```-0.0```. – FPK Jun 18 '22 at 10:12
  • Thanks, that's what I was going to investigate next. Yeah, missed optimization, then. You can report it on https://github.com/llvm/llvm-project/issues. Feel free to link this Q&A and/or quote some of my comments. – Peter Cordes Jun 18 '22 at 10:14
  • Oh right, [as Marc Glisse (GCC dev) points out](https://stackoverflow.com/questions/33272994/why-does-clang-optimize-away-x-1-0-but-not-x-0-0#comment74952587_33273367), optimizing away `- 0.0` isn't legal with `-frounding-math`, because it can change `+0.0` into `-0.0`. https://godbolt.org/z/E9rcGj3ro confirms that current GCC and clang both handle it correctly. But as Marc warns, it still doesn't correctly handle the case of the rounding mode changing within a function: https://gcc.gnu.org/wiki/FloatingPointMath. e.g. doing common-subexpression elim across potential rounding-mode changes. – Peter Cordes Jun 18 '22 at 10:24
  • So anywhere that optimizing away `x - 0.0` is legal, so is optimizing away `x + 0.0` if `x` is the result of adding or subtracting a non-zero value. (There might be corner cases like FTZ without DAZ, though: `-DBL_MIN` plus a small positive subnormal would flush to `-0.0`. But other than that, I don't think it's possible for FP addition to underflow to zero, only produce zero exactly. Thus the rule about giving +0.0 for a sum/difference of zero applies, except when the inputs were both negative zero.) – Peter Cordes Jun 18 '22 at 10:34

0 Answers0