Skip to content

[ConstantFold] Fold ilogb and ilogbf when the input parameter is a constant value. #113014

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 20, 2024

Conversation

c8ef
Copy link
Contributor

@c8ef c8ef commented Oct 19, 2024

This patch adds support for constant folding for the ilogb and ilogbf libc functions.

@c8ef c8ef changed the title Draft [ConstantFold] Fold ilogb and ilogbf when the input parameter is a constant value. Oct 19, 2024
@c8ef c8ef marked this pull request as ready for review October 19, 2024 03:49
@c8ef c8ef requested review from arsenm, davemgreen and dtcxzyw October 19, 2024 03:50
@llvmbot
Copy link
Member

llvmbot commented Oct 19, 2024

@llvm/pr-subscribers-llvm-transforms

@llvm/pr-subscribers-llvm-analysis

Author: None (c8ef)

Changes

This patch adds support for constant folding for the ilogb and ilogbf libc functions.


Full diff: https://github.com/llvm/llvm-project/pull/113014.diff

2 Files Affected:

  • (modified) llvm/lib/Analysis/ConstantFolding.cpp (+20-1)
  • (added) llvm/test/Transforms/InstCombine/ilogb.ll (+203)
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 74df67a4ff9b43..d9eea2cc2915bb 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1677,6 +1677,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) {
     return Name == "fabs" || Name == "fabsf" ||
            Name == "floor" || Name == "floorf" ||
            Name == "fmod" || Name == "fmodf";
+  case 'i':
+    return Name == "ilogb" || Name == "ilogbf";
   case 'l':
     return Name == "log" || Name == "logf" || Name == "logl" ||
            Name == "log2" || Name == "log2f" || Name == "log10" ||
@@ -1772,6 +1774,17 @@ inline bool llvm_fenv_testexcept() {
   return false;
 }
 
+Constant *ConstantFoldInt(int (*NativeFP)(double), const APFloat &V, Type *Ty) {
+  llvm_fenv_clearexcept();
+  int Result = NativeFP(V.convertToDouble());
+  if (llvm_fenv_testexcept()) {
+    llvm_fenv_clearexcept();
+    return nullptr;
+  }
+
+  return ConstantInt::get(Ty, Result, true);
+}
+
 Constant *ConstantFoldFP(double (*NativeFP)(double), const APFloat &V,
                          Type *Ty) {
   llvm_fenv_clearexcept();
@@ -2131,7 +2144,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
     }
 #endif
 
-    if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy())
+    if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy() &&
+        !Ty->isIntegerTy())
       return nullptr;
 
     // Use internal versions of these intrinsics.
@@ -2391,6 +2405,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
         // TODO: What about hosts that lack a C99 library?
         return ConstantFoldFP(log10, APF, Ty);
       break;
+    case LibFunc_ilogb:
+    case LibFunc_ilogbf:
+      if (!APF.isZero() && TLI->has(Func))
+        return ConstantFoldInt(ilogb, APF, Ty);
+      break;
     case LibFunc_logb:
     case LibFunc_logbf:
       if (!APF.isZero() && TLI->has(Func))
