Issue 91674
Summary __arithmetic_fence() doesn't protect against contract in clang
Labels clang, floating-point
Assignees
Reporter andykaylor
    clang only generates an intrinsic call for the __arithmetic_fence builtin if reassociation is enabled. That covers most cases, but there are some cases where fp-contract can lead to operations being fused across the fence.

The simplest case occurs like this:
```
float foo(float a, float b, float c) {
  return __arithmetic_fence(a * b) + c;
}
```
When this code is compiled with `clang -O2 -mfma` the fence will be ignored and an FMA instruction will be generated.

https://godbolt.org/z/77KdorPj8

A more complicated case can occur with `-ffp-contract=fast` if I'm trying to use a fence to limit which part of an _expression_ can be contracted.
```
float foo(float a, float b, float c, float d) {
  return a + __arithmetic_fence(b * c + d);
}
```
Here the front end will generate `fmul` and `fadd` instructions with the `contract` flag set, leaving it to the backend to determine what gets contracted. That's usually ok, but if I compile this with `-ffp-contract=fast -fno-signed-zeros` and the optimizer ends up being able to prove that `d` is zero, the _expression_ will get fused as fma(a, b, c). If I compile with `-ffast-math` instead, the `llvm.arithmetic.fence()` intrinsic is generated and the fusion is protected as intended.

https://godbolt.org/z/b1Mq6EeYY
_______________________________________________
llvm-bugs mailing list
llvm-bugs@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to