Index: lib/Transforms/InstCombine/InstCombineCalls.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCalls.cpp +++ lib/Transforms/InstCombine/InstCombineCalls.cpp @@ -998,6 +998,65 @@ return nullptr; } +Instruction *InstCombiner::getReducedInstruction(IntrinsicInst *II) { + Value *Arg0 = II->getArgOperand(0); + Value *Arg1 = II->getArgOperand(1); + Value *X = nullptr; + Value *Y = nullptr; + + if (II->getIntrinsicID() == Intrinsic::maxnum) { + // fmax(x, fmin(x, y)) -> select isnan(x)?y:x + // fmax(y, fmin(x, y)) -> select isnan(y)?x:y + if (match(Arg1, m_FMin(m_Value(X), m_Value(Y)))) { + if (Arg0 == X || Arg0 == Y) { + IntrinsicInst *I = cast(Arg1); + if (I->hasNoNaNs()) + return replaceInstUsesWith(*II, Arg0); + Instruction *Result = new FCmpInst(II, FCmpInst::FCMP_UNO, Arg0, Arg0); + return SelectInst::Create(Result, Arg0 == X ? Y : X, Arg0); + } + } + // fmax(fmin(x, y), x) -> select isnan(x)?y:x + // fmax(fmin(x, y), y) -> select isnan(y)?x:y + if (match(Arg0, m_FMin(m_Value(X), m_Value(Y)))) { + if (Arg1 == X || Arg1 == Y) { + IntrinsicInst *I = cast(Arg0); + if (I->hasNoNaNs()) + return replaceInstUsesWith(*II, Arg1); + Instruction *Result = new FCmpInst(II, FCmpInst::FCMP_UNO, Arg1, Arg1); + return SelectInst::Create(Result, Arg1 == X ? Y : X, Arg1); + } + } + + } else { + // fmin(x, fmax(x, y)) -> select isnan(x)?y:x + // fmin(y, fmax(x, y)) -> select isnan(y)?x:y + if (match(Arg1, m_FMax(m_Value(X), m_Value(Y)))) { + if (Arg0 == X || Arg0 == Y) { + IntrinsicInst *I = cast(Arg1); + if (I->hasNoNaNs()) + return replaceInstUsesWith(*II, Arg0); + Instruction *Result = new FCmpInst(II, FCmpInst::FCMP_UNO, Arg0, Arg0); + return SelectInst::Create(Result, Arg0 == X ? Y : X, Arg0); + } + } + + // fmin(fmax(x, y), x) -> select isnan(x)?y:x + // fmin(fmax(x, y), y) -> select isnan(y)?x:y + if (match(Arg0, m_FMax(m_Value(X), m_Value(Y)))) { + if (Arg1 == X || Arg1 == Y) { + IntrinsicInst *I = cast(Arg0); + if (I->hasNoNaNs()) + return replaceInstUsesWith(*II, Arg1); + Instruction *Result = new FCmpInst(II, FCmpInst::FCMP_UNO, Arg1, Arg1); + return SelectInst::Create(Result, Arg1 == X ? Y : X, Arg1); + } + } + } + + return nullptr; +} + static Value *simplifyMinnumMaxnum(const IntrinsicInst &II) { Value *Arg0 = II.getArgOperand(0); Value *Arg1 = II.getArgOperand(1); @@ -1524,6 +1583,10 @@ } if (Value *V = simplifyMinnumMaxnum(*II)) return replaceInstUsesWith(*II, V); + + if (Instruction *I = getReducedInstruction(II)) + return I; + break; } case Intrinsic::ppc_altivec_lvx: Index: lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- lib/Transforms/InstCombine/InstCombineInternal.h +++ lib/Transforms/InstCombine/InstCombineInternal.h @@ -172,6 +172,8 @@ bool MadeIRChange; + Instruction *getReducedInstruction(IntrinsicInst *II); + public: InstCombiner(InstCombineWorklist &Worklist, BuilderTy *Builder, bool MinimizeSize, bool ExpensiveCombines, AliasAnalysis *AA, Index: test/Transforms/InstCombine/maxnum.ll =================================================================== --- test/Transforms/InstCombine/maxnum.ll +++ test/Transforms/InstCombine/maxnum.ll @@ -1,6 +1,7 @@ ; RUN: opt -S -instcombine < %s | FileCheck %s declare float @llvm.maxnum.f32(float, float) #0 +declare float @llvm.minnum.f32(float, float) #0 declare float @llvm.maxnum.v2f32(<2 x float>, <2 x float>) #0 declare <4 x float> @llvm.maxnum.v4f32(<4 x float>, <4 x float>) #0 @@ -219,4 +220,48 @@ ret float %val } +; CHECK-LABEL: @maxnum_x_minnum_x_y +; CHECK-NEXT: %1 = fcmp uno float %x, 0.000000e+00 +; CHECK-NEXT: %b = select i1 %1, float %y, float %x +; CHECK-NEXT: ret float %b +define float @maxnum_x_minnum_x_y(float %x, float %y) #0 { + %a = call float @llvm.minnum.f32(float %x, float %y) #0 + %b = call float @llvm.maxnum.f32(float %x, float %a) #0 + ret float %b +} + +; CHECK-LABEL: @maxnum_x_minnum_x_y_nnan +; CHECK-NEXT: ret float %x +define float @maxnum_x_minnum_x_y_nnan(float %x, float %y) #0 { + %a = call nnan float @llvm.minnum.f32(float %x, float %y) #0 + %b = call float @llvm.maxnum.f32(float %x, float %a) #0 + ret float %b +} + +; CHECK-LABEL: @minnum_x_y_maxnum_y +; CHECK-NEXT: %1 = fcmp uno float %y, 0.000000e+00 +; CHECK-NEXT: %b = select i1 %1, float %x, float %y +; CHECK-NEXT: ret float %b +define float @minnum_x_y_maxnum_y(float %x, float %y) #0 { + %a = call float @llvm.minnum.f32(float %x, float %y) #0 + %b = call float @llvm.maxnum.f32(float %a, float %y) #0 + ret float %b +} + +; CHECK-LABEL: @minnum_x_y_maxnum_y_nnan +; CHECK-NEXT: ret float %y +define float @minnum_x_y_maxnum_y_nnan(float %x, float %y) #0 { + %a = call nnan float @llvm.minnum.f32(float %x, float %y) #0 + %b = call float @llvm.maxnum.f32(float %a, float %y) #0 + ret float %b +} + +; CHECK-LABEL: @minnum_x_nan_maxnum_nan +; CHECK-NEXT: ret float %x +define float @minnum_x_nan_maxnum_nan(float %x) #0 { + %a = call float @llvm.minnum.f32(float %x, float 0x7FF8000000000000) #0 + %b = call float @llvm.maxnum.f32(float %a, float 0x7FF8000000000000) #0 + ret float %b +} + attributes #0 = { nounwind readnone } Index: test/Transforms/InstCombine/minnum.ll =================================================================== --- test/Transforms/InstCombine/minnum.ll +++ test/Transforms/InstCombine/minnum.ll @@ -1,13 +1,13 @@ ; RUN: opt -S -instcombine < %s | FileCheck %s declare float @llvm.minnum.f32(float, float) #0 +declare float @llvm.maxnum.f32(float, float) #0 declare float @llvm.minnum.v2f32(<2 x float>, <2 x float>) #0 declare <4 x float> @llvm.minnum.v4f32(<4 x float>, <4 x float>) #0 declare double @llvm.minnum.f64(double, double) #0 declare <2 x double> @llvm.minnum.v2f64(<2 x double>, <2 x double>) #0 -declare float @llvm.maxnum.f32(float, float) #0 ; CHECK-LABEL: @constant_fold_minnum_f32 ; CHECK-NEXT: ret float 1.000000e+00 @@ -206,26 +206,6 @@ ret float %c } -; CHECK-LABEL: @minnum_x_maxnum_x_y -; CHECK-NEXT: call float @llvm.maxnum.f32 -; CHECK-NEXT: call float @llvm.minnum.f32 -; CHECK-NEXT: ret float -define float @minnum_x_maxnum_x_y(float %x, float %y) #0 { - %a = call float @llvm.maxnum.f32(float %x, float %y) #0 - %b = call float @llvm.minnum.f32(float %x, float %a) #0 - ret float %b -} - -; CHECK-LABEL: @maxnum_x_minnum_x_y -; CHECK-NEXT: call float @llvm.minnum.f32 -; CHECK-NEXT: call float @llvm.maxnum.f32 -; CHECK-NEXT: ret float -define float @maxnum_x_minnum_x_y(float %x, float %y) #0 { - %a = call float @llvm.minnum.f32(float %x, float %y) #0 - %b = call float @llvm.maxnum.f32(float %x, float %a) #0 - ret float %b -} - ; CHECK-LABEL: @fold_minnum_f32_inf_val ; CHECK-NEXT: call float @llvm.minnum.f32(float %x, float 0x7FF0000000000000) ; CHECK-NEXT: ret float @@ -241,4 +221,51 @@ ret float %val } +; CHECK-LABEL: @minnum_x_maxnum_x_y +; CHECK-NEXT: %1 = fcmp uno float %x, 0.000000e+00 +; CHECK-NEXT: %b = select i1 %1, float %y, float %x +; CHECK-NEXT: ret float %b + +define float @minnum_x_maxnum_x_y(float %x, float %y) #0 { + %a = call float @llvm.maxnum.f32(float %x, float %y) #0 + %b = call float @llvm.minnum.f32(float %x, float %a) #0 + ret float %b +} + +; CHECK-LABEL: @minnum_x_maxnum_x_y_nnan +; CHECK-NEXT: ret float %x + +define float @minnum_x_maxnum_x_y_nnan(float %x, float %y) #0 { + %a = call nnan float @llvm.maxnum.f32(float %x, float %y) #0 + %b = call float @llvm.minnum.f32(float %x, float %a) #0 + ret float %b +} + + +; CHECK-LABEL: @maxnum_x_y_minnum_y +; CHECK-NEXT: %1 = fcmp uno float %y, 0.000000e+00 +; CHECK-NEXT: %b = select i1 %1, float %x, float %y +; CHECK-NEXT: ret float %b +define float @maxnum_x_y_minnum_y(float %x, float %y) #0 { + %a = call float @llvm.maxnum.f32(float %x, float %y) #0 + %b = call float @llvm.minnum.f32(float %a, float %y) #0 + ret float %b +} + +; CHECK-LABEL: @maxnum_x_y_minnum_y_nnan +; CHECK-NEXT: ret float %y +define float @maxnum_x_y_minnum_y_nnan(float %x, float %y) #0 { + %a = call nnan float @llvm.maxnum.f32(float %x, float %y) #0 + %b = call float @llvm.minnum.f32(float %a, float %y) #0 + ret float %b +} + +; CHECK-LABEL: @maxnum_y_nan_minnum_nan +; CHECK-NEXT: ret float %y +define float @maxnum_y_nan_minnum_nan(float %y) #0 { + %a = call float @llvm.maxnum.f32(float 0x7FF8000000000000, float %y) #0 + %b = call float @llvm.minnum.f32(float %a, float 0x7FF8000000000000) #0 + ret float %b +} + attributes #0 = { nounwind readnone }