[llvm] r322255 - [InstCombine] Missed optimization in math expression: sin(x) / cos(x) => tan(x)

Dmitry Venikov via llvm-commits llvm-commits at lists.llvm.org
Wed Jan 10 22:33:00 PST 2018


Author: quolyk
Date: Wed Jan 10 22:33:00 2018
New Revision: 322255

URL: http://llvm.org/viewvc/llvm-project?rev=322255&view=rev
Log:
[InstCombine] Missed optimization in math expression: sin(x) / cos(x) => tan(x)

Summary: This patch enables folding sin(x) / cos(x) -> tan(x), cos(x) / sin(x) -> 1 / tan(x) under -ffast-math flag

Reviewers: hfinkel, spatel

Reviewed By: spatel

Subscribers: andrew.w.kaylor, efriedma, scanon, llvm-commits

Differential Revision: https://reviews.llvm.org/D41286

Added:
    llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll
    llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll
Modified:
    llvm/trunk/include/llvm/Transforms/Utils/BuildLibCalls.h
    llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/trunk/lib/Transforms/Utils/BuildLibCalls.cpp
    llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp

Modified: llvm/trunk/include/llvm/Transforms/Utils/BuildLibCalls.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Transforms/Utils/BuildLibCalls.h?rev=322255&r1=322254&r2=322255&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Transforms/Utils/BuildLibCalls.h (original)
+++ llvm/trunk/include/llvm/Transforms/Utils/BuildLibCalls.h Wed Jan 10 22:33:00 2018
@@ -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 @@ namespace llvm {
   /// 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);
 

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp?rev=322255&r1=322254&r2=322255&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp Wed Jan 10 22:33:00 2018
@@ -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 <cassert>
 #include <cstddef>
 #include <cstdint>
@@ -1468,6 +1469,40 @@ Instruction *InstCombiner::visitFDiv(Bin
     }
   }
 
+  if (AllowReassociate &&
+      Op0->hasOneUse() && Op1->hasOneUse()) {
+    Value *A;
+    // sin(a) / cos(a) -> tan(a)
+    if (match(Op0, m_Intrinsic<Intrinsic::sin>(m_Value(A))) &&
+        match(Op1, m_Intrinsic<Intrinsic::cos>(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<Intrinsic::cos>(m_Value(A))) &&
+        match(Op1, m_Intrinsic<Intrinsic::sin>(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;
 

Modified: llvm/trunk/lib/Transforms/Utils/BuildLibCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/BuildLibCalls.cpp?rev=322255&r1=322254&r2=322255&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/BuildLibCalls.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/BuildLibCalls.cpp Wed Jan 10 22:33:00 2018
@@ -709,6 +709,19 @@ bool llvm::inferLibFuncAttributes(Functi
   }
 }
 
+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) {

Modified: llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp?rev=322255&r1=322254&r2=322255&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp (original)
+++ llvm/trunk/lib/Transforms/Utils/SimplifyLibCalls.cpp Wed Jan 10 22:33:00 2018
@@ -104,21 +104,6 @@ static bool callHasFloatingPointArgument
   });
 }
 
-/// \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
 //===----------------------------------------------------------------------===//

Added: llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll?rev=322255&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fdiv-cos-sin.ll Wed Jan 10 22:33:00 2018
@@ -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)

Added: llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll?rev=322255&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/fdiv-sin-cos.ll Wed Jan 10 22:33:00 2018
@@ -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)




More information about the llvm-commits mailing list