[RFC] A consistent set of semantics for the floating-point minimum and maximum operations

(Sorry about lack of an earlier response, I took a long december holiday!)

  1. Make Clang guarantee signed zero ordering for fmin. I don’t think we should do this unless and until the C standard makes this a requirement.

Agree, especially because it would require that we avoid libcalls, which is a non-starter.

C23 added fminimum_num, which guarantees signed zero ordering

Yes, but fmin is a much better name, so I predict that everyone’s going to keep using it. Anytime the language has nondeterminism in its semantics is unfortunate. IMHO, nondeterminism in sign of zeros is not a desirable feature to have by default (users who want this should ask for it with -fno-signed-zeros!), and I hope a future C standard does tighten the rules on fmin.

And one way to make it more likely for a future standard to do this is if implementations are already aligning in that direction.

  1. Make Clang respect signed zero ordering in inline expansions as a matter of QoI, but still lower to libcalls that may not have signed zero ordering. TBH I don’t understand what benefit this approach provides.

Yes, this is the alternative I support.

The benefit would be that it moves us towards eliminating this weird gotcha from fmin/fmax, but without the downsides of losing the ability to lower fmin to a libcall while everything is in flux.

On many platforms other than x86, the most efficient possible implementation already orders zeros for free. Having LLVM IR semantics defined such that it allows the compiler to “misoptimize” code which naturally works is unfortunate.

I will grant that only users of platforms where libc also provides the “recommended” behavior would immediately benefit…but there’s already many such libc, and more may be fixed in the future. I sent a patch to glibc right before holidays to modify all of its its fmin/fmax implementations always order signed zeros. I now need to address feedback on that patch, but early response looks somewhat positive, so it’s possible that the next release of glibc’s out-of-line fmin implementation will order signed zeros on all platforms.

We get the cost of signed zero ordering on x86, without getting the benefit of guaranteed signed zero order.

The cost on X86 inline lowering seems to be a key point of conflict in this debate. So, I’d like to decouple my suggestion from the discussion on whether to change the X86 backend’s lowering.

I propose that we should, at least for now, leave X86 lowering of llvm.minnum as is, and ensure LangRef semantics remain compatible with that. I would, therefore, like the wording to specify that some targets might reliably order signed zeros but others may not. The concrete effect of this would be to allow X86 backend’s current lowering, but to prohibit middle-end optimization passes from breaking the signed-zero ordering for targets which do provide it e.g. aarch64.

(Potentially, at some future point in time, I think we could still modify the X86 backend’s lowering to order signed zeros. I don’t think the cost is really excessive. But, the time for that is not now.)