-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[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
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) ChangesThis patch adds constant folding support for Closes #99497. Full diff: https://github.com/llvm/llvm-project/pull/99647.diff 3 Files Affected:
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 |
There was a problem hiding this comment.
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.
✅ With the latest revision this PR passed the C/C++ code formatter. |
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
Typo in title |
remquo
remquo
ret float %call | ||
} | ||
|
||
declare float @remquof(float, float, ptr) |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See remquo_f32_strictfp
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
This patch adds constant folding support for
remquo
.Reference: https://en.cppreference.com/w/cpp/numeric/math/remquo
Closes #99497.