[llvm] [InstCombine] Convert @log to @llvm.log if the input is known positive. (PR #111428)

David Green via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 9 02:43:20 PDT 2024


https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/111428

>From 1268da307d2d0fb147898997a03f6fb349143fd1 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Wed, 9 Oct 2024 10:42:07 +0100
Subject: [PATCH] [InstCombine] Convert @log to @llvm.log if the input is known
 positive.

Similar to 112aac4e8961b9626bb84f36deeaa5a674f03f5a, this converts log libcalls
to llvm.log.f64 intrinsics if we know they do not set errno, as the input is
not zero and not negative. As log will produce errno if the input is 0
(returning -inf) or if the input is negative (returning nan), we also perform
the conversion when we have noinf and nonan.
---
 .../lib/Transforms/Utils/SimplifyLibCalls.cpp | 46 +++++++++++++------
 .../InstCombine/double-float-shrink-1.ll      | 21 +++++----
 llvm/test/Transforms/InstCombine/log-pow.ll   |  6 +--
 .../InstCombine/log-to-intrinsic.ll           | 20 ++++----
 4 files changed, 56 insertions(+), 37 deletions(-)

diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 347e4d62244c80..5f902eec2899de 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -2510,20 +2510,15 @@ Value *LibCallSimplifier::optimizeLog(CallInst *Log, IRBuilderBase &B) {
   Intrinsic::ID LogID = LogFn->getIntrinsicID();
   Module *Mod = Log->getModule();
   Type *Ty = Log->getType();
-  Value *Ret = nullptr;
 
   if (UnsafeFPShrink && hasFloatVersion(Mod, LogNm))
-    Ret = optimizeUnaryDoubleFP(Log, B, TLI, true);
-
-  // The earlier call must also be 'fast' in order to do these transforms.
-  CallInst *Arg = dyn_cast<CallInst>(Log->getArgOperand(0));
-  if (!Log->isFast() || !Arg || !Arg->isFast() || !Arg->hasOneUse())
-    return Ret;
+    if (Value *Ret = optimizeUnaryDoubleFP(Log, B, TLI, true))
+      return Ret;
 
   LibFunc LogLb, ExpLb, Exp2Lb, Exp10Lb, PowLb;
 
   // This is only applicable to log(), log2(), log10().
-  if (TLI->getLibFunc(LogNm, LogLb))
+  if (TLI->getLibFunc(LogNm, LogLb)) {
     switch (LogLb) {
     case LibFunc_logf:
       LogID = Intrinsic::log;
@@ -2589,10 +2584,28 @@ Value *LibCallSimplifier::optimizeLog(CallInst *Log, IRBuilderBase &B) {
       PowLb = LibFunc_powl;
       break;
     default:
-      return Ret;
+      return nullptr;
+    }
+
+    // Convert libcall to intrinsic if the value is known > 0.
+    bool IsKnownNoErrno = Log->hasNoNaNs() && Log->hasNoInfs();
+    if (!IsKnownNoErrno) {
+      SimplifyQuery SQ(DL, TLI, DT, AC, Log, true, true, DC);
+      KnownFPClass Known = computeKnownFPClass(
+          Log->getOperand(0),
+          KnownFPClass::OrderedLessThanZeroMask | fcSubnormal,
+          /*Depth=*/0, SQ);
+      Function *F = Log->getParent()->getParent();
+      IsKnownNoErrno = Known.cannotBeOrderedLessThanZero() &&
+                       Known.isKnownNeverLogicalZero(*F, Ty);
+    }
+    if (IsKnownNoErrno) {
+      auto *NewLog = B.CreateUnaryIntrinsic(LogID, Log->getArgOperand(0), Log);
+      NewLog->copyMetadata(*Log);
+      return copyFlags(*Log, NewLog);
     }
-  else if (LogID == Intrinsic::log || LogID == Intrinsic::log2 ||
-           LogID == Intrinsic::log10) {
+  } else if (LogID == Intrinsic::log || LogID == Intrinsic::log2 ||
+             LogID == Intrinsic::log10) {
     if (Ty->getScalarType()->isFloatTy()) {
       ExpLb = LibFunc_expf;
       Exp2Lb = LibFunc_exp2f;
@@ -2604,9 +2617,14 @@ Value *LibCallSimplifier::optimizeLog(CallInst *Log, IRBuilderBase &B) {
       Exp10Lb = LibFunc_exp10;
       PowLb = LibFunc_pow;
     } else
-      return Ret;
+      return nullptr;
   } else
-    return Ret;
+    return nullptr;
+
+  // The earlier call must also be 'fast' in order to do these transforms.
+  CallInst *Arg = dyn_cast<CallInst>(Log->getArgOperand(0));
+  if (!Log->isFast() || !Arg || !Arg->isFast() || !Arg->hasOneUse())
+    return nullptr;
 
   IRBuilderBase::FastMathFlagGuard Guard(B);
   B.setFastMathFlags(FastMathFlags::getFast());
@@ -2655,7 +2673,7 @@ Value *LibCallSimplifier::optimizeLog(CallInst *Log, IRBuilderBase &B) {
     return MulY;
   }
 
-  return Ret;
+  return nullptr;
 }
 
 // sqrt(exp(X)) -> exp(X * 0.5)
diff --git a/llvm/test/Transforms/InstCombine/double-float-shrink-1.ll b/llvm/test/Transforms/InstCombine/double-float-shrink-1.ll
index 85c9a01e5fabab..c13a01bb9d4890 100644
--- a/llvm/test/Transforms/InstCombine/double-float-shrink-1.ll
+++ b/llvm/test/Transforms/InstCombine/double-float-shrink-1.ll
@@ -249,10 +249,10 @@ define double @exp10_test2(float %f)   {
 
 define float @log_test1(float %f)   {
 ; CHECK-LABEL: @log_test1(
-; LINUX-NEXT:    [[LOGF:%.*]] = call fast float @logf(float [[F:%.*]])
+; LINUX-NEXT:    [[LOGF:%.*]] = call fast float @llvm.log.f32(float [[F:%.*]])
 ; LINUX-NEXT:    ret float [[LOGF]]
-; MS32:          [[LOGF:%.*]] = call fast double @log(double [[F:%.*]])
-; MS64-NEXT:     [[LOGF:%.*]] = call fast float @logf(float [[F:%.*]])
+; MS32:          [[LOGF:%.*]] = call fast double @llvm.log.f64(double [[F:%.*]])
+; MS64-NEXT:     [[LOGF:%.*]] = call fast float @llvm.log.f32(float [[F:%.*]])
 ;
   %conv = fpext float %f to double
   %call = call fast double @log(double %conv)
@@ -263,7 +263,7 @@ define float @log_test1(float %f)   {
 define double @log_test2(float %f)   {
 ; CHECK-LABEL: @log_test2(
 ; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
-; CHECK-NEXT:    [[CALL:%.*]] = call fast double @log(double [[CONV]])
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @llvm.log.f64(double [[CONV]])
 ; CHECK-NEXT:    ret double [[CALL]]
 ;
   %conv = fpext float %f to double
@@ -273,10 +273,10 @@ define double @log_test2(float %f)   {
 
 define float @log10_test1(float %f)   {
 ; CHECK-LABEL: @log10_test1(
-; LINUX-NEXT:    [[LOG10F:%.*]] = call fast float @log10f(float [[F:%.*]])
+; LINUX-NEXT:    [[LOG10F:%.*]] = call fast float @llvm.log10.f32(float [[F:%.*]])
 ; LINUX-NEXT:    ret float [[LOG10F]]
-; MS32:          [[LOG10F:%.*]] = call fast double @log10(double [[F:%.*]])
-; MS64-NEXT:     [[LOG10F:%.*]] = call fast float @log10f(float [[F:%.*]])
+; MS32:          [[LOG10F:%.*]] = call fast double @llvm.log10.f64(double [[F:%.*]])
+; MS64-NEXT:     [[LOG10F:%.*]] = call fast float @llvm.log10.f32(float [[F:%.*]])
 ;
   %conv = fpext float %f to double
   %call = call fast double @log10(double %conv)
@@ -287,7 +287,7 @@ define float @log10_test1(float %f)   {
 define double @log10_test2(float %f) {
 ; CHECK-LABEL: @log10_test2(
 ; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
-; CHECK-NEXT:    [[CALL:%.*]] = call fast double @log10(double [[CONV]])
+; CHECK-NEXT:    [[CALL:%.*]] = call fast double @llvm.log10.f64(double [[CONV]])
 ; CHECK-NEXT:    ret double [[CALL]]
 ;
   %conv = fpext float %f to double
@@ -320,7 +320,7 @@ define double @log1p_test2(float %f)   {
 
 define float @log2_test1(float %f)   {
 ; CHECK-LABEL: @log2_test1(
-; ISC99-NEXT:    [[LOG2F:%.*]] = call fast float @log2f(float [[F:%.*]])
+; ISC99-NEXT:    [[LOG2F:%.*]] = call fast float @llvm.log2.f32(float [[F:%.*]])
 ; ISC99-NEXT:    ret float [[LOG2F]]
 ; ISC89:         [[LOG2F:%.*]] = call fast double @log2(double [[F:%.*]])
 ;
@@ -333,7 +333,8 @@ define float @log2_test1(float %f)   {
 define double @log2_test2(float %f)   {
 ; CHECK-LABEL: @log2_test2(
 ; CHECK-NEXT:    [[CONV:%.*]] = fpext float [[F:%.*]] to double
-; CHECK-NEXT:    [[CALL:%.*]] = call fast double @log2(double [[CONV]])
+; ISC99-NEXT:    [[CALL:%.*]] = call fast double @llvm.log2.f64(double [[CONV]])
+; ISC89-NEXT:    [[LOG2F:%.*]] = call fast double @log2(double [[F:%.*]])
 ; CHECK-NEXT:    ret double [[CALL]]
 ;
   %conv = fpext float %f to double
diff --git a/llvm/test/Transforms/InstCombine/log-pow.ll b/llvm/test/Transforms/InstCombine/log-pow.ll
index b628e7cc57f15f..bfa636e470bb45 100644
--- a/llvm/test/Transforms/InstCombine/log-pow.ll
+++ b/llvm/test/Transforms/InstCombine/log-pow.ll
@@ -73,7 +73,7 @@ define float @logf_powfi_nonconst(float %x, i32 %y) {
 define double @log_powi_not_fast(double %x, i32 %y) {
 ; CHECK-LABEL: @log_powi_not_fast(
 ; CHECK-NEXT:    [[POW:%.*]] = call double @llvm.powi.f64.i32(double [[X:%.*]], i32 [[Y:%.*]])
-; CHECK-NEXT:    [[LOG:%.*]] = call fast double @log(double [[POW]])
+; CHECK-NEXT:    [[LOG:%.*]] = call fast double @llvm.log.f64(double [[POW]])
 ; CHECK-NEXT:    ret double [[LOG]]
 ;
   %pow = call double @llvm.powi.f64.i32(double %x, i32 %y)
@@ -106,7 +106,7 @@ define <2 x double> @log2v_powv(<2 x double> %x, <2 x double> %y) {
 define double @log_pow_not_fast(double %x, double %y) {
 ; CHECK-LABEL: @log_pow_not_fast(
 ; CHECK-NEXT:    [[POW:%.*]] = call double @pow(double [[X:%.*]], double [[Y:%.*]])
-; CHECK-NEXT:    [[LOG:%.*]] = call fast double @log(double [[POW]])
+; CHECK-NEXT:    [[LOG:%.*]] = call fast double @llvm.log.f64(double [[POW]])
 ; CHECK-NEXT:    ret double [[LOG]]
 ;
   %pow = call double @pow(double %x, double %y)
@@ -158,7 +158,7 @@ define float @log2f_exp10f(float %x) {
 define double @log_exp2_not_fast(double %x) {
 ; CHECK-LABEL: @log_exp2_not_fast(
 ; CHECK-NEXT:    [[EXP:%.*]] = call double @exp2(double [[X:%.*]])
-; CHECK-NEXT:    [[LOG:%.*]] = call fast double @log(double [[EXP]])
+; CHECK-NEXT:    [[LOG:%.*]] = call fast double @llvm.log.f64(double [[EXP]])
 ; CHECK-NEXT:    ret double [[LOG]]
 ;
   %exp = call double @exp2(double %x)
diff --git a/llvm/test/Transforms/InstCombine/log-to-intrinsic.ll b/llvm/test/Transforms/InstCombine/log-to-intrinsic.ll
index 6b397423b7959c..273d44c0919199 100644
--- a/llvm/test/Transforms/InstCombine/log-to-intrinsic.ll
+++ b/llvm/test/Transforms/InstCombine/log-to-intrinsic.ll
@@ -8,7 +8,7 @@ define float @test_logf_pos(float %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt float [[F]], 0.000000e+00
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call float @logf(float [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call float @llvm.log.f32(float [[F]])
 ; CHECK-NEXT:    ret float [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret float 0.000000e+00
@@ -32,7 +32,7 @@ define double @test_log_pos(double %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt double [[F]], 0.000000e+00
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call double @log(double [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call double @llvm.log.f64(double [[F]])
 ; CHECK-NEXT:    ret double [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret double 0.000000e+00
@@ -56,7 +56,7 @@ define fp128 @test_logl_pos(fp128 %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt fp128 [[F]], 0xL00000000000000000000000000000000
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call fp128 @logl(fp128 [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call fp128 @llvm.log.f128(fp128 [[F]])
 ; CHECK-NEXT:    ret fp128 [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret fp128 0xL00000000000000000000000000000000
@@ -80,7 +80,7 @@ define float @test_log10f_pos(float %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt float [[F]], 0.000000e+00
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call float @log10f(float [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call float @llvm.log10.f32(float [[F]])
 ; CHECK-NEXT:    ret float [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret float 0.000000e+00
@@ -104,7 +104,7 @@ define double @test_log10_pos(double %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt double [[F]], 0.000000e+00
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call double @log10(double [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call double @llvm.log10.f64(double [[F]])
 ; CHECK-NEXT:    ret double [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret double 0.000000e+00
@@ -128,7 +128,7 @@ define fp128 @test_log10l_pos(fp128 %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt fp128 [[F]], 0xL00000000000000000000000000000000
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call fp128 @log10l(fp128 [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call fp128 @llvm.log10.f128(fp128 [[F]])
 ; CHECK-NEXT:    ret fp128 [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret fp128 0xL00000000000000000000000000000000
@@ -152,7 +152,7 @@ define float @test_log2f_pos(float %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt float [[F]], 0.000000e+00
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call float @log2f(float [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call float @llvm.log2.f32(float [[F]])
 ; CHECK-NEXT:    ret float [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret float 0.000000e+00
@@ -176,7 +176,7 @@ define double @test_log2_pos(double %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt double [[F]], 0.000000e+00
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call double @log2(double [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call double @llvm.log2.f64(double [[F]])
 ; CHECK-NEXT:    ret double [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret double 0.000000e+00
@@ -200,7 +200,7 @@ define fp128 @test_log2l_pos(fp128 %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt fp128 [[F]], 0xL00000000000000000000000000000000
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call fp128 @log2l(fp128 [[F]])
+; CHECK-NEXT:    [[CALL:%.*]] = tail call fp128 @llvm.log2.f128(fp128 [[F]])
 ; CHECK-NEXT:    ret fp128 [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret fp128 0xL00000000000000000000000000000000
@@ -273,7 +273,7 @@ define float @metadata(float %f) {
 ; CHECK-NEXT:    [[ISINF:%.*]] = fcmp ugt float [[F]], 0.000000e+00
 ; CHECK-NEXT:    br i1 [[ISINF]], label %[[IF_END:.*]], label %[[RETURN:.*]]
 ; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    [[CALL:%.*]] = tail call float @logf(float [[F]]), !fpmath [[META0:![0-9]+]]
+; CHECK-NEXT:    [[CALL:%.*]] = tail call float @llvm.log.f32(float [[F]]), !fpmath [[META0:![0-9]+]]
 ; CHECK-NEXT:    ret float [[CALL]]
 ; CHECK:       [[RETURN]]:
 ; CHECK-NEXT:    ret float 0.000000e+00



More information about the llvm-commits mailing list