From b1e4bf86d09d31483f7ee94b8a538a8dabb8fb0e Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Fri, 13 Jun 2025 14:33:06 +0200 Subject: [PATCH 1/2] Add icmp gep chain tests --- llvm/test/Transforms/InstCombine/icmp-gep.ll | 65 ++++++++++++++++++++ 1 file changed, 65 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/icmp-gep.ll b/llvm/test/Transforms/InstCombine/icmp-gep.ll index 7f8f1ae73948d..01c409e38d148 100644 --- a/llvm/test/Transforms/InstCombine/icmp-gep.ll +++ b/llvm/test/Transforms/InstCombine/icmp-gep.ll @@ -757,3 +757,68 @@ define i1 @gep_diff_base_same_indices_nuw_nusw(ptr %x, ptr %y, i64 %z) { %cmp = icmp ult ptr %gep1, %gep2 ret i1 %cmp } + +define i1 @gep_multiple_eq(ptr %base, i64 %idx, i64 %idx2) { +; CHECK-LABEL: @gep_multiple_eq( +; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] +; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[GEP1]], i64 [[IDX2:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[GEP2]], [[BASE]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %gep1 = getelementptr i32, ptr %base, i64 %idx + %gep2 = getelementptr i32, ptr %gep1, i64 %idx2 + %cmp = icmp eq ptr %gep2, %base + ret i1 %cmp +} + +define i1 @gep_multiple_eq_commuted(ptr %base, i64 %idx, i64 %idx2) { +; CHECK-LABEL: @gep_multiple_eq_commuted( +; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] +; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[GEP1]], i64 [[IDX2:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[BASE]], [[GEP2]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %gep1 = getelementptr i32, ptr %base, i64 %idx + %gep2 = getelementptr i32, ptr %gep1, i64 %idx2 + %cmp = icmp eq ptr %base, %gep2 + ret i1 %cmp +} + +define i1 @gep_mugtiple_ugt_nuw(ptr %base, i64 %idx, i64 %idx2) { +; CHECK-LABEL: @gep_mugtiple_ugt_nuw( +; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] +; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nuw i32, ptr [[GEP1]], i64 [[IDX2:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt ptr [[GEP2]], [[BASE]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %gep1 = getelementptr nuw i32, ptr %base, i64 %idx + %gep2 = getelementptr nuw i32, ptr %gep1, i64 %idx2 + %cmp = icmp ugt ptr %gep2, %base + ret i1 %cmp +} + +define i1 @gep_mugtiple_ugt_not_all_nuw(ptr %base, i64 %idx, i64 %idx2) { +; CHECK-LABEL: @gep_mugtiple_ugt_not_all_nuw( +; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] +; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[GEP1]], i64 [[IDX2:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt ptr [[GEP2]], [[BASE]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %gep1 = getelementptr nuw i32, ptr %base, i64 %idx + %gep2 = getelementptr i32, ptr %gep1, i64 %idx2 + %cmp = icmp ugt ptr %gep2, %base + ret i1 %cmp +} + +define i1 @gep_mugtiple_ugt_inbounds_nusw(ptr %base, i64 %idx, i64 %idx2) { +; CHECK-LABEL: @gep_mugtiple_ugt_inbounds_nusw( +; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] +; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nusw i32, ptr [[GEP1]], i64 [[IDX2:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ugt ptr [[GEP2]], [[BASE]] +; CHECK-NEXT: ret i1 [[CMP]] +; + %gep1 = getelementptr inbounds i32, ptr %base, i64 %idx + %gep2 = getelementptr nusw i32, ptr %gep1, i64 %idx2 + %cmp = icmp ugt ptr %gep2, %base + ret i1 %cmp +} From f223184fb2506c226d5c2a955a9872d34a1b34f5 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Wed, 11 Jun 2025 18:13:10 +0200 Subject: [PATCH 2/2] [InstCombine] Fold icmp of gep chain with base Fold icmp between a chain of geps and its based pointer. Previously only a single gep was supported. This will be extended to handle the case of two gep chains with a common base in a followup. --- .../InstCombine/InstCombineCompares.cpp | 9 +++++--- .../Transforms/InstCombine/getelementptr.ll | 2 +- llvm/test/Transforms/InstCombine/icmp-gep.ll | 23 +++++++++---------- llvm/test/Transforms/InstCombine/pr39908.ll | 12 +++------- 4 files changed, 21 insertions(+), 25 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index c112fae351817..60cd93f9e2d42 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -708,10 +708,12 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, return I; }; - Value *PtrBase = GEPLHS->getOperand(0); - if (PtrBase == RHS && CanFold(GEPLHS->getNoWrapFlags())) { + CommonPointerBase Base = CommonPointerBase::compute(GEPLHS, RHS); + if (Base.Ptr == RHS && CanFold(Base.LHSNW)) { // ((gep Ptr, OFFSET) cmp Ptr) ---> (OFFSET cmp 0). - Value *Offset = EmitGEPOffset(GEPLHS); + Type *IdxTy = DL.getIndexType(GEPLHS->getType()); + Value *Offset = + EmitGEPOffsets(Base.LHSGEPs, Base.LHSNW, IdxTy, /*RewriteGEPs=*/false); return NewICmp(GEPLHS->getNoWrapFlags(), Offset, Constant::getNullValue(Offset->getType())); } @@ -750,6 +752,7 @@ Instruction *InstCombinerImpl::foldGEPICmp(GEPOperator *GEPLHS, Value *RHS, // If the base pointers are different, but the indices are the same, just // compare the base pointer. + Value *PtrBase = GEPLHS->getOperand(0); if (PtrBase != GEPRHS->getOperand(0)) { bool IndicesTheSame = GEPLHS->getNumOperands() == GEPRHS->getNumOperands() && diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll index 61236df80bfa6..23e682f5217cd 100644 --- a/llvm/test/Transforms/InstCombine/getelementptr.ll +++ b/llvm/test/Transforms/InstCombine/getelementptr.ll @@ -694,7 +694,7 @@ define i32 @test28() nounwind { ; CHECK-NEXT: [[TMP0:%.*]] = sext i32 [[T12_REC]] to i64 ; CHECK-NEXT: [[T12:%.*]] = getelementptr inbounds [[STRUCT_X:%.*]], ptr [[T45]], i64 [[TMP0]] ; CHECK-NEXT: [[T16:%.*]] = call i32 (ptr, ...) @printf(ptr noundef nonnull dereferenceable(1) @.str1, ptr nonnull [[T12]]) #[[ATTR0]] -; CHECK-NEXT: [[T84:%.*]] = icmp eq ptr [[T12]], [[ORIENTATIONS]] +; CHECK-NEXT: [[T84:%.*]] = icmp eq i32 [[INDVAR]], 0 ; CHECK-NEXT: [[INDVAR_NEXT]] = add i32 [[INDVAR]], 1 ; CHECK-NEXT: br i1 [[T84]], label [[BB17:%.*]], label [[BB10]] ; CHECK: bb17: diff --git a/llvm/test/Transforms/InstCombine/icmp-gep.ll b/llvm/test/Transforms/InstCombine/icmp-gep.ll index 01c409e38d148..c2ec3bc83e066 100644 --- a/llvm/test/Transforms/InstCombine/icmp-gep.ll +++ b/llvm/test/Transforms/InstCombine/icmp-gep.ll @@ -760,9 +760,9 @@ define i1 @gep_diff_base_same_indices_nuw_nusw(ptr %x, ptr %y, i64 %z) { define i1 @gep_multiple_eq(ptr %base, i64 %idx, i64 %idx2) { ; CHECK-LABEL: @gep_multiple_eq( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[GEP1]], i64 [[IDX2:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[GEP2]], [[BASE]] +; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] +; CHECK-NEXT: [[DOTMASK:%.*]] = and i64 [[GEP1_IDX1]], 4611686018427387903 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[DOTMASK]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %gep1 = getelementptr i32, ptr %base, i64 %idx @@ -773,9 +773,9 @@ define i1 @gep_multiple_eq(ptr %base, i64 %idx, i64 %idx2) { define i1 @gep_multiple_eq_commuted(ptr %base, i64 %idx, i64 %idx2) { ; CHECK-LABEL: @gep_multiple_eq_commuted( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr i32, ptr [[GEP1]], i64 [[IDX2:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[BASE]], [[GEP2]] +; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] +; CHECK-NEXT: [[DOTMASK:%.*]] = and i64 [[GEP1_IDX1]], 4611686018427387903 +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[DOTMASK]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %gep1 = getelementptr i32, ptr %base, i64 %idx @@ -786,9 +786,8 @@ define i1 @gep_multiple_eq_commuted(ptr %base, i64 %idx, i64 %idx2) { define i1 @gep_mugtiple_ugt_nuw(ptr %base, i64 %idx, i64 %idx2) { ; CHECK-LABEL: @gep_mugtiple_ugt_nuw( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr nuw i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nuw i32, ptr [[GEP1]], i64 [[IDX2:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt ptr [[GEP2]], [[BASE]] +; CHECK-NEXT: [[GEP1_IDX1:%.*]] = sub i64 0, [[IDX2:%.*]] +; CHECK-NEXT: [[CMP:%.*]] = icmp ne i64 [[IDX:%.*]], [[GEP1_IDX1]] ; CHECK-NEXT: ret i1 [[CMP]] ; %gep1 = getelementptr nuw i32, ptr %base, i64 %idx @@ -812,9 +811,9 @@ define i1 @gep_mugtiple_ugt_not_all_nuw(ptr %base, i64 %idx, i64 %idx2) { define i1 @gep_mugtiple_ugt_inbounds_nusw(ptr %base, i64 %idx, i64 %idx2) { ; CHECK-LABEL: @gep_mugtiple_ugt_inbounds_nusw( -; CHECK-NEXT: [[GEP1:%.*]] = getelementptr inbounds i32, ptr [[BASE:%.*]], i64 [[IDX:%.*]] -; CHECK-NEXT: [[GEP2:%.*]] = getelementptr nusw i32, ptr [[GEP1]], i64 [[IDX2:%.*]] -; CHECK-NEXT: [[CMP:%.*]] = icmp ugt ptr [[GEP2]], [[BASE]] +; CHECK-NEXT: [[GEP1_IDX1:%.*]] = add i64 [[IDX:%.*]], [[IDX2:%.*]] +; CHECK-NEXT: [[TMP1:%.*]] = shl i64 [[GEP1_IDX1]], 2 +; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i64 [[TMP1]], 0 ; CHECK-NEXT: ret i1 [[CMP]] ; %gep1 = getelementptr inbounds i32, ptr %base, i64 %idx diff --git a/llvm/test/Transforms/InstCombine/pr39908.ll b/llvm/test/Transforms/InstCombine/pr39908.ll index ca143f417fb27..5d13a331c6d2e 100644 --- a/llvm/test/Transforms/InstCombine/pr39908.ll +++ b/llvm/test/Transforms/InstCombine/pr39908.ll @@ -7,9 +7,7 @@ target datalayout = "p:32:32" define i1 @test(ptr %p, i32 %n) { ; CHECK-LABEL: @test( -; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[N:%.*]], i32 0, i32 0 -; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[N:%.*]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ; %end = getelementptr inbounds [0 x %S], ptr %p, i32 0, i32 %n, i32 0, i32 0 @@ -22,9 +20,7 @@ define i1 @test(ptr %p, i32 %n) { define i1 @test64(ptr %p, i64 %n) { ; CHECK-LABEL: @test64( ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32 -; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[TMP1]], i32 0, i32 0 -; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ; %end = getelementptr inbounds [0 x %S], ptr %p, i64 0, i64 %n, i32 0, i64 0 @@ -37,9 +33,7 @@ define i1 @test64(ptr %p, i64 %n) { define i1 @test64_overflow(ptr %p, i64 %n) { ; CHECK-LABEL: @test64_overflow( ; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[N:%.*]] to i32 -; CHECK-NEXT: [[END:%.*]] = getelementptr inbounds [0 x %S], ptr [[P:%.*]], i32 0, i32 [[TMP1]], i32 0, i32 0 -; CHECK-NEXT: [[LAST:%.*]] = getelementptr inbounds i8, ptr [[END]], i32 -8 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[LAST]], [[P]] +; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP1]], 1 ; CHECK-NEXT: ret i1 [[CMP]] ; %end = getelementptr inbounds [0 x %S], ptr %p, i64 0, i64 %n, i32 0, i64 8589934592