[llvm] [SimplfiyLibCalls] Constant fold `remquo` (PR #99647)

via llvm-commits llvm-commits at lists.llvm.org
Fri Jul 19 06:15:28 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

<details>
<summary>Changes</summary>

This patch adds constant folding support for `remquo`.
Reference: https://en.cppreference.com/w/cpp/numeric/math/remquo

Closes https://github.com/llvm/llvm-project/issues/99497.


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


3 Files Affected:

- (modified) llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h (+1) 
- (modified) llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp (+33) 
- (added) llvm/test/Transforms/InstCombine/remquo.ll (+116) 


``````````diff
diff --git a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
index e2682b429e9db..770da12e01233 100644
--- a/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
+++ b/llvm/include/llvm/Transforms/Utils/SimplifyLibCalls.h
@@ -205,6 +205,7 @@ class LibCallSimplifier {
   Value *optimizeSinCosPi(CallInst *CI, bool IsSin, IRBuilderBase &B);
   Value *optimizeTrigInversionPairs(CallInst *CI, IRBuilderBase &B);
   Value *optimizeSymmetric(CallInst *CI, LibFunc Func, IRBuilderBase &B);
+  Value *optimizeRemquo(CallInst *CI, IRBuilderBase &B);
   // Wrapper for all floating point library call optimizations
   Value *optimizeFloatingPointLibCall(CallInst *CI, LibFunc Func,
                                       IRBuilderBase &B);
diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
index 89c8c5bf08954..f62c53c208f9f 100644
--- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
@@ -3018,6 +3018,35 @@ void LibCallSimplifier::classifyArgUse(
   }
 }
 
+/// Constant folds remquo
+Value *LibCallSimplifier::optimizeRemquo(CallInst *CI, IRBuilderBase &B) {
+  const APFloat *X, *Y;
+  if (!match(CI->getArgOperand(0), m_APFloat(X)) || !match(CI->getArgOperand(1), m_APFloat(Y)))
+    return nullptr;
+
+  if (X->isNaN() || Y->isNaN() || X->isInfinity() || Y->isZero())
+    return nullptr;
+
+  APFloat::opStatus Status;
+  APFloat Quot = *X;
+  Status = Quot.divide(*Y, APFloat::rmNearestTiesToEven);
+  if (Status != APFloat::opOK && Status != APFloat::opInexact)
+    return nullptr;
+  APFloat Rem = *X;
+  if (Rem.remainder(*Y) != APFloat::opOK)
+    return nullptr;
+
+  // TODO: We can only keep at least the three of the last bits of x/y
+  APSInt QuotInt(32, /*isUnsigned=*/false);
+  bool IsExact;
+  Status = Quot.convertToInteger(QuotInt, APFloat::rmNearestTiesToEven, &IsExact);
+  if (Status != APFloat::opOK || Status != APFloat::opInexact)
+    return nullptr;
+
+  B.CreateAlignedStore(ConstantInt::get(B.getInt32Ty(), QuotInt.getExtValue()), CI->getArgOperand(2), CI->getParamAlign(2));
+  return ConstantFP::get(CI->getType(), Rem);
+}
+
 //===----------------------------------------------------------------------===//
 // Integer Library Call Optimizations
 //===----------------------------------------------------------------------===//
@@ -3926,6 +3955,10 @@ Value *LibCallSimplifier::optimizeFloatingPointLibCall(CallInst *CI,
   case LibFunc_cabsf:
   case LibFunc_cabsl:
     return optimizeCAbs(CI, Builder);
+  case LibFunc_remquo:
+  case LibFunc_remquof:
+  case LibFunc_remquol:
+    return optimizeRemquo(CI, Builder);
   default:
     return nullptr;
   }
diff --git a/llvm/test/Transforms/InstCombine/remquo.ll b/llvm/test/Transforms/InstCombine/remquo.ll
new file mode 100644
index 0000000000000..691086ac1c8f7
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/remquo.ll
@@ -0,0 +1,116 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define float @remquo_f32(ptr %quo) {
+; CHECK-LABEL: define float @remquo_f32(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store i32 -2, ptr [[QUO]], align 4
+; CHECK-NEXT:    ret float 1.000000e+00
+;
+entry:
+  %call = call float @remquof(float -5.000000e+00, float 3.000000e+00, ptr %quo)
+  ret float %call
+}
+
+define float @remquo_f32_quo_sign(ptr %quo) {
+; CHECK-LABEL: define float @remquo_f32_quo_sign(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store i32 2, ptr [[QUO]], align 4
+; CHECK-NEXT:    ret float -1.000000e+00
+;
+entry:
+  %call = call float @remquof(float 5.000000e+00, float 3.000000e+00, ptr %quo)
+  ret float %call
+}
+
+define float @remquo_f32_round(ptr %quo) {
+; CHECK-LABEL: define float @remquo_f32_round(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store i32 -6, ptr [[QUO]], align 4
+; CHECK-NEXT:    ret float 0xBFC9999900000000
+;
+entry:
+  %call = call float @remquof(float -5.000000e+00, float 0x3FE99999A0000000, ptr %quo)
+  ret float %call
+}
+
+define double @remquo_f64(ptr %quo) {
+; CHECK-LABEL: define double @remquo_f64(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    store i32 -5, ptr [[QUO]], align 4
+; CHECK-NEXT:    ret double -0.000000e+00
+;
+entry:
+  %call = call double @remquo(double -5.000000e+00, double 1.000000e+00, ptr %quo)
+  ret double %call
+}
+
+define double @remquo_f80(ptr %quo) {
+; CHECK-LABEL: define double @remquo_f80(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CALL:%.*]] = call double @remquol(x86_fp80 0xKC001A000000000000000, x86_fp80 0xK4000C000000000000000, ptr [[QUO]])
+; CHECK-NEXT:    ret double [[CALL]]
+;
+entry:
+  %call = call double @remquol(x86_fp80 0xKC001A000000000000000, x86_fp80 0xK4000C000000000000000, ptr %quo)
+  ret double %call
+}
+
+; Negative tests
+
+define float @remquo_f32_inf_x(ptr %quo) {
+; CHECK-LABEL: define float @remquo_f32_inf_x(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @remquof(float 0x7FF0000000000000, float 1.000000e+00, ptr [[QUO]])
+; CHECK-NEXT:    ret float [[CALL]]
+;
+entry:
+  %call = call float @remquof(float 0x7FF0000000000000, float 1.000000e+00, ptr %quo)
+  ret float %call
+}
+
+define float @remquo_f32_zero_y(ptr %quo) {
+; CHECK-LABEL: define float @remquo_f32_zero_y(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @remquof(float -5.000000e+00, float 0.000000e+00, ptr [[QUO]])
+; CHECK-NEXT:    ret float [[CALL]]
+;
+entry:
+  %call = call float @remquof(float -5.000000e+00, float 0.000000e+00, ptr %quo)
+  ret float %call
+}
+
+define float @remquo_f32_nan_x(ptr %quo) {
+; CHECK-LABEL: define float @remquo_f32_nan_x(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @remquof(float 0x7FF8000000000000, float 1.000000e+00, ptr [[QUO]])
+; CHECK-NEXT:    ret float [[CALL]]
+;
+entry:
+  %call = call float @remquof(float 0x7FF8000000000000, float 1.000000e+00, ptr %quo)
+  ret float %call
+}
+
+define float @remquo_f32_nan_y(ptr %quo) {
+; CHECK-LABEL: define float @remquo_f32_nan_y(
+; CHECK-SAME: ptr [[QUO:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[CALL:%.*]] = call float @remquof(float 1.000000e+00, float 0x7FF8000000000000, ptr [[QUO]])
+; CHECK-NEXT:    ret float [[CALL]]
+;
+entry:
+  %call = call float @remquof(float 1.000000e+00, float 0x7FF8000000000000, ptr %quo)
+  ret float %call
+}
+
+declare float @remquof(float, float, ptr)
+declare double @remquo(double, double, ptr)
+declare x86_fp80 @remquol(x86_fp80, x86_fp80, ptr)

``````````

</details>


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


More information about the llvm-commits mailing list