-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
[InstCombine] Canonicalize icmp ult (add X, C2), C
expressions
#95649
[InstCombine] Canonicalize icmp ult (add X, C2), C
expressions
#95649
Conversation
@llvm/pr-subscribers-llvm-transforms Author: Antonio Frighetto (antoniofrighetto) Changes
Proofs: https://alive2.llvm.org/ce/z/P-VVmQ. Fixes: #75613. Full diff: https://github.com/llvm/llvm-project/pull/95649.diff 2 Files Affected:
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 34b0f8b860497..51dd3384c1fb5 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3130,6 +3130,13 @@ Instruction *InstCombinerImpl::foldICmpAddConstant(ICmpInst &Cmp,
return new ICmpInst(ICmpInst::ICMP_EQ, Builder.CreateAnd(X, -C),
ConstantExpr::getNeg(cast<Constant>(Y)));
+ // X+C2 <u C -> (X & C) == 2C
+ // iff C == -(C2)
+ // C2 is a power of 2
+ if (Pred == ICmpInst::ICMP_ULT && C2->isPowerOf2() && (C == -(*C2)))
+ return new ICmpInst(ICmpInst::ICMP_NE, Builder.CreateAnd(X, C),
+ ConstantInt::get(Ty, C * 2));
+
// X+C >u C2 -> (X & ~C2) != C
// iff C & C2 == 0
// C2+1 is a power of 2
diff --git a/llvm/test/Transforms/InstCombine/icmp-add.ll b/llvm/test/Transforms/InstCombine/icmp-add.ll
index 6b4e5a5372c52..f5e8a58580ce8 100644
--- a/llvm/test/Transforms/InstCombine/icmp-add.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-add.ll
@@ -3023,4 +3023,69 @@ define i1 @icmp_addnuw_nonzero_fail_multiuse(i32 %x, i32 %y) {
ret i1 %c
}
+define i1 @ult_add_C2_pow2_C_neg(i8 %x) {
+; CHECK-LABEL: @ult_add_C2_pow2_C_neg(
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -32
+; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[TMP1]], -64
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %i = add i8 %x, 32
+ %c = icmp ult i8 %i, -32
+ ret i1 %c
+}
+
+define i1 @ult_add_nsw_C2_pow2_C_neg(i8 %x) {
+; CHECK-LABEL: @ult_add_nsw_C2_pow2_C_neg(
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -32
+; CHECK-NEXT: [[C:%.*]] = icmp ne i8 [[TMP1]], -64
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %i = add nsw i8 %x, 32
+ %c = icmp ult i8 %i, -32
+ ret i1 %c
+}
+
+define i1 @ult_add_nuw_nsw_C2_pow2_C_neg(i8 %x) {
+; CHECK-LABEL: @ult_add_nuw_nsw_C2_pow2_C_neg(
+; CHECK-NEXT: [[C:%.*]] = icmp ult i8 [[X:%.*]], -64
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %i = add nuw nsw i8 %x, 32
+ %c = icmp ult i8 %i, -32
+ ret i1 %c
+}
+
+define i1 @ult_add_C2_neg_C_pow2(i8 %x) {
+; CHECK-LABEL: @ult_add_C2_neg_C_pow2(
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -32
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], 32
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %i = add i8 %x, -32
+ %c = icmp ult i8 %i, 32
+ ret i1 %c
+}
+
+define <2 x i1> @ult_add_C2_pow2_C_neg_vec(<2 x i8> %x) {
+; CHECK-LABEL: @ult_add_C2_pow2_C_neg_vec(
+; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[X:%.*]], <i8 -32, i8 -32>
+; CHECK-NEXT: [[C:%.*]] = icmp ne <2 x i8> [[TMP1]], <i8 -64, i8 -64>
+; CHECK-NEXT: ret <2 x i1> [[C]]
+;
+ %i = add <2 x i8> %x, <i8 32, i8 32>
+ %c = icmp ult <2 x i8> %i, <i8 -32, i8 -32>
+ ret <2 x i1> %c
+}
+
+define i1 @uge_add_C2_pow2_C_neg(i8 %x) {
+; CHECK-LABEL: @uge_add_C2_pow2_C_neg(
+; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[X:%.*]], -32
+; CHECK-NEXT: [[C:%.*]] = icmp eq i8 [[TMP1]], -64
+; CHECK-NEXT: ret i1 [[C]]
+;
+ %i = add i8 %x, 32
+ %c = icmp uge i8 %i, -32
+ ret i1 %c
+}
+
declare void @llvm.assume(i1)
|
2ed0210
to
f4ff5cc
Compare
NB regarding the proofs, you can just do |
LGTM, but can you look into CI failures. |
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 key question here is whether this is the right canonicalization direction -- do we prefer a mask check over a range check? I guess if @dtcxzyw's tests don't show regressions from this, then this direction is fine.
W.o |
Done. |
Added a multi-use, thanks. CI failures look unrelated. |
797932a
to
21ac510
Compare
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.
LGTM
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.
LGTM.
`icmp ult (add X, C2), C` can be folded to `icmp ne (and X, C), 2C`, subject to `C == -C2` and C2 being a power of 2. Proofs: https://alive2.llvm.org/ce/z/P-VVmQ. Fixes: llvm#75613.
21ac510
to
a4b44c0
Compare
icmp ult (add X, C2), C
can be folded toicmp ne (and X, C), 2C
, subject toC == -C2
and C2 being a power of 2.Proofs: https://alive2.llvm.org/ce/z/P-VVmQ.
Fixes: #75613.