Index: include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- include/llvm/Analysis/TargetLibraryInfo.def +++ include/llvm/Analysis/TargetLibraryInfo.def @@ -457,6 +457,15 @@ /// 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") Index: include/llvm/Transforms/Utils/SimplifyLibCalls.h =================================================================== --- include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ include/llvm/Transforms/Utils/SimplifyLibCalls.h @@ -129,6 +129,7 @@ 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 *optimizeExp2(CallInst *CI, IRBuilder<> &B); Index: lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- lib/Analysis/TargetLibraryInfo.cpp +++ lib/Analysis/TargetLibraryInfo.cpp @@ -182,6 +182,9 @@ 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,18 @@ return (NumParams == 1 && FTy.getParamType(0)->isPointerTy() && FTy.getReturnType()->isIntegerTy()); + case LibFunc_cabs: + case LibFunc_cabsf: + case LibFunc_cabsl: + // NOTE: These prototypes are target specific and currently only supports + // "complex" being passed as an array. Add other calling conventions as + // necessary to take advantage of libcall optimizations. + return (NumParams == 1 && + FTy.getParamType(0)->isArrayTy() && + FTy.getParamType(0)->getArrayNumElements() == 2 && + FTy.getReturnType() == FTy.getParamType(0)->getArrayElementType() && + FTy.getReturnType()->isFloatingPointTy()); + case LibFunc::NumLibFuncs: break; } Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1033,6 +1033,27 @@ 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 *Op = CI->getArgOperand(0); + Value *Real = B.CreateExtractValue(Op, 0, "real"); + Value *Imag = B.CreateExtractValue(Op, 1, "imag"); + + 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; @@ -2144,6 +2165,10 @@ 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; } Index: test/Transforms/InstCombine/cabs.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/cabs.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]) Index: unittests/Analysis/TargetLibraryInfoTest.cpp =================================================================== --- unittests/Analysis/TargetLibraryInfoTest.cpp +++ unittests/Analysis/TargetLibraryInfoTest.cpp @@ -131,6 +131,9 @@ "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"