Skip to content

[InstCombine] Check nowrap flags when folding comparison of GEPs with the same base pointer #121892

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 4 commits into from
Feb 1, 2025

Conversation

dtcxzyw
Copy link
Member

@dtcxzyw dtcxzyw commented Jan 7, 2025

Alive2: https://alive2.llvm.org/ce/z/P5XbMx
Closes #121890

TODO: It is still safe to perform this transform without nowrap flags if the corresponding scale factor is 1 byte: https://alive2.llvm.org/ce/z/J-JCJd

@dtcxzyw dtcxzyw requested a review from goldsteinn January 7, 2025 07:08
@dtcxzyw dtcxzyw requested a review from nikic as a code owner January 7, 2025 07:08
@llvmbot llvmbot added llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms labels Jan 7, 2025
@llvmbot
Copy link
Member

llvmbot commented Jan 7, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Yingwei Zheng (dtcxzyw)

Changes

Alive2: https://alive2.llvm.org/ce/z/P5XbMx
Closes #121890

TODO: It is still safe to perform this transform without nowrap flags if the corresponding scale factor is 1 byte: https://alive2.llvm.org/ce/z/J-JCJd


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

2 Files Affected:

  • (modified) llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp (+5-2)
  • (modified) llvm/test/Transforms/InstCombine/opaque-ptr.ll (+35)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 8b23583c510637..9f136860724db8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -833,8 +833,11 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS,
       if (NumDifferences == 0)   // SAME GEP?
         return replaceInstUsesWith(I, // No comparison is needed here.
           ConstantInt::get(I.getType(), ICmpInst::isTrueWhenEqual(Cond)));
