This is an archive of the discontinued LLVM Phabricator instance.

[ValueTracking] Add support for floating-point minnum and maxnum
ClosedPublic

Authored by jmolloy on Jul 13 2015, 8:26 AM.

Details

Summary

The select pattern recognition in ValueTracking (as used by InstCombine
and SelectionDAGBuilder) only knew about integer patterns. This teaches
it about minimum and maximum operations.

The semantics of the patterns it matches match the C99 minnum/maxnum
operations; namely that when presented with two operands one of which
being a QNaN, the non-QNaN operand is returned.

Diff Detail

Repository
rL LLVM

Event Timeline

jmolloy updated this revision to Diff 29572.Jul 13 2015, 8:26 AM
jmolloy retitled this revision from to [ValueTracking] Add support for floating-point minnum and maxnum.
jmolloy updated this object.
jmolloy added a reviewer: hfinkel.
jmolloy set the repository for this revision to rL LLVM.
jmolloy added a subscriber: llvm-commits.
jmolloy added inline comments.Jul 13 2015, 8:31 AM
lib/Transforms/InstCombine/InstCombineSelect.cpp
42

I've currently put the onus on the user of matchSelectPattern to work out if an ordered or unordered FCMP is needed. I was in two minds about this, the alternative being to change matchSelectPattern to return a struct containing the pattern kind, the orderedness and the fast-math flags if applicable.

jmolloy updated this revision to Diff 29667.Jul 14 2015, 5:24 AM

Updated diff:

  1. Added extra checking to ensure we don't convert (0.0 <= -0.0 ? 0.0 : -0.0) to minnum, as we'll return the wrong value.
  2. Switched the logic for which operand needs to be non-NaN for unordered and ordered comparisons - it turns out there are two mutually-incompatible implementations of this, one in the ARM backend and one in AArch64. It looks like AArch64 is correct; luckily both will be defunct in a few commits time!
jmolloy updated this revision to Diff 29783.Jul 15 2015, 8:13 AM
jmolloy added reviewers: t.p.northover, majnemer.

Hi,

It's a good thing this hasn't started being reviewed yet - I've just rewritten a bunch of it because I realised the previous implementation wasn't sufficient.

The previous version was only matching C99-style fminf/fmaxf; if one operand is NaN, it must return the other operand. However, idiomatic C is the opposite - "a < b ? a : b" would return NaN (due to ordered comparisons).

So now matchSelectPattern detects floating point mins and maxes regardless of its behaviour under NaN, and returns an extra enum value informing the user what its NaN behaviour is.

If the user (such as InstCombine) wants to rewrite the min/max, they have to use the correct ordered/unordered predicates in their FCMP, so it also returns the orderedness required (if any).

Adding extra reviewers too to widen the review net a bit and because I've been unfairly loading Hal recently!

arsenm added a subscriber: arsenm.Jul 15 2015, 11:35 AM
arsenm added inline comments.
lib/Analysis/ValueTracking.cpp
3325–3326

No return after else

3332–3333

ditto

3358

This could use a better name.

3402–3404

This indentation is confusing looking. The assignments should be on their own line, the O = !O looks like it's under the else if

test/Transforms/InstCombine/minmax-fp.ll
140

I don't think I see a test that explicitly checks for fcmp nnan

unittests/Analysis/ValueTrackingTest.cpp
37

I don't think you need the .c_str() here

jmolloy updated this revision to Diff 29876.Jul 16 2015, 2:35 AM
jmolloy removed rL LLVM as the repository for this revision.
jmolloy marked 5 inline comments as done.

Hi Matt,

Thanks for your review! All your comments applied.

Cheers,

James

majnemer added inline comments.Jul 16 2015, 2:46 AM
lib/Analysis/ValueTracking.cpp
3323

Use auto *, we know the type from the LHS.

3329

Ditto.

jmolloy updated this revision to Diff 29880.Jul 16 2015, 3:52 AM
jmolloy set the repository for this revision to rL LLVM.

Hi David,

Thanks for your review. Done!

James

arsenm added inline comments.Jul 16 2015, 11:13 AM
lib/Analysis/ValueTracking.cpp
3345

This comment is inaccurate. minnum is specifically allowed to return either 0.0 or -0.0 in this case

3362

This comment is also inaccurate.

a < b is an ordered comparison.
If a is NaN the compare is false and this will return b.
If b is NaN, this will return the NaN b. This is the behavior of the min/max_legacy AMDGPU instructions which do behave as a compare + select. minnum/maxnum can't be matched to a single compare and select except in the special no nan cases. I think the code below is doing the right thing though.

jmolloy updated this revision to Diff 29980.Jul 17 2015, 12:53 AM

Hi Matt,

Agreed. Comments updated.

I've kept the conservative behaviour of bailing out when one input may be a signed zero (and nsz is not set) for the moment.

If you think it's worth being more aggressive in that case, We'll need to add another field to SelectPatternResult modelling the behavior with signed zeroes (ARM's minnum instruction would return -0.0; I have no idea what yours might do). But I suspect there aren't enough cases to justify this extra modelling, not at the moment anyway.

James

jmolloy added inline comments.Jul 17 2015, 12:56 AM
lib/Analysis/ValueTracking.cpp
3362

Typo: This should of course read 'b', not 'a'; I've updated this locally.

arsenm added inline comments.Jul 20 2015, 1:15 PM
test/Transforms/InstCombine/minmax-fp.ll
5–6

I think these really need to check the operands of these instructions. At the very minimum, at least the fcmp compare type.

Besides that LGTM

hfinkel added inline comments.Jul 26 2015, 6:05 AM
lib/Analysis/ValueTracking.cpp
3345

I feel compelled to say that this is sad. The relevant text for minNum/maxNum even notes, "this means results might differ among implementations", and this is the only place I can find in the standard that says that.

3409

This comment should now say icmp/fcmp (or similar).

lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
2277–2278

Line is too long.

lib/Transforms/InstCombine/InstCombineCasts.cpp
1312

What is the canonical form? I think it would be helpful to say (or refer to somewhere else that says).

jmolloy updated this revision to Diff 30693.Jul 27 2015, 7:44 AM

Hi Matt, Hal,

Both your comments are addressed. Hal, does this LGTY?

Cheers,

James

hfinkel accepted this revision.Aug 9 2015, 7:54 PM
hfinkel edited edge metadata.

LGTM.

lib/Analysis/ValueTracking.cpp
3377

"so RHS is NaN" is a bit too much short-hand I think. We don't know that the RHS is NaN, we know that if it is NaN, then it will be returned. Please make the comment a bit more specific.

This revision is now accepted and ready to land.Aug 9 2015, 7:54 PM
jmolloy closed this revision.Aug 12 2015, 8:13 AM

Landed in r244754.