Add a emitUnaryFloatFnCall version that fetches the function name from TLI

Summary:
In several places in the code we use the following pattern:

  if (hasUnaryFloatFn(&TLI, Ty, LibFunc_tan, LibFunc_tanf, LibFunc_tanl)) {
    [...]
    Value *Res = emitUnaryFloatFnCall(X, TLI.getName(LibFunc_tan), B, Attrs);
    [...]
  }

In short, we check if there is a lib-function for a certain type, and then
we _always_ fetch the name of the "double" version of the lib function and
construct a call to the appropriate function, that we just checked exists,
using that "double" name as a basis.

This is of course a problem in cases where the target doesn't support the
"double" version, but e.g. only the "float" version.

In that case TLI.getName(LibFunc_tan) returns "", and
emitUnaryFloatFnCall happily appends an "f" to "", and we erroneously end
up with a call to a function called "f".

To solve this, the above pattern is changed to

  if (hasUnaryFloatFn(&TLI, Ty, LibFunc_tan, LibFunc_tanf, LibFunc_tanl)) {
    [...]
    Value *Res = emitUnaryFloatFnCall(X, &TLI, LibFunc_tan, LibFunc_tanf,
                                      LibFunc_tanl, B, Attrs);
    [...]
  }

I.e instead of first fetching the name of the "double" version and then
letting emitUnaryFloatFnCall() add the final "f" or "l", we let
emitUnaryFloatFnCall() fetch the right name from TLI.

Reviewers: eli.friedman, efriedma

Reviewed By: efriedma

Subscribers: efriedma, bjope, llvm-commits

Differential Revision: https://reviews.llvm.org/D53370

llvm-svn: 344725
This commit is contained in:
Mikael Holmen 2018-10-18 06:27:53 +00:00
parent fa41add2e5
commit e3605d0f70
4 changed files with 78 additions and 11 deletions

View File

@ -37,6 +37,12 @@ namespace llvm {
LibFunc DoubleFn, LibFunc FloatFn,
LibFunc LongDoubleFn);
/// Get the name of the overloaded unary floating point function
/// corresponding to \a Ty.
StringRef getUnaryFloatFn(const TargetLibraryInfo *TLI, Type *Ty,
LibFunc DoubleFn, LibFunc FloatFn,
LibFunc LongDoubleFn);
/// Return V if it is an i8*, otherwise cast it to i8*.
Value *castToCStr(Value *V, IRBuilder<> &B);
@ -94,6 +100,13 @@ namespace llvm {
Value *emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
const AttributeList &Attrs);
/// Emit a call to the unary function DoubleFn, FloatFn or LongDoubleFn,
/// depending of the type of Op.
Value *emitUnaryFloatFnCall(Value *Op, const TargetLibraryInfo *TLI,
LibFunc DoubleFn, LibFunc FloatFn,
LibFunc LongDoubleFn, IRBuilder<> &B,
const AttributeList &Attrs);
/// 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

View File

