[llvm] [InstCombine] Restore splat gep support in OptimizePointerDifference() (PR #143906)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 12 07:18:06 PDT 2025


https://github.com/nikic created https://github.com/llvm/llvm-project/pull/143906

When looking for the common base pointer, support the case where the type changes because the GEP goes from pointer to vector of pointers. This was supported prior to #142958.

>From d80ab8141801f104e4e8674d9e4adaa50c0406b2 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 12 Jun 2025 15:46:53 +0200
Subject: [PATCH 1/2] Add tests for diff of splat geps

---
 llvm/test/Transforms/InstCombine/sub-gep.ll | 36 +++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/sub-gep.ll b/llvm/test/Transforms/InstCombine/sub-gep.ll
index 9444fef1887d3..2de979b2ff349 100644
--- a/llvm/test/Transforms/InstCombine/sub-gep.ll
+++ b/llvm/test/Transforms/InstCombine/sub-gep.ll
@@ -995,3 +995,39 @@ define i64 @multiple_geps_inbounds_nuw(ptr %base, i64 %idx, i64 %idx2) {
   %d = sub i64 %i2, %i1
   ret i64 %d
 }
+
+define <2 x i64> @splat_geps(ptr %base, <2 x i64> %idx1, <2 x i64> %idx2) {
+; CHECK-LABEL: @splat_geps(
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], <2 x i64> [[IDX1:%.*]]
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[BASE]], <2 x i64> [[IDX2:%.*]]
+; CHECK-NEXT:    [[GEP1_INT:%.*]] = ptrtoint <2 x ptr> [[GEP1]] to <2 x i64>
+; CHECK-NEXT:    [[GEP2_INT:%.*]] = ptrtoint <2 x ptr> [[GEP2]] to <2 x i64>
+; CHECK-NEXT:    [[D:%.*]] = sub <2 x i64> [[GEP2_INT]], [[GEP1_INT]]
+; CHECK-NEXT:    ret <2 x i64> [[D]]
+;
+  %gep1 = getelementptr inbounds i8, ptr %base, <2 x i64> %idx1
+  %gep2 = getelementptr inbounds i8, ptr %base, <2 x i64> %idx2
+  %gep1.int = ptrtoint <2 x ptr> %gep1 to <2 x i64>
+  %gep2.int = ptrtoint <2 x ptr> %gep2 to <2 x i64>
+  %d = sub <2 x i64> %gep2.int, %gep1.int
+  ret <2 x i64> %d
+}
+
+define <2 x i64> @splat_geps_multiple(ptr %base, i64 %idx0, <2 x i64> %idx1, <2 x i64> %idx2) {
+; CHECK-LABEL: @splat_geps_multiple(
+; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i64 [[IDX0:%.*]]
+; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[GEP0]], <2 x i64> [[IDX1:%.*]]
+; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[BASE]], <2 x i64> [[IDX2:%.*]]
+; CHECK-NEXT:    [[GEP1_INT:%.*]] = ptrtoint <2 x ptr> [[GEP1]] to <2 x i64>
+; CHECK-NEXT:    [[GEP2_INT:%.*]] = ptrtoint <2 x ptr> [[GEP2]] to <2 x i64>
+; CHECK-NEXT:    [[D:%.*]] = sub <2 x i64> [[GEP2_INT]], [[GEP1_INT]]
+; CHECK-NEXT:    ret <2 x i64> [[D]]
+;
+  %gep0 = getelementptr inbounds i8, ptr %base, i64 %idx0
+  %gep1 = getelementptr inbounds i8, ptr %gep0, <2 x i64> %idx1
+  %gep2 = getelementptr inbounds i8, ptr %base, <2 x i64> %idx2
+  %gep1.int = ptrtoint <2 x ptr> %gep1 to <2 x i64>
+  %gep2.int = ptrtoint <2 x ptr> %gep2 to <2 x i64>
+  %d = sub <2 x i64> %gep2.int, %gep1.int
+  ret <2 x i64> %d
+}

>From a2ae6f557b5df567f68bf753c6ebdb4f5b12f335 Mon Sep 17 00:00:00 2001
From: Nikita Popov <npopov at redhat.com>
Date: Thu, 12 Jun 2025 16:16:13 +0200
Subject: [PATCH 2/2] [InstCombine] Restore splat gep support in
 OptimizePointerDifference()

