Index: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -2012,6 +2012,19 @@ } } + // Canonicalize select of FP values where NaN and -0.0 are not valid as + // minnum/maxnum intrinsics. + if (isa(SI) && SI.hasNoNaNs() && SI.hasNoSignedZeros()) { + Value *X, *Y; + if (match(&SI, m_OrdFMax(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)))) + return replaceInstUsesWith( + SI, Builder.CreateBinaryIntrinsic(Intrinsic::minnum, X, Y, &SI)); + } + // See if we can fold the select into a phi node if the condition is a select. if (auto *PN = dyn_cast(SI.getCondition())) // The true/false values have to be live in the PHI predecessor's blocks. Index: llvm/test/Transforms/InstCombine/fast-math.ll =================================================================== --- llvm/test/Transforms/InstCombine/fast-math.ll +++ llvm/test/Transforms/InstCombine/fast-math.ll @@ -816,12 +816,11 @@ ; alternate the attributes for additional test coverage. ; 'nsz' is implied by the definition of fmax or fmin itself. -; Shrink and remove the call. +; Shrink and convert the call. define float @max1(float %a, float %b) { ; CHECK-LABEL: @max1( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast ogt float [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], float [[A]], float [[B]] -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.maxnum.f32(float [[A:%.*]], float [[B:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] ; %c = fpext float %a to double %d = fpext float %b to double @@ -832,9 +831,8 @@ define float @max2(float %a, float %b) { ; CHECK-LABEL: @max2( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz ogt float [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], float [[A]], float [[B]] -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[A:%.*]], float [[B:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] ; %c = call nnan float @fmaxf(float %a, float %b) ret float %c @@ -843,9 +841,8 @@ define double @max3(double %a, double %b) { ; CHECK-LABEL: @max3( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast ogt double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], double [[A]], double [[B]] -; CHECK-NEXT: ret double [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call fast double @llvm.maxnum.f64(double [[A:%.*]], double [[B:%.*]]) +; CHECK-NEXT: ret double [[TMP1]] ; %c = call fast double @fmax(double %a, double %b) ret double %c @@ -853,20 +850,18 @@ define fp128 @max4(fp128 %a, fp128 %b) { ; CHECK-LABEL: @max4( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz ogt fp128 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], fp128 [[A]], fp128 [[B]] -; CHECK-NEXT: ret fp128 [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz fp128 @llvm.maxnum.f128(fp128 [[A:%.*]], fp128 [[B:%.*]]) +; CHECK-NEXT: ret fp128 [[TMP1]] ; %c = call nnan fp128 @fmaxl(fp128 %a, fp128 %b) ret fp128 %c } -; Shrink and remove the call. +; Shrink and convert the call. define float @min1(float %a, float %b) { ; CHECK-LABEL: @min1( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz olt float [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], float [[A]], float [[B]] -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz float @llvm.minnum.f32(float [[A:%.*]], float [[B:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] ; %c = fpext float %a to double %d = fpext float %b to double @@ -877,9 +872,8 @@ define float @min2(float %a, float %b) { ; CHECK-LABEL: @min2( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast olt float [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], float [[A]], float [[B]] -; CHECK-NEXT: ret float [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call fast float @llvm.minnum.f32(float [[A:%.*]], float [[B:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] ; %c = call fast float @fminf(float %a, float %b) ret float %c @@ -887,9 +881,8 @@ define double @min3(double %a, double %b) { ; CHECK-LABEL: @min3( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan nsz olt double [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select nnan nsz i1 [[TMP1]], double [[A]], double [[B]] -; CHECK-NEXT: ret double [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz double @llvm.minnum.f64(double [[A:%.*]], double [[B:%.*]]) +; CHECK-NEXT: ret double [[TMP1]] ; %c = call nnan double @fmin(double %a, double %b) ret double %c @@ -897,9 +890,8 @@ define fp128 @min4(fp128 %a, fp128 %b) { ; CHECK-LABEL: @min4( -; CHECK-NEXT: [[TMP1:%.*]] = fcmp fast olt fp128 [[A:%.*]], [[B:%.*]] -; CHECK-NEXT: [[TMP2:%.*]] = select fast i1 [[TMP1]], fp128 [[A]], fp128 [[B]] -; CHECK-NEXT: ret fp128 [[TMP2]] +; CHECK-NEXT: [[TMP1:%.*]] = call fast fp128 @llvm.minnum.f128(fp128 [[A:%.*]], fp128 [[B:%.*]]) +; CHECK-NEXT: ret fp128 [[TMP1]] ; %c = call fast fp128 @fminl(fp128 %a, fp128 %b) ret fp128 %c