Index: llvm/trunk/include/llvm/Analysis/TargetLibraryInfo.def =================================================================== --- llvm/trunk/include/llvm/Analysis/TargetLibraryInfo.def +++ llvm/trunk/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: llvm/trunk/include/llvm/Transforms/Utils/SimplifyLibCalls.h =================================================================== --- llvm/trunk/include/llvm/Transforms/Utils/SimplifyLibCalls.h +++ llvm/trunk/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 *replacePowWithSqrt(CallInst *Pow, IRBuilder<> &B); Index: llvm/trunk/lib/Analysis/TargetLibraryInfo.cpp =================================================================== --- llvm/trunk/lib/Analysis/TargetLibraryInfo.cpp +++ llvm/trunk/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,25 @@ 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; } Index: llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1033,6 +1033,35 @@ 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 @@ 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: llvm/trunk/test/Transforms/InstCombine/cabs-array.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/cabs-array.ll +++ llvm/trunk/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]) Index: llvm/trunk/test/Transforms/InstCombine/cabs-discrete.ll =================================================================== --- llvm/trunk/test/Transforms/InstCombine/cabs-discrete.ll +++ llvm/trunk/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) Index: llvm/trunk/unittests/Analysis/TargetLibraryInfoTest.cpp =================================================================== --- llvm/trunk/unittests/Analysis/TargetLibraryInfoTest.cpp +++ llvm/trunk/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"