When looking for the common base pointer, support the case where
the type changes because the GEP goes from pointer to vector of
pointers. This was supported prior to #142958.
---
 .../Transforms/InstCombine/InstCombineAddSub.cpp |  7 ++++---
 llvm/test/Transforms/InstCombine/sub-gep.ll      | 16 +++++-----------
 2 files changed, 9 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 86d318967403d..0d91e7d77e4a7 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2088,8 +2088,6 @@ CommonPointerBase CommonPointerBase::compute(Value *LHS, Value *RHS) {
   // Find common base and collect RHS GEPs.
   while (true) {
     if (Ptrs.contains(RHS)) {
-      if (LHS->getType() != RHS->getType())
-        return Base;
       Base.Ptr = RHS;
       break;
     }
@@ -2132,12 +2130,15 @@ Value *InstCombinerImpl::OptimizePointerDifference(Value *LHS, Value *RHS,
   // TODO: We should probably do this even if there is only one GEP.
   bool RewriteGEPs = !Base.LHSGEPs.empty() && !Base.RHSGEPs.empty();
 
-  Type *IdxTy = DL.getIndexType(Base.Ptr->getType());
+  Type *IdxTy = DL.getIndexType(LHS->getType());
   auto EmitOffsetFromBase = [&](ArrayRef<GEPOperator *> GEPs,
                                 GEPNoWrapFlags NW) -> Value * {
     Value *Sum = nullptr;
     for (GEPOperator *GEP : reverse(GEPs)) {
       Value *Offset = EmitGEPOffset(GEP, RewriteGEPs);
+      if (Offset->getType() != IdxTy)
+        Offset = Builder.CreateVectorSplat(
+            cast<VectorType>(IdxTy)->getElementCount(), Offset);
       if (Sum)
         Sum = Builder.CreateAdd(Sum, Offset, "", NW.hasNoUnsignedWrap(),
                                 NW.isInBounds());
diff --git a/llvm/test/Transforms/InstCombine/sub-gep.ll b/llvm/test/Transforms/InstCombine/sub-gep.ll
index 2de979b2ff349..375be8a3d69c3 100644
--- a/llvm/test/Transforms/InstCombine/sub-gep.ll
+++ b/llvm/test/Transforms/InstCombine/sub-gep.ll
@@ -998,11 +998,7 @@ define i64 @multiple_geps_inbounds_nuw(ptr %base, i64 %idx, i64 %idx2) {
 
 define <2 x i64> @splat_geps(ptr %base, <2 x i64> %idx1, <2 x i64> %idx2) {
 ; CHECK-LABEL: @splat_geps(
-; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], <2 x i64> [[IDX1:%.*]]
-; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[BASE]], <2 x i64> [[IDX2:%.*]]
-; CHECK-NEXT:    [[GEP1_INT:%.*]] = ptrtoint <2 x ptr> [[GEP1]] to <2 x i64>
-; CHECK-NEXT:    [[GEP2_INT:%.*]] = ptrtoint <2 x ptr> [[GEP2]] to <2 x i64>
-; CHECK-NEXT:    [[D:%.*]] = sub <2 x i64> [[GEP2_INT]], [[GEP1_INT]]
+; CHECK-NEXT:    [[D:%.*]] = sub nsw <2 x i64> [[IDX2:%.*]], [[IDX1:%.*]]
 ; CHECK-NEXT:    ret <2 x i64> [[D]]
 ;
   %gep1 = getelementptr inbounds i8, ptr %base, <2 x i64> %idx1
@@ -1015,12 +1011,10 @@ define <2 x i64> @splat_geps(ptr %base, <2 x i64> %idx1, <2 x i64> %idx2) {
 
 define <2 x i64> @splat_geps_multiple(ptr %base, i64 %idx0, <2 x i64> %idx1, <2 x i64> %idx2) {
 ; CHECK-LABEL: @splat_geps_multiple(
-; CHECK-NEXT:    [[GEP0:%.*]] = getelementptr inbounds i8, ptr [[BASE:%.*]], i64 [[IDX0:%.*]]
-; CHECK-NEXT:    [[GEP1:%.*]] = getelementptr inbounds i8, ptr [[GEP0]], <2 x i64> [[IDX1:%.*]]
-; CHECK-NEXT:    [[GEP2:%.*]] = getelementptr inbounds i8, ptr [[BASE]], <2 x i64> [[IDX2:%.*]]
-; CHECK-NEXT:    [[GEP1_INT:%.*]] = ptrtoint <2 x ptr> [[GEP1]] to <2 x i64>
-; CHECK-NEXT:    [[GEP2_INT:%.*]] = ptrtoint <2 x ptr> [[GEP2]] to <2 x i64>
-; CHECK-NEXT:    [[D:%.*]] = sub <2 x i64> [[GEP2_INT]], [[GEP1_INT]]
+; CHECK-NEXT:    [[DOTSPLATINSERT:%.*]] = insertelement <2 x i64> poison, i64 [[IDX0:%.*]], i64 0
+; CHECK-NEXT:    [[DOTSPLAT:%.*]] = shufflevector <2 x i64> [[DOTSPLATINSERT]], <2 x i64> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[TMP1:%.*]] = add nsw <2 x i64> [[DOTSPLAT]], [[IDX1:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = sub nsw <2 x i64> [[IDX2:%.*]], [[TMP1]]
 ; CHECK-NEXT:    ret <2 x i64> [[D]]
 ;
   %gep0 = getelementptr inbounds i8, ptr %base, i64 %idx0



More information about the llvm-commits mailing list