summaryrefslogtreecommitdiff
path: root/lib/Transforms/Utils/SimplifyLibCalls.cpp
diff options
context:
space:
mode:
authorMeador Inge <meadori@codesourcery.com>2012-11-13 04:16:17 +0000
committerMeador Inge <meadori@codesourcery.com>2012-11-13 04:16:17 +0000
commit2920a71663b96f2c33b1fee09ca5ca9f5dc1cf12 (patch)
treede057ca88e82ce75a40dc65a04b4d4db0db0a2ec /lib/Transforms/Utils/SimplifyLibCalls.cpp
parent4712b804dfe02bc7bbf948f9a5e352b3f14cc89a (diff)
downloadllvm-2920a71663b96f2c33b1fee09ca5ca9f5dc1cf12.tar.gz
llvm-2920a71663b96f2c33b1fee09ca5ca9f5dc1cf12.tar.bz2
llvm-2920a71663b96f2c33b1fee09ca5ca9f5dc1cf12.tar.xz
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
Diffstat (limited to 'lib/Transforms/Utils/SimplifyLibCalls.cpp')
-rw-r--r--lib/Transforms/Utils/SimplifyLibCalls.cpp265
1 files changed, 262 insertions, 3 deletions
diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 20281181b2..cceec666df 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<FPTruncInst>(*UseI);
+ if (Cast == 0 || !Cast->getType()->isFloatTy())
+ return 0;
+ }
+ }
+
+ // If this is something like 'floor((double)floatval)', convert to floorf.
+ FPExtInst *Cast = dyn_cast<FPExtInst>(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<BinaryOperator>(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<ConstantFP>(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<ConstantFP>(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<SIToFPInst>(Op)) {
+ if (OpC->getOperand(0)->getType()->getPrimitiveSizeInBits() <= 32)
+ LdExpArg = B.CreateSExt(OpC->getOperand(0), B.getInt32Ty());
+ } else if (UIToFPInst *OpC = dyn_cast<UIToFPInst>(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<Function>(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<LibCallOptimization*> 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() {