[llvm] [InstCombine] Optimize `sinh` and `cosh` divisions (PR #81433)

Farzon Lotfi via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 16 11:42:55 PDT 2024


================
@@ -1886,23 +1886,82 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
     Value *X;
     bool IsTan = match(Op0, m_Intrinsic<Intrinsic::sin>(m_Value(X))) &&
                  match(Op1, m_Intrinsic<Intrinsic::cos>(m_Specific(X)));
-    bool IsCot =
-        !IsTan && match(Op0, m_Intrinsic<Intrinsic::cos>(m_Value(X))) &&
-                  match(Op1, m_Intrinsic<Intrinsic::sin>(m_Specific(X)));
+    bool IsCot = !IsTan &&
+                 match(Op0, m_Intrinsic<Intrinsic::cos>(m_Value(X))) &&
+                 match(Op1, m_Intrinsic<Intrinsic::sin>(m_Specific(X)));
 
-    if ((IsTan || IsCot) && hasFloatFn(M, &TLI, I.getType(), LibFunc_tan,
-                                       LibFunc_tanf, LibFunc_tanl)) {
+    auto GetReplacement = [&](Value *Arg, bool IsInv, LibFunc DoubleFunc,
+                              LibFunc FloatFunc,
+                              LibFunc LongDoubleFunc) -> Value * {
       IRBuilder<> B(&I);
       IRBuilder<>::FastMathFlagGuard FMFGuard(B);
       B.setFastMathFlags(I.getFastMathFlags());
       AttributeList Attrs =
           cast<CallBase>(Op0)->getCalledFunction()->getAttributes();
-      Value *Res = emitUnaryFloatFnCall(X, &TLI, LibFunc_tan, LibFunc_tanf,
-                                        LibFunc_tanl, B, Attrs);
-      if (IsCot)
+      Value *Res = emitUnaryFloatFnCall(Arg, &TLI, DoubleFunc, FloatFunc,
+                                        LongDoubleFunc, B, Attrs);
+
+      if (IsInv)
         Res = B.CreateFDiv(ConstantFP::get(I.getType(), 1.0), Res);
+
+      return Res;
+    };
+
+    if ((IsTan || IsCot) && hasFloatFn(M, &TLI, I.getType(), LibFunc_tan,
+                                       LibFunc_tanf, LibFunc_tanl)) {
+
+      Value *Res =
+          GetReplacement(X, IsCot, LibFunc_tan, LibFunc_tanf, LibFunc_tanl);
+
       return replaceInstUsesWith(I, Res);
     }
+
+    // sinh(X) / cosh(X) -> tanh(X)
+    // cosh(X) / sinh(X) -> 1/tanh(X)
+    Value *Y;
+    CallBase *Op0AsCallBase = dyn_cast<CallBase>(Op0);
+    CallBase *Op1AsCallBase = dyn_cast<CallBase>(Op1);
+    LibFunc Op0LibFunc, Op1LibFunc;
+
+    if (Op1AsCallBase && Op0AsCallBase) {
+      TLI.getLibFunc(*Op1AsCallBase, Op1LibFunc);
+      TLI.getLibFunc(*Op0AsCallBase, Op0LibFunc);
+
+      bool ArgsMatch = match(Op0AsCallBase->getArgOperand(0), m_Value(Y)) &&
+                       match(Op1AsCallBase->getArgOperand(0), m_Specific(Y));
+
+      bool IsTanH =
----------------
farzonl wrote:

I'm not disputing the correctness of your assertion. I mearly stating that there are no `InstCombine` cases of sine\cosine libfuncs. so doing these changes here to handle libcalls is adding a new pattern.

https://github.com/search?q=repo%3Allvm%2Fllvm-project%20LibFunc_sin&type=code
https://github.com/search?q=repo%3Allvm%2Fllvm-project+LibFunc_cos&type=code

In fact looking at the main branch the libcall pattern only exists in two other cases one of which is `LibFunc_tan` which I think should also be an intrinsic.

```bash
 git grep -n "LibFunc_"
InstCombineMulDivRem.cpp:1943:    if ((IsTan || IsCot) && hasFloatFn(M, &TLI, I.getType(), LibFunc_tan,
InstCombineMulDivRem.cpp:1944:                                       LibFunc_tanf, LibFunc_tanl)) {
InstCombineMulDivRem.cpp:1950:      Value *Res = emitUnaryFloatFnCall(X, &TLI, LibFunc_tan, LibFunc_tanf,
InstCombineMulDivRem.cpp:1951:                                        LibFunc_tanl, B, Attrs);
InstructionCombining.cpp:3162:            TLI.has(TheLibFunc) && TheLibFunc == LibFunc_aligned_alloc &&
InstructionCombining.cpp:3484:    if (TLI.getLibFunc(FI, Func) && TLI.has(Func) && Func == LibFunc_free
```
By adding `LibFunc` handling here we are increasing the exposure and usage of `LibFunc` unecessarily. 

https://github.com/llvm/llvm-project/pull/81433


More information about the llvm-commits mailing list