Index: llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1563,40 +1563,30 @@ } Value *LibCallSimplifier::optimizeFMinFMax(CallInst *CI, IRBuilder<> &B) { - Function *Callee = CI->getCalledFunction(); // If we can shrink the call to a float function rather than a double // function, do that first. + Function *Callee = CI->getCalledFunction(); StringRef Name = Callee->getName(); if ((Name == "fmin" || Name == "fmax") && hasFloatVersion(Name)) if (Value *Ret = optimizeBinaryDoubleFP(CI, B)) return Ret; + // The LLVM intrinsics minnum/maxnum correspond to fmin/fmax. Canonicalize to + // the intrinsics for improved optimization (for example, vectorization). + // No-signed-zeros is implied by the definitions of fmax/fmin themselves. + // From the C standard draft WG14/N1256: + // "Ideally, fmax would be sensitive to the sign of zero, for example + // fmax(-0.0, +0.0) would return +0; however, implementation in software + // might be impractical." IRBuilder<>::FastMathFlagGuard Guard(B); - FastMathFlags FMF; - if (CI->isFast()) { - // If the call is 'fast', then anything we create here will also be 'fast'. - FMF.setFast(); - } else { - // At a minimum, no-nans-fp-math must be true. - if (!CI->hasNoNaNs()) - return nullptr; - // No-signed-zeros is implied by the definitions of fmax/fmin themselves: - // "Ideally, fmax would be sensitive to the sign of zero, for example - // fmax(-0. 0, +0. 0) would return +0; however, implementation in software - // might be impractical." - FMF.setNoSignedZeros(); - FMF.setNoNaNs(); - } + FastMathFlags FMF = CI->getFastMathFlags(); + FMF.setNoSignedZeros(); B.setFastMathFlags(FMF); - // We have a relaxed floating-point environment. We can ignore NaN-handling - // and transform to a compare and select. We do not have to consider errno or - // exceptions, because fmin/fmax do not have those. - Value *Op0 = CI->getArgOperand(0); - Value *Op1 = CI->getArgOperand(1); - Value *Cmp = Callee->getName().startswith("fmin") ? - B.CreateFCmpOLT(Op0, Op1) : B.CreateFCmpOGT(Op0, Op1); - return B.CreateSelect(Cmp, Op0, Op1); + Intrinsic::ID IID = Callee->getName().startswith("fmin") ? Intrinsic::minnum + : Intrinsic::maxnum; + Function *F = Intrinsic::getDeclaration(CI->getModule(), IID, CI->getType()); + return B.CreateCall(F, { CI->getArgOperand(0), CI->getArgOperand(1) }); } Value *LibCallSimplifier::optimizeLog(CallInst *CI, IRBuilder<> &B) { Index: llvm/test/Transforms/InstCombine/fast-math.ll =================================================================== --- llvm/test/Transforms/InstCombine/fast-math.ll +++ llvm/test/Transforms/InstCombine/fast-math.ll @@ -811,17 +811,13 @@ declare fp128 @fmaxl(fp128, fp128) declare fp128 @fminl(fp128, fp128) -; No NaNs is the minimum requirement to replace these calls. -; This should always be set when unsafe-fp-math is true, but -; 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 replace 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,8 +828,8 @@ define float @fmax_no_fmf(float %a, float %b) { ; CHECK-LABEL: @fmax_no_fmf( -; CHECK-NEXT: [[C:%.*]] = call float @fmaxf(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: ret float [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = call nsz float @llvm.maxnum.f32(float [[A:%.*]], float [[B:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] ; %c = call float @fmaxf(float %a, float %b) ret float %c @@ -841,9 +837,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 @@ -852,9 +847,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 @@ -862,9 +856,8 @@ 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 @@ -873,9 +866,8 @@ ; Shrink and remove 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 @@ -886,8 +878,8 @@ define float @fmin_no_fmf(float %a, float %b) { ; CHECK-LABEL: @fmin_no_fmf( -; CHECK-NEXT: [[C:%.*]] = call float @fminf(float [[A:%.*]], float [[B:%.*]]) -; CHECK-NEXT: ret float [[C]] +; CHECK-NEXT: [[TMP1:%.*]] = call nsz float @llvm.minnum.f32(float [[A:%.*]], float [[B:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] ; %c = call float @fminf(float %a, float %b) ret float %c @@ -895,9 +887,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 @@ -905,9 +896,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 @@ -915,9 +905,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