diff --git a/llvm/test/Transforms/InstCombine/ilogb.ll b/llvm/test/Transforms/InstCombine/ilogb.ll
new file mode 100644
index 00000000000000..e30791fe68e7b2
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/ilogb.ll
@@ -0,0 +1,203 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i32 @ilogbf_const1() {
+; CHECK-LABEL: define i32 @ilogbf_const1() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 7.000000e+00)
+; CHECK-NEXT:    ret i32 2
+;
+  %r = call i32 @ilogbf(float 7.000000e+00)
+  ret i32 %r
+}
+
+define i32 @ilogb_const1() {
+; CHECK-LABEL: define i32 @ilogb_const1() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double -7.000000e+00)
+; CHECK-NEXT:    ret i32 2
+;
+  %r = call i32 @ilogb(double -7.000000e+00)
+  ret i32 %r
+}
+
+define i32 @ilogbf_const2() {
+; CHECK-LABEL: define i32 @ilogbf_const2() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 5.000000e-01)
+; CHECK-NEXT:    ret i32 -1
+;
+  %r = call i32 @ilogbf(float 5.000000e-01)
+  ret i32 %r
+}
+
+define i32 @ilogb_const2() {
+; CHECK-LABEL: define i32 @ilogb_const2() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double -5.000000e-01)
+; CHECK-NEXT:    ret i32 -1
+;
+  %r = call i32 @ilogb(double -5.000000e-01)
+  ret i32 %r
+}
+
+define i32 @ilogbf_zero() {
+; CHECK-LABEL: define i32 @ilogbf_zero() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 0.000000e+00)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float 0.000000e+00)
+  ret i32 %r
+}
+
+define i32 @ilogb_zero() {
+; CHECK-LABEL: define i32 @ilogb_zero() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double 0.000000e+00)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double 0.000000e+00)
+  ret i32 %r
+}
+
+define i32 @ilogbf_neg_zero() {
+; CHECK-LABEL: define i32 @ilogbf_neg_zero() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float -0.000000e+00)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float -0.000000e+00)
+  ret i32 %r
+}
+
+define i32 @ilogb_neg_zero() {
+; CHECK-LABEL: define i32 @ilogb_neg_zero() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double -0.000000e+00)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double -0.000000e+00)
+  ret i32 %r
+}
+
+define i32 @ilogbf_inf() {
+; CHECK-LABEL: define i32 @ilogbf_inf() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 0x7FF0000000000000)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float 0x7FF0000000000000)
+  ret i32 %r
+}
+
+define i32 @ilogb_inf() {
+; CHECK-LABEL: define i32 @ilogb_inf() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double 0x7FF0000000000000)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double 0x7FF0000000000000)
+  ret i32 %r
+}
+
+define i32 @ilogbf_nan() {
+; CHECK-LABEL: define i32 @ilogbf_nan() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 0x7FF8000000000000)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float 0x7FF8000000000000)
+  ret i32 %r
+}
+
+define i32 @ilogb_nan() {
+; CHECK-LABEL: define i32 @ilogb_nan() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double 0x7FF8000000000000)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double 0x7FF8000000000000)
+  ret i32 %r
+}
+
+define i32 @ilogbf_zero_readnone() {
+; CHECK-LABEL: define i32 @ilogbf_zero_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 0.000000e+00) #[[ATTR0:[0-9]+]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float 0.000000e+00) readnone
+  ret i32 %r
+}
+
+define i32 @ilogb_zero_readnone() {
+; CHECK-LABEL: define i32 @ilogb_zero_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double 0.000000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double 0.000000e+00) readnone
+  ret i32 %r
+}
+
+define i32 @ilogbf_neg_zero_readnone() {
+; CHECK-LABEL: define i32 @ilogbf_neg_zero_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float -0.000000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float -0.000000e+00) readnone
+  ret i32 %r
+}
+
+define i32 @ilogb_neg_zero_readnone() {
+; CHECK-LABEL: define i32 @ilogb_neg_zero_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double -0.000000e+00) #[[ATTR0]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double -0.000000e+00) readnone
+  ret i32 %r
+}
+
+define i32 @ilogbf_inf_readnone() {
+; CHECK-LABEL: define i32 @ilogbf_inf_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 0x7FF0000000000000) #[[ATTR0]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float 0x7FF0000000000000) readnone
+  ret i32 %r
+}
+
+define i32 @ilogb_inf_readnone() {
+; CHECK-LABEL: define i32 @ilogb_inf_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double 0x7FF0000000000000) #[[ATTR0]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double 0x7FF0000000000000) readnone
+  ret i32 %r
+}
+
+define i32 @ilogbf_nan_readnone() {
+; CHECK-LABEL: define i32 @ilogbf_nan_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float 0x7FF8000000000000) #[[ATTR0]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float 0x7FF8000000000000) readnone
+  ret i32 %r
+}
+
+define i32 @ilogb_nan_readnone() {
+; CHECK-LABEL: define i32 @ilogb_nan_readnone() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double 0x7FF8000000000000) #[[ATTR0]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double 0x7FF8000000000000) readnone
+  ret i32 %r
+}
+
+define i32 @ilogbf_poison() {
+; CHECK-LABEL: define i32 @ilogbf_poison() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogbf(float poison)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogbf(float poison)
+  ret i32 %r
+}
+
+define i32 @ilogb_poison() {
+; CHECK-LABEL: define i32 @ilogb_poison() {
+; CHECK-NEXT:    [[R:%.*]] = call i32 @ilogb(double poison)
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %r = call i32 @ilogb(double poison)
+  ret i32 %r
+}
+
+declare i32 @ilogbf(float)
+declare i32 @ilogb(double)

case LibFunc_ilogb:
case LibFunc_ilogbf:
if (!APF.isZero() && TLI->has(Func))
return ConstantFoldInt(ilogb, APF, Ty);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use int ilogb(const APFloat &Arg).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea!

@@ -2131,7 +2133,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name,
}
#endif

if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy())
if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy() &&
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should just handle this case before here, or just delete the whole check.

This function could use some cleanup. Why isn't this using a switch over the intrinsic ID?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably should just handle this case before here, or just delete the whole check.

It appears that the check is necessary to guard certain types, such as vector or fp128 types.

Copy link
Contributor

@arsenm arsenm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but please consider cleaning up this function. There should be a switch over intrinsic IDs.

The repeated TLI->has(func) in each case could be done once for all the libcall cases.

It would also be good to avoid explicitly listing the edge cases in the pre-check of the ConstantFoldFP call

This reverts commit 5f1f693.
@c8ef
Copy link
Contributor Author

c8ef commented Oct 19, 2024

LGTM but please consider cleaning up this function. There should be a switch over intrinsic IDs.

For libcalls like ilogb that do not have corresponding intrinsics, their intrinsic ID is 0. Therefore, we may still need to switch over the name for them.

The repeated TLI->has(func) in each case could be done once for all the libcall cases.

It would also be good to avoid explicitly listing the edge cases in the pre-check of the ConstantFoldFP call

This could be partially achieved by the solution proposed in #112113 (comment).

@arsenm
Copy link
Contributor

arsenm commented Oct 19, 2024

For libcalls like ilogb that do not have corresponding intrinsics, their intrinsic ID is 0. Therefore, we may still need to switch over the name for them.

Yes, there needs to be duplicated handling for intrinsics and libcalls (part of why I think most of the math intrinsics should be removed)

@c8ef c8ef merged commit 1336e3d into llvm:main Oct 20, 2024
8 checks passed
@c8ef c8ef deleted the ilogb branch October 20, 2024 03:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants