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

Matt Arsenault via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 16 10:34:51 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 =
----------------
arsenm wrote:

The problem is handling the intrinsics is not a complete solution. You can still do transforms on errno-writing libcalls, in addition to the intrinsics as long as you go from intrinsic->intrinsic and libcall->libcall. But intrinsics also suffer from another issue where there's no plausible mechanism for querying whether the intrinsic can lower, since in principle it should always be lowerable (but in the real world it's just an alias for an environment dependent libcall) 

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


More information about the llvm-commits mailing list