-
-      else if (NumDifferences == 1 && CanFold(NW)) {
+      // If two GEPs only differ by an index/the base pointer, compare them.
+      // Note that nowrap flags are always needed when comparing two indices.
+      else if (NumDifferences == 1 &&
+               (DiffOperand == 0 ? CanFold(NW)
+                                 : NW != GEPNoWrapFlags::none())) {
         Value *LHSV = GEPLHS->getOperand(DiffOperand);
         Value *RHSV = GEPRHS->getOperand(DiffOperand);
         return NewICmp(NW, LHSV, RHSV);
diff --git a/llvm/test/Transforms/InstCombine/opaque-ptr.ll b/llvm/test/Transforms/InstCombine/opaque-ptr.ll
index b05274658e812e..be734243d14a10 100644
--- a/llvm/test/Transforms/InstCombine/opaque-ptr.ll
+++ b/llvm/test/Transforms/InstCombine/opaque-ptr.ll
@@ -467,6 +467,41 @@ define i1 @cmp_gep_same_base_same_type(ptr %ptr, i64 %idx1, i64 %idx2) {
   ret i1 %cmp
 }
 
+define i1 @cmp_gep_same_base_same_type_maywrap(ptr %ptr, i64 %idx1, i64 %idx2) {
+; CHECK-LABEL: @cmp_gep_same_base_same_type_maywrap(
+; CHECK-NEXT:    [[CMP_UNSHIFTED:%.*]] = xor i64 [[IDX1:%.*]], [[IDX2:%.*]]
+; CHECK-NEXT:    [[CMP_MASK:%.*]] = and i64 [[CMP_UNSHIFTED]], 4611686018427387903
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[CMP_MASK]], 0
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %gep1 = getelementptr i32, ptr %ptr, i64 %idx1
+  %gep2 = getelementptr i32, ptr %ptr, i64 %idx2
+  %cmp = icmp eq ptr %gep1, %gep2
+  ret i1 %cmp
+}
+
+define i1 @cmp_gep_same_base_same_type_nuw(ptr %ptr, i64 %idx1, i64 %idx2) {
+; CHECK-LABEL: @cmp_gep_same_base_same_type_nuw(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[IDX1:%.*]], [[IDX2:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %gep1 = getelementptr nuw i32, ptr %ptr, i64 %idx1
+  %gep2 = getelementptr nuw i32, ptr %ptr, i64 %idx2
+  %cmp = icmp eq ptr %gep1, %gep2
+  ret i1 %cmp
+}
+
+define i1 @cmp_gep_same_base_same_type_nusw(ptr %ptr, i64 %idx1, i64 %idx2) {
+; CHECK-LABEL: @cmp_gep_same_base_same_type_nusw(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i64 [[IDX1:%.*]], [[IDX2:%.*]]
+; CHECK-NEXT:    ret i1 [[CMP]]
+;
+  %gep1 = getelementptr nusw i32, ptr %ptr, i64 %idx1
+  %gep2 = getelementptr nusw i32, ptr %ptr, i64 %idx2
+  %cmp = icmp eq ptr %gep1, %gep2
+  ret i1 %cmp
+}
+
 define i1 @cmp_gep_same_base_different_type(ptr %ptr, i64 %idx1, i64 %idx2) {
 ; CHECK-LABEL: @cmp_gep_same_base_different_type(
 ; CHECK-NEXT:    [[GEP1_IDX:%.*]] = shl nsw i64 [[IDX1:%.*]], 2

// If two GEPs only differ by an index/the base pointer, compare them.
// Note that nowrap flags are always needed when comparing two indices.
else if (NumDifferences == 1 &&
(DiffOperand == 0 ? CanFold(NW)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think DiffOperand == 0 can happen here? The above loop only goes over the index operands. The case of base pointer difference is handled by different code further up.

Copy link
Contributor

@nikic nikic left a comment

Choose a reason for hiding this comment

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

LGTM. We'll still fall back to the generic handling below, so I think the simple check is fine.

@nikic
Copy link
Contributor

nikic commented Jan 29, 2025

Reverse ping :)

@dtcxzyw
Copy link
Member Author

dtcxzyw commented Jan 31, 2025

Reverse ping :)

Is it necessary to merge this PR now? I was previously planning to merge it after fixing the regression.

@nikic
Copy link
Contributor

nikic commented Feb 1, 2025

Reverse ping :)

Is it necessary to merge this PR now? I was previously planning to merge it after fixing the regression.

As it fixes a miscompile and the regression doesn't seem particularly significant, I think it's better to merge it earlier than later.

@dtcxzyw dtcxzyw merged commit 9725595 into llvm:main Feb 1, 2025
6 of 8 checks passed
@dtcxzyw dtcxzyw deleted the perf/fix-121890 branch February 1, 2025 12:41
@nikic nikic added this to the LLVM 20.X Release milestone Feb 2, 2025
@nikic
Copy link
Contributor

nikic commented Feb 2, 2025

/cherry-pick 9725595

@llvmbot
Copy link
Member

llvmbot commented Feb 2, 2025

Failed to cherry-pick: 9725595

https://github.com/llvm/llvm-project/actions/runs/13097312131

Please manually backport the fix and push it to your github fork. Once this is done, please create a pull request

nikic pushed a commit to nikic/llvm-project that referenced this pull request Feb 5, 2025
… the same base pointer (llvm#121892)

Alive2: https://alive2.llvm.org/ce/z/P5XbMx
Closes llvm#121890

TODO: It is still safe to perform this transform without nowrap flags if
the corresponding scale factor is 1 byte:
https://alive2.llvm.org/ce/z/J-JCJd

(cherry picked from commit 9725595)
nikic pushed a commit to nikic/llvm-project that referenced this pull request Feb 11, 2025
… the same base pointer (llvm#121892)

Alive2: https://alive2.llvm.org/ce/z/P5XbMx
Closes llvm#121890

TODO: It is still safe to perform this transform without nowrap flags if
the corresponding scale factor is 1 byte:
https://alive2.llvm.org/ce/z/J-JCJd

(cherry picked from commit 9725595)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
llvm:instcombine Covers the InstCombine, InstSimplify and AggressiveInstCombine passes llvm:transforms release:cherry-pick-failed
Projects
Development

Successfully merging this pull request may close these issues.

[InstCombine] Missing flag check when folding comparison of geps with the same base pointer
3 participants