[llvm-dev] Proposed new min and max intrinsics

Thomas Lively via llvm-dev llvm-dev at lists.llvm.org
Fri Nov 9 14:54:34 PST 2018


Unfortunately the draft spec in section 6.2.3 does specify that the output
NaN should be one of the input NaNs, and this property is important for
WebAssembly as well. It's good to know that the bar for unreasonable
expansions is higher than I would have expected.

On Fri, Nov 9, 2018 at 2:22 PM Fabian Giesen <fabiang at radgametools.com>
wrote:

> Ah, forget about the +-0 issue!
>
> Slightly different way to handle them: XOR the two arguments, AND to
> keep only the sign bit, then OR it back into the result at the end (for
> minimum; maximum would do a bit clear/and-not).
>
> The argument goes as follows:
> 1) If the two sign bits agree, this does nothing
> 2) If the two sign bits disagree:
>    2.1) If the comparison was unordered, we already return a NaN; this
> makes us return a NaN with sign bit set. (But still a NaN. I don't see
> anything in the rules for minimum/maximum guaranteeing a specific NaN.)
>    2.2) If the comparison was ordered and not between two 0s, the value
> with the sign bit set is the smaller one, so the OR ends up doing nothing.
>    2.3) If the comparison was ordered and between two 0s, the OR
> guarantees we return a negative 0.
>
> If you write this out with the required bitcasts it probably still gets
> lengthy in LLVM IR form (so might still want to put it in compiler-rt),
> but this seems like a preferable implementation provided the target lets
> you do the required bitwise ops on FP registers.
>
> -Fabian
>
> On 11/9/18 10:56 AM, Thomas Lively wrote:
>
> > I would agree, but the expansion also has to properly treat negative
> > zero as less than zero, which leads to something like the following:
> >
> > ;; Find minimum if both zero
> > %a_sign = fgetsign %a
> > %b_sign = fgetsign %b
> > %a_is_lesser_zero = icmp ugt %a_sign, %b_sign
> > %minimum_zeros = select %a_is_lesser_zero, %a, %b
> >
> > ;; Find minimum if not both zero (from above)
> > %no_nan_and_a_lesser = fcmp olt %a, %b
> > %lesser_or_b_if_nan = select %no_nan_and_a_lesser, %a, %b
> > %a_not_nan = fcmp ord %a, %a
> > %minimum_not_zeros = select %a_not_nan, %lesser_or_b_if_nan, %a
> >
> > ;; Choose between zeros and not-zeros
> > %a_is_zero = fcmp oeq %a, 0
> > %b_is_zero = fcmp oeq %b, 0
> > %both_zero = and %a_is_zero, %b_is_zero
> > %minimum = select %both_zero, %minimum_zeros, %minimum_not_zeros
> >
> > Which is considerably less reasonable.
> >
> >
> >
> > On Fri, Nov 9, 2018 at 7:00 AM Cameron McInally via llvm-dev
> > <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
> >
> >     On Thu, Nov 8, 2018 at 11:35 PM Fabian Giesen via llvm-dev
> >     <llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>> wrote:
> >
> >         What is so complicated about these? Shouldn't they just
> >         correspond to
> >         two compares + selects?
> >
> >         To give a concrete example, x86 MIN[SP][SD] and MAX[SP][SD],
> >         respectively, correspond exactly to
> >
> >            MIN*: select(a < b, a, b) (i.e. "a < b ? a : b")
> >            MAX*: select(a > b, a, b) (i.e. "a > b ? a : b")
> >
> >         IIRC, MINIMUM and MAXIMUM have the added requirement that they
> >         should
> >         return NaN if _either_ input is NaN, whereas the above will
> >         return NaN
> >         if the second input (i.e. b) is NaN, but not if the first is.
> >
> >         So we need to explicitly catch the case where a is NaN as
> >         well. For
> >         minimum, that works out to something like:
> >
> >            %3 = fcmp olt float %a, %b
> >            %4 = select i1 %3, float %a, float %b ; (a < b) ? a : b
> >            %5 = fcmp ord float %a, %a ; true if !isNaN(a)
> >            %6 = select i1 %5, float %4, float %a ; if a was NaN, return a
> >
> >         for the entire operation. The logic here is that if isNaN(a) ||
> >         isNaN(b), the initial comparison will evaluate to false and %4
> >         ends up
> >         being b. If isNaN(b), this is a NaN value (as required). The
> >         case we are
> >         missing is when isNaN(a) && !isNaN(b), where %4 is not a NaN;
> >         the second
> >         compare + select fixes that one up.
> >
> >         The first pair of these corresponds to a single (x86-style)
> >         MIN/MAX, and
> >         the second turns into a compare followed by (depending on target
> >         instruction set) either a BLEND or some logic ops.
> >
> >         For minimumNumber/maximumNumber, you should be able to use a
> >         similar
> >         construction. Showing the example for minimumNumber here:
> >
> >            %3 = fcmp olt float %a, %b
> >            %4 = select i1 %3, float %a, float %b ; (a < b) ? a : b
> >            %5 = fcmp ord float %b, %b ; true if !isNaN(b)
> >            %6 = select i1 %5, float %4, float %a ; if b was NaN, return a
> >
> >         Starts out the same as before. Here, the tricky case is
> >         !isNaN(a) &&
> >         isNaN(b). The initial select %4 will result in the (NaN) b in
> >         that case,
> >         and the second compare/select pair switches the result to a
> >         instead; we
> >         will only get a NaN result if both inputs were NaN.
> >
> >         I might be missing something here, but that seems like a
> >         fairly harmless
> >         expansion, as such things go, and going to compiler-rt feels
> >         like overkill.
> >
> >
> >     +1
> >     _______________________________________________
> >     LLVM Developers mailing list
> >     llvm-dev at lists.llvm.org <mailto:llvm-dev at lists.llvm.org>
> >     http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
> >
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20181109/eb79b69d/attachment.html>


More information about the llvm-dev mailing list