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,23 @@ } } + // sin(a) / cos(a) -> tan(a) + if (AllowReassociate) { + Value *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); + } + } + } + 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.ll =================================================================== --- test/Transforms/InstCombine/fdiv.ll +++ test/Transforms/InstCombine/fdiv.ll @@ -1,3 +1,4 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; RUN: opt -S -instcombine < %s | FileCheck %s define float @test1(float %x) nounwind readnone ssp { @@ -67,3 +68,96 @@ %div = fdiv fast float %x.fneg, %y.fneg ret float %div } + +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(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 double @tan(double) +declare float @tanf(float) +declare fp128 @tanl(fp128)