[llvm] [InstCombine] Canonicalize `gep T* X, V / sizeof(T)` to `gep i8* X, V` (PR #76458)

Yingwei Zheng via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 28 09:04:28 PST 2023


https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/76458

>From b8dc2c8dee4fa5f3cd5a129d099817d6ae0d065c Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 28 Dec 2023 01:23:08 +0800
Subject: [PATCH 1/3] [InstCombine] Add pre-commit tests. NFC.

---
 .../Transforms/InstCombine/getelementptr.ll   | 88 +++++++++++++++++++
 1 file changed, 88 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll
index bc7fdc9352df6c..0ecf166b84da6d 100644
--- a/llvm/test/Transforms/InstCombine/getelementptr.ll
+++ b/llvm/test/Transforms/InstCombine/getelementptr.ll
@@ -1453,4 +1453,92 @@ define ptr @const_gep_chain(ptr %p, i64 %a) {
   ret ptr %p4
 }
 
+define ptr @gep_sdiv(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv(
+; CHECK-NEXT:    [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    ret ptr [[PTR]]
+;
+  %index = sdiv exact i64 %off, 7
+  %ptr = getelementptr %struct.C, ptr %p, i64 %index
+  ret ptr %ptr
+}
+
+define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) {
+; CHECK-LABEL: @gep_sdiv_vec(
+; CHECK-NEXT:    [[INDEX:%.*]] = sdiv exact <2 x i64> [[OFF:%.*]], <i64 7, i64 7>
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], <2 x ptr> [[P:%.*]], <2 x i64> [[INDEX]]
+; CHECK-NEXT:    ret <2 x ptr> [[PTR]]
+;
+  %index = sdiv exact <2 x i64> %off, <i64 7, i64 7>
+  %ptr = getelementptr %struct.C, <2 x ptr> %p, <2 x i64> %index
+  ret <2 x ptr> %ptr
+}
+
+define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv_inbounds(
+; CHECK-NEXT:    [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    ret ptr [[PTR]]
+;
+  %index = sdiv exact i64 %off, 7
+  %ptr = getelementptr inbounds %struct.C, ptr %p, i64 %index
+  ret ptr %ptr
+}
+
+define ptr @gep_ashr(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_ashr(
+; CHECK-NEXT:    [[INDEX:%.*]] = ashr exact i64 [[OFF:%.*]], 2
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    ret ptr [[PTR]]
+;
+  %index = ashr exact i64 %off, 2
+  %ptr = getelementptr i32, ptr %p, i64 %index
+  ret ptr %ptr
+}
+
+; Negative tests
+
+define ptr @gep_i8(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_i8(
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
+; CHECK-NEXT:    ret ptr [[PTR]]
+;
+  %ptr = getelementptr i8, ptr %p, i64 %off
+  ret ptr %ptr
+}
+
+define ptr @gep_sdiv_mismatched_size(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv_mismatched_size(
+; CHECK-NEXT:    [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 20
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    ret ptr [[PTR]]
+;
+  %index = sdiv exact i64 %off, 20
+  %ptr = getelementptr %struct.C, ptr %p, i64 %index
+  ret ptr %ptr
+}
+
+define ptr @gep_sdiv_without_exact(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_sdiv_without_exact(
+; CHECK-NEXT:    [[INDEX:%.*]] = sdiv i64 [[OFF:%.*]], 7
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    ret ptr [[PTR]]
+;
+  %index = sdiv i64 %off, 7
+  %ptr = getelementptr %struct.C, ptr %p, i64 %index
+  ret ptr %ptr
+}
+
+define ptr @gep_ashr_without_exact(ptr %p, i64 %off) {
+; CHECK-LABEL: @gep_ashr_without_exact(
+; CHECK-NEXT:    [[INDEX:%.*]] = ashr i64 [[OFF:%.*]], 2
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    ret ptr [[PTR]]
+;
+  %index = ashr i64 %off, 2
+  %ptr = getelementptr i32, ptr %p, i64 %index
+  ret ptr %ptr
+}
+
 !0 = !{!"branch_weights", i32 2, i32 10}

>From 8c4a86cd8ce457a0cee3acdf74e5e359255015bd Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 28 Dec 2023 01:32:52 +0800
Subject: [PATCH 2/3] [InstCombine] Canonicalize `gep T* X, V / sizeof(T)` to
 `gep i8* X, V`

---
 .../InstCombine/InstructionCombining.cpp      | 26 ++++++++++++-------
 .../Transforms/InstCombine/getelementptr.ll   | 12 +++------
 2 files changed, 20 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index 7f5a7b666903db..fed311cec24a2f 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2470,20 +2470,18 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
       uint64_t TyAllocSize = DL.getTypeAllocSize(GEPEltType).getFixedValue();
 
       bool Matched = false;
-      uint64_t C;
       Value *V = nullptr;
       if (TyAllocSize == 1) {
         V = GEP.getOperand(1);
         Matched = true;
-      } else if (match(GEP.getOperand(1),
-                       m_AShr(m_Value(V), m_ConstantInt(C)))) {
-        if (TyAllocSize == 1ULL << C)
-          Matched = true;
-      } else if (match(GEP.getOperand(1),
-                       m_SDiv(m_Value(V), m_ConstantInt(C)))) {
-        if (TyAllocSize == C)
-          Matched = true;
-      }
+      } else if (has_single_bit(TyAllocSize) &&
+                 match(GEP.getOperand(1),
+                       m_Exact(m_AShr(m_Value(V), m_SpecificInt(countr_zero(
+                                                      TyAllocSize))))))
+        Matched = true;
+      else if (match(GEP.getOperand(1),
+                     m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize)))))
+        Matched = true;
 
       // Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y), but
       // only if both point to the same underlying object (otherwise provenance
@@ -2494,6 +2492,14 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
           match(V, m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
           getUnderlyingObject(X) == getUnderlyingObject(Y))
         return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType);
+
+      // Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V)
+      if (Matched && TyAllocSize != 1) {
+        GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
+            Builder.getInt8Ty(), GEP.getPointerOperand(), V);
+        NewGEP->setIsInBounds(GEP.isInBounds());
+        return NewGEP;
+      }
     }
   }
   // We do not handle pointer-vector geps here.
diff --git a/llvm/test/Transforms/InstCombine/getelementptr.ll b/llvm/test/Transforms/InstCombine/getelementptr.ll
index 0ecf166b84da6d..7d67f2583aa24d 100644
--- a/llvm/test/Transforms/InstCombine/getelementptr.ll
+++ b/llvm/test/Transforms/InstCombine/getelementptr.ll
@@ -1455,8 +1455,7 @@ define ptr @const_gep_chain(ptr %p, i64 %a) {
 
 define ptr @gep_sdiv(ptr %p, i64 %off) {
 ; CHECK-LABEL: @gep_sdiv(
-; CHECK-NEXT:    [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7
-; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
 ; CHECK-NEXT:    ret ptr [[PTR]]
 ;
   %index = sdiv exact i64 %off, 7
@@ -1466,8 +1465,7 @@ define ptr @gep_sdiv(ptr %p, i64 %off) {
 
 define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) {
 ; CHECK-LABEL: @gep_sdiv_vec(
-; CHECK-NEXT:    [[INDEX:%.*]] = sdiv exact <2 x i64> [[OFF:%.*]], <i64 7, i64 7>
-; CHECK-NEXT:    [[PTR:%.*]] = getelementptr [[STRUCT_C:%.*]], <2 x ptr> [[P:%.*]], <2 x i64> [[INDEX]]
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i8, <2 x ptr> [[P:%.*]], <2 x i64> [[OFF:%.*]]
 ; CHECK-NEXT:    ret <2 x ptr> [[PTR]]
 ;
   %index = sdiv exact <2 x i64> %off, <i64 7, i64 7>
@@ -1477,8 +1475,7 @@ define <2 x ptr> @gep_sdiv_vec(<2 x ptr> %p, <2 x i64> %off) {
 
 define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) {
 ; CHECK-LABEL: @gep_sdiv_inbounds(
-; CHECK-NEXT:    [[INDEX:%.*]] = sdiv exact i64 [[OFF:%.*]], 7
-; CHECK-NEXT:    [[PTR:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
 ; CHECK-NEXT:    ret ptr [[PTR]]
 ;
   %index = sdiv exact i64 %off, 7
@@ -1488,8 +1485,7 @@ define ptr @gep_sdiv_inbounds(ptr %p, i64 %off) {
 
 define ptr @gep_ashr(ptr %p, i64 %off) {
 ; CHECK-LABEL: @gep_ashr(
-; CHECK-NEXT:    [[INDEX:%.*]] = ashr exact i64 [[OFF:%.*]], 2
-; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i32, ptr [[P:%.*]], i64 [[INDEX]]
+; CHECK-NEXT:    [[PTR:%.*]] = getelementptr i8, ptr [[P:%.*]], i64 [[OFF:%.*]]
 ; CHECK-NEXT:    ret ptr [[PTR]]
 ;
   %index = ashr exact i64 %off, 2

>From 57533c1c2847f40b4ebe00a93afee2cc5a599f75 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Fri, 29 Dec 2023 01:03:28 +0800
Subject: [PATCH 3/3] [InstCombine] Do the ptrtoint transform after
 canonicalizing the SrcTy to i8

---
 .../InstCombine/InstructionCombining.cpp      | 52 ++++++++-----------
 1 file changed, 23 insertions(+), 29 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index fed311cec24a2f..df393d72a85bf2 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2469,36 +2469,30 @@ Instruction *InstCombinerImpl::visitGetElementPtrInst(GetElementPtrInst &GEP) {
         DL.getIndexSizeInBits(AS)) {
       uint64_t TyAllocSize = DL.getTypeAllocSize(GEPEltType).getFixedValue();
 
-      bool Matched = false;
-      Value *V = nullptr;
       if (TyAllocSize == 1) {
-        V = GEP.getOperand(1);
-        Matched = true;
-      } else if (has_single_bit(TyAllocSize) &&
-                 match(GEP.getOperand(1),
-                       m_Exact(m_AShr(m_Value(V), m_SpecificInt(countr_zero(
-                                                      TyAllocSize))))))
-        Matched = true;
-      else if (match(GEP.getOperand(1),
-                     m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize)))))
-        Matched = true;
-
-      // Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y), but
-      // only if both point to the same underlying object (otherwise provenance
-      // is not necessarily retained).
-      Value *Y;
-      Value *X = GEP.getOperand(0);
-      if (Matched &&
-          match(V, m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
-          getUnderlyingObject(X) == getUnderlyingObject(Y))
-        return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType);
-
-      // Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V)
-      if (Matched && TyAllocSize != 1) {
-        GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
-            Builder.getInt8Ty(), GEP.getPointerOperand(), V);
-        NewGEP->setIsInBounds(GEP.isInBounds());
-        return NewGEP;
+        // Canonicalize (gep i8* X, (ptrtoint Y)-(ptrtoint X)) to (bitcast Y),
+        // but only if both point to the same underlying object (otherwise
+        // provenance is not necessarily retained).
+        Value *X = GEP.getPointerOperand();
+        Value *Y;
+        if (match(GEP.getOperand(1),
+                  m_Sub(m_PtrToInt(m_Value(Y)), m_PtrToInt(m_Specific(X)))) &&
+            getUnderlyingObject(X) == getUnderlyingObject(Y))
+          return CastInst::CreatePointerBitCastOrAddrSpaceCast(Y, GEPType);
+      } else {
+        // Canonicalize (gep T* X, V / sizeof(T)) to (gep i8* X, V)
+        Value *V;
+        if ((has_single_bit(TyAllocSize) &&
+             match(GEP.getOperand(1),
+                   m_Exact(m_AShr(m_Value(V),
+                                  m_SpecificInt(countr_zero(TyAllocSize)))))) ||
+            match(GEP.getOperand(1),
+                  m_Exact(m_SDiv(m_Value(V), m_SpecificInt(TyAllocSize))))) {
+          GetElementPtrInst *NewGEP = GetElementPtrInst::Create(
+              Builder.getInt8Ty(), GEP.getPointerOperand(), V);
+          NewGEP->setIsInBounds(GEP.isInBounds());
+          return NewGEP;
+        }
       }
     }
   }



More information about the llvm-commits mailing list