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

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Sun Feb 11 23:21:42 PST 2024


================
@@ -1770,26 +1768,81 @@ Instruction *InstCombinerImpl::visitFDiv(BinaryOperator &I) {
   if (I.hasAllowReassoc() && Op0->hasOneUse() && Op1->hasOneUse()) {
     // sin(X) / cos(X) -> tan(X)
     // cos(X) / sin(X) -> 1/tan(X) (cotangent)
-    Value *X;
+    // sinh(X) / cosh(X) -> tanh(X)
+    // cosh(X) / sinh(X) -> 1/tanh(X)
+    Value *X, *Y;
+
     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);
     }
+
+    if (isa<CallBase>(Op0) && isa<CallBase>(Op1)) {
+
+      CallBase *Op0AsCallBase = cast<CallBase>(Op0);
+      CallBase *Op1AsCallBase = cast<CallBase>(Op1);
+
+      bool ArgsMatch = match(Op0AsCallBase->getArgOperand(0), m_Value(Y)) &&
+                       match(Op1AsCallBase->getArgOperand(0), m_Specific(Y));
+
+      bool IsTanH = Op0AsCallBase->getCalledFunction()->getName() == "sinh" &&
+                    Op1AsCallBase->getCalledFunction()->getName() == "cosh" &&
+                    ArgsMatch;
+
+      bool IsCotH = !IsTanH && ArgsMatch &&
+                    Op0AsCallBase->getCalledFunction()->getName() == "cosh" &&
+                    Op1AsCallBase->getCalledFunction()->getName() == "sinh";
+
+      if ((IsTanH || IsCotH) && hasFloatFn(M, &TLI, I.getType(), LibFunc_tanh,
+                                           LibFunc_tanhf, LibFunc_tanhl)) {
+
+        Value *Res =
+            GetReplacement(Y, false, LibFunc_tanh, LibFunc_tanf, LibFunc_tanl);
+
+        Instruction *Result = replaceInstUsesWith(I, Res);
+
+        // Call instructions of sinh and cosh need to be erased seperatly
+        if (!Op0AsCallBase->use_empty())
+          Op0AsCallBase->replaceAllUsesWith(
+              UndefValue::get(Op0AsCallBase->getType()));
+
+        if (!Op1AsCallBase->use_empty())
+          Op1AsCallBase->replaceAllUsesWith(
+              UndefValue::get(Op1AsCallBase->getType()));
+
+        Op0AsCallBase->eraseFromParent();
+        Op1AsCallBase->eraseFromParent();
----------------
dtcxzyw wrote:

```suggestion
```

`InstCombiner` will erase trivially dead instructions automatically.


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


More information about the llvm-commits mailing list