Convert calls to __sinpi and __cospi into __sincospi_stret

This adds an SimplifyLibCalls case which converts the special __sinpi and
__cospi (float & double variants) into a __sincospi_stret where appropriate to
remove duplicated work.

Patch by Tim Northover

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@193943 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bob Wilson
2013-11-03 06:48:38 +00:00
parent cb01efb798
commit 208130f113
4 changed files with 292 additions and 0 deletions

View File

@ -17,6 +17,7 @@
#include "llvm/Transforms/Utils/SimplifyLibCalls.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/Triple.h"
#include "llvm/Analysis/ValueTracking.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Function.h"
@ -1252,6 +1253,155 @@ struct Exp2Opt : public UnsafeFPLibCallOptimization {
}
};
struct SinCosPiOpt : public LibCallOptimization {
SinCosPiOpt() {}
virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &B) {
// Make sure the prototype is as expected, otherwise the rest of the
// function is probably invalid and likely to abort.
if (!isTrigLibCall(CI))
return 0;
Value *Arg = CI->getArgOperand(0);
SmallVector<CallInst *, 1> SinCalls;
SmallVector<CallInst *, 1> CosCalls;
SmallVector<CallInst *, 1> SinCosCalls;
bool IsFloat = Arg->getType()->isFloatTy();
// Look for all compatible sinpi, cospi and sincospi calls with the same
// argument. If there are enough (in some sense) we can make the
// substitution.
for (Value::use_iterator UI = Arg->use_begin(), UE = Arg->use_end();
UI != UE; ++UI)
classifyArgUse(*UI, CI->getParent(), IsFloat, SinCalls, CosCalls,
SinCosCalls);
// It's only worthwhile if both sinpi and cospi are actually used.
if (SinCosCalls.empty() && (SinCalls.empty() || CosCalls.empty()))
return 0;
Value *Sin, *Cos, *SinCos;
insertSinCosCall(B, CI->getCalledFunction(), Arg, IsFloat, Sin, Cos,
SinCos);
replaceTrigInsts(SinCalls, Sin);
replaceTrigInsts(CosCalls, Cos);
replaceTrigInsts(SinCosCalls, SinCos);
return 0;
}
bool isTrigLibCall(CallInst *CI) {
Function *Callee = CI->getCalledFunction();
FunctionType *FT = Callee->getFunctionType();
// We can only hope to do anything useful if we can ignore things like errno
// and floating-point exceptions.
bool AttributesSafe = CI->hasFnAttr(Attribute::NoUnwind) &&
CI->hasFnAttr(Attribute::ReadNone);
// Other than that we need float(float) or double(double)
return AttributesSafe && FT->getNumParams() == 1 &&
FT->getReturnType() == FT->getParamType(0) &&
(FT->getParamType(0)->isFloatTy() ||
FT->getParamType(0)->isDoubleTy());
}
void classifyArgUse(Value *Val, BasicBlock *BB, bool IsFloat,
SmallVectorImpl<CallInst *> &SinCalls,
SmallVectorImpl<CallInst *> &CosCalls,
SmallVectorImpl<CallInst *> &SinCosCalls) {
CallInst *CI = dyn_cast<CallInst>(Val);
if (!CI)
return;
Function *Callee = CI->getCalledFunction();
StringRef FuncName = Callee->getName();
LibFunc::Func Func;
if (!TLI->getLibFunc(FuncName, Func) || !TLI->has(Func) ||
!isTrigLibCall(CI))
return;
if (IsFloat) {
if (Func == LibFunc::sinpif)
SinCalls.push_back(CI);
else if (Func == LibFunc::cospif)
CosCalls.push_back(CI);
else if (Func == LibFunc::sincospi_stretf)
SinCosCalls.push_back(CI);
} else {
if (Func == LibFunc::sinpi)
SinCalls.push_back(CI);
else if (Func == LibFunc::cospi)
CosCalls.push_back(CI);
else if (Func == LibFunc::sincospi_stret)
SinCosCalls.push_back(CI);
}
}
void replaceTrigInsts(SmallVectorImpl<CallInst*> &Calls, Value *Res) {
for (SmallVectorImpl<CallInst*>::iterator I = Calls.begin(),
E = Calls.end();
I != E; ++I) {
LCS->replaceAllUsesWith(*I, Res);
}
}
void insertSinCosCall(IRBuilder<> &B, Function *OrigCallee, Value *Arg,
bool UseFloat, Value *&Sin, Value *&Cos,
Value *&SinCos) {
Type *ArgTy = Arg->getType();
Type *ResTy;
StringRef Name;
Triple T(OrigCallee->getParent()->getTargetTriple());
if (UseFloat) {
Name = "__sincospi_stretf";
assert(T.getArch() != Triple::x86 && "x86 messy and unsupported for now");
// x86_64 can't use {float, float} since that would be returned in both
// xmm0 and xmm1, which isn't what a real struct would do.
ResTy = T.getArch() == Triple::x86_64
? static_cast<Type *>(VectorType::get(ArgTy, 2))
: static_cast<Type *>(StructType::get(ArgTy, ArgTy, NULL));
} else {
Name = "__sincospi_stret";
ResTy = StructType::get(ArgTy, ArgTy, NULL);
}
Module *M = OrigCallee->getParent();
Value *Callee = M->getOrInsertFunction(Name, OrigCallee->getAttributes(),
ResTy, ArgTy, NULL);
if (Instruction *ArgInst = dyn_cast<Instruction>(Arg)) {
// If the argument is an instruction, it must dominate all uses so put our
// sincos call there.
BasicBlock::iterator Loc = ArgInst;
B.SetInsertPoint(ArgInst->getParent(), ++Loc);
} else {
// Otherwise (e.g. for a constant) the beginning of the function is as
// good a place as any.
BasicBlock &EntryBB = B.GetInsertBlock()->getParent()->getEntryBlock();
B.SetInsertPoint(&EntryBB, EntryBB.begin());
}
SinCos = B.CreateCall(Callee, Arg, "sincospi");
if (SinCos->getType()->isStructTy()) {
Sin = B.CreateExtractValue(SinCos, 0, "sinpi");
Cos = B.CreateExtractValue(SinCos, 1, "cospi");
} else {
Sin = B.CreateExtractElement(SinCos, ConstantInt::get(B.getInt32Ty(), 0),
"sinpi");
Cos = B.CreateExtractElement(SinCos, ConstantInt::get(B.getInt32Ty(), 1),
"cospi");
}
}
};
//===----------------------------------------------------------------------===//
// Integer Library Call Optimizations
//===----------------------------------------------------------------------===//
@ -1764,6 +1914,7 @@ static MemSetOpt MemSet;
// Math library call optimizations.
static UnaryDoubleFPOpt UnaryDoubleFP(false);
static UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true);
static SinCosPiOpt SinCosPi;
// Integer library call optimizations.
static FFSOpt FFS;
@ -1848,6 +1999,11 @@ LibCallOptimization *LibCallSimplifierImpl::lookupOptimization(CallInst *CI) {
case LibFunc::cos:
case LibFunc::cosl:
return &Cos;
case LibFunc::sinpif:
case LibFunc::sinpi:
case LibFunc::cospif:
case LibFunc::cospi:
return &SinCosPi;
case LibFunc::powf:
case LibFunc::pow:
case LibFunc::powl: