[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