summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Analysis/TargetLibraryInfo.def9
-rw-r--r--llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h1
-rw-r--r--llvm/lib/Analysis/TargetLibraryInfo.cpp22
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp33
-rw-r--r--llvm/test/Transforms/InstCombine/cabs-array.ll65
-rw-r--r--llvm/test/Transforms/InstCombine/cabs-discrete.ll59
-rw-r--r--llvm/unittests/Analysis/TargetLibraryInfoTest.cpp3
7 files changed, 192 insertions, 0 deletions
diff --git a/llvm/include/llvm/Analysis/TargetLibraryInfo.def b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
index 9cbe917c146..a461ed813b9 100644
--- a/llvm/include/llvm/Analysis/TargetLibraryInfo.def
+++ b/llvm/include/llvm/Analysis/TargetLibraryInfo.def
@@ -457,6 +457,15 @@ TLI_DEFINE_STRING_INTERNAL("bcopy")
/// void bzero(void *s, size_t n);
TLI_DEFINE_ENUM_INTERNAL(bzero)
TLI_DEFINE_STRING_INTERNAL("bzero")
+/// double cabs(double complex z)
+TLI_DEFINE_ENUM_INTERNAL(cabs)
+TLI_DEFINE_STRING_INTERNAL("cabs")
+/// float cabs(float complex z)
+TLI_DEFINE_ENUM_INTERNAL(cabsf)
+TLI_DEFINE_STRING_INTERNAL("cabsf")
+/// long double cabs(long double complex z)
+TLI_DEFINE_ENUM_INTERNAL(cabsl)
+TLI_DEFINE_STRING_INTERNAL("cabsl")
/// void *calloc(size_t count, size_t size);
TLI_DEFINE_ENUM_INTERNAL(calloc)
TLI_DEFINE_STRING_INTERNAL("calloc")
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index c8a37343321..73a62f59203 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -129,6 +129,7 @@ private:
Value *optimizeStringMemoryLibCall(CallInst *CI, IRBuilder<> &B);
// Math Library Optimizations
+ Value *optimizeCAbs(CallInst *CI, IRBuilder<> &B);
Value *optimizeCos(CallInst *CI, IRBuilder<> &B);
Value *optimizePow(CallInst *CI, IRBuilder<> &B);
Value *replacePowWithSqrt(CallInst *Pow, IRBuilder<> &B);
diff --git a/llvm/lib/Analysis/TargetLibraryInfo.cpp b/llvm/lib/Analysis/TargetLibraryInfo.cpp
index f8facf28277..609b9961deb 100644
--- a/llvm/lib/Analysis/TargetLibraryInfo.cpp
+++ b/llvm/lib/Analysis/TargetLibraryInfo.cpp
@@ -182,6 +182,9 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T,
TLI.setUnavailable(LibFunc_atanh);
TLI.setUnavailable(LibFunc_atanhf);
TLI.setUnavailable(LibFunc_atanhl);
+ TLI.setUnavailable(LibFunc_cabs);
+ TLI.setUnavailable(LibFunc_cabsf);
+ TLI.setUnavailable(LibFunc_cabsl);
TLI.setUnavailable(LibFunc_cbrt);
TLI.setUnavailable(LibFunc_cbrtf);
TLI.setUnavailable(LibFunc_cbrtl);
@@ -1267,6 +1270,25 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy,
return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() &&
FTy.getReturnType()->isIntegerTy());
+ case LibFunc_cabs:
+ case LibFunc_cabsf:
+ case LibFunc_cabsl: {
+ Type* RetTy = FTy.getReturnType();
+ if (!RetTy->isFloatingPointTy())
+ return false;
+
+ // NOTE: These prototypes are target specific and currently support
+ // "complex" passed as an array or discrete real & imaginary parameters.
+ // Add other calling conventions to enable libcall optimizations.
+ if (NumParams == 1)
+ return (FTy.getParamType(0)->isArrayTy() &&
+ FTy.getParamType(0)->getArrayNumElements() == 2 &&
+ FTy.getParamType(0)->getArrayElementType() == RetTy);
+ else if (NumParams == 2)
+ return (FTy.getParamType(0) == RetTy && FTy.getParamType(1) == RetTy);
+ else
+ return false;
+ }
case LibFunc::NumLibFuncs:
break;
}
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 60f6c600b5a..03a1d55ddc3 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -1033,6 +1033,35 @@ static Value *optimizeBinaryDoubleFP(CallInst *CI, IRBuilder<> &B) {
return B.CreateFPExt(V, B.getDoubleTy());
}
+// cabs(z) -> sqrt((creal(z)*creal(z)) + (cimag(z)*cimag(z)))
+Value *LibCallSimplifier::optimizeCAbs(CallInst *CI, IRBuilder<> &B) {
+ if (!CI->isFast())
+ return nullptr;
+
+ // Propagate fast-math flags from the existing call to new instructions.
+ IRBuilder<>::FastMathFlagGuard Guard(B);
+ B.setFastMathFlags(CI->getFastMathFlags());
+
+ Value *Real, *Imag;
+ if (CI->getNumArgOperands() == 1) {
+ Value *Op = CI->getArgOperand(0);
+ assert(Op->getType()->isArrayTy() && "Unexpected signature for cabs!");
+ Real = B.CreateExtractValue(Op, 0, "real");
+ Imag = B.CreateExtractValue(Op, 1, "imag");
+ } else {
+ assert(CI->getNumArgOperands() == 2 && "Unexpected signature for cabs!");
+ Real = CI->getArgOperand(0);
+ Imag = CI->getArgOperand(1);
+ }
+
+ Value *RealReal = B.CreateFMul(Real, Real);
+ Value *ImagImag = B.CreateFMul(Imag, Imag);
+
+ Function *FSqrt = Intrinsic::getDeclaration(CI->getModule(), Intrinsic::sqrt,
+ CI->getType());
+ return B.CreateCall(FSqrt, B.CreateFAdd(RealReal, ImagImag), "cabs");
+}
+
Value *LibCallSimplifier::optimizeCos(CallInst *CI, IRBuilder<> &B) {
Function *Callee = CI->getCalledFunction();
Value *Ret = nullptr;
@@ -2162,6 +2191,10 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
case LibFunc_fmax:
case LibFunc_fmaxl:
return optimizeFMinFMax(CI, Builder);
+ case LibFunc_cabs:
+ case LibFunc_cabsf:
+ case LibFunc_cabsl:
+ return optimizeCAbs(CI, Builder);
default:
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/cabs-array.ll b/llvm/test/Transforms/InstCombine/cabs-array.ll
new file mode 100644
index 00000000000..1c15dc1c545
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/cabs-array.ll
@@ -0,0 +1,65 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define double @std_cabs([2 x double] %z) {
+; CHECK-LABEL: define double @std_cabs(
+; CHECK: tail call double @cabs(
+ %call = tail call double @cabs([2 x double] %z)
+ ret double %call
+}
+
+define float @std_cabsf([2 x float] %z) {
+; CHECK-LABEL: define float @std_cabsf(
+; CHECK: tail call float @cabsf(
+ %call = tail call float @cabsf([2 x float] %z)
+ ret float %call
+}
+
+define fp128 @std_cabsl([2 x fp128] %z) {
+; CHECK-LABEL: define fp128 @std_cabsl(
+; CHECK: tail call fp128 @cabsl(
+ %call = tail call fp128 @cabsl([2 x fp128] %z)
+ ret fp128 %call
+}
+
+define double @fast_cabs([2 x double] %z) {
+; CHECK-LABEL: define double @fast_cabs(
+; CHECK: %real = extractvalue [2 x double] %z, 0
+; CHECK: %imag = extractvalue [2 x double] %z, 1
+; CHECK: %1 = fmul fast double %real, %real
+; CHECK: %2 = fmul fast double %imag, %imag
+; CHECK: %3 = fadd fast double %1, %2
+; CHECK: %cabs = call fast double @llvm.sqrt.f64(double %3)
+; CHECK: ret double %cabs
+ %call = tail call fast double @cabs([2 x double] %z)
+ ret double %call
+}
+
+define float @fast_cabsf([2 x float] %z) {
+; CHECK-LABEL: define float @fast_cabsf(
+; CHECK: %real = extractvalue [2 x float] %z, 0
+; CHECK: %imag = extractvalue [2 x float] %z, 1
+; CHECK: %1 = fmul fast float %real, %real
+; CHECK: %2 = fmul fast float %imag, %imag
+; CHECK: %3 = fadd fast float %1, %2
+; CHECK: %cabs = call fast float @llvm.sqrt.f32(float %3)
+; CHECK: ret float %cabs
+ %call = tail call fast float @cabsf([2 x float] %z)
+ ret float %call
+}
+
+define fp128 @fast_cabsl([2 x fp128] %z) {
+; CHECK-LABEL: define fp128 @fast_cabsl(
+; CHECK: %real = extractvalue [2 x fp128] %z, 0
+; CHECK: %imag = extractvalue [2 x fp128] %z, 1
+; CHECK: %1 = fmul fast fp128 %real, %real
+; CHECK: %2 = fmul fast fp128 %imag, %imag
+; CHECK: %3 = fadd fast fp128 %1, %2
+; CHECK: %cabs = call fast fp128 @llvm.sqrt.f128(fp128 %3)
+; CHECK: ret fp128 %cabs
+ %call = tail call fast fp128 @cabsl([2 x fp128] %z)
+ ret fp128 %call
+}
+
+declare double @cabs([2 x double])
+declare float @cabsf([2 x float])
+declare fp128 @cabsl([2 x fp128])
diff --git a/llvm/test/Transforms/InstCombine/cabs-discrete.ll b/llvm/test/Transforms/InstCombine/cabs-discrete.ll
new file mode 100644
index 00000000000..405c073c194
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/cabs-discrete.ll
@@ -0,0 +1,59 @@
+; RUN: opt < %s -instcombine -S | FileCheck %s
+
+define double @std_cabs(double %real, double %imag) {
+; CHECK-LABEL: define double @std_cabs(
+; CHECK: tail call double @cabs(
+ %call = tail call double @cabs(double %real, double %imag)
+ ret double %call
+}
+
+define float @std_cabsf(float %real, float %imag) {
+; CHECK-LABEL: define float @std_cabsf(
+; CHECK: tail call float @cabsf(
+ %call = tail call float @cabsf(float %real, float %imag)
+ ret float %call
+}
+
+define fp128 @std_cabsl(fp128 %real, fp128 %imag) {
+; CHECK-LABEL: define fp128 @std_cabsl(
+; CHECK: tail call fp128 @cabsl(
+ %call = tail call fp128 @cabsl(fp128 %real, fp128 %imag)
+ ret fp128 %call
+}
+
+define double @fast_cabs(double %real, double %imag) {
+; CHECK-LABEL: define double @fast_cabs(
+; CHECK: %1 = fmul fast double %real, %real
+; CHECK: %2 = fmul fast double %imag, %imag
+; CHECK: %3 = fadd fast double %1, %2
+; CHECK: %cabs = call fast double @llvm.sqrt.f64(double %3)
+; CHECK: ret double %cabs
+ %call = tail call fast double @cabs(double %real, double %imag)
+ ret double %call
+}
+
+define float @fast_cabsf(float %real, float %imag) {
+; CHECK-LABEL: define float @fast_cabsf(
+; CHECK: %1 = fmul fast float %real, %real
+; CHECK: %2 = fmul fast float %imag, %imag
+; CHECK: %3 = fadd fast float %1, %2
+; CHECK: %cabs = call fast float @llvm.sqrt.f32(float %3)
+; CHECK: ret float %cabs
+ %call = tail call fast float @cabsf(float %real, float %imag)
+ ret float %call
+}
+
+define fp128 @fast_cabsl(fp128 %real, fp128 %imag) {
+; CHECK-LABEL: define fp128 @fast_cabsl(
+; CHECK: %1 = fmul fast fp128 %real, %real
+; CHECK: %2 = fmul fast fp128 %imag, %imag
+; CHECK: %3 = fadd fast fp128 %1, %2
+; CHECK: %cabs = call fast fp128 @llvm.sqrt.f128(fp128 %3)
+; CHECK: ret fp128 %cabs
+ %call = tail call fast fp128 @cabsl(fp128 %real, fp128 %imag)
+ ret fp128 %call
+}
+
+declare double @cabs(double %real, double %imag)
+declare float @cabsf(float %real, float %imag)
+declare fp128 @cabsl(fp128 %real, fp128 %imag)
diff --git a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
index 9d852cf0301..ef558a434c7 100644
--- a/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
+++ b/llvm/unittests/Analysis/TargetLibraryInfoTest.cpp
@@ -131,6 +131,9 @@ TEST_F(TargetLibraryInfoTest, ValidProto) {
"declare double @copysign(double, double)\n"
"declare float @copysignf(float, float)\n"
"declare x86_fp80 @copysignl(x86_fp80, x86_fp80)\n"
+ "declare double @cabs([2 x double])\n"
+ "declare float @cabsf([2 x float])\n"
+ "declare x86_fp80 @cabsl([2 x x86_fp80])\n"
"declare double @cos(double)\n"
"declare float @cosf(float)\n"
"declare double @cosh(double)\n"
OpenPOWER on IntegriCloud