Not that it solves the actual issue at hand, but I think the better starting point is to have LLVM IR use IEEE 754 semantics (insofar as IEEE 754 fully specifies it), with an exception for the Table 9.1 math functions that are rarely implemented to the mandated correct rounding.
I’m not sure what you mean here. Can you elaborate on what IEEE 754 semantics we aren’t currently using?
There are issues like Basic floating-point operations are underspecified · Issue #60942 · llvm/llvm-project · GitHub, but that’s mostly a documentation issue there I think.
The point I was going for instead was that in terms of operational semantics, we should be able to optimize knowing the properties of IEEE 754 semantics [1]. So if we see roundToIntegralTiesToAway(0.5) (to use the IEEE 754 name of the operation), we are allowed to replace that with the value that IEEE 754 prescribes, namely, 1.0. Instead, it’s only a small subset of the operations that the compiler cannot evaluate at compile-time (probably limited to Table 9.1 of IEEE 754, or the list of functions C2x Annex F.3p20 provides that C implementations are not required to correctly round).
I guess log(-1.0) is slightly more of a gray area, but assuming you accept my premise above that changing the payload of a NaN is OK, I think we could fold “log(-1.0) → NaN” in the case of the llvm.log intrinsic since log() should always return some NaN for negative numbers and the intrinsic (unlike the function call) doesn’t have side effects. It’s interesting that the current constant folding implementation doesn’t fold this case specifically because it is checking to see if an exception is raised.
Deciding what to do affects more than constant folding; we have logic in ValueTracking (thanks to @arsenm) that narrows down the possible fpclass of calls to relevant intrinsics based on their possible fpclass inputs, so it in effect has to assume things like log(negative number) = NaN. We already have some constraints as to what the behavior of a libm log et al can do, so I think we can reasonably accept many kinds of these folds in the optimizer, even without always folding it. But it does require some investigation to figure out how reliable various libm implementations to know which inputs we can assume are reliably handled and foldable.