diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h index 8c6b7895470b8..c3349c9772c7a 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -2387,6 +2387,32 @@ m_UnordFMin(const LHS &L, const RHS &R) { return MaxMin_match(L, R); } +/// Match an 'ordered' or 'unordered' floating point maximum function. +/// Floating point has one special value 'NaN'. Therefore, there is no total +/// order. However, if we can ignore the 'NaN' value (for example, because of a +/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'maximum' +/// semantics. +template +inline match_combine_or, + MaxMin_match> +m_OrdOrUnordFMax(const LHS &L, const RHS &R) { + return m_CombineOr(MaxMin_match(L, R), + MaxMin_match(L, R)); +} + +/// Match an 'ordered' or 'unordered' floating point minimum function. +/// Floating point has one special value 'NaN'. Therefore, there is no total +/// order. However, if we can ignore the 'NaN' value (for example, because of a +/// 'no-nans-float-math' flag) a combination of a fcmp and select has 'minimum' +/// semantics. +template +inline match_combine_or, + MaxMin_match> +m_OrdOrUnordFMin(const LHS &L, const RHS &R) { + return m_CombineOr(MaxMin_match(L, R), + MaxMin_match(L, R)); +} + /// Matches a 'Not' as 'xor V, -1' or 'xor -1, V'. /// NOTE: we first match the 'Not' (by matching '-1'), /// and only then match the inner matcher! diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp index 53001421ce6f7..76cde01782bb0 100644 --- a/llvm/lib/Analysis/IVDescriptors.cpp +++ b/llvm/lib/Analysis/IVDescriptors.cpp @@ -690,13 +690,9 @@ RecurrenceDescriptor::isMinMaxPattern(Instruction *I, RecurKind Kind, return InstDesc(Kind == RecurKind::SMax, I); if (match(I, m_SMin(m_Value(), m_Value()))) return InstDesc(Kind == RecurKind::SMin, I); - if (match(I, m_OrdFMin(m_Value(), m_Value()))) + if (match(I, m_OrdOrUnordFMin(m_Value(), m_Value()))) return InstDesc(Kind == RecurKind::FMin, I); - if (match(I, m_OrdFMax(m_Value(), m_Value()))) - return InstDesc(Kind == RecurKind::FMax, I); - if (match(I, m_UnordFMin(m_Value(), m_Value()))) - return InstDesc(Kind == RecurKind::FMin, I); - if (match(I, m_UnordFMax(m_Value(), m_Value()))) + if (match(I, m_OrdOrUnordFMax(m_Value(), m_Value()))) return InstDesc(Kind == RecurKind::FMax, I); if (match(I, m_Intrinsic(m_Value(), m_Value()))) return InstDesc(Kind == RecurKind::FMin, I); diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 446ff42f3e243..be0df136bd752 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -8240,9 +8240,7 @@ static SelectPatternResult matchFastFloatClamp(CmpInst::Predicate Pred, case CmpInst::FCMP_OLE: case CmpInst::FCMP_ULT: case CmpInst::FCMP_ULE: - if (match(FalseVal, - m_CombineOr(m_OrdFMin(m_Specific(CmpLHS), m_APFloat(FC2)), - m_UnordFMin(m_Specific(CmpLHS), m_APFloat(FC2)))) && + if (match(FalseVal, m_OrdOrUnordFMin(m_Specific(CmpLHS), m_APFloat(FC2))) && *FC1 < *FC2) return {SPF_FMAXNUM, SPNB_RETURNS_ANY, false}; break; @@ -8250,9 +8248,7 @@ static SelectPatternResult matchFastFloatClamp(CmpInst::Predicate Pred, case CmpInst::FCMP_OGE: case CmpInst::FCMP_UGT: case CmpInst::FCMP_UGE: - if (match(FalseVal, - m_CombineOr(m_OrdFMax(m_Specific(CmpLHS), m_APFloat(FC2)), - m_UnordFMax(m_Specific(CmpLHS), m_APFloat(FC2)))) && + if (match(FalseVal, m_OrdOrUnordFMax(m_Specific(CmpLHS), m_APFloat(FC2))) && *FC1 > *FC2) return {SPF_FMINNUM, SPNB_RETURNS_ANY, false}; break; diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index 358563a5fcd53..2ae3698295434 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -3834,11 +3834,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) { // minnum/maxnum intrinsics. if (SIFPOp->hasNoNaNs() && SIFPOp->hasNoSignedZeros()) { Value *X, *Y; - if (match(&SI, m_OrdFMax(m_Value(X), m_Value(Y)))) + if (match(&SI, m_OrdOrUnordFMax(m_Value(X), m_Value(Y)))) return replaceInstUsesWith( SI, Builder.CreateBinaryIntrinsic(Intrinsic::maxnum, X, Y, &SI)); - if (match(&SI, m_OrdFMin(m_Value(X), m_Value(Y)))) + if (match(&SI, m_OrdOrUnordFMin(m_Value(X), m_Value(Y)))) return replaceInstUsesWith( SI, Builder.CreateBinaryIntrinsic(Intrinsic::minnum, X, Y, &SI)); } diff --git a/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll b/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll index 1dd0b17e9f46d..c6fee0914f0e7 100644 --- a/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll +++ b/llvm/test/Transforms/InstCombine/clamp-to-minmax.ll @@ -67,10 +67,10 @@ define float @clamp_float_fast_ordered_nonstrict_minmax(float %x) { ; (X < C1) ? C1 : MIN(X, C2) define float @clamp_float_fast_unordered_strict_maxmin(float %x) { ; CHECK-LABEL: @clamp_float_fast_unordered_strict_maxmin( -; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02 -; CHECK-NEXT: [[MIN:%.*]] = select fast i1 [[CMP2_INV]], float 2.550000e+02, float [[X]] -; CHECK-NEXT: [[R1:%.*]] = call fast float @llvm.maxnum.f32(float [[MIN]], float 1.000000e+00) -; CHECK-NEXT: ret float [[R1]] +; CHECK-NEXT: [[MIN:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02) +; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ult float [[X]], 1.000000e+00 +; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]] +; CHECK-NEXT: ret float [[R]] ; %cmp2 = fcmp fast ult float %x, 255.0 %min = select i1 %cmp2, float %x, float 255.0 @@ -82,10 +82,10 @@ define float @clamp_float_fast_unordered_strict_maxmin(float %x) { ; (X <= C1) ? C1 : MIN(X, C2) define float @clamp_float_fast_unordered_nonstrict_maxmin(float %x) { ; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_maxmin( -; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02 -; CHECK-NEXT: [[MIN:%.*]] = select fast i1 [[CMP2_INV]], float 2.550000e+02, float [[X]] -; CHECK-NEXT: [[R1:%.*]] = call fast float @llvm.maxnum.f32(float [[MIN]], float 1.000000e+00) -; CHECK-NEXT: ret float [[R1]] +; CHECK-NEXT: [[MIN:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02) +; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ule float [[X]], 1.000000e+00 +; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 1.000000e+00, float [[MIN]] +; CHECK-NEXT: ret float [[R]] ; %cmp2 = fcmp fast ult float %x, 255.0 %min = select i1 %cmp2, float %x, float 255.0 @@ -97,10 +97,10 @@ define float @clamp_float_fast_unordered_nonstrict_maxmin(float %x) { ; (X > C1) ? C1 : MAX(X, C2) define float @clamp_float_fast_unordered_strict_minmax(float %x) { ; CHECK-LABEL: @clamp_float_fast_unordered_strict_minmax( -; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[MAX:%.*]] = select fast i1 [[CMP2_INV]], float 1.000000e+00, float [[X]] -; CHECK-NEXT: [[R1:%.*]] = call fast float @llvm.minnum.f32(float [[MAX]], float 2.550000e+02) -; CHECK-NEXT: ret float [[R1]] +; CHECK-NEXT: [[MAX:%.*]] = call fast float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00) +; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast ugt float [[X]], 2.550000e+02 +; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]] +; CHECK-NEXT: ret float [[R]] ; %cmp2 = fcmp fast ugt float %x, 1.0 %max = select i1 %cmp2, float %x, float 1.0 @@ -112,10 +112,10 @@ define float @clamp_float_fast_unordered_strict_minmax(float %x) { ; (X >= C1) ? C1 : MAX(X, C2) define float @clamp_float_fast_unordered_nonstrict_minmax(float %x) { ; CHECK-LABEL: @clamp_float_fast_unordered_nonstrict_minmax( -; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast ole float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[MAX:%.*]] = select fast i1 [[CMP2_INV]], float 1.000000e+00, float [[X]] -; CHECK-NEXT: [[R1:%.*]] = call fast float @llvm.minnum.f32(float [[MAX]], float 2.550000e+02) -; CHECK-NEXT: ret float [[R1]] +; CHECK-NEXT: [[MAX:%.*]] = call fast float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00) +; CHECK-NEXT: [[CMP1:%.*]] = fcmp fast uge float [[X]], 2.550000e+02 +; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP1]], float 2.550000e+02, float [[MAX]] +; CHECK-NEXT: ret float [[R]] ; %cmp2 = fcmp fast ugt float %x, 1.0 %max = select i1 %cmp2, float %x, float 1.0 @@ -127,13 +127,12 @@ define float @clamp_float_fast_unordered_nonstrict_minmax(float %x) { ; Some more checks with fast ; (X > 1.0) ? min(x, 255.0) : 1.0 -; That did not match because select was in inverse order. define float @clamp_test_1(float %x) { ; CHECK-LABEL: @clamp_test_1( -; CHECK-NEXT: [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02 -; CHECK-NEXT: [[INNER_SEL:%.*]] = select fast i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]] -; CHECK-NEXT: [[R1:%.*]] = call fast float @llvm.maxnum.f32(float [[INNER_SEL]], float 1.000000e+00) -; CHECK-NEXT: ret float [[R1]] +; CHECK-NEXT: [[INNER_SEL:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02) +; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast ugt float [[X]], 1.000000e+00 +; CHECK-NEXT: [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 1.000000e+00 +; CHECK-NEXT: ret float [[R]] ; %inner_cmp = fcmp fast ult float %x, 255.0 %inner_sel = select i1 %inner_cmp, float %x, float 255.0 @@ -147,8 +146,7 @@ define float @clamp_test_1(float %x) { ; Like @clamp_test_1 but HighConst < LowConst define float @clamp_negative_wrong_const(float %x) { ; CHECK-LABEL: @clamp_negative_wrong_const( -; CHECK-NEXT: [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02 -; CHECK-NEXT: [[INNER_SEL:%.*]] = select fast i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]] +; CHECK-NEXT: [[INNER_SEL:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02) ; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast ugt float [[X]], 5.120000e+02 ; CHECK-NEXT: [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 5.120000e+02 ; CHECK-NEXT: ret float [[R]] @@ -163,8 +161,7 @@ define float @clamp_negative_wrong_const(float %x) { ; Like @clamp_test_1 but both are min define float @clamp_negative_same_op(float %x) { ; CHECK-LABEL: @clamp_negative_same_op( -; CHECK-NEXT: [[INNER_CMP_INV:%.*]] = fcmp fast oge float [[X:%.*]], 2.550000e+02 -; CHECK-NEXT: [[INNER_SEL:%.*]] = select fast i1 [[INNER_CMP_INV]], float 2.550000e+02, float [[X]] +; CHECK-NEXT: [[INNER_SEL:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 2.550000e+02) ; CHECK-NEXT: [[OUTER_CMP:%.*]] = fcmp fast ult float [[X]], 1.000000e+00 ; CHECK-NEXT: [[R:%.*]] = select i1 [[OUTER_CMP]], float [[INNER_SEL]], float 1.000000e+00 ; CHECK-NEXT: ret float [[R]] diff --git a/llvm/test/Transforms/InstCombine/minmax-fold.ll b/llvm/test/Transforms/InstCombine/minmax-fold.ll index 26cd4996e687d..ec1c7aff40966 100644 --- a/llvm/test/Transforms/InstCombine/minmax-fold.ll +++ b/llvm/test/Transforms/InstCombine/minmax-fold.ll @@ -852,10 +852,8 @@ define i32 @common_factor_umax_extra_use_both(i32 %a, i32 %b, i32 %c) { define float @not_min_of_min(i8 %i, float %x) { ; CHECK-LABEL: @not_min_of_min( -; CHECK-NEXT: [[CMP1_INV:%.*]] = fcmp fast oge float [[X:%.*]], 1.000000e+00 -; CHECK-NEXT: [[MIN1:%.*]] = select fast i1 [[CMP1_INV]], float 1.000000e+00, float [[X]] -; CHECK-NEXT: [[CMP2_INV:%.*]] = fcmp fast oge float [[X]], 2.000000e+00 -; CHECK-NEXT: [[MIN2:%.*]] = select fast i1 [[CMP2_INV]], float 2.000000e+00, float [[X]] +; CHECK-NEXT: [[MIN1:%.*]] = call fast float @llvm.minnum.f32(float [[X:%.*]], float 1.000000e+00) +; CHECK-NEXT: [[MIN2:%.*]] = call fast float @llvm.minnum.f32(float [[X]], float 2.000000e+00) ; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i8 [[I:%.*]], 16 ; CHECK-NEXT: [[R:%.*]] = select i1 [[CMP3]], float [[MIN1]], float [[MIN2]] ; CHECK-NEXT: ret float [[R]] diff --git a/llvm/test/Transforms/InstCombine/minmax-fp.ll b/llvm/test/Transforms/InstCombine/minmax-fp.ll index b9e46caa63753..1276b7b3e3867 100644 --- a/llvm/test/Transforms/InstCombine/minmax-fp.ll +++ b/llvm/test/Transforms/InstCombine/minmax-fp.ll @@ -160,8 +160,7 @@ define i8 @t9(float %a) { ; Either operand could be NaN, but fast modifier applied. define i8 @t11(float %a, float %b) { ; CHECK-LABEL: @t11( -; CHECK-NEXT: [[DOTINV:%.*]] = fcmp fast oge float [[B:%.*]], [[A:%.*]] -; CHECK-NEXT: [[DOTV:%.*]] = select fast i1 [[DOTINV]], float [[A]], float [[B]] +; CHECK-NEXT: [[DOTV:%.*]] = call fast float @llvm.minnum.f32(float [[B:%.*]], float [[A:%.*]]) ; CHECK-NEXT: [[TMP1:%.*]] = fptosi float [[DOTV]] to i8 ; CHECK-NEXT: ret i8 [[TMP1]] ; @@ -282,8 +281,7 @@ define float @fneg_fmax(float %x, float %y) { define <2 x float> @fsub_fmax(<2 x float> %x, <2 x float> %y) { ; CHECK-LABEL: @fsub_fmax( -; CHECK-NEXT: [[COND_INV:%.*]] = fcmp nnan nsz ogt <2 x float> [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[MAX_V:%.*]] = select nnan nsz <2 x i1> [[COND_INV]], <2 x float> [[Y]], <2 x float> [[X]] +; CHECK-NEXT: [[MAX_V:%.*]] = call nnan nsz <2 x float> @llvm.minnum.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]]) ; CHECK-NEXT: [[MAX:%.*]] = fneg <2 x float> [[MAX_V]] ; CHECK-NEXT: ret <2 x float> [[MAX]] ; @@ -310,8 +308,7 @@ define <2 x double> @fsub_fmin(<2 x double> %x, <2 x double> %y) { define double @fneg_fmin(double %x, double %y) { ; CHECK-LABEL: @fneg_fmin( -; CHECK-NEXT: [[COND_INV:%.*]] = fcmp nnan nsz olt double [[X:%.*]], [[Y:%.*]] -; CHECK-NEXT: [[MAX_V:%.*]] = select nnan nsz i1 [[COND_INV]], double [[Y]], double [[X]] +; CHECK-NEXT: [[MAX_V:%.*]] = call nnan nsz double @llvm.maxnum.f64(double [[X:%.*]], double [[Y:%.*]]) ; CHECK-NEXT: [[MAX:%.*]] = fneg double [[MAX_V]] ; CHECK-NEXT: ret double [[MAX]] ; diff --git a/llvm/test/Transforms/InstCombine/unordered-fcmp-select.ll b/llvm/test/Transforms/InstCombine/unordered-fcmp-select.ll index 62c12c15a075c..b164dd983a892 100644 --- a/llvm/test/Transforms/InstCombine/unordered-fcmp-select.ll +++ b/llvm/test/Transforms/InstCombine/unordered-fcmp-select.ll @@ -115,7 +115,7 @@ define float @select_max_ugt_2_use_cmp(float %a, float %b) { ; CHECK-LABEL: @select_max_ugt_2_use_cmp( ; CHECK-NEXT: [[CMP:%.*]] = fcmp reassoc ugt float [[A:%.*]], [[B:%.*]] ; CHECK-NEXT: call void @foo(i1 [[CMP]]) -; CHECK-NEXT: [[SEL:%.*]] = select fast i1 [[CMP]], float [[A]], float [[B]] +; CHECK-NEXT: [[SEL:%.*]] = call fast float @llvm.maxnum.f32(float [[A]], float [[B]]) ; CHECK-NEXT: ret float [[SEL]] ; %cmp = fcmp reassoc ugt float %a, %b diff --git a/llvm/unittests/IR/PatternMatch.cpp b/llvm/unittests/IR/PatternMatch.cpp index 7dc4b9f448d38..367ba6ab52a59 100644 --- a/llvm/unittests/IR/PatternMatch.cpp +++ b/llvm/unittests/IR/PatternMatch.cpp @@ -1040,6 +1040,140 @@ TEST_F(PatternMatchTest, FloatingPointUnorderedMax) { EXPECT_EQ(R, MatchR); } +TEST_F(PatternMatchTest, FloatingPointMin) { + Type *FltTy = IRB.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + Value *MatchL, *MatchR; + + // Test OLT. + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test OLE. + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test ULT. + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test ULE. + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test no match on OGE. + EXPECT_FALSE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGE(L, R), L, R))); + + // Test no match on OGT. + EXPECT_FALSE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGT(L, R), L, R))); + + // Test no match on UGE. + EXPECT_FALSE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGE(L, R), L, R))); + + // Test no match on UGT. + EXPECT_FALSE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGT(L, R), L, R))); + + // Test inverted selects. Note, that this "inverts" the ordering, e.g.: + // %cmp = fcmp oge L, R + // %min = select %cmp R, L + + // [OU]GE with inverted select. + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGE(L, R), R, L))); + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGE(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // [OU]GT with inverted select. + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGT(L, R), R, L))); + EXPECT_TRUE(m_OrdOrUnordFMin(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGT(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); +} + +TEST_F(PatternMatchTest, FloatingPointMax) { + Type *FltTy = IRB.getFloatTy(); + Value *L = ConstantFP::get(FltTy, 1.0); + Value *R = ConstantFP::get(FltTy, 2.0); + Value *MatchL, *MatchR; + + // Test OGT. + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test OGE. + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOGE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test UGT. + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGT(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test UGE. + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpUGE(L, R), L, R))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // Test no match on OLE. + EXPECT_FALSE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLE(L, R), L, R))); + + // Test no match on OLT. + EXPECT_FALSE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLT(L, R), L, R))); + + // Test no match on ULE. + EXPECT_FALSE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULE(L, R), L, R))); + + // Test no match on ULT. + EXPECT_FALSE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULT(L, R), L, R))); + + // Test inverted selects. Note, that this "inverts" the ordering, e.g.: + // %cmp = fcmp ole L, R + // %max = select %cmp, R, L + + // [OU]LE with inverted select. + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLE(L, R), R, L))); + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULE(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); + + // [OUT]LT with inverted select. + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpOLT(L, R), R, L))); + EXPECT_TRUE(m_OrdOrUnordFMax(m_Value(MatchL), m_Value(MatchR)) + .match(IRB.CreateSelect(IRB.CreateFCmpULT(L, R), R, L))); + EXPECT_EQ(L, MatchL); + EXPECT_EQ(R, MatchR); +} + TEST_F(PatternMatchTest, OverflowingBinOps) { Value *L = IRB.getInt32(1); Value *R = IRB.getInt32(2);