Skip to content

[SimplifyLibCalls] Constant fold remquo #99647

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 7 commits into from
Jul 24, 2024
Merged

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Jul 19, 2024

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

Closes #99497.

@llvmbot
Copy link
Member

llvmbot commented Jul 19, 2024

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

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

Closes #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 --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)

if (Rem.remainder(*Y) != APFloat::opOK)
return nullptr;

// TODO: We can only keep at least the three of the last bits of x/y
Copy link
Member Author

Choose a reason for hiding this comment

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

The current implementation is slightly conservative. The integer part of x/y may be out of range of i32.

Copy link

github-actions bot commented Jul 19, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Comment on lines 3030 to 3044
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;
Copy link
Contributor

Choose a reason for hiding this comment

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

Should pull the actual implementation into APFloat

Copy link
Member Author

Choose a reason for hiding this comment

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

See #99647 (comment). The current implementation doesn't match the standard behavior. I don't think it's appropriate to move these logic into APFloat.

@arsenm
Copy link
Contributor

arsenm commented Jul 21, 2024

Typo in title

@dtcxzyw dtcxzyw changed the title [SimplfiyLibCalls] Constant fold remquo [SimplifyLibCalls] Constant fold remquo Jul 21, 2024
ret float %call
}

declare float @remquof(float, float, ptr)
Copy link
Contributor

Choose a reason for hiding this comment

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

Need a non-edgcase strictfp case?

Copy link
Member Author

Choose a reason for hiding this comment

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

See remquo_f32_strictfp

@arsenm arsenm added the floating-point Floating-point math label Jul 23, 2024
@dtcxzyw dtcxzyw merged commit 9d45b45 into llvm:main Jul 24, 2024
6 of 8 checks passed
@dtcxzyw dtcxzyw deleted the remquo-support-part2 branch July 24, 2024 05:32
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
Summary:
This patch adds constant folding support for `remquo`.
Reference: https://en.cppreference.com/w/cpp/numeric/math/remquo

Closes #99497.

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60250753
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

std::remainder(x,y) and std::remquo(x, y, z) are not optimized at the compilation time when (x, y) is constant
3 participants