summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYi Jiang <yjiang@apple.com>2013-12-16 22:42:40 +0000
committerYi Jiang <yjiang@apple.com>2013-12-16 22:42:40 +0000
commit4faf2ba0c7ef9f28a5d4a6c096105ff8aca94279 (patch)
tree5c8d932a90cd2150ae476c55f02bc79a25771f98
parent89452cf827d9699027b60212b2795b9e14d5ea7a (diff)
downloadllvm-4faf2ba0c7ef9f28a5d4a6c096105ff8aca94279.tar.gz
llvm-4faf2ba0c7ef9f28a5d4a6c096105ff8aca94279.tar.bz2
llvm-4faf2ba0c7ef9f28a5d4a6c096105ff8aca94279.tar.xz
Enable double to float shrinking optimizations for binary functions like 'fmin/fmax'. Fix radar:15283121
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@197434 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r--include/llvm/Target/TargetLibraryInfo.h14
-rw-r--r--include/llvm/Transforms/Utils/BuildLibCalls.h8
-rw-r--r--lib/Target/TargetLibraryInfo.cpp10
-rw-r--r--lib/Transforms/Utils/BuildLibCalls.cpp46
-rw-r--r--lib/Transforms/Utils/SimplifyLibCalls.cpp49
-rw-r--r--test/Transforms/InstCombine/float-shrink-compare.ll54
6 files changed, 172 insertions, 9 deletions
diff --git a/include/llvm/Target/TargetLibraryInfo.h b/include/llvm/Target/TargetLibraryInfo.h
index 46eaef2871..326104da0e 100644
--- a/include/llvm/Target/TargetLibraryInfo.h
+++ b/include/llvm/Target/TargetLibraryInfo.h
@@ -251,6 +251,18 @@ namespace llvm {
floorf,
/// long double floorl(long double x);
floorl,
+ /// double fmax(double x, double y);
+ fmax,
+ /// float fmaxf(float x, float y);
+ fmaxf,
+ /// long double fmaxl(long double x, long double y);
+ fmaxl,
+ /// double fmin(double x, double y);
+ fmin,
+ /// float fminf(float x, float y);
+ fminf,
+ /// long double fminl(long double x, long double y);
+ fminl,
/// double fmod(double x, double y);
fmod,
/// float fmodf(float x, float y);
@@ -703,6 +715,8 @@ public:
case LibFunc::sqrt: case LibFunc::sqrtf: case LibFunc::sqrtl:
case LibFunc::sqrt_finite: case LibFunc::sqrtf_finite:
case LibFunc::sqrtl_finite:
+ case LibFunc::fmax: case LibFunc::fmaxf: case LibFunc::fmaxl:
+ case LibFunc::fmin: case LibFunc::fminf: case LibFunc::fminl:
case LibFunc::floor: case LibFunc::floorf: case LibFunc::floorl:
case LibFunc::nearbyint: case LibFunc::nearbyintf: case LibFunc::nearbyintl:
case LibFunc::ceil: case LibFunc::ceilf: case LibFunc::ceill:
diff --git a/include/llvm/Transforms/Utils/BuildLibCalls.h b/include/llvm/Transforms/Utils/BuildLibCalls.h
index 181ed071ea..0f39ada566 100644
--- a/include/llvm/Transforms/Utils/BuildLibCalls.h
+++ b/include/llvm/Transforms/Utils/BuildLibCalls.h
@@ -83,6 +83,14 @@ namespace llvm {
Value *EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
const AttributeSet &Attrs);
+ /// EmitUnaryFloatFnCall - 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 the suffix of name, if 'Op1/Op2' are float, we
+ /// add a 'f' suffix.
+ Value *EmitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name,
+ IRBuilder<> &B, const AttributeSet &Attrs);
+
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
/// is an integer.
Value *EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD,
diff --git a/lib/Target/TargetLibraryInfo.cpp b/lib/Target/TargetLibraryInfo.cpp
index 2a9fb35652..4bbf2005a9 100644
--- a/lib/Target/TargetLibraryInfo.cpp
+++ b/lib/Target/TargetLibraryInfo.cpp
@@ -140,6 +140,12 @@ const char* TargetLibraryInfo::StandardNames[LibFunc::NumLibFuncs] =
"floor",
"floorf",
"floorl",
+ "fmax",
+ "fmaxf",
+ "fmaxl",
+ "fmin",
+ "fminf",
+ "fminl",
"fmod",
"fmodf",
"fmodl",
@@ -453,6 +459,8 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T,
TLI.setUnavailable(LibFunc::fabsf); // Win32 and Win64 both lack fabsf
TLI.setUnavailable(LibFunc::fabsl);
TLI.setUnavailable(LibFunc::floorl);
+ TLI.setUnavailable(LibFunc::fmaxl);
+ TLI.setUnavailable(LibFunc::fminl);
TLI.setUnavailable(LibFunc::fmodl);
TLI.setUnavailable(LibFunc::frexpl);
TLI.setUnavailable(LibFunc::logl);
@@ -523,6 +531,8 @@ static void initialize(TargetLibraryInfo &TLI, const Triple &T,
TLI.setUnavailable(LibFunc::coshf);
TLI.setUnavailable(LibFunc::expf);
TLI.setUnavailable(LibFunc::floorf);
+ TLI.setUnavailable(LibFunc::fminf);
+ TLI.setUnavailable(LibFunc::fmaxf);
TLI.setUnavailable(LibFunc::fmodf);
TLI.setUnavailable(LibFunc::logf);
TLI.setUnavailable(LibFunc::powf);
diff --git a/lib/Transforms/Utils/BuildLibCalls.cpp b/lib/Transforms/Utils/BuildLibCalls.cpp
index 6d13217df5..82384a1edf 100644
--- a/lib/Transforms/Utils/BuildLibCalls.cpp
+++ b/lib/Transforms/Utils/BuildLibCalls.cpp
@@ -286,6 +286,21 @@ Value *llvm::EmitMemCmp(Value *Ptr1, Value *Ptr2,
return CI;
}
+/// Append a suffix to the function name according to the type of 'Op'.
+static void AppendTypeSuffix(Value *Op, StringRef &Name, SmallString<20> &NameBuffer) {
+ if (!Op->getType()->isDoubleTy()) {
+ NameBuffer += Name;
+
+ if (Op->getType()->isFloatTy())
+ NameBuffer += 'f';
+ else
+ NameBuffer += 'l';
+
+ Name = NameBuffer;
+ }
+ return;
+}
+
/// EmitUnaryFloatFnCall - Emit a call to the unary function named 'Name' (e.g.
/// 'floor'). This function is known to take a single of type matching 'Op' and
/// returns one value with the same type. If 'Op' is a long double, 'l' is
@@ -293,15 +308,7 @@ Value *llvm::EmitMemCmp(Value *Ptr1, Value *Ptr2,
Value *llvm::EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
const AttributeSet &Attrs) {
SmallString<20> NameBuffer;
- if (!Op->getType()->isDoubleTy()) {
- // If we need to add a suffix, copy into NameBuffer.
- NameBuffer += Name;
- if (Op->getType()->isFloatTy())
- NameBuffer += 'f'; // floorf
- else
- NameBuffer += 'l'; // floorl
- Name = NameBuffer;
- }
+ AppendTypeSuffix(Op, Name, NameBuffer);
Module *M = B.GetInsertBlock()->getParent()->getParent();
Value *Callee = M->getOrInsertFunction(Name, Op->getType(),
@@ -314,6 +321,27 @@ Value *llvm::EmitUnaryFloatFnCall(Value *Op, StringRef Name, IRBuilder<> &B,
return CI;
}
+/// EmitBinaryFloatFnCall - 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 the suffix of name, if 'Op1/Op2' is a float, we add a 'f'
+/// suffix.
+Value *llvm::EmitBinaryFloatFnCall(Value *Op1, Value *Op2, StringRef Name,
+ IRBuilder<> &B, const AttributeSet &Attrs) {
+ SmallString<20> NameBuffer;
+ AppendTypeSuffix(Op1, Name, NameBuffer);
+
+ Module *M = B.GetInsertBlock()->getParent()->getParent();
+ Value *Callee = M->getOrInsertFunction(Name, Op1->getType(),
+ Op1->getType(), Op2->getType(), NULL);
+ CallInst *CI = B.CreateCall2(Callee, Op1, Op2, Name);
+ CI->setAttributes(Attrs);
+ if (const Function *F = dyn_cast<Function>(Callee->stripPointerCasts()))
+ CI->setCallingConv(F->getCallingConv());
+
+ return CI;
+}
+
/// EmitPutChar - Emit a call to the putchar function. This assumes that Char
/// is an integer.
Value *llvm::EmitPutChar(Value *Char, IRBuilder<> &B, const DataLayout *TD,
diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp
index b555cf8bdd..36d24624f9 100644
--- a/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -1100,6 +1100,49 @@ struct UnaryDoubleFPOpt : public LibCallOptimization {
}
};
+// Double -> Float Shrinking Optimizations for Binary Functions like 'fmin/fmax'
+struct BinaryDoubleFPOpt : public LibCallOptimization {
+ bool CheckRetType;
+ BinaryDoubleFPOpt(bool CheckReturnType): CheckRetType(CheckReturnType) {}
+ virtual Value *callOptimizer(Function *Callee, CallInst *CI, IRBuilder<> &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 0;
+
+ if (CheckRetType) {
+ // Check if all the uses for function like 'fmin/fmax' 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 'fmin((double)floatval1, (double)floatval2)',
+ // we convert it to fminf.
+ FPExtInst *Cast1 = dyn_cast<FPExtInst>(CI->getArgOperand(0));
+ FPExtInst *Cast2 = dyn_cast<FPExtInst>(CI->getArgOperand(1));
+ if (Cast1 == 0 || !Cast1->getOperand(0)->getType()->isFloatTy() ||
+ Cast2 == 0 || !Cast2->getOperand(0)->getType()->isFloatTy())
+ return 0;
+
+ // fmin((double)floatval1, (double)floatval2)
+ // -> (double)fmin(floatval1, floatval2)
+ Value *V = NULL;
+ Value *V1 = Cast1->getOperand(0);
+ Value *V2 = Cast2->getOperand(0);
+ V = EmitBinaryFloatFnCall(V1, V2, Callee->getName(), B,
+ Callee->getAttributes());
+ return B.CreateFPExt(V, B.getDoubleTy());
+ }
+};
+
struct UnsafeFPLibCallOptimization : public LibCallOptimization {
bool UnsafeFPShrink;
UnsafeFPLibCallOptimization(bool UnsafeFPShrink) {
@@ -1981,6 +2024,7 @@ static MemSetOpt MemSet;
// Math library call optimizations.
static UnaryDoubleFPOpt UnaryDoubleFP(false);
+static BinaryDoubleFPOpt BinaryDoubleFP(false);
static UnaryDoubleFPOpt UnsafeUnaryDoubleFP(true);
static SinCosPiOpt SinCosPi;
@@ -2150,6 +2194,11 @@ LibCallOptimization *LibCallSimplifierImpl::lookupOptimization(CallInst *CI) {
if (UnsafeFPShrink && hasFloatVersion(FuncName))
return &UnsafeUnaryDoubleFP;
return 0;
+ case LibFunc::fmin:
+ case LibFunc::fmax:
+ if (hasFloatVersion(FuncName))
+ return &BinaryDoubleFP;
+ return 0;
case LibFunc::memcpy_chk:
return &MemCpyChk;
default:
diff --git a/test/Transforms/InstCombine/float-shrink-compare.ll b/test/Transforms/InstCombine/float-shrink-compare.ll
index 26f77a7f70..e50046790d 100644
--- a/test/Transforms/InstCombine/float-shrink-compare.ll
+++ b/test/Transforms/InstCombine/float-shrink-compare.ll
@@ -170,6 +170,58 @@ define i32 @test14(float %x, float %y) nounwind uwtable {
; CHECK-NEXT: fcmp oeq float %truncf, %y
}
+define i32 @test15(float %x, float %y, float %z) nounwind uwtable {
+ %1 = fpext float %x to double
+ %2 = fpext float %y to double
+ %3 = call double @fmin(double %1, double %2) nounwind
+ %4 = fpext float %z to double
+ %5 = fcmp oeq double %3, %4
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+; CHECK-LABEL: @test15(
+; CHECK-NEXT: %fminf = call float @fminf(float %x, float %y)
+; CHECK-NEXT: fcmp oeq float %fminf, %z
+}
+
+define i32 @test16(float %x, float %y, float %z) nounwind uwtable {
+ %1 = fpext float %z to double
+ %2 = fpext float %x to double
+ %3 = fpext float %y to double
+ %4 = call double @fmin(double %2, double %3) nounwind
+ %5 = fcmp oeq double %1, %4
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+; CHECK-LABEL: @test16(
+; CHECK-NEXT: %fminf = call float @fminf(float %x, float %y)
+; CHECK-NEXT: fcmp oeq float %fminf, %z
+}
+
+define i32 @test17(float %x, float %y, float %z) nounwind uwtable {
+ %1 = fpext float %x to double
+ %2 = fpext float %y to double
+ %3 = call double @fmax(double %1, double %2) nounwind
+ %4 = fpext float %z to double
+ %5 = fcmp oeq double %3, %4
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+; CHECK-LABEL: @test17(
+; CHECK-NEXT: %fmaxf = call float @fmaxf(float %x, float %y)
+; CHECK-NEXT: fcmp oeq float %fmaxf, %z
+}
+
+define i32 @test18(float %x, float %y, float %z) nounwind uwtable {
+ %1 = fpext float %z to double
+ %2 = fpext float %x to double
+ %3 = fpext float %y to double
+ %4 = call double @fmax(double %2, double %3) nounwind
+ %5 = fcmp oeq double %1, %4
+ %6 = zext i1 %5 to i32
+ ret i32 %6
+; CHECK-LABEL: @test18(
+; CHECK-NEXT: %fmaxf = call float @fmaxf(float %x, float %y)
+; CHECK-NEXT: fcmp oeq float %fmaxf, %z
+}
+
declare double @fabs(double) nounwind readnone
declare double @ceil(double) nounwind readnone
declare double @floor(double) nounwind readnone
@@ -177,3 +229,5 @@ declare double @nearbyint(double) nounwind readnone
declare double @rint(double) nounwind readnone
declare double @round(double) nounwind readnone
declare double @trunc(double) nounwind readnone
+declare double @fmin(double, double) nounwind readnone
+declare double @fmax(double, double) nounwind readnone