Index: include/llvm/Transforms/Utils/BuildLibCalls.h =================================================================== --- include/llvm/Transforms/Utils/BuildLibCalls.h +++ include/llvm/Transforms/Utils/BuildLibCalls.h @@ -15,6 +15,7 @@ #ifndef LLVM_TRANSFORMS_UTILS_BUILDLIBCALLS_H #define LLVM_TRANSFORMS_UTILS_BUILDLIBCALLS_H +#include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/IRBuilder.h" namespace llvm { @@ -29,6 +30,12 @@ /// Returns true if any attributes were set and false otherwise. bool inferLibFuncAttributes(Function &F, const TargetLibraryInfo &TLI); + /// Check whether the overloaded unary floating point function + /// corresponding to \a Ty is available. + bool hasUnaryFloatFn(const TargetLibraryInfo *TLI, Type *Ty, + LibFunc DoubleFn, LibFunc FloatFn, + LibFunc LongDoubleFn); + /// Return V if it is an i8*, otherwise cast it to i8*. Value *castToCStr(Value *V, IRBuilder<> &B); Index: lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -33,6 +33,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/KnownBits.h" #include "llvm/Transforms/InstCombine/InstCombineWorklist.h" +#include "llvm/Transforms/Utils/BuildLibCalls.h" #include #include #include @@ -1468,6 +1469,40 @@ } } + if (AllowReassociate && + Op0->hasOneUse() && Op1->hasOneUse()) { + Value *A; + // sin(a) / cos(a) -> tan(a) + if (match(Op0, m_Intrinsic(m_Value(A))) && + match(Op1, m_Intrinsic(m_Specific(A)))) { + if (hasUnaryFloatFn(&TLI, I.getType(), LibFunc_tan, + LibFunc_tanf, LibFunc_tanl)) { + IRBuilder<> B(&I); + IRBuilder<>::FastMathFlagGuard Guard(B); + B.setFastMathFlags(I.getFastMathFlags()); + Value *Tan = emitUnaryFloatFnCall(A, TLI.getName(LibFunc_tan), + B, I.getFunction()->getAttributes()); + return replaceInstUsesWith(I, Tan); + } + } + + // cos(a) / sin(a) -> 1/tan(a) + if (match(Op0, m_Intrinsic(m_Value(A))) && + match(Op1, m_Intrinsic(m_Specific(A)))) { + if (hasUnaryFloatFn(&TLI, I.getType(), LibFunc_tan, + LibFunc_tanf, LibFunc_tanl)) { + IRBuilder<> B(&I); + IRBuilder<>::FastMathFlagGuard Guard(B); + B.setFastMathFlags(I.getFastMathFlags()); + Value *Tan = emitUnaryFloatFnCall(A, TLI.getName(LibFunc_tan), + B, I.getFunction()->getAttributes()); + Value *One = ConstantFP::get(Tan->getType(), 1.0); + Value *Div = B.CreateFDiv(One, Tan); + return replaceInstUsesWith(I, Div); + } + } + } + Value *LHS; Value *RHS; Index: lib/Transforms/Utils/BuildLibCalls.cpp =================================================================== --- lib/Transforms/Utils/BuildLibCalls.cpp +++ lib/Transforms/Utils/BuildLibCalls.cpp @@ -709,6 +709,19 @@ } } +bool llvm::hasUnaryFloatFn(const TargetLibraryInfo *TLI, Type *Ty, + LibFunc DoubleFn, LibFunc FloatFn, + LibFunc LongDoubleFn) { + switch (Ty->getTypeID()) { + case Type::FloatTyID: + return TLI->has(FloatFn); + case Type::DoubleTyID: + return TLI->has(DoubleFn); + default: + return TLI->has(LongDoubleFn); + } +} + //- Emit LibCalls ------------------------------------------------------------// Value *llvm::castToCStr(Value *V, IRBuilder<> &B) { Index: lib/Transforms/Utils/SimplifyLibCalls.cpp =================================================================== --- lib/Transforms/Utils/SimplifyLibCalls.cpp +++ lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -104,21 +104,6 @@ }); } -/// \brief Check whether the overloaded unary floating point function -/// corresponding to \a Ty is available. -static bool hasUnaryFloatFn(const TargetLibraryInfo *TLI, Type *Ty, - LibFunc DoubleFn, LibFunc FloatFn, - LibFunc LongDoubleFn) { - switch (Ty->getTypeID()) { - case Type::FloatTyID: - return TLI->has(FloatFn); - case Type::DoubleTyID: - return TLI->has(DoubleFn); - default: - return TLI->has(LongDoubleFn); - } -} - //===----------------------------------------------------------------------===// // String and Memory Library Call Optimizations //===----------------------------------------------------------------------===// Index: test/Transforms/InstCombine/fdiv-cos-sin.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/fdiv-cos-sin.ll @@ -0,0 +1,113 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instcombine < %s | FileCheck %s + +define double @fdiv_cos_sin(double %a) { +; CHECK-LABEL: @fdiv_cos_sin( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret double [[DIV]] +; + %1 = call double @llvm.cos.f64(double %a) + %2 = call double @llvm.sin.f64(double %a) + %div = fdiv double %1, %2 + ret double %div +} + +define double @fdiv_strict_cos_strict_sin_fast(double %a) { +; CHECK-LABEL: @fdiv_strict_cos_strict_sin_fast( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.cos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call fast double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret double [[DIV]] +; + %1 = call double @llvm.cos.f64(double %a) + %2 = call fast double @llvm.sin.f64(double %a) + %div = fdiv double %1, %2 + ret double %div +} + +define double @fdiv_fast_cos_strict_sin_strict(double %a) { +; CHECK-LABEL: @fdiv_fast_cos_strict_sin_strict( +; CHECK-NEXT: [[TAN:%.*]] = call fast double @tan(double [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = fdiv fast double 1.000000e+00, [[TAN]] +; CHECK-NEXT: ret double [[TMP1]] +; + %1 = call double @llvm.cos.f64(double %a) + %2 = call double @llvm.sin.f64(double %a) + %div = fdiv fast double %1, %2 + ret double %div +} + +define double @fdiv_fast_cos_fast_sin_strict(double %a) { +; CHECK-LABEL: @fdiv_fast_cos_fast_sin_strict( +; CHECK-NEXT: [[TAN:%.*]] = call fast double @tan(double [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = fdiv fast double 1.000000e+00, [[TAN]] +; CHECK-NEXT: ret double [[TMP1]] +; + %1 = call fast double @llvm.cos.f64(double %a) + %2 = call double @llvm.sin.f64(double %a) + %div = fdiv fast double %1, %2 + ret double %div +} + +define double @fdiv_cos_sin_fast_multiple_uses(double %a) { +; CHECK-LABEL: @fdiv_cos_sin_fast_multiple_uses( +; CHECK-NEXT: [[TMP1:%.*]] = call fast double @llvm.cos.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call fast double @llvm.sin.f64(double [[A]]) +; CHECK-NEXT: [[DIV:%.*]] = fdiv fast double [[TMP1]], [[TMP2]] +; CHECK-NEXT: call void @use(double [[TMP2]]) +; CHECK-NEXT: ret double [[DIV]] +; + %1 = call fast double @llvm.cos.f64(double %a) + %2 = call fast double @llvm.sin.f64(double %a) + %div = fdiv fast double %1, %2 + call void @use(double %2) + ret double %div +} + +define double @fdiv_cos_sin_fast(double %a) { +; CHECK-LABEL: @fdiv_cos_sin_fast( +; CHECK-NEXT: [[TAN:%.*]] = call fast double @tan(double [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = fdiv fast double 1.000000e+00, [[TAN]] +; CHECK-NEXT: ret double [[TMP1]] +; + %1 = call fast double @llvm.cos.f64(double %a) + %2 = call fast double @llvm.sin.f64(double %a) + %div = fdiv fast double %1, %2 + ret double %div +} + +define float @fdiv_cosf_sinf_fast(float %a) { +; CHECK-LABEL: @fdiv_cosf_sinf_fast( +; CHECK-NEXT: [[TANF:%.*]] = call fast float @tanf(float [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = fdiv fast float 1.000000e+00, [[TANF]] +; CHECK-NEXT: ret float [[TMP1]] +; + %1 = call fast float @llvm.cos.f32(float %a) + %2 = call fast float @llvm.sin.f32(float %a) + %div = fdiv fast float %1, %2 + ret float %div +} + +define fp128 @fdiv_cosfp128_sinfp128_fast(fp128 %a) { +; CHECK-LABEL: @fdiv_cosfp128_sinfp128_fast( +; CHECK-NEXT: [[TANL:%.*]] = call fast fp128 @tanl(fp128 [[A:%.*]]) +; CHECK-NEXT: [[TMP1:%.*]] = fdiv fast fp128 0xL00000000000000003FFF000000000000, [[TANL]] +; CHECK-NEXT: ret fp128 [[TMP1]] +; + %1 = call fast fp128 @llvm.cos.fp128(fp128 %a) + %2 = call fast fp128 @llvm.sin.fp128(fp128 %a) + %div = fdiv fast fp128 %1, %2 + ret fp128 %div +} + +declare double @llvm.cos.f64(double) +declare float @llvm.cos.f32(float) +declare fp128 @llvm.cos.fp128(fp128) + +declare double @llvm.sin.f64(double) +declare float @llvm.sin.f32(float) +declare fp128 @llvm.sin.fp128(fp128) + +declare void @use(double) Index: test/Transforms/InstCombine/fdiv-sin-cos.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/fdiv-sin-cos.ll @@ -0,0 +1,108 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -instcombine < %s | FileCheck %s + +define double @fdiv_sin_cos(double %a) { +; CHECK-LABEL: @fdiv_sin_cos( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.sin.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call double @llvm.cos.f64(double [[A]]) +; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret double [[DIV]] +; + %1 = call double @llvm.sin.f64(double %a) + %2 = call double @llvm.cos.f64(double %a) + %div = fdiv double %1, %2 + ret double %div +} + +define double @fdiv_strict_sin_strict_cos_fast(double %a) { +; CHECK-LABEL: @fdiv_strict_sin_strict_cos_fast( +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.sin.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call fast double @llvm.cos.f64(double [[A]]) +; CHECK-NEXT: [[DIV:%.*]] = fdiv double [[TMP1]], [[TMP2]] +; CHECK-NEXT: ret double [[DIV]] +; + %1 = call double @llvm.sin.f64(double %a) + %2 = call fast double @llvm.cos.f64(double %a) + %div = fdiv double %1, %2 + ret double %div +} + +define double @fdiv_fast_sin_strict_cos_strict(double %a) { +; CHECK-LABEL: @fdiv_fast_sin_strict_cos_strict( +; CHECK-NEXT: [[TAN:%.*]] = call fast double @tan(double [[A:%.*]]) +; CHECK-NEXT: ret double [[TAN]] +; + %1 = call double @llvm.sin.f64(double %a) + %2 = call double @llvm.cos.f64(double %a) + %div = fdiv fast double %1, %2 + ret double %div +} + +define double @fdiv_fast_sin_fast_cos_strict(double %a) { +; CHECK-LABEL: @fdiv_fast_sin_fast_cos_strict( +; CHECK-NEXT: [[TAN:%.*]] = call fast double @tan(double [[A:%.*]]) +; CHECK-NEXT: ret double [[TAN]] +; + %1 = call fast double @llvm.sin.f64(double %a) + %2 = call double @llvm.cos.f64(double %a) + %div = fdiv fast double %1, %2 + ret double %div +} + +define double @fdiv_sin_cos_fast_multiple_uses(double %a) { +; CHECK-LABEL: @fdiv_sin_cos_fast_multiple_uses( +; CHECK-NEXT: [[TMP1:%.*]] = call fast double @llvm.sin.f64(double [[A:%.*]]) +; CHECK-NEXT: [[TMP2:%.*]] = call fast double @llvm.cos.f64(double [[A]]) +; CHECK-NEXT: [[DIV:%.*]] = fdiv fast double [[TMP1]], [[TMP2]] +; CHECK-NEXT: call void @use(double [[TMP2]]) +; CHECK-NEXT: ret double [[DIV]] +; + %1 = call fast double @llvm.sin.f64(double %a) + %2 = call fast double @llvm.cos.f64(double %a) + %div = fdiv fast double %1, %2 + call void @use(double %2) + ret double %div +} + +define double @fdiv_sin_cos_fast(double %a) { +; CHECK-LABEL: @fdiv_sin_cos_fast( +; CHECK-NEXT: [[TMP1:%.*]] = call fast double @tan(double [[A:%.*]]) +; CHECK-NEXT: ret double [[TMP1]] +; + %1 = call fast double @llvm.sin.f64(double %a) + %2 = call fast double @llvm.cos.f64(double %a) + %div = fdiv fast double %1, %2 + ret double %div +} + +define float @fdiv_sinf_cosf_fast(float %a) { +; CHECK-LABEL: @fdiv_sinf_cosf_fast( +; CHECK-NEXT: [[TMP1:%.*]] = call fast float @tanf(float [[A:%.*]]) +; CHECK-NEXT: ret float [[TMP1]] +; + %1 = call fast float @llvm.sin.f32(float %a) + %2 = call fast float @llvm.cos.f32(float %a) + %div = fdiv fast float %1, %2 + ret float %div +} + +define fp128 @fdiv_sinfp128_cosfp128_fast(fp128 %a) { +; CHECK-LABEL: @fdiv_sinfp128_cosfp128_fast( +; CHECK-NEXT: [[TMP0:%.*]] = call fast fp128 @tanl(fp128 [[A:%.*]]) +; CHECK-NEXT: ret fp128 [[TMP0]] +; + %1 = call fast fp128 @llvm.sin.fp128(fp128 %a) + %2 = call fast fp128 @llvm.cos.fp128(fp128 %a) + %div = fdiv fast fp128 %1, %2 + ret fp128 %div +} + +declare double @llvm.sin.f64(double) +declare float @llvm.sin.f32(float) +declare fp128 @llvm.sin.fp128(fp128) + +declare double @llvm.cos.f64(double) +declare float @llvm.cos.f32(float) +declare fp128 @llvm.cos.fp128(fp128) + +declare void @use(double)