[llvm] [InstCombine] Fold more 'fcmp' 'select' instrs idioms into 'fabs' (PR #83381)

Joshua Cranmer via llvm-commits llvm-commits at lists.llvm.org
Wed Mar 27 12:17:07 PDT 2024


jcranmer-intel wrote:

> If we fixed that and added a way to attach fast-math flags to parameters, that might also be a way to solve this. That seems to be the direction you were going with the `nofpclass` attributes. We talked about this a bit in today LLVM FP working group meeting, and @jcranmer-intel expressed general concerns about setting fast-math flags on `select` and `phi` instructions. I think his concerns about the vagueness of the semantics in that case would also apply to using it on a function argument.
> 
> Specifically, Joshua's concern is that select and phi don't actually perform an operation, they are just data moving operations, so fast-math shouldn't affect their results. That's a general concern he has, not specific to the `nsz` flag, I think, but the current definition of `nsz` is definitely insufficient. It says "Allow optimizations to treat the sign of a zero argument or zero result as insignificant." That's a bit ambiguous. I think we need it to say something like "Allow optimizations to treat 0.0 and -0.0 as if they were exactly the same value when used as arguments and return values."

To elucidate this with more detail:
`nsz` (and to a degree `nofpclass`-like stuff in general) are--to a high-level programming language--essentially exposing new variants of floating-point types that have slightly different representations. For `nofpclass`, it's an assertion that certain classes are trap representations; for `nsz`, it considers there to be a single `0` value that has two equivalent representations that is not expected to be stable (almost like NaN payloads, although we would want something weaker than LLVM's payload guarantees). In other words, if LLVM had a `fast_float` type, we wouldn't need any flags on PHIs or selects to enable this optimization, since the type alone would be sufficient to guarantee it.

In lieu of a new floating-point type family, we're essentially inferring the floating-point type of the values based on the flags applied to operations, with bitcasts between the types being implicit. But without flags on select, we have no way to distinguish between `cmp(fast_float x) { x < 0 ? -x : x }` (where the optimization is legal) and `cmp(float x) { (fast_float)x < 0 ? -(fast_float)x : x }` (where it's not legal).

You might get back there by being able to annotate basically any float value with something indicating the desired `nsz` bit on arguments and loads and casts and intrinsics and etc. that let you exhaustively distinguish between `fast_float` and `float` for all operands (there's still several FP instructions right now that can't have fast math flags, like casts). In such a scenario, I think you can have a reliable rule that a `select` or a `phi` where all arguments are `nsz` is itself `nsz`.

https://github.com/llvm/llvm-project/pull/83381


More information about the llvm-commits mailing list