@ -1157,7 +1157,8 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) {
IRBuilder<>::FastMathFlagGuard FMFGuard(B);
B.setFastMathFlags(I.getFastMathFlags());
AttributeList Attrs = CallSite(Op0).getCalledFunction()->getAttributes();
Value *Res = emitUnaryFloatFnCall(X, TLI.getName(LibFunc_tan), B, Attrs);
Value *Res = emitUnaryFloatFnCall(X, &TLI, LibFunc_tan, LibFunc_tanf,
LibFunc_tanl, B, Attrs);
if (IsCot)
Res = B.CreateFDiv(ConstantFP::get(I.getType(), 1.0), Res);
return replaceInstUsesWith(I, Res);

View File

@ -765,6 +765,24 @@ bool llvm::hasUnaryFloatFn(const TargetLibraryInfo *TLI, Type *Ty,
}
}
StringRef llvm::getUnaryFloatFn(const TargetLibraryInfo *TLI, Type *Ty,
LibFunc DoubleFn, LibFunc FloatFn,
LibFunc LongDoubleFn) {
assert(hasUnaryFloatFn(TLI, Ty, DoubleFn, FloatFn, LongDoubleFn) &&
"Cannot get name for unavailable function!");
switch (Ty->getTypeID()) {
case Type::HalfTyID:
llvm_unreachable("No name for HalfTy!");
case Type::FloatTyID:
return TLI->getName(FloatFn);
case Type::DoubleTyID:
return TLI->getName(DoubleFn);
default:
return TLI->getName(LongDoubleFn);
}
}
//- Emit LibCalls ------------------------------------------------------------//
Value *llvm::castToCStr(Value *V, IRBuilder<> &B) {
@ -942,10 +960,10 @@ static void appendTypeSuffix(Value *Op, StringRef &Name,
}
}
Value *llvm::emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
const AttributeList &Attrs) {
SmallString<20> NameBuffer;
appendTypeSuffix(Op, Name, NameBuffer);
static Value *emitUnaryFloatFnCallHelper(Value *Op, StringRef Name,
IRBuilder<> &B,
const AttributeList &Attrs) {
assert((Name != "") && "Must specify Name to emitUnaryFloatFnCall");
Module *M = B.GetInsertBlock()->getModule();
Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
@ -964,8 +982,29 @@ Value *llvm::emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
return CI;
}
Value *llvm::emitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
const AttributeList &Attrs) {
SmallString<20> NameBuffer;
appendTypeSuffix(Op, Name, NameBuffer);
return emitUnaryFloatFnCallHelper(Op, Name, B, Attrs);
}
Value *llvm::emitUnaryFloatFnCall(Value *Op, const TargetLibraryInfo *TLI,
LibFunc DoubleFn, LibFunc FloatFn,
LibFunc LongDoubleFn, IRBuilder<> &B,
const AttributeList &Attrs) {
// Get the name of the function according to TLI.
StringRef Name = getUnaryFloatFn(TLI, Op->getType(),
DoubleFn, FloatFn, LongDoubleFn);
return emitUnaryFloatFnCallHelper(Op, Name, B, Attrs);
}
Value *llvm::emitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name,
IRBuilder<> &B, const AttributeList &Attrs) {
assert((Name != "") && "Must specify Name to emitBinaryFloatFnCall");
SmallString<20> NameBuffer;
appendTypeSuffix(Op1, Name, NameBuffer);

View File

@ -1219,17 +1219,26 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilder<> &B) {
StringRef ExpName;
Intrinsic::ID ID;
Value *ExpFn;
LibFunc LibFnFloat;
LibFunc LibFnDouble;
LibFunc LibFnLongDouble;
switch (LibFn) {
default:
return nullptr;
case LibFunc_expf: case LibFunc_exp: case LibFunc_expl:
ExpName = TLI->getName(LibFunc_exp);
ExpName = "exp";
ID = Intrinsic::exp;
LibFnFloat = LibFunc_expf;
LibFnDouble = LibFunc_exp;
LibFnLongDouble = LibFunc_expl;
break;
case LibFunc_exp2f: case LibFunc_exp2: case LibFunc_exp2l:
ExpName = TLI->getName(LibFunc_exp2);
ExpName = "exp2";
ID = Intrinsic::exp2;
LibFnFloat = LibFunc_exp2f;
LibFnDouble = LibFunc_exp2;
LibFnLongDouble = LibFunc_exp2l;
break;
}
@ -1238,7 +1247,9 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilder<> &B) {
ExpFn = BaseFn->doesNotAccessMemory()
? B.CreateCall(Intrinsic::getDeclaration(Mod, ID, Ty),
FMul, ExpName)
: emitUnaryFloatFnCall(FMul, ExpName, B, BaseFn->getAttributes());
: emitUnaryFloatFnCall(FMul, TLI, LibFnDouble, LibFnFloat,
LibFnLongDouble, B,
BaseFn->getAttributes());
// Since the new exp{,2}() is different from the original one, dead code
// elimination cannot be trusted to remove it, since it may have side
@ -1275,7 +1286,8 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilder<> &B) {
return B.CreateCall(Intrinsic::getDeclaration(Mod, Intrinsic::exp2, Ty),
FMul, "exp2");
else
return emitUnaryFloatFnCall(FMul, TLI->getName(LibFunc_exp2), B, Attrs);
return emitUnaryFloatFnCall(FMul, TLI, LibFunc_exp2, LibFunc_exp2f,
LibFunc_exp2l, B, Attrs);
}
}
@ -1283,7 +1295,8 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilder<> &B) {
// TODO: There is no exp10() intrinsic yet, but some day there shall be one.
if (match(Base, m_SpecificFP(10.0)) &&
hasUnaryFloatFn(TLI, Ty, LibFunc_exp10, LibFunc_exp10f, LibFunc_exp10l))
return emitUnaryFloatFnCall(Expo, TLI->getName(LibFunc_exp10), B, Attrs);
return emitUnaryFloatFnCall(Expo, TLI, LibFunc_exp10, LibFunc_exp10f,
LibFunc_exp10l, B, Attrs);
return nullptr;
}
@ -1304,7 +1317,8 @@ static Value *getSqrtCall(Value *V, AttributeList Attrs, bool NoErrno,
// TODO: We also should check that the target can in fact lower the sqrt()
// libcall. We currently have no way to ask this question, so we ask if
// the target has a sqrt() libcall, which is not exactly the same.
return emitUnaryFloatFnCall(V, TLI->getName(LibFunc_sqrt), B, Attrs);
return emitUnaryFloatFnCall(V, TLI, LibFunc_sqrt, LibFunc_sqrtf,
LibFunc_sqrtl, B, Attrs);
return nullptr;
}