forked from OSchip/llvm-project
[SLC] Refactor shrinking of functions (NFC)
Merge the helper functions for shrinking unary and binary functions into a single one, while keeping all their functionality. Otherwise, NFC. llvm-svn: 338905
This commit is contained in:
parent
c7d3d34b98
commit
5aa217ac68
|
@ -927,6 +927,20 @@ Value *LibCallSimplifier::optimizeRealloc(CallInst *CI, IRBuilder<> &B) {
|
|||
// Math Library Optimizations
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Replace a libcall \p CI with a call to intrinsic \p IID
|
||||
static Value *replaceUnaryCall(CallInst *CI, IRBuilder<> &B, Intrinsic::ID IID) {
|
||||
// Propagate fast-math flags from the existing call to the new call.
|
||||
IRBuilder<>::FastMathFlagGuard Guard(B);
|
||||
B.setFastMathFlags(CI->getFastMathFlags());
|
||||
|
||||
Module *M = CI->getModule();
|
||||
Value *V = CI->getArgOperand(0);
|
||||
Function *F = Intrinsic::getDeclaration(M, IID, CI->getType());
|
||||
CallInst *NewCall = B.CreateCall(F, V);
|
||||
NewCall->takeName(CI);
|
||||
return NewCall;
|
||||
}
|
||||
|
||||
/// Return a variant of Val with float type.
|
||||
/// Currently this works in two cases: If Val is an FPExtension of a float
|
||||
/// value to something bigger, simply return the operand.
|
||||
|
@ -949,104 +963,73 @@ static Value *valueHasFloatPrecision(Value *Val) {
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
/// Shrink double -> float for unary functions like 'floor'.
|
||||
static Value *optimizeUnaryDoubleFP(CallInst *CI, IRBuilder<> &B,
|
||||
bool CheckRetType) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
// We know this libcall has a valid prototype, but we don't know which.
|
||||
/// Shrink double -> float functions.
|
||||
static Value *optimizeDoubleFP(CallInst *CI, IRBuilder<> &B,
|
||||
bool isBinary, bool doResultCheck = false) {
|
||||
if (!CI->getType()->isDoubleTy())
|
||||
return nullptr;
|
||||
|
||||
if (CheckRetType) {
|
||||
// Check if all the uses for function like 'sin' are converted to float.
|
||||
// Check if all the uses of the function are converted to float.
|
||||
if (doResultCheck)
|
||||
for (User *U : CI->users()) {
|
||||
FPTruncInst *Cast = dyn_cast<FPTruncInst>(U);
|
||||
if (!Cast || !Cast->getType()->isFloatTy())
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// If this is something like 'floor((double)floatval)', convert to floorf.
|
||||
Value *V = valueHasFloatPrecision(CI->getArgOperand(0));
|
||||
if (V == nullptr)
|
||||
// If this is something like 'g((double) float)', convert to 'gf(float)'.
|
||||
Value *V[2];
|
||||
V[0] = valueHasFloatPrecision(CI->getArgOperand(0));
|
||||
V[1] = isBinary ? valueHasFloatPrecision(CI->getArgOperand(1)) : nullptr;
|
||||
if (!V[0] || (isBinary && !V[1]))
|
||||
return nullptr;
|
||||
|
||||
// If call isn't an intrinsic, check that it isn't within a function with the
|
||||
// same name as the float version of this call.
|
||||
// same name as the float version of this call, otherwise the result is an
|
||||
// infinite loop. For example, from MinGW-w64:
|
||||
//
|
||||
// e.g. inline float expf(float val) { return (float) exp((double) val); }
|
||||
//
|
||||
// A similar such definition exists in the MinGW-w64 math.h header file which
|
||||
// when compiled with -O2 -ffast-math causes the generation of infinite loops
|
||||
// where expf is called.
|
||||
if (!Callee->isIntrinsic()) {
|
||||
const Function *F = CI->getFunction();
|
||||
StringRef FName = F->getName();
|
||||
StringRef CalleeName = Callee->getName();
|
||||
if ((FName.size() == (CalleeName.size() + 1)) &&
|
||||
(FName.back() == 'f') &&
|
||||
FName.startswith(CalleeName))
|
||||
// float expf(float val) { return (float) exp((double) val); }
|
||||
Function *CalleeFn = CI->getCalledFunction();
|
||||
StringRef CalleeNm = CalleeFn->getName();
|
||||
AttributeList CalleeAt = CalleeFn->getAttributes();
|
||||
if (CalleeFn && !CalleeFn->isIntrinsic()) {
|
||||
const Function *Fn = CI->getFunction();
|
||||
StringRef FnName = Fn->getName();
|
||||
if (FnName.back() == 'f' &&
|
||||
FnName.size() == (CalleeNm.size() + 1) &&
|
||||
FnName.startswith(CalleeNm))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Propagate fast-math flags from the existing call to the new call.
|
||||
// Propagate the math semantics from the current function to the new function.
|
||||
IRBuilder<>::FastMathFlagGuard Guard(B);
|
||||
B.setFastMathFlags(CI->getFastMathFlags());
|
||||
|
||||
// floor((double)floatval) -> (double)floorf(floatval)
|
||||
if (Callee->isIntrinsic()) {
|
||||
// g((double) float) -> (double) gf(float)
|
||||
Value *R;
|
||||
if (CalleeFn->isIntrinsic()) {
|
||||
Module *M = CI->getModule();
|
||||
Intrinsic::ID IID = Callee->getIntrinsicID();
|
||||
Function *F = Intrinsic::getDeclaration(M, IID, B.getFloatTy());
|
||||
V = B.CreateCall(F, V);
|
||||
} else {
|
||||
// The call is a library call rather than an intrinsic.
|
||||
V = emitUnaryFloatFnCall(V, Callee->getName(), B, Callee->getAttributes());
|
||||
Intrinsic::ID IID = CalleeFn->getIntrinsicID();
|
||||
Function *Fn = Intrinsic::getDeclaration(M, IID, B.getFloatTy());
|
||||
R = isBinary ? B.CreateCall(Fn, V) : B.CreateCall(Fn, V[0]);
|
||||
}
|
||||
else
|
||||
R = isBinary ? emitBinaryFloatFnCall(V[0], V[1], CalleeNm, B, CalleeAt)
|
||||
: emitUnaryFloatFnCall(V[0], CalleeNm, B, CalleeAt);
|
||||
|
||||
return B.CreateFPExt(V, B.getDoubleTy());
|
||||
return B.CreateFPExt(R, B.getDoubleTy());
|
||||
}
|
||||
|
||||
// Replace a libcall \p CI with a call to intrinsic \p IID
|
||||
static Value *replaceUnaryCall(CallInst *CI, IRBuilder<> &B, Intrinsic::ID IID) {
|
||||
// Propagate fast-math flags from the existing call to the new call.
|
||||
IRBuilder<>::FastMathFlagGuard Guard(B);
|
||||
B.setFastMathFlags(CI->getFastMathFlags());
|
||||
|
||||
Module *M = CI->getModule();
|
||||
Value *V = CI->getArgOperand(0);
|
||||
Function *F = Intrinsic::getDeclaration(M, IID, CI->getType());
|
||||
CallInst *NewCall = B.CreateCall(F, V);
|
||||
NewCall->takeName(CI);
|
||||
return NewCall;
|
||||
/// Shrink double -> float for unary functions.
|
||||
static Value *optimizeUnaryDoubleFP(CallInst *CI, IRBuilder<> &B,
|
||||
bool doResultCheck = false) {
|
||||
return optimizeDoubleFP(CI, B, false, doResultCheck);
|
||||
}
|
||||
|
||||
/// Shrink double -> float for binary functions like 'fmin/fmax'.
|
||||
static Value *optimizeBinaryDoubleFP(CallInst *CI, IRBuilder<> &B) {
|
||||
Function *Callee = CI->getCalledFunction();
|
||||
// We know this libcall has a valid prototype, but we don't know which.
|
||||
if (!CI->getType()->isDoubleTy())
|
||||
return nullptr;
|
||||
|
||||
// If this is something like 'fmin((double)floatval1, (double)floatval2)',
|
||||
// or fmin(1.0, (double)floatval), then we convert it to fminf.
|
||||
Value *V1 = valueHasFloatPrecision(CI->getArgOperand(0));
|
||||
if (V1 == nullptr)
|
||||
return nullptr;
|
||||
Value *V2 = valueHasFloatPrecision(CI->getArgOperand(1));
|
||||
if (V2 == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// Propagate fast-math flags from the existing call to the new call.
|
||||
IRBuilder<>::FastMathFlagGuard Guard(B);
|
||||
B.setFastMathFlags(CI->getFastMathFlags());
|
||||
|
||||
// fmin((double)floatval1, (double)floatval2)
|
||||
// -> (double)fminf(floatval1, floatval2)
|
||||
// TODO: Handle intrinsics in the same way as in optimizeUnaryDoubleFP().
|
||||
Value *V = emitBinaryFloatFnCall(V1, V2, Callee->getName(), B,
|
||||
Callee->getAttributes());
|
||||
return B.CreateFPExt(V, B.getDoubleTy());
|
||||
/// Shrink double -> float for binary functions.
|
||||
static Value *optimizeBinaryDoubleFP(CallInst *CI, IRBuilder<> &B,
|
||||
bool doResultCheck = false) {
|
||||
return optimizeDoubleFP(CI, B, true, doResultCheck);
|
||||
}
|
||||
|
||||
// cabs(z) -> sqrt((creal(z)*creal(z)) + (cimag(z)*cimag(z)))
|
||||
|
|
Loading…
Reference in New Issue