From 67f2e8e3f8cbae89cfb152b33043f2dcd813d741 Mon Sep 17 00:00:00 2001 From: Yi Jiang Date: Mon, 16 Dec 2013 22:42:40 +0000 Subject: [PATCH] Enable double to float shrinking optimizations for binary functions like 'fmin/fmax'. Fix radar:15283121 llvm-svn: 197434 --- include/llvm/Target/TargetLibraryInfo.h | 14 +++++ include/llvm/Transforms/Utils/BuildLibCalls.h | 8 +++ lib/Target/TargetLibraryInfo.cpp | 10 ++++ lib/Transforms/Utils/BuildLibCalls.cpp | 46 ++++++++++++---- lib/Transforms/Utils/SimplifyLibCalls.cpp | 49 +++++++++++++++++ .../InstCombine/float-shrink-compare.ll | 54 +++++++++++++++++++ 6 files changed, 172 insertions(+), 9 deletions(-) diff --git a/include/llvm/Target/TargetLibraryInfo.h b/include/llvm/Target/TargetLibraryInfo.h index 46eaef2871b..326104da0e9 100644 --- a/include/llvm/Target/TargetLibraryInfo.h +++ b/include/llvm/Target/TargetLibraryInfo.h @@ -251,6 +251,18 @@ namespace llvm { floorf, /// long double floorl(long double x); floorl, + /// double fmax(double x, double y); + fmax, + /// float fmaxf(float x, float y); + fmaxf, + /// long double fmaxl(long double x, long double y); + fmaxl, + /// double fmin(double x, double y); + fmin, + /// float fminf(float x, float y); + fminf, + /// long double fminl(long double x, long double y); + fminl, /// double fmod(double x, double y); fmod, /// float fmodf(float x, float y); @@ -703,6 +715,8 @@ public: case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl: case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite: case LibFunc::sqrtl_finite: + case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl: + case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl: case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl: case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl: case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill: diff --git a/include/llvm/Transforms/Utils/BuildLibCalls.h b/include/llvm/Transforms/Utils/BuildLibCalls.h index 181ed071eab..0f39ada566e 100644 --- a/include/llvm/Transforms/Utils/BuildLibCalls.h +++ b/include/llvm/Transforms/Utils/BuildLibCalls.h @@ -83,6 +83,14 @@ namespace llvm { Value *EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B, const AttributeSet &Attrs); + /// EmitUnaryFloatFnCall - Emit a call to the binary function named 'Name' + /// (e.g. 'fmin'). This function is known to take type matching 'Op1' and + /// 'Op2' and return one value with the same type. If 'Op1/Op2' are long + /// double, 'l' is added as the suffix of name, if 'Op1/Op2' are float, we + /// add a 'f' suffix. + Value *EmitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name, + IRBuilder<> &B, const AttributeSet &Attrs); + /// EmitPutChar - Emit a call to the putchar function. This assumes that Char /// is an integer. Value *EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD, diff --git a/lib/Target/TargetLibraryInfo.cpp b/lib/Target/TargetLibraryInfo.cpp index 2a9fb356528..4bbf2005a9c 100644 --- a/lib/Target/TargetLibraryInfo.cpp +++ b/lib/Target/TargetLibraryInfo.cpp @@ -140,6 +140,12 @@ const char* TargetLibraryInfo::StandardNames[LibFunc::NumLibFuncs] = "floor", "floorf", "floorl", + "fmax", + "fmaxf", + "fmaxl", + "fmin", + "fminf", + "fminl", "fmod", "fmodf", "fmodl", @@ -453,6 +459,8 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, TLI.setUnavailable(LibFunc::fabsf); // Win32 and Win64 both lack fabsf TLI.setUnavailable(LibFunc::fabsl); TLI.setUnavailable(LibFunc::floorl); + TLI.setUnavailable(LibFunc::fmaxl); + TLI.setUnavailable(LibFunc::fminl); TLI.setUnavailable(LibFunc::fmodl); TLI.setUnavailable(LibFunc::frexpl); TLI.setUnavailable(LibFunc::logl); @@ -523,6 +531,8 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T, TLI.setUnavailable(LibFunc::coshf); TLI.setUnavailable(LibFunc::expf); TLI.setUnavailable(LibFunc::floorf); + TLI.setUnavailable(LibFunc::fminf); + TLI.setUnavailable(LibFunc::fmaxf); TLI.setUnavailable(LibFunc::fmodf); TLI.setUnavailable(LibFunc::logf); TLI.setUnavailable(LibFunc::powf); diff --git a/lib/Transforms/Utils/BuildLibCalls.cpp b/lib/Transforms/Utils/BuildLibCalls.cpp index 6d13217df55..82384a1edf5 100644 --- a/lib/Transforms/Utils/BuildLibCalls.cpp +++ b/lib/Transforms/Utils/BuildLibCalls.cpp @@ -286,6 +286,21 @@ Value *llvm::EmitMemCmp(Value *Ptr1, Value *Ptr2, return CI; } +/// Append a suffix to the function name according to the type of 'Op'. +static void AppendTypeSuffix(Value *Op, StringRef &Name, SmallString<20> &NameBuffer) { + if (!Op->getType()->isDoubleTy()) { + NameBuffer += Name; + + if (Op->getType()->isFloatTy()) + NameBuffer += 'f'; + else + NameBuffer += 'l'; + + Name = NameBuffer; + } + return; +} + /// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' (e.g. /// 'floor'). This function is known to take a single of type matching 'Op' and /// returns one value with the same type. If 'Op' is a long double, 'l' is @@ -293,15 +308,7 @@ Value *llvm::EmitMemCmp(Value *Ptr1, Value *Ptr2, Value *llvm::EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B, const AttributeSet &Attrs) { SmallString<20> NameBuffer; - if (!Op->getType()->isDoubleTy()) { - // If we need to add a suffix, copy into NameBuffer. - NameBuffer += Name; - if (Op->getType()->isFloatTy()) - NameBuffer += 'f'; // floorf - else - NameBuffer += 'l'; // floorl - Name = NameBuffer; - } + AppendTypeSuffix(Op, Name, NameBuffer); Module *M = B.GetInsertBlock()->getParent()->getParent(); Value *Callee = M->getOrInsertFunction(Name, Op->getType(), @@ -314,6 +321,27 @@ Value *llvm::EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B, return CI; } +/// EmitBinaryFloatFnCall - Emit a call to the binary function named 'Name' +/// (e.g. 'fmin'). This function is known to take type matching 'Op1' and 'Op2' +/// and return one value with the same type. If 'Op1/Op2' are long double, 'l' +/// is added as the suffix of name, if 'Op1/Op2' is a float, we add a 'f' +/// suffix. +Value *llvm::EmitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name, + IRBuilder<> &B, const AttributeSet &Attrs) { + SmallString<20> NameBuffer; + AppendTypeSuffix(Op1, Name, NameBuffer); + + Module *M = B.GetInsertBlock()->getParent()->getParent(); + Value *Callee = M->getOrInsertFunction(Name, Op1->getType(), + Op1->getType(), Op2->getType(), NULL); + CallInst *CI = B.CreateCall2(Callee, Op1, Op2, Name); + CI->setAttributes(Attrs); + if (const Function *F = dyn_cast(Callee->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + + return CI; +} + /// EmitPutChar - Emit a call to the putchar function. This assumes that Char /// is an integer. Value *llvm::EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD, diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index b555cf8bddb..36d24624f94 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1100,6 +1100,49 @@ struct UnaryDoubleFPOpt : public LibCallOptimization { } }; +// Double -> Float Shrinking Optimizations for Binary Functions like 'fmin/fmax' +struct BinaryDoubleFPOpt : public LibCallOptimization { + bool CheckRetType; + BinaryDoubleFPOpt(bool CheckReturnType): CheckRetType(CheckReturnType) {} + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + FunctionType *FT = Callee->getFunctionType(); + // Just make sure this has 2 arguments of the same FP type, which match the + // result type. + if (FT->getNumParams() != 2 || FT->getReturnType() != FT->getParamType(0) || + FT->getParamType(0) != FT->getParamType(1) || + !FT->getParamType(0)->isFloatingPointTy()) + return 0; + + if (CheckRetType) { + // Check if all the uses for function like 'fmin/fmax' are converted to + // float. + for (Value::use_iterator UseI = CI->use_begin(); UseI != CI->use_end(); + ++UseI) { + FPTruncInst *Cast = dyn_cast(*UseI); + if (Cast == 0 || !Cast->getType()->isFloatTy()) + return 0; + } + } + + // If this is something like 'fmin((double)floatval1, (double)floatval2)', + // we convert it to fminf. + FPExtInst *Cast1 = dyn_cast(CI->getArgOperand(0)); + FPExtInst *Cast2 = dyn_cast(CI->getArgOperand(1)); + if (Cast1 == 0 || !Cast1->getOperand(0)->getType()->isFloatTy() || + Cast2 == 0 || !Cast2->getOperand(0)->getType()->isFloatTy()) + return 0; + + // fmin((double)floatval1, (double)floatval2) + // -> (double)fmin(floatval1, floatval2) + Value *V = NULL; + Value *V1 = Cast1->getOperand(0); + Value *V2 = Cast2->getOperand(0); + V = EmitBinaryFloatFnCall(V1, V2, Callee->getName(), B, + Callee->getAttributes()); + return B.CreateFPExt(V, B.getDoubleTy()); + } +}; + struct UnsafeFPLibCallOptimization : public LibCallOptimization { bool UnsafeFPShrink; UnsafeFPLibCallOptimization(bool UnsafeFPShrink) { @@ -1981,6 +2024,7 @@ static MemSetOpt MemSet; // Math library call optimizations. static UnaryDoubleFPOpt UnaryDoubleFP(false); +static BinaryDoubleFPOpt BinaryDoubleFP(false); static UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true); static SinCosPiOpt SinCosPi; @@ -2150,6 +2194,11 @@ LibCallOptimization *LibCallSimplifierImpl::lookupOptimization(CallInst *CI) { if (UnsafeFPShrink && hasFloatVersion(FuncName)) return &UnsafeUnaryDoubleFP; return 0; + case LibFunc::fmin: + case LibFunc::fmax: + if (hasFloatVersion(FuncName)) + return &BinaryDoubleFP; + return 0; case LibFunc::memcpy_chk: return &MemCpyChk; default: diff --git a/test/Transforms/InstCombine/float-shrink-compare.ll b/test/Transforms/InstCombine/float-shrink-compare.ll index 26f77a7f702..e50046790da 100644 --- a/test/Transforms/InstCombine/float-shrink-compare.ll +++ b/test/Transforms/InstCombine/float-shrink-compare.ll @@ -170,6 +170,58 @@ define i32 @test14(float %x, float %y) nounwind uwtable { ; CHECK-NEXT: fcmp oeq float %truncf, %y } +define i32 @test15(float %x, float %y, float %z) nounwind uwtable { + %1 = fpext float %x to double + %2 = fpext float %y to double + %3 = call double @fmin(double %1, double %2) nounwind + %4 = fpext float %z to double + %5 = fcmp oeq double %3, %4 + %6 = zext i1 %5 to i32 + ret i32 %6 +; CHECK-LABEL: @test15( +; CHECK-NEXT: %fminf = call float @fminf(float %x, float %y) +; CHECK-NEXT: fcmp oeq float %fminf, %z +} + +define i32 @test16(float %x, float %y, float %z) nounwind uwtable { + %1 = fpext float %z to double + %2 = fpext float %x to double + %3 = fpext float %y to double + %4 = call double @fmin(double %2, double %3) nounwind + %5 = fcmp oeq double %1, %4 + %6 = zext i1 %5 to i32 + ret i32 %6 +; CHECK-LABEL: @test16( +; CHECK-NEXT: %fminf = call float @fminf(float %x, float %y) +; CHECK-NEXT: fcmp oeq float %fminf, %z +} + +define i32 @test17(float %x, float %y, float %z) nounwind uwtable { + %1 = fpext float %x to double + %2 = fpext float %y to double + %3 = call double @fmax(double %1, double %2) nounwind + %4 = fpext float %z to double + %5 = fcmp oeq double %3, %4 + %6 = zext i1 %5 to i32 + ret i32 %6 +; CHECK-LABEL: @test17( +; CHECK-NEXT: %fmaxf = call float @fmaxf(float %x, float %y) +; CHECK-NEXT: fcmp oeq float %fmaxf, %z +} + +define i32 @test18(float %x, float %y, float %z) nounwind uwtable { + %1 = fpext float %z to double + %2 = fpext float %x to double + %3 = fpext float %y to double + %4 = call double @fmax(double %2, double %3) nounwind + %5 = fcmp oeq double %1, %4 + %6 = zext i1 %5 to i32 + ret i32 %6 +; CHECK-LABEL: @test18( +; CHECK-NEXT: %fmaxf = call float @fmaxf(float %x, float %y) +; CHECK-NEXT: fcmp oeq float %fmaxf, %z +} + declare double @fabs(double) nounwind readnone declare double @ceil(double) nounwind readnone declare double @floor(double) nounwind readnone @@ -177,3 +229,5 @@ declare double @nearbyint(double) nounwind readnone declare double @rint(double) nounwind readnone declare double @round(double) nounwind readnone declare double @trunc(double) nounwind readnone +declare double @fmin(double, double) nounwind readnone +declare double @fmax(double, double) nounwind readnone