From: Meador Inge Date: Tue, 13 Nov 2012 04:16:17 +0000 (+0000) Subject: instcombine: Migrate math library call simplifications X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=commitdiff_plain;h=2920a71663b96f2c33b1fee09ca5ca9f5dc1cf12 instcombine: Migrate math library call simplifications This patch migrates the math library call simplifications from the simplify-libcalls pass into the instcombine library call simplifier. I have typically migrated just one simplifier at a time, but the math simplifiers are interdependent because: 1. CosOpt, PowOpt, and Exp2Opt all depend on UnaryDoubleFPOpt. 2. CosOpt, PowOpt, Exp2Opt, and UnaryDoubleFPOpt all depend on the option -enable-double-float-shrink. These two factors made migrating each of these simplifiers individually more of a pain than it would be worth. So, I migrated them all together. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@167815 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/include/llvm/Transforms/Utils/SimplifyLibCalls.h index fde452bca23..6bb81be2fd5 100644 --- a/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ b/include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -31,7 +31,8 @@ namespace llvm { /// simplifier. LibCallSimplifierImpl *Impl; public: - LibCallSimplifier(const DataLayout *TD, const TargetLibraryInfo *TLI); + LibCallSimplifier(const DataLayout *TD, const TargetLibraryInfo *TLI, + bool UnsafeFPShrink); virtual ~LibCallSimplifier(); /// optimizeCall - Take the given call instruction and return a more diff --git a/lib/Transforms/InstCombine/InstructionCombining.cpp b/lib/Transforms/InstCombine/InstructionCombining.cpp index 9a46f25e66f..feef2ccee4c 100644 --- a/lib/Transforms/InstCombine/InstructionCombining.cpp +++ b/lib/Transforms/InstCombine/InstructionCombining.cpp @@ -44,6 +44,7 @@ #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Transforms/Utils/Local.h" #include "llvm/Support/CFG.h" +#include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/PatternMatch.h" @@ -65,6 +66,11 @@ STATISTIC(NumExpand, "Number of expansions"); STATISTIC(NumFactor , "Number of factorizations"); STATISTIC(NumReassoc , "Number of reassociations"); +static cl::opt UnsafeFPShrink("enable-double-float-shrink", cl::Hidden, + cl::init(false), + cl::desc("Enable unsafe double to float " + "shrinking for math lib calls")); + // Initialization Routines void llvm::initializeInstCombine(PassRegistry &Registry) { initializeInstCombinerPass(Registry); @@ -2374,7 +2380,7 @@ public: InstCombinerLibCallSimplifier(const DataLayout *TD, const TargetLibraryInfo *TLI, InstCombiner *IC) - : LibCallSimplifier(TD, TLI) { + : LibCallSimplifier(TD, TLI, UnsafeFPShrink) { this->IC = IC; } diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index 17d07cdb2d4..8f31cd11c7d 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -39,10 +39,6 @@ using namespace llvm; STATISTIC(NumSimplified, "Number of library calls simplified"); STATISTIC(NumAnnotated, "Number of attributes added to library functions"); -static cl::opt UnsafeFPShrink("enable-double-float-shrink", cl::Hidden, - cl::init(false), - cl::desc("Enable unsafe double to float " - "shrinking for math lib calls")); //===----------------------------------------------------------------------===// // Optimizer Base Class //===----------------------------------------------------------------------===// @@ -100,192 +96,6 @@ static bool CallHasFloatingPointArgument(const CallInst *CI) { } namespace { -//===----------------------------------------------------------------------===// -// Math Library Optimizations -//===----------------------------------------------------------------------===// - -//===---------------------------------------===// -// Double -> Float Shrinking Optimizations for Unary Functions like 'floor' - -struct UnaryDoubleFPOpt : public LibCallOptimization { - bool CheckRetType; - UnaryDoubleFPOpt(bool CheckReturnType): CheckRetType(CheckReturnType) {} - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - FunctionType *FT = Callee->getFunctionType(); - if (FT->getNumParams() != 1 || !FT->getReturnType()->isDoubleTy() || - !FT->getParamType(0)->isDoubleTy()) - return 0; - - if (CheckRetType) { - // Check if all the uses for function like 'sin' 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 'floor((double)floatval)', convert to floorf. - FPExtInst *Cast = dyn_cast(CI->getArgOperand(0)); - if (Cast == 0 || !Cast->getOperand(0)->getType()->isFloatTy()) - return 0; - - // floor((double)floatval) -> (double)floorf(floatval) - Value *V = Cast->getOperand(0); - V = EmitUnaryFloatFnCall(V, Callee->getName(), B, Callee->getAttributes()); - return B.CreateFPExt(V, B.getDoubleTy()); - } -}; - -//===---------------------------------------===// -// 'cos*' Optimizations -struct CosOpt : public LibCallOptimization { - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - Value *Ret = NULL; - if (UnsafeFPShrink && Callee->getName() == "cos" && - TLI->has(LibFunc::cosf)) { - UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true); - Ret = UnsafeUnaryDoubleFP.CallOptimizer(Callee, CI, B); - } - - FunctionType *FT = Callee->getFunctionType(); - // Just make sure this has 1 argument of FP type, which matches the - // result type. - if (FT->getNumParams() != 1 || FT->getReturnType() != FT->getParamType(0) || - !FT->getParamType(0)->isFloatingPointTy()) - return Ret; - - // cos(-x) -> cos(x) - Value *Op1 = CI->getArgOperand(0); - if (BinaryOperator::isFNeg(Op1)) { - BinaryOperator *BinExpr = cast(Op1); - return B.CreateCall(Callee, BinExpr->getOperand(1), "cos"); - } - return Ret; - } -}; - -//===---------------------------------------===// -// 'pow*' Optimizations - -struct PowOpt : public LibCallOptimization { - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - Value *Ret = NULL; - if (UnsafeFPShrink && Callee->getName() == "pow" && - TLI->has(LibFunc::powf)) { - UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true); - Ret = UnsafeUnaryDoubleFP.CallOptimizer(Callee, CI, 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 Ret; - - Value *Op1 = CI->getArgOperand(0), *Op2 = CI->getArgOperand(1); - if (ConstantFP *Op1C = dyn_cast(Op1)) { - if (Op1C->isExactlyValue(1.0)) // pow(1.0, x) -> 1.0 - return Op1C; - if (Op1C->isExactlyValue(2.0)) // pow(2.0, x) -> exp2(x) - return EmitUnaryFloatFnCall(Op2, "exp2", B, Callee->getAttributes()); - } - - ConstantFP *Op2C = dyn_cast(Op2); - if (Op2C == 0) return Ret; - - if (Op2C->getValueAPF().isZero()) // pow(x, 0.0) -> 1.0 - return ConstantFP::get(CI->getType(), 1.0); - - if (Op2C->isExactlyValue(0.5)) { - // Expand pow(x, 0.5) to (x == -infinity ? +infinity : fabs(sqrt(x))). - // This is faster than calling pow, and still handles negative zero - // and negative infinity correctly. - // TODO: In fast-math mode, this could be just sqrt(x). - // TODO: In finite-only mode, this could be just fabs(sqrt(x)). - Value *Inf = ConstantFP::getInfinity(CI->getType()); - Value *NegInf = ConstantFP::getInfinity(CI->getType(), true); - Value *Sqrt = EmitUnaryFloatFnCall(Op1, "sqrt", B, - Callee->getAttributes()); - Value *FAbs = EmitUnaryFloatFnCall(Sqrt, "fabs", B, - Callee->getAttributes()); - Value *FCmp = B.CreateFCmpOEQ(Op1, NegInf); - Value *Sel = B.CreateSelect(FCmp, Inf, FAbs); - return Sel; - } - - if (Op2C->isExactlyValue(1.0)) // pow(x, 1.0) -> x - return Op1; - if (Op2C->isExactlyValue(2.0)) // pow(x, 2.0) -> x*x - return B.CreateFMul(Op1, Op1, "pow2"); - if (Op2C->isExactlyValue(-1.0)) // pow(x, -1.0) -> 1.0/x - return B.CreateFDiv(ConstantFP::get(CI->getType(), 1.0), - Op1, "powrecip"); - return 0; - } -}; - -//===---------------------------------------===// -// 'exp2' Optimizations - -struct Exp2Opt : public LibCallOptimization { - virtual Value *CallOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { - Value *Ret = NULL; - if (UnsafeFPShrink && Callee->getName() == "exp2" && - TLI->has(LibFunc::exp2)) { - UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true); - Ret = UnsafeUnaryDoubleFP.CallOptimizer(Callee, CI, B); - } - - FunctionType *FT = Callee->getFunctionType(); - // Just make sure this has 1 argument of FP type, which matches the - // result type. - if (FT->getNumParams() != 1 || FT->getReturnType() != FT->getParamType(0) || - !FT->getParamType(0)->isFloatingPointTy()) - return Ret; - - Value *Op = CI->getArgOperand(0); - // Turn exp2(sitofp(x)) -> ldexp(1.0, sext(x)) if sizeof(x) <= 32 - // Turn exp2(uitofp(x)) -> ldexp(1.0, zext(x)) if sizeof(x) < 32 - Value *LdExpArg = 0; - if (SIToFPInst *OpC = dyn_cast(Op)) { - if (OpC->getOperand(0)->getType()->getPrimitiveSizeInBits() <= 32) - LdExpArg = B.CreateSExt(OpC->getOperand(0), B.getInt32Ty()); - } else if (UIToFPInst *OpC = dyn_cast(Op)) { - if (OpC->getOperand(0)->getType()->getPrimitiveSizeInBits() < 32) - LdExpArg = B.CreateZExt(OpC->getOperand(0), B.getInt32Ty()); - } - - if (LdExpArg) { - const char *Name; - if (Op->getType()->isFloatTy()) - Name = "ldexpf"; - else if (Op->getType()->isDoubleTy()) - Name = "ldexp"; - else - Name = "ldexpl"; - - Constant *One = ConstantFP::get(*Context, APFloat(1.0f)); - if (!Op->getType()->isFloatTy()) - One = ConstantExpr::getFPExtend(One, Op->getType()); - - Module *M = Caller->getParent(); - Value *Callee = M->getOrInsertFunction(Name, Op->getType(), - Op->getType(), - B.getInt32Ty(), NULL); - CallInst *CI = B.CreateCall2(Callee, One, LdExpArg); - if (const Function *F = dyn_cast(Callee->stripPointerCasts())) - CI->setCallingConv(F->getCallingConv()); - - return CI; - } - return Ret; - } -}; - //===----------------------------------------------------------------------===// // Integer Optimizations //===----------------------------------------------------------------------===// @@ -768,9 +578,6 @@ namespace { TargetLibraryInfo *TLI; StringMap Optimizations; - // Math Library Optimizations - CosOpt Cos; PowOpt Pow; Exp2Opt Exp2; - UnaryDoubleFPOpt UnaryDoubleFP, UnsafeUnaryDoubleFP; // Integer Optimizations FFSOpt FFS; AbsOpt Abs; IsDigitOpt IsDigit; IsAsciiOpt IsAscii; ToAsciiOpt ToAscii; @@ -782,8 +589,7 @@ namespace { bool Modified; // This is only used by doInitialization. public: static char ID; // Pass identification - SimplifyLibCalls() : FunctionPass(ID), UnaryDoubleFP(false), - UnsafeUnaryDoubleFP(true) { + SimplifyLibCalls() : FunctionPass(ID) { initializeSimplifyLibCallsPass(*PassRegistry::getPassRegistry()); } void AddOpt(LibFunc::Func F, LibCallOptimization* Opt); @@ -833,59 +639,6 @@ void SimplifyLibCalls::AddOpt(LibFunc::Func F1, LibFunc::Func F2, /// Optimizations - Populate the Optimizations map with all the optimizations /// we know. void SimplifyLibCalls::InitOptimizations() { - // Math Library Optimizations - Optimizations["cosf"] = &Cos; - Optimizations["cos"] = &Cos; - Optimizations["cosl"] = &Cos; - Optimizations["powf"] = &Pow; - Optimizations["pow"] = &Pow; - Optimizations["powl"] = &Pow; - Optimizations["llvm.pow.f32"] = &Pow; - Optimizations["llvm.pow.f64"] = &Pow; - Optimizations["llvm.pow.f80"] = &Pow; - Optimizations["llvm.pow.f128"] = &Pow; - Optimizations["llvm.pow.ppcf128"] = &Pow; - Optimizations["exp2l"] = &Exp2; - Optimizations["exp2"] = &Exp2; - Optimizations["exp2f"] = &Exp2; - Optimizations["llvm.exp2.ppcf128"] = &Exp2; - Optimizations["llvm.exp2.f128"] = &Exp2; - Optimizations["llvm.exp2.f80"] = &Exp2; - Optimizations["llvm.exp2.f64"] = &Exp2; - Optimizations["llvm.exp2.f32"] = &Exp2; - - AddOpt(LibFunc::ceil, LibFunc::ceilf, &UnaryDoubleFP); - AddOpt(LibFunc::fabs, LibFunc::fabsf, &UnaryDoubleFP); - AddOpt(LibFunc::floor, LibFunc::floorf, &UnaryDoubleFP); - AddOpt(LibFunc::rint, LibFunc::rintf, &UnaryDoubleFP); - AddOpt(LibFunc::round, LibFunc::roundf, &UnaryDoubleFP); - AddOpt(LibFunc::nearbyint, LibFunc::nearbyintf, &UnaryDoubleFP); - AddOpt(LibFunc::trunc, LibFunc::truncf, &UnaryDoubleFP); - - if(UnsafeFPShrink) { - AddOpt(LibFunc::acos, LibFunc::acosf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::acosh, LibFunc::acoshf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::asin, LibFunc::asinf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::asinh, LibFunc::asinhf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::atan, LibFunc::atanf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::atanh, LibFunc::atanhf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::cbrt, LibFunc::cbrtf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::cosh, LibFunc::coshf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::exp, LibFunc::expf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::exp10, LibFunc::exp10f, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::expm1, LibFunc::expm1f, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::log, LibFunc::logf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::log10, LibFunc::log10f, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::log1p, LibFunc::log1pf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::log2, LibFunc::log2f, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::logb, LibFunc::logbf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::sin, LibFunc::sinf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::sinh, LibFunc::sinhf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::sqrt, LibFunc::sqrtf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::tan, LibFunc::tanf, &UnsafeUnaryDoubleFP); - AddOpt(LibFunc::tanh, LibFunc::tanhf, &UnsafeUnaryDoubleFP); - } - // Integer Optimizations Optimizations["ffs"] = &FFS; Optimizations["ffsl"] = &FFS; diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index 20281181b2a..cceec666dfc 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -20,6 +20,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Function.h" #include "llvm/IRBuilder.h" +#include "llvm/Module.h" #include "llvm/LLVMContext.h" #include "llvm/Target/TargetLibraryInfo.h" #include "llvm/Transforms/Utils/BuildLibCalls.h" @@ -1023,6 +1024,194 @@ struct MemSetOpt : public LibCallOptimization { } }; +//===----------------------------------------------------------------------===// +// Math Library Optimizations +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// Double -> Float Shrinking Optimizations for Unary Functions like 'floor' + +struct UnaryDoubleFPOpt : public LibCallOptimization { + bool CheckRetType; + UnaryDoubleFPOpt(bool CheckReturnType): CheckRetType(CheckReturnType) {} + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + FunctionType *FT = Callee->getFunctionType(); + if (FT->getNumParams() != 1 || !FT->getReturnType()->isDoubleTy() || + !FT->getParamType(0)->isDoubleTy()) + return 0; + + if (CheckRetType) { + // Check if all the uses for function like 'sin' 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 'floor((double)floatval)', convert to floorf. + FPExtInst *Cast = dyn_cast(CI->getArgOperand(0)); + if (Cast == 0 || !Cast->getOperand(0)->getType()->isFloatTy()) + return 0; + + // floor((double)floatval) -> (double)floorf(floatval) + Value *V = Cast->getOperand(0); + V = EmitUnaryFloatFnCall(V, Callee->getName(), B, Callee->getAttributes()); + return B.CreateFPExt(V, B.getDoubleTy()); + } +}; + +struct UnsafeFPLibCallOptimization : public LibCallOptimization { + bool UnsafeFPShrink; + UnsafeFPLibCallOptimization(bool UnsafeFPShrink) { + this->UnsafeFPShrink = UnsafeFPShrink; + } +}; + +struct CosOpt : public UnsafeFPLibCallOptimization { + CosOpt(bool UnsafeFPShrink) : UnsafeFPLibCallOptimization(UnsafeFPShrink) {} + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + Value *Ret = NULL; + if (UnsafeFPShrink && Callee->getName() == "cos" && + TLI->has(LibFunc::cosf)) { + UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true); + Ret = UnsafeUnaryDoubleFP.callOptimizer(Callee, CI, B); + } + + FunctionType *FT = Callee->getFunctionType(); + // Just make sure this has 1 argument of FP type, which matches the + // result type. + if (FT->getNumParams() != 1 || FT->getReturnType() != FT->getParamType(0) || + !FT->getParamType(0)->isFloatingPointTy()) + return Ret; + + // cos(-x) -> cos(x) + Value *Op1 = CI->getArgOperand(0); + if (BinaryOperator::isFNeg(Op1)) { + BinaryOperator *BinExpr = cast(Op1); + return B.CreateCall(Callee, BinExpr->getOperand(1), "cos"); + } + return Ret; + } +}; + +struct PowOpt : public UnsafeFPLibCallOptimization { + PowOpt(bool UnsafeFPShrink) : UnsafeFPLibCallOptimization(UnsafeFPShrink) {} + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + Value *Ret = NULL; + if (UnsafeFPShrink && Callee->getName() == "pow" && + TLI->has(LibFunc::powf)) { + UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true); + Ret = UnsafeUnaryDoubleFP.callOptimizer(Callee, CI, 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 Ret; + + Value *Op1 = CI->getArgOperand(0), *Op2 = CI->getArgOperand(1); + if (ConstantFP *Op1C = dyn_cast(Op1)) { + if (Op1C->isExactlyValue(1.0)) // pow(1.0, x) -> 1.0 + return Op1C; + if (Op1C->isExactlyValue(2.0)) // pow(2.0, x) -> exp2(x) + return EmitUnaryFloatFnCall(Op2, "exp2", B, Callee->getAttributes()); + } + + ConstantFP *Op2C = dyn_cast(Op2); + if (Op2C == 0) return Ret; + + if (Op2C->getValueAPF().isZero()) // pow(x, 0.0) -> 1.0 + return ConstantFP::get(CI->getType(), 1.0); + + if (Op2C->isExactlyValue(0.5)) { + // Expand pow(x, 0.5) to (x == -infinity ? +infinity : fabs(sqrt(x))). + // This is faster than calling pow, and still handles negative zero + // and negative infinity correctly. + // TODO: In fast-math mode, this could be just sqrt(x). + // TODO: In finite-only mode, this could be just fabs(sqrt(x)). + Value *Inf = ConstantFP::getInfinity(CI->getType()); + Value *NegInf = ConstantFP::getInfinity(CI->getType(), true); + Value *Sqrt = EmitUnaryFloatFnCall(Op1, "sqrt", B, + Callee->getAttributes()); + Value *FAbs = EmitUnaryFloatFnCall(Sqrt, "fabs", B, + Callee->getAttributes()); + Value *FCmp = B.CreateFCmpOEQ(Op1, NegInf); + Value *Sel = B.CreateSelect(FCmp, Inf, FAbs); + return Sel; + } + + if (Op2C->isExactlyValue(1.0)) // pow(x, 1.0) -> x + return Op1; + if (Op2C->isExactlyValue(2.0)) // pow(x, 2.0) -> x*x + return B.CreateFMul(Op1, Op1, "pow2"); + if (Op2C->isExactlyValue(-1.0)) // pow(x, -1.0) -> 1.0/x + return B.CreateFDiv(ConstantFP::get(CI->getType(), 1.0), + Op1, "powrecip"); + return 0; + } +}; + +struct Exp2Opt : public UnsafeFPLibCallOptimization { + Exp2Opt(bool UnsafeFPShrink) : UnsafeFPLibCallOptimization(UnsafeFPShrink) {} + virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) { + Value *Ret = NULL; + if (UnsafeFPShrink && Callee->getName() == "exp2" && + TLI->has(LibFunc::exp2)) { + UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true); + Ret = UnsafeUnaryDoubleFP.callOptimizer(Callee, CI, B); + } + + FunctionType *FT = Callee->getFunctionType(); + // Just make sure this has 1 argument of FP type, which matches the + // result type. + if (FT->getNumParams() != 1 || FT->getReturnType() != FT->getParamType(0) || + !FT->getParamType(0)->isFloatingPointTy()) + return Ret; + + Value *Op = CI->getArgOperand(0); + // Turn exp2(sitofp(x)) -> ldexp(1.0, sext(x)) if sizeof(x) <= 32 + // Turn exp2(uitofp(x)) -> ldexp(1.0, zext(x)) if sizeof(x) < 32 + Value *LdExpArg = 0; + if (SIToFPInst *OpC = dyn_cast(Op)) { + if (OpC->getOperand(0)->getType()->getPrimitiveSizeInBits() <= 32) + LdExpArg = B.CreateSExt(OpC->getOperand(0), B.getInt32Ty()); + } else if (UIToFPInst *OpC = dyn_cast(Op)) { + if (OpC->getOperand(0)->getType()->getPrimitiveSizeInBits() < 32) + LdExpArg = B.CreateZExt(OpC->getOperand(0), B.getInt32Ty()); + } + + if (LdExpArg) { + const char *Name; + if (Op->getType()->isFloatTy()) + Name = "ldexpf"; + else if (Op->getType()->isDoubleTy()) + Name = "ldexp"; + else + Name = "ldexpl"; + + Constant *One = ConstantFP::get(*Context, APFloat(1.0f)); + if (!Op->getType()->isFloatTy()) + One = ConstantExpr::getFPExtend(One, Op->getType()); + + Module *M = Caller->getParent(); + Value *Callee = M->getOrInsertFunction(Name, Op->getType(), + Op->getType(), + B.getInt32Ty(), NULL); + CallInst *CI = B.CreateCall2(Callee, One, LdExpArg); + if (const Function *F = dyn_cast(Callee->stripPointerCasts())) + CI->setCallingConv(F->getCallingConv()); + + return CI; + } + return Ret; + } +}; + } // End anonymous namespace. namespace llvm { @@ -1031,6 +1220,7 @@ class LibCallSimplifierImpl { const DataLayout *TD; const TargetLibraryInfo *TLI; const LibCallSimplifier *LCS; + bool UnsafeFPShrink; StringMap Optimizations; // Fortified library call optimizations. @@ -1064,14 +1254,23 @@ class LibCallSimplifierImpl { MemMoveOpt MemMove; MemSetOpt MemSet; + // Math library call optimizations. + UnaryDoubleFPOpt UnaryDoubleFP, UnsafeUnaryDoubleFP; + CosOpt Cos; PowOpt Pow; Exp2Opt Exp2; + void initOptimizations(); void addOpt(LibFunc::Func F, LibCallOptimization* Opt); + void addOpt(LibFunc::Func F1, LibFunc::Func F2, LibCallOptimization* Opt); public: LibCallSimplifierImpl(const DataLayout *TD, const TargetLibraryInfo *TLI, - const LibCallSimplifier *LCS) { + const LibCallSimplifier *LCS, + bool UnsafeFPShrink = false) + : UnaryDoubleFP(false), UnsafeUnaryDoubleFP(true), + Cos(UnsafeFPShrink), Pow(UnsafeFPShrink), Exp2(UnsafeFPShrink) { this->TD = TD; this->TLI = TLI; this->LCS = LCS; + this->UnsafeFPShrink = UnsafeFPShrink; } Value *optimizeCall(CallInst *CI); @@ -1115,6 +1314,59 @@ void LibCallSimplifierImpl::initOptimizations() { addOpt(LibFunc::memcpy, &MemCpy); addOpt(LibFunc::memmove, &MemMove); addOpt(LibFunc::memset, &MemSet); + + // Math library call optimizations. + addOpt(LibFunc::ceil, LibFunc::ceilf, &UnaryDoubleFP); + addOpt(LibFunc::fabs, LibFunc::fabsf, &UnaryDoubleFP); + addOpt(LibFunc::floor, LibFunc::floorf, &UnaryDoubleFP); + addOpt(LibFunc::rint, LibFunc::rintf, &UnaryDoubleFP); + addOpt(LibFunc::round, LibFunc::roundf, &UnaryDoubleFP); + addOpt(LibFunc::nearbyint, LibFunc::nearbyintf, &UnaryDoubleFP); + addOpt(LibFunc::trunc, LibFunc::truncf, &UnaryDoubleFP); + + if(UnsafeFPShrink) { + addOpt(LibFunc::acos, LibFunc::acosf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::acosh, LibFunc::acoshf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::asin, LibFunc::asinf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::asinh, LibFunc::asinhf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::atan, LibFunc::atanf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::atanh, LibFunc::atanhf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::cbrt, LibFunc::cbrtf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::cosh, LibFunc::coshf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::exp, LibFunc::expf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::exp10, LibFunc::exp10f, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::expm1, LibFunc::expm1f, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::log, LibFunc::logf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::log10, LibFunc::log10f, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::log1p, LibFunc::log1pf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::log2, LibFunc::log2f, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::logb, LibFunc::logbf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::sin, LibFunc::sinf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::sinh, LibFunc::sinhf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::sqrt, LibFunc::sqrtf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::tan, LibFunc::tanf, &UnsafeUnaryDoubleFP); + addOpt(LibFunc::tanh, LibFunc::tanhf, &UnsafeUnaryDoubleFP); + } + + addOpt(LibFunc::cosf, &Cos); + addOpt(LibFunc::cos, &Cos); + addOpt(LibFunc::cosl, &Cos); + addOpt(LibFunc::powf, &Pow); + addOpt(LibFunc::pow, &Pow); + addOpt(LibFunc::powl, &Pow); + Optimizations["llvm.pow.f32"] = &Pow; + Optimizations["llvm.pow.f64"] = &Pow; + Optimizations["llvm.pow.f80"] = &Pow; + Optimizations["llvm.pow.f128"] = &Pow; + Optimizations["llvm.pow.ppcf128"] = &Pow; + addOpt(LibFunc::exp2l, &Exp2); + addOpt(LibFunc::exp2, &Exp2); + addOpt(LibFunc::exp2f, &Exp2); + Optimizations["llvm.exp2.ppcf128"] = &Exp2; + Optimizations["llvm.exp2.f128"] = &Exp2; + Optimizations["llvm.exp2.f80"] = &Exp2; + Optimizations["llvm.exp2.f64"] = &Exp2; + Optimizations["llvm.exp2.f32"] = &Exp2; } Value *LibCallSimplifierImpl::optimizeCall(CallInst *CI) { @@ -1135,9 +1387,16 @@ void LibCallSimplifierImpl::addOpt(LibFunc::Func F, LibCallOptimization* Opt) { Optimizations[TLI->getName(F)] = Opt; } +void LibCallSimplifierImpl::addOpt(LibFunc::Func F1, LibFunc::Func F2, + LibCallOptimization* Opt) { + if (TLI->has(F1) && TLI->has(F2)) + Optimizations[TLI->getName(F1)] = Opt; +} + LibCallSimplifier::LibCallSimplifier(const DataLayout *TD, - const TargetLibraryInfo *TLI) { - Impl = new LibCallSimplifierImpl(TD, TLI, this); + const TargetLibraryInfo *TLI, + bool UnsafeFPShrink) { + Impl = new LibCallSimplifierImpl(TD, TLI, this, UnsafeFPShrink); } LibCallSimplifier::~LibCallSimplifier() { diff --git a/test/Transforms/InstCombine/cos-1.ll b/test/Transforms/InstCombine/cos-1.ll new file mode 100644 index 00000000000..b92e448abd9 --- /dev/null +++ b/test/Transforms/InstCombine/cos-1.ll @@ -0,0 +1,38 @@ +; Test that the cos library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s -check-prefix=NO-FLOAT-SHRINK +; RUN: opt < %s -instcombine -enable-double-float-shrink -S | FileCheck %s -check-prefix=DO-FLOAT-SHRINK + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +declare double @cos(double) + +; Check cos(-x) -> cos(x); + +define double @test_simplify1(double %d) { +; NO-FLOAT-SHRINK: @test_simplify1 + %neg = fsub double -0.000000e+00, %d + %cos = call double @cos(double %neg) +; NO-FLOAT-SHRINK: call double @cos(double %d) + ret double %cos +} + +define float @test_simplify2(float %f) { +; DO-FLOAT-SHRINK: @test_simplify2 + %conv1 = fpext float %f to double + %neg = fsub double -0.000000e+00, %conv1 + %cos = call double @cos(double %neg) + %conv2 = fptrunc double %cos to float +; DO-FLOAT-SHRINK: call float @cosf(float %f) + ret float %conv2 +} + +define float @test_simplify3(float %f) { +; NO-FLOAT-SHRINK: @test_simplify3 + %conv1 = fpext float %f to double + %neg = fsub double -0.000000e+00, %conv1 + %cos = call double @cos(double %neg) +; NO-FLOAT-SHRINK: call double @cos(double %conv1) + %conv2 = fptrunc double %cos to float + ret float %conv2 +} diff --git a/test/Transforms/InstCombine/cos-2.ll b/test/Transforms/InstCombine/cos-2.ll new file mode 100644 index 00000000000..2f2dfafe484 --- /dev/null +++ b/test/Transforms/InstCombine/cos-2.ll @@ -0,0 +1,17 @@ +; Test that the cos library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" + +declare float @cos(double) + +; Check that cos functions with the wrong prototype aren't simplified. + +define float @test_no_simplify1(double %d) { +; CHECK: @test_no_simplify1 + %neg = fsub double -0.000000e+00, %d + %cos = call float @cos(double %neg) +; CHECK: call float @cos(double %neg) + ret float %cos +} diff --git a/test/Transforms/InstCombine/double-float-shrink-1.ll b/test/Transforms/InstCombine/double-float-shrink-1.ll new file mode 100644 index 00000000000..e5448ee0076 --- /dev/null +++ b/test/Transforms/InstCombine/double-float-shrink-1.ll @@ -0,0 +1,333 @@ +; RUN: opt < %s -instcombine -enable-double-float-shrink -S | FileCheck %s + +target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define float @acos_test(float %f) nounwind readnone { +; CHECK: acos_test + %conv = fpext float %f to double + %call = call double @acos(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @acosf(float %f) +} + +define double @acos_test2(float %f) nounwind readnone { +; CHECK: acos_test2 + %conv = fpext float %f to double + %call = call double @acos(double %conv) + ret double %call +; CHECK: call double @acos(double %conv) +} + +define float @acosh_test(float %f) nounwind readnone { +; CHECK: acosh_test + %conv = fpext float %f to double + %call = call double @acosh(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @acoshf(float %f) +} + +define double @acosh_test2(float %f) nounwind readnone { +; CHECK: acosh_test2 + %conv = fpext float %f to double + %call = call double @acosh(double %conv) + ret double %call +; CHECK: call double @acosh(double %conv) +} + +define float @asin_test(float %f) nounwind readnone { +; CHECK: asin_test + %conv = fpext float %f to double + %call = call double @asin(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @asinf(float %f) +} + +define double @asin_test2(float %f) nounwind readnone { +; CHECK: asin_test2 + %conv = fpext float %f to double + %call = call double @asin(double %conv) + ret double %call +; CHECK: call double @asin(double %conv) +} + +define float @asinh_test(float %f) nounwind readnone { +; CHECK: asinh_test + %conv = fpext float %f to double + %call = call double @asinh(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @asinhf(float %f) +} + +define double @asinh_test2(float %f) nounwind readnone { +; CHECK: asinh_test2 + %conv = fpext float %f to double + %call = call double @asinh(double %conv) + ret double %call +; CHECK: call double @asinh(double %conv) +} + +define float @atan_test(float %f) nounwind readnone { +; CHECK: atan_test + %conv = fpext float %f to double + %call = call double @atan(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @atanf(float %f) +} + +define double @atan_test2(float %f) nounwind readnone { +; CHECK: atan_test2 + %conv = fpext float %f to double + %call = call double @atan(double %conv) + ret double %call +; CHECK: call double @atan(double %conv) +} +define float @atanh_test(float %f) nounwind readnone { +; CHECK: atanh_test + %conv = fpext float %f to double + %call = call double @atanh(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @atanhf(float %f) +} + +define double @atanh_test2(float %f) nounwind readnone { +; CHECK: atanh_test2 + %conv = fpext float %f to double + %call = call double @atanh(double %conv) + ret double %call +; CHECK: call double @atanh(double %conv) +} +define float @cbrt_test(float %f) nounwind readnone { +; CHECK: cbrt_test + %conv = fpext float %f to double + %call = call double @cbrt(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @cbrtf(float %f) +} + +define double @cbrt_test2(float %f) nounwind readnone { +; CHECK: cbrt_test2 + %conv = fpext float %f to double + %call = call double @cbrt(double %conv) + ret double %call +; CHECK: call double @cbrt(double %conv) +} +define float @exp_test(float %f) nounwind readnone { +; CHECK: exp_test + %conv = fpext float %f to double + %call = call double @exp(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @expf(float %f) +} + +define double @exp_test2(float %f) nounwind readnone { +; CHECK: exp_test2 + %conv = fpext float %f to double + %call = call double @exp(double %conv) + ret double %call +; CHECK: call double @exp(double %conv) +} +define float @expm1_test(float %f) nounwind readnone { +; CHECK: expm1_test + %conv = fpext float %f to double + %call = call double @expm1(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @expm1f(float %f) +} + +define double @expm1_test2(float %f) nounwind readnone { +; CHECK: expm1_test2 + %conv = fpext float %f to double + %call = call double @expm1(double %conv) + ret double %call +; CHECK: call double @expm1(double %conv) +} +define float @exp10_test(float %f) nounwind readnone { +; CHECK: exp10_test + %conv = fpext float %f to double + %call = call double @exp10(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @exp10f(float %f) +} + +define double @exp10_test2(float %f) nounwind readnone { +; CHECK: exp10_test2 + %conv = fpext float %f to double + %call = call double @exp10(double %conv) + ret double %call +; CHECK: call double @exp10(double %conv) +} +define float @log_test(float %f) nounwind readnone { +; CHECK: log_test + %conv = fpext float %f to double + %call = call double @log(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @logf(float %f) +} + +define double @log_test2(float %f) nounwind readnone { +; CHECK: log_test2 + %conv = fpext float %f to double + %call = call double @log(double %conv) + ret double %call +; CHECK: call double @log(double %conv) +} +define float @log10_test(float %f) nounwind readnone { +; CHECK: log10_test + %conv = fpext float %f to double + %call = call double @log10(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @log10f(float %f) +} + +define double @log10_test2(float %f) nounwind readnone { +; CHECK: log10_test2 + %conv = fpext float %f to double + %call = call double @log10(double %conv) + ret double %call +; CHECK: call double @log10(double %conv) +} +define float @log1p_test(float %f) nounwind readnone { +; CHECK: log1p_test + %conv = fpext float %f to double + %call = call double @log1p(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @log1pf(float %f) +} + +define double @log1p_test2(float %f) nounwind readnone { +; CHECK: log1p_test2 + %conv = fpext float %f to double + %call = call double @log1p(double %conv) + ret double %call +; CHECK: call double @log1p(double %conv) +} +define float @log2_test(float %f) nounwind readnone { +; CHECK: log2_test + %conv = fpext float %f to double + %call = call double @log2(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @log2f(float %f) +} + +define double @log2_test2(float %f) nounwind readnone { +; CHECK: log2_test2 + %conv = fpext float %f to double + %call = call double @log2(double %conv) + ret double %call +; CHECK: call double @log2(double %conv) +} +define float @logb_test(float %f) nounwind readnone { +; CHECK: logb_test + %conv = fpext float %f to double + %call = call double @logb(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @logbf(float %f) +} + +define double @logb_test2(float %f) nounwind readnone { +; CHECK: logb_test2 + %conv = fpext float %f to double + %call = call double @logb(double %conv) + ret double %call +; CHECK: call double @logb(double %conv) +} +define float @sin_test(float %f) nounwind readnone { +; CHECK: sin_test + %conv = fpext float %f to double + %call = call double @sin(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @sinf(float %f) +} + +define double @sin_test2(float %f) nounwind readnone { +; CHECK: sin_test2 + %conv = fpext float %f to double + %call = call double @sin(double %conv) + ret double %call +; CHECK: call double @sin(double %conv) +} +define float @sqrt_test(float %f) nounwind readnone { +; CHECK: sqrt_test + %conv = fpext float %f to double + %call = call double @sqrt(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @sqrtf(float %f) +} + +define double @sqrt_test2(float %f) nounwind readnone { +; CHECK: sqrt_test2 + %conv = fpext float %f to double + %call = call double @sqrt(double %conv) + ret double %call +; CHECK: call double @sqrt(double %conv) +} +define float @tan_test(float %f) nounwind readnone { +; CHECK: tan_test + %conv = fpext float %f to double + %call = call double @tan(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @tanf(float %f) +} + +define double @tan_test2(float %f) nounwind readnone { +; CHECK: tan_test2 + %conv = fpext float %f to double + %call = call double @tan(double %conv) + ret double %call +; CHECK: call double @tan(double %conv) +} +define float @tanh_test(float %f) nounwind readnone { +; CHECK: tanh_test + %conv = fpext float %f to double + %call = call double @tanh(double %conv) + %conv1 = fptrunc double %call to float + ret float %conv1 +; CHECK: call float @tanhf(float %f) +} + +define double @tanh_test2(float %f) nounwind readnone { +; CHECK: tanh_test2 + %conv = fpext float %f to double + %call = call double @tanh(double %conv) + ret double %call +; CHECK: call double @tanh(double %conv) +} + +declare double @tanh(double) nounwind readnone +declare double @tan(double) nounwind readnone +declare double @sqrt(double) nounwind readnone +declare double @sin(double) nounwind readnone +declare double @log2(double) nounwind readnone +declare double @log1p(double) nounwind readnone +declare double @log10(double) nounwind readnone +declare double @log(double) nounwind readnone +declare double @logb(double) nounwind readnone +declare double @exp10(double) nounwind readnone +declare double @expm1(double) nounwind readnone +declare double @exp(double) nounwind readnone +declare double @cbrt(double) nounwind readnone +declare double @atanh(double) nounwind readnone +declare double @atan(double) nounwind readnone +declare double @acos(double) nounwind readnone +declare double @acosh(double) nounwind readnone +declare double @asin(double) nounwind readnone +declare double @asinh(double) nounwind readnone diff --git a/test/Transforms/InstCombine/double-float-shrink-2.ll b/test/Transforms/InstCombine/double-float-shrink-2.ll new file mode 100644 index 00000000000..7f6df92c96c --- /dev/null +++ b/test/Transforms/InstCombine/double-float-shrink-2.ll @@ -0,0 +1,80 @@ +; RUN: opt < %s -instcombine -S -mtriple "i386-pc-linux" | FileCheck -check-prefix=DO-SIMPLIFY %s +; RUN: opt < %s -instcombine -S -mtriple "i386-pc-win32" | FileCheck -check-prefix=DONT-SIMPLIFY %s +; RUN: opt < %s -instcombine -S -mtriple "x86_64-pc-win32" | FileCheck -check-prefix=C89-SIMPLIFY %s +; RUN: opt < %s -instcombine -S -mtriple "i386-pc-mingw32" | FileCheck -check-prefix=DO-SIMPLIFY %s +; RUN: opt < %s -instcombine -S -mtriple "x86_64-pc-mingw32" | FileCheck -check-prefix=DO-SIMPLIFY %s +; RUN: opt < %s -instcombine -S -mtriple "sparc-sun-solaris" | FileCheck -check-prefix=DO-SIMPLIFY %s + +; DO-SIMPLIFY: call float @floorf( +; DO-SIMPLIFY: call float @ceilf( +; DO-SIMPLIFY: call float @roundf( +; DO-SIMPLIFY: call float @nearbyintf( +; DO-SIMPLIFY: call float @truncf( +; DO-SIMPLIFY: call float @fabsf( + +; C89-SIMPLIFY: call float @floorf( +; C89-SIMPLIFY: call float @ceilf( +; C89-SIMPLIFY: call double @round( +; C89-SIMPLIFY: call double @nearbyint( + +; DONT-SIMPLIFY: call double @floor( +; DONT-SIMPLIFY: call double @ceil( +; DONT-SIMPLIFY: call double @round( +; DONT-SIMPLIFY: call double @nearbyint( +; DONT-SIMPLIFY: call double @trunc( +; DONT-SIMPLIFY: call double @fabs( + +declare double @floor(double) +declare double @ceil(double) +declare double @round(double) +declare double @nearbyint(double) +declare double @trunc(double) +declare double @fabs(double) + +define float @test_floor(float %C) { + %D = fpext float %C to double + ; --> floorf + %E = call double @floor(double %D) + %F = fptrunc double %E to float + ret float %F +} + +define float @test_ceil(float %C) { + %D = fpext float %C to double + ; --> ceilf + %E = call double @ceil(double %D) + %F = fptrunc double %E to float + ret float %F +} + +define float @test_round(float %C) { + %D = fpext float %C to double + ; --> roundf + %E = call double @round(double %D) + %F = fptrunc double %E to float + ret float %F +} + +define float @test_nearbyint(float %C) { + %D = fpext float %C to double + ; --> nearbyintf + %E = call double @nearbyint(double %D) + %F = fptrunc double %E to float + ret float %F +} + +define float @test_trunc(float %C) { + %D = fpext float %C to double + ; --> truncf + %E = call double @trunc(double %D) + %F = fptrunc double %E to float + ret float %F +} + +define float @test_fabs(float %C) { + %D = fpext float %C to double + ; --> fabsf + %E = call double @fabs(double %D) + %F = fptrunc double %E to float + ret float %F +} diff --git a/test/Transforms/InstCombine/exp2-1.ll b/test/Transforms/InstCombine/exp2-1.ll new file mode 100644 index 00000000000..1b0ad500041 --- /dev/null +++ b/test/Transforms/InstCombine/exp2-1.ll @@ -0,0 +1,76 @@ +; Test that the exp2 library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" + +declare double @exp2(double) +declare float @exp2f(float) + +; Check exp2(sitofp(x)) -> ldexp(1.0, sext(x)). + +define double @test_simplify1(i32 %x) { +; CHECK: @test_simplify1 + %conv = sitofp i32 %x to double + %ret = call double @exp2(double %conv) +; CHECK: call double @ldexp + ret double %ret +} + +define double @test_simplify2(i16 signext %x) { +; CHECK: @test_simplify2 + %conv = sitofp i16 %x to double + %ret = call double @exp2(double %conv) +; CHECK: call double @ldexp + ret double %ret +} + +define double @test_simplify3(i8 signext %x) { +; CHECK: @test_simplify3 + %conv = sitofp i8 %x to double + %ret = call double @exp2(double %conv) +; CHECK: call double @ldexp + ret double %ret +} + +define float @test_simplify4(i32 %x) { +; CHECK: @test_simplify4 + %conv = sitofp i32 %x to float + %ret = call float @exp2f(float %conv) +; CHECK: call float @ldexpf + ret float %ret +} + +; Check exp2(uitofp(x)) -> ldexp(1.0, zext(x)). + +define double @test_no_simplify1(i32 %x) { +; CHECK: @test_no_simplify1 + %conv = uitofp i32 %x to double + %ret = call double @exp2(double %conv) +; CHECK: call double @exp2 + ret double %ret +} + +define double @test_simplify6(i16 zeroext %x) { +; CHECK: @test_simplify6 + %conv = uitofp i16 %x to double + %ret = call double @exp2(double %conv) +; CHECK: call double @ldexp + ret double %ret +} + +define double @test_simplify7(i8 zeroext %x) { +; CHECK: @test_simplify7 + %conv = uitofp i8 %x to double + %ret = call double @exp2(double %conv) +; CHECK: call double @ldexp + ret double %ret +} + +define float @test_simplify8(i8 zeroext %x) { +; CHECK: @test_simplify8 + %conv = uitofp i8 %x to float + %ret = call float @exp2f(float %conv) +; CHECK: call float @ldexpf + ret float %ret +} diff --git a/test/Transforms/InstCombine/exp2-2.ll b/test/Transforms/InstCombine/exp2-2.ll new file mode 100644 index 00000000000..bed063798e2 --- /dev/null +++ b/test/Transforms/InstCombine/exp2-2.ll @@ -0,0 +1,17 @@ +; Test that the exp2 library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" + +declare float @exp2(double) + +; Check that exp2 functions with the wrong prototype aren't simplified. + +define float @test_no_simplify1(i32 %x) { +; CHECK: @test_no_simplify1 + %conv = sitofp i32 %x to double + %ret = call float @exp2(double %conv) +; CHECK: call float @exp2(double %conv) + ret float %ret +} diff --git a/test/Transforms/InstCombine/pow-1.ll b/test/Transforms/InstCombine/pow-1.ll new file mode 100644 index 00000000000..c8e5f3806f9 --- /dev/null +++ b/test/Transforms/InstCombine/pow-1.ll @@ -0,0 +1,152 @@ +; Test that the pow library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s +; rdar://7251832 + +; NOTE: The readonly attribute on the pow call should be preserved +; in the cases below where pow is transformed into another function call. + +declare float @powf(float, float) nounwind readonly +declare double @pow(double, double) nounwind readonly + +; Check pow(1.0, x) -> 1.0. + +define float @test_simplify1(float %x) { +; CHECK: @test_simplify1 + %retval = call float @powf(float 1.0, float %x) + ret float %retval +; CHECK-NEXT: ret float 1.000000e+00 +} + +define double @test_simplify2(double %x) { +; CHECK: @test_simplify2 + %retval = call double @pow(double 1.0, double %x) + ret double %retval +; CHECK-NEXT: ret double 1.000000e+00 +} + +; Check pow(2.0, x) -> exp2(x). + +define float @test_simplify3(float %x) { +; CHECK: @test_simplify3 + %retval = call float @powf(float 2.0, float %x) +; CHECK-NEXT: [[EXP2F:%[a-z0-9]+]] = call float @exp2f(float %x) nounwind readonly + ret float %retval +; CHECK-NEXT: ret float [[EXP2F]] +} + +define double @test_simplify4(double %x) { +; CHECK: @test_simplify4 + %retval = call double @pow(double 2.0, double %x) +; CHECK-NEXT: [[EXP2:%[a-z0-9]+]] = call double @exp2(double %x) nounwind readonly + ret double %retval +; CHECK-NEXT: ret double [[EXP2]] +} + +; Check pow(x, 0.0) -> 1.0. + +define float @test_simplify5(float %x) { +; CHECK: @test_simplify5 + %retval = call float @powf(float %x, float 0.0) + ret float %retval +; CHECK-NEXT: ret float 1.000000e+00 +} + +define double @test_simplify6(double %x) { +; CHECK: @test_simplify6 + %retval = call double @pow(double %x, double 0.0) + ret double %retval +; CHECK-NEXT: ret double 1.000000e+00 +} + +; Check pow(x, 0.5) -> fabs(sqrt(x)), where x != -infinity. + +define float @test_simplify7(float %x) { +; CHECK: @test_simplify7 + %retval = call float @powf(float %x, float 0.5) +; CHECK-NEXT: [[SQRTF:%[a-z0-9]+]] = call float @sqrtf(float %x) nounwind readonly +; CHECK-NEXT: [[FABSF:%[a-z0-9]+]] = call float @fabsf(float [[SQRTF]]) nounwind readonly +; CHECK-NEXT: [[FCMP:%[a-z0-9]+]] = fcmp oeq float %x, 0xFFF0000000000000 +; CHECK-NEXT: [[SELECT:%[a-z0-9]+]] = select i1 [[FCMP]], float 0x7FF0000000000000, float [[FABSF]] + ret float %retval +; CHECK-NEXT: ret float [[SELECT]] +} + +define double @test_simplify8(double %x) { +; CHECK: @test_simplify8 + %retval = call double @pow(double %x, double 0.5) +; CHECK-NEXT: [[SQRT:%[a-z0-9]+]] = call double @sqrt(double %x) nounwind readonly +; CHECK-NEXT: [[FABS:%[a-z0-9]+]] = call double @fabs(double [[SQRT]]) nounwind readonly +; CHECK-NEXT: [[FCMP:%[a-z0-9]+]] = fcmp oeq double %x, 0xFFF0000000000000 +; CHECK-NEXT: [[SELECT:%[a-z0-9]+]] = select i1 [[FCMP]], double 0x7FF0000000000000, double [[FABS]] + ret double %retval +; CHECK-NEXT: ret double [[SELECT]] +} + +; Check pow(-infinity, 0.5) -> +infinity. + +define float @test_simplify9(float %x) { +; CHECK: @test_simplify9 + %retval = call float @powf(float 0xFFF0000000000000, float 0.5) + ret float %retval +; CHECK-NEXT: ret float 0x7FF0000000000000 +} + +define double @test_simplify10(double %x) { +; CHECK: @test_simplify10 + %retval = call double @pow(double 0xFFF0000000000000, double 0.5) + ret double %retval +; CHECK-NEXT: ret double 0x7FF0000000000000 +} + +; Check pow(x, 1.0) -> x. + +define float @test_simplify11(float %x) { +; CHECK: @test_simplify11 + %retval = call float @powf(float %x, float 1.0) + ret float %retval +; CHECK-NEXT: ret float %x +} + +define double @test_simplify12(double %x) { +; CHECK: @test_simplify12 + %retval = call double @pow(double %x, double 1.0) + ret double %retval +; CHECK-NEXT: ret double %x +} + +; Check pow(x, 2.0) -> x*x. + +define float @test_simplify13(float %x) { +; CHECK: @test_simplify13 + %retval = call float @powf(float %x, float 2.0) +; CHECK-NEXT: [[SQUARE:%[a-z0-9]+]] = fmul float %x, %x + ret float %retval +; CHECK-NEXT: ret float [[SQUARE]] +} + +define double @test_simplify14(double %x) { +; CHECK: @test_simplify14 + %retval = call double @pow(double %x, double 2.0) +; CHECK-NEXT: [[SQUARE:%[a-z0-9]+]] = fmul double %x, %x + ret double %retval +; CHECK-NEXT: ret double [[SQUARE]] +} + +; Check pow(x, -1.0) -> 1.0/x. + +define float @test_simplify15(float %x) { +; CHECK: @test_simplify15 + %retval = call float @powf(float %x, float -1.0) +; CHECK-NEXT: [[RECIPROCAL:%[a-z0-9]+]] = fdiv float 1.000000e+00, %x + ret float %retval +; CHECK-NEXT: ret float [[RECIPROCAL]] +} + +define double @test_simplify16(double %x) { +; CHECK: @test_simplify16 + %retval = call double @pow(double %x, double -1.0) +; CHECK-NEXT: [[RECIPROCAL:%[a-z0-9]+]] = fdiv double 1.000000e+00, %x + ret double %retval +; CHECK-NEXT: ret double [[RECIPROCAL]] +} diff --git a/test/Transforms/InstCombine/pow-2.ll b/test/Transforms/InstCombine/pow-2.ll new file mode 100644 index 00000000000..af64cda0904 --- /dev/null +++ b/test/Transforms/InstCombine/pow-2.ll @@ -0,0 +1,14 @@ +; Test that the pow library call simplifier works correctly. +; +; RUN: opt < %s -instcombine -S | FileCheck %s + +declare float @pow(double, double) + +; Check that pow functions with the wrong prototype aren't simplified. + +define float @test_no_simplify1(double %x) { +; CHECK: @test_no_simplify1 + %retval = call float @pow(double 1.0, double %x) +; CHECK-NEXT: call float @pow(double 1.000000e+00, double %x) + ret float %retval +} diff --git a/test/Transforms/SimplifyLibCalls/cos.ll b/test/Transforms/SimplifyLibCalls/cos.ll deleted file mode 100644 index 6a8ce8c3881..00000000000 --- a/test/Transforms/SimplifyLibCalls/cos.ll +++ /dev/null @@ -1,14 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s - -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define double @foo(double %d) nounwind readnone { -; CHECK: @foo - %1 = fsub double -0.000000e+00, %d - %2 = call double @cos(double %1) nounwind readnone -; CHECK: call double @cos(double %d) - ret double %2 -} - -declare double @cos(double) nounwind readnone diff --git a/test/Transforms/SimplifyLibCalls/double-float-shrink.ll b/test/Transforms/SimplifyLibCalls/double-float-shrink.ll deleted file mode 100644 index b4ab8b4ceb9..00000000000 --- a/test/Transforms/SimplifyLibCalls/double-float-shrink.ll +++ /dev/null @@ -1,333 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -enable-double-float-shrink -S | FileCheck %s - -target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -define float @acos_test(float %f) nounwind readnone { -; CHECK: acos_test - %conv = fpext float %f to double - %call = call double @acos(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @acosf(float %f) -} - -define double @acos_test2(float %f) nounwind readnone { -; CHECK: acos_test2 - %conv = fpext float %f to double - %call = call double @acos(double %conv) - ret double %call -; CHECK: call double @acos(double %conv) -} - -define float @acosh_test(float %f) nounwind readnone { -; CHECK: acosh_test - %conv = fpext float %f to double - %call = call double @acosh(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @acoshf(float %f) -} - -define double @acosh_test2(float %f) nounwind readnone { -; CHECK: acosh_test2 - %conv = fpext float %f to double - %call = call double @acosh(double %conv) - ret double %call -; CHECK: call double @acosh(double %conv) -} - -define float @asin_test(float %f) nounwind readnone { -; CHECK: asin_test - %conv = fpext float %f to double - %call = call double @asin(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @asinf(float %f) -} - -define double @asin_test2(float %f) nounwind readnone { -; CHECK: asin_test2 - %conv = fpext float %f to double - %call = call double @asin(double %conv) - ret double %call -; CHECK: call double @asin(double %conv) -} - -define float @asinh_test(float %f) nounwind readnone { -; CHECK: asinh_test - %conv = fpext float %f to double - %call = call double @asinh(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @asinhf(float %f) -} - -define double @asinh_test2(float %f) nounwind readnone { -; CHECK: asinh_test2 - %conv = fpext float %f to double - %call = call double @asinh(double %conv) - ret double %call -; CHECK: call double @asinh(double %conv) -} - -define float @atan_test(float %f) nounwind readnone { -; CHECK: atan_test - %conv = fpext float %f to double - %call = call double @atan(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @atanf(float %f) -} - -define double @atan_test2(float %f) nounwind readnone { -; CHECK: atan_test2 - %conv = fpext float %f to double - %call = call double @atan(double %conv) - ret double %call -; CHECK: call double @atan(double %conv) -} -define float @atanh_test(float %f) nounwind readnone { -; CHECK: atanh_test - %conv = fpext float %f to double - %call = call double @atanh(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @atanhf(float %f) -} - -define double @atanh_test2(float %f) nounwind readnone { -; CHECK: atanh_test2 - %conv = fpext float %f to double - %call = call double @atanh(double %conv) - ret double %call -; CHECK: call double @atanh(double %conv) -} -define float @cbrt_test(float %f) nounwind readnone { -; CHECK: cbrt_test - %conv = fpext float %f to double - %call = call double @cbrt(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @cbrtf(float %f) -} - -define double @cbrt_test2(float %f) nounwind readnone { -; CHECK: cbrt_test2 - %conv = fpext float %f to double - %call = call double @cbrt(double %conv) - ret double %call -; CHECK: call double @cbrt(double %conv) -} -define float @exp_test(float %f) nounwind readnone { -; CHECK: exp_test - %conv = fpext float %f to double - %call = call double @exp(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @expf(float %f) -} - -define double @exp_test2(float %f) nounwind readnone { -; CHECK: exp_test2 - %conv = fpext float %f to double - %call = call double @exp(double %conv) - ret double %call -; CHECK: call double @exp(double %conv) -} -define float @expm1_test(float %f) nounwind readnone { -; CHECK: expm1_test - %conv = fpext float %f to double - %call = call double @expm1(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @expm1f(float %f) -} - -define double @expm1_test2(float %f) nounwind readnone { -; CHECK: expm1_test2 - %conv = fpext float %f to double - %call = call double @expm1(double %conv) - ret double %call -; CHECK: call double @expm1(double %conv) -} -define float @exp10_test(float %f) nounwind readnone { -; CHECK: exp10_test - %conv = fpext float %f to double - %call = call double @exp10(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @exp10f(float %f) -} - -define double @exp10_test2(float %f) nounwind readnone { -; CHECK: exp10_test2 - %conv = fpext float %f to double - %call = call double @exp10(double %conv) - ret double %call -; CHECK: call double @exp10(double %conv) -} -define float @log_test(float %f) nounwind readnone { -; CHECK: log_test - %conv = fpext float %f to double - %call = call double @log(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @logf(float %f) -} - -define double @log_test2(float %f) nounwind readnone { -; CHECK: log_test2 - %conv = fpext float %f to double - %call = call double @log(double %conv) - ret double %call -; CHECK: call double @log(double %conv) -} -define float @log10_test(float %f) nounwind readnone { -; CHECK: log10_test - %conv = fpext float %f to double - %call = call double @log10(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @log10f(float %f) -} - -define double @log10_test2(float %f) nounwind readnone { -; CHECK: log10_test2 - %conv = fpext float %f to double - %call = call double @log10(double %conv) - ret double %call -; CHECK: call double @log10(double %conv) -} -define float @log1p_test(float %f) nounwind readnone { -; CHECK: log1p_test - %conv = fpext float %f to double - %call = call double @log1p(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @log1pf(float %f) -} - -define double @log1p_test2(float %f) nounwind readnone { -; CHECK: log1p_test2 - %conv = fpext float %f to double - %call = call double @log1p(double %conv) - ret double %call -; CHECK: call double @log1p(double %conv) -} -define float @log2_test(float %f) nounwind readnone { -; CHECK: log2_test - %conv = fpext float %f to double - %call = call double @log2(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @log2f(float %f) -} - -define double @log2_test2(float %f) nounwind readnone { -; CHECK: log2_test2 - %conv = fpext float %f to double - %call = call double @log2(double %conv) - ret double %call -; CHECK: call double @log2(double %conv) -} -define float @logb_test(float %f) nounwind readnone { -; CHECK: logb_test - %conv = fpext float %f to double - %call = call double @logb(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @logbf(float %f) -} - -define double @logb_test2(float %f) nounwind readnone { -; CHECK: logb_test2 - %conv = fpext float %f to double - %call = call double @logb(double %conv) - ret double %call -; CHECK: call double @logb(double %conv) -} -define float @sin_test(float %f) nounwind readnone { -; CHECK: sin_test - %conv = fpext float %f to double - %call = call double @sin(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @sinf(float %f) -} - -define double @sin_test2(float %f) nounwind readnone { -; CHECK: sin_test2 - %conv = fpext float %f to double - %call = call double @sin(double %conv) - ret double %call -; CHECK: call double @sin(double %conv) -} -define float @sqrt_test(float %f) nounwind readnone { -; CHECK: sqrt_test - %conv = fpext float %f to double - %call = call double @sqrt(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @sqrtf(float %f) -} - -define double @sqrt_test2(float %f) nounwind readnone { -; CHECK: sqrt_test2 - %conv = fpext float %f to double - %call = call double @sqrt(double %conv) - ret double %call -; CHECK: call double @sqrt(double %conv) -} -define float @tan_test(float %f) nounwind readnone { -; CHECK: tan_test - %conv = fpext float %f to double - %call = call double @tan(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @tanf(float %f) -} - -define double @tan_test2(float %f) nounwind readnone { -; CHECK: tan_test2 - %conv = fpext float %f to double - %call = call double @tan(double %conv) - ret double %call -; CHECK: call double @tan(double %conv) -} -define float @tanh_test(float %f) nounwind readnone { -; CHECK: tanh_test - %conv = fpext float %f to double - %call = call double @tanh(double %conv) - %conv1 = fptrunc double %call to float - ret float %conv1 -; CHECK: call float @tanhf(float %f) -} - -define double @tanh_test2(float %f) nounwind readnone { -; CHECK: tanh_test2 - %conv = fpext float %f to double - %call = call double @tanh(double %conv) - ret double %call -; CHECK: call double @tanh(double %conv) -} - -declare double @tanh(double) nounwind readnone -declare double @tan(double) nounwind readnone -declare double @sqrt(double) nounwind readnone -declare double @sin(double) nounwind readnone -declare double @log2(double) nounwind readnone -declare double @log1p(double) nounwind readnone -declare double @log10(double) nounwind readnone -declare double @log(double) nounwind readnone -declare double @logb(double) nounwind readnone -declare double @exp10(double) nounwind readnone -declare double @expm1(double) nounwind readnone -declare double @exp(double) nounwind readnone -declare double @cbrt(double) nounwind readnone -declare double @atanh(double) nounwind readnone -declare double @atan(double) nounwind readnone -declare double @acos(double) nounwind readnone -declare double @acosh(double) nounwind readnone -declare double @asin(double) nounwind readnone -declare double @asinh(double) nounwind readnone diff --git a/test/Transforms/SimplifyLibCalls/exp2.ll b/test/Transforms/SimplifyLibCalls/exp2.ll deleted file mode 100644 index a5927757cf9..00000000000 --- a/test/Transforms/SimplifyLibCalls/exp2.ll +++ /dev/null @@ -1,38 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S | grep "call.*ldexp" | count 4 -; rdar://5852514 - -target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" -target triple = "i386-apple-darwin8" - -define double @t1(i32 %x) nounwind { -entry: - %tmp12 = sitofp i32 %x to double ; [#uses=1] - %exp2 = tail call double @exp2( double %tmp12 ) ; [#uses=1] - ret double %exp2 -} - -define float @t4(i8 zeroext %x) nounwind { -entry: - %tmp12 = uitofp i8 %x to float ; [#uses=1] - %tmp3 = tail call float @exp2f( float %tmp12 ) nounwind readonly ; [#uses=1] - ret float %tmp3 -} - -declare float @exp2f(float) nounwind readonly - -define double @t3(i16 zeroext %x) nounwind { -entry: - %tmp12 = uitofp i16 %x to double ; [#uses=1] - %exp2 = tail call double @exp2( double %tmp12 ) ; [#uses=1] - ret double %exp2 -} - -define double @t2(i16 signext %x) nounwind { -entry: - %tmp12 = sitofp i16 %x to double ; [#uses=1] - %exp2 = tail call double @exp2( double %tmp12 ) ; [#uses=1] - ret double %exp2 -} - -declare double @exp2(double) - diff --git a/test/Transforms/SimplifyLibCalls/floor.ll b/test/Transforms/SimplifyLibCalls/floor.ll deleted file mode 100644 index 93c62c20023..00000000000 --- a/test/Transforms/SimplifyLibCalls/floor.ll +++ /dev/null @@ -1,85 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S -mtriple "i386-pc-linux" | FileCheck -check-prefix=DO-SIMPLIFY %s -; RUN: opt < %s -simplify-libcalls -S -mtriple "i386-pc-win32" | FileCheck -check-prefix=DONT-SIMPLIFY %s -; RUN: opt < %s -simplify-libcalls -S -mtriple "x86_64-pc-win32" | FileCheck -check-prefix=C89-SIMPLIFY %s -; RUN: opt < %s -simplify-libcalls -S -mtriple "i386-pc-mingw32" | FileCheck -check-prefix=DO-SIMPLIFY %s -; RUN: opt < %s -simplify-libcalls -S -mtriple "x86_64-pc-mingw32" | FileCheck -check-prefix=DO-SIMPLIFY %s -; RUN: opt < %s -simplify-libcalls -S -mtriple "sparc-sun-solaris" | FileCheck -check-prefix=DO-SIMPLIFY %s - -; DO-SIMPLIFY: call float @floorf( -; DO-SIMPLIFY: call float @ceilf( -; DO-SIMPLIFY: call float @roundf( -; DO-SIMPLIFY: call float @nearbyintf( -; DO-SIMPLIFY: call float @truncf( -; DO-SIMPLIFY: call float @fabsf( - -; C89-SIMPLIFY: call float @floorf( -; C89-SIMPLIFY: call float @ceilf( -; C89-SIMPLIFY: call double @round( -; C89-SIMPLIFY: call double @nearbyint( - -; DONT-SIMPLIFY: call double @floor( -; DONT-SIMPLIFY: call double @ceil( -; DONT-SIMPLIFY: call double @round( -; DONT-SIMPLIFY: call double @nearbyint( -; DONT-SIMPLIFY: call double @trunc( -; DONT-SIMPLIFY: call double @fabs( - -declare double @floor(double) - -declare double @ceil(double) - -declare double @round(double) - -declare double @nearbyint(double) - -declare double @trunc(double) - -declare double @fabs(double) - -define float @test_floor(float %C) { - %D = fpext float %C to double ; [#uses=1] - ; --> floorf - %E = call double @floor( double %D ) ; [#uses=1] - %F = fptrunc double %E to float ; [#uses=1] - ret float %F -} - -define float @test_ceil(float %C) { - %D = fpext float %C to double ; [#uses=1] - ; --> ceilf - %E = call double @ceil( double %D ) ; [#uses=1] - %F = fptrunc double %E to float ; [#uses=1] - ret float %F -} - -define float @test_round(float %C) { - %D = fpext float %C to double ; [#uses=1] - ; --> roundf - %E = call double @round( double %D ) ; [#uses=1] - %F = fptrunc double %E to float ; [#uses=1] - ret float %F -} - -define float @test_nearbyint(float %C) { - %D = fpext float %C to double ; [#uses=1] - ; --> nearbyintf - %E = call double @nearbyint( double %D ) ; [#uses=1] - %F = fptrunc double %E to float ; [#uses=1] - ret float %F -} - -define float @test_trunc(float %C) { - %D = fpext float %C to double - ; --> truncf - %E = call double @trunc(double %D) - %F = fptrunc double %E to float - ret float %F -} - -define float @test_fabs(float %C) { - %D = fpext float %C to double - ; --> fabsf - %E = call double @fabs(double %D) - %F = fptrunc double %E to float - ret float %F -} diff --git a/test/Transforms/SimplifyLibCalls/pow-to-sqrt.ll b/test/Transforms/SimplifyLibCalls/pow-to-sqrt.ll deleted file mode 100644 index 0480fdda891..00000000000 --- a/test/Transforms/SimplifyLibCalls/pow-to-sqrt.ll +++ /dev/null @@ -1,33 +0,0 @@ -; RUN: opt < %s -simplify-libcalls -S | FileCheck %s -; rdar://7251832 - -; SimplifyLibcalls should optimize pow(x, 0.5) to sqrt plus code to handle -; special cases. The readonly attribute on the call should be preserved. - -; CHECK: define float @foo(float %x) nounwind { -; CHECK: %sqrtf = call float @sqrtf(float %x) nounwind readonly -; CHECK: %fabsf = call float @fabsf(float %sqrtf) nounwind readonly -; CHECK: %1 = fcmp oeq float %x, 0xFFF0000000000000 -; CHECK: %retval = select i1 %1, float 0x7FF0000000000000, float %fabsf -; CHECK: ret float %retval - -define float @foo(float %x) nounwind { - %retval = call float @powf(float %x, float 0.5) - ret float %retval -} - -; CHECK: define double @doo(double %x) nounwind { -; CHECK: %sqrt = call double @sqrt(double %x) nounwind readonly -; CHECK: %fabs = call double @fabs(double %sqrt) nounwind readonly -; CHECK: %1 = fcmp oeq double %x, 0xFFF0000000000000 -; CHECK: %retval = select i1 %1, double 0x7FF0000000000000, double %fabs -; CHECK: ret double %retval -; CHECK: } - -define double @doo(double %x) nounwind { - %retval = call double @pow(double %x, double 0.5) - ret double %retval -} - -declare float @powf(float, float) nounwind readonly -declare double @pow(double, double) nounwind readonly diff --git a/test/Transforms/SimplifyLibCalls/pow2.ll b/test/Transforms/SimplifyLibCalls/pow2.ll deleted file mode 100644 index f0964e7d6da..00000000000 --- a/test/Transforms/SimplifyLibCalls/pow2.ll +++ /dev/null @@ -1,37 +0,0 @@ -; Testcase for calls to the standard C "pow" function -; -; RUN: opt < %s -simplify-libcalls -S | not grep "call .pow" - - -declare double @pow(double, double) -declare float @powf(float, float) - -define double @test1(double %X) { - %Y = call double @pow( double %X, double 0.000000e+00 ) ; [#uses=1] - ret double %Y -} - -define double @test2(double %X) { - %Y = call double @pow( double %X, double -0.000000e+00 ) ; [#uses=1] - ret double %Y -} - -define double @test3(double %X) { - %Y = call double @pow( double 1.000000e+00, double %X ) ; [#uses=1] - ret double %Y -} - -define double @test4(double %X) { - %Y = call double @pow( double %X, double 2.0) - ret double %Y -} - -define float @test4f(float %X) { - %Y = call float @powf( float %X, float 2.0) - ret float %Y -} - -define float @test5f(float %X) { - %Y = call float @powf(float 2.0, float %X) ;; exp2 - ret float %Y -}