[llvm] a911914 - [InstCombine] Changing constant-indexed GEP of GEP to i8* for merging

William Huang via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 30 14:27:12 PDT 2022


Author: William Huang
Date: 2022-06-30T21:26:11Z
New Revision: a9119143a2d1f4d0d0bc1fe0d819e5351b4e0deb

URL: https://github.com/llvm/llvm-project/commit/a9119143a2d1f4d0d0bc1fe0d819e5351b4e0deb
DIFF: https://github.com/llvm/llvm-project/commit/a9119143a2d1f4d0d0bc1fe0d819e5351b4e0deb.diff

LOG: [InstCombine] Changing constant-indexed GEP of GEP to i8* for merging

When merging GEP of GEP with constant indices, if the second GEP's offset is not divisible by the first GEP's element size, convert both type to i8* and merge.

Reviewed By: nikic

Differential Revision: https://reviews.llvm.org/D125934

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
    llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
    llvm/test/Transforms/InstCombine/opaque-ptr.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
index cfcf37b63d15..0816a4a575d9 100644
--- a/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstructionCombining.cpp
@@ -2023,11 +2023,23 @@ Instruction *InstCombinerImpl::visitGEPOfGEP(GetElementPtrInst &GEP,
     if (!GEP.accumulateConstantOffset(DL, Offset))
       return nullptr;
 
+    APInt OffsetOld = Offset;
     // Convert the total offset back into indices.
     SmallVector<APInt> ConstIndices =
         DL.getGEPIndicesForOffset(BaseType, Offset);
-    if (!Offset.isZero() || (!IsFirstType && !ConstIndices[0].isZero()))
+    if (!Offset.isZero() || (!IsFirstType && !ConstIndices[0].isZero())) {
+      // If both GEP are constant-indexed, and cannot be merged in either way,
+      // convert them to a GEP of i8.
+      if (Src->hasAllConstantIndices())
+        return isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP))
+            ? GetElementPtrInst::CreateInBounds(
+                Builder.getInt8Ty(), Src->getOperand(0),
+                Builder.getInt(OffsetOld), GEP.getName())
+            : GetElementPtrInst::Create(
+                Builder.getInt8Ty(), Src->getOperand(0),
+                Builder.getInt(OffsetOld), GEP.getName());
       return nullptr;
+    }
 
     bool IsInBounds = isMergedGEPInBounds(*Src, *cast<GEPOperator>(&GEP));
     SmallVector<Value *> Indices;

diff  --git a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
index b82c366ca9e9..9e11070fef87 100644
--- a/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
+++ b/llvm/test/Transforms/InstCombine/gep-merge-constant-indices.ll
@@ -20,7 +20,7 @@ define ptr @mergeBasic(ptr %p) {
   ret ptr %2
 }
 
-; First GEP is merged into the second.
+; Converted to i8* and merged.
 ; result = (i8*) p + 10
 define ptr @mergeDifferentTypes(ptr %p) {
 ; CHECK-LABEL: @mergeDifferentTypes(
@@ -32,13 +32,12 @@ define ptr @mergeDifferentTypes(ptr %p) {
   ret ptr %2
 }
 
-; Second GEP is merged into the first.
+; Converted to i8* and merged.
 ; result = (i8*) p + 10
 define ptr @mergeReverse(ptr %p) {
 ; CHECK-LABEL: @mergeReverse(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 2
-; CHECK-NEXT:    ret ptr [[TMP2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 10
+; CHECK-NEXT:    ret ptr [[TMP1]]
 ;
   %1 = getelementptr inbounds i64, ptr %p, i64 1
   %2 = getelementptr inbounds i8, ptr %1, i64 2
@@ -67,36 +66,24 @@ define ptr @array1(ptr %p) {
   ret ptr %2
 }
 
-; result = (i8*) p + 14
-define ptr @array2(ptr %p, i64 %a) {
+; Converted to i8* and merged.
+; result = (i8*) p + 20
+define ptr @array2(ptr %p) {
 ; CHECK-LABEL: @array2(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [7 x i32], ptr [[P:%.*]], i64 0, i64 3
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 2
-; CHECK-NEXT:    ret ptr [[TMP2]]
-;
-  %1 = getelementptr inbounds [7 x i32], ptr %p, i64 0, i64 3
-  %2 = getelementptr inbounds i8, ptr %1, i64 2
-  ret ptr %2
-}
-
-; result = (i8*) (([3 x i8]*) p + 6) + 2
-define ptr @array3(ptr %p) {
-; CHECK-LABEL: @array3(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 2
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [3 x i8], ptr [[TMP1]], i64 1, i64 1
-; CHECK-NEXT:    ret ptr [[TMP2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 20
+; CHECK-NEXT:    ret ptr [[TMP1]]
 ;
   %1 = getelementptr inbounds i64, ptr %p, i64 2
   %2 = getelementptr inbounds [3 x i8], ptr %1, i64 1, i64 1
   ret ptr %2
 }
 
-; result = (struct.C*) p + 3
+; Converted to i8* and merged.
+; result = (i8*) p + 36
 define ptr @struct1(ptr %p) {
 ; CHECK-LABEL: @struct1(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 3
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 1
-; CHECK-NEXT:    ret ptr [[TMP2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 36
+; CHECK-NEXT:    ret ptr [[TMP1]]
 ;
   %1 = getelementptr inbounds i64, ptr %p, i64 3
   %2 = getelementptr inbounds %struct.C, ptr %1, i64 1
@@ -114,28 +101,6 @@ define ptr @struct2(ptr %p) {
   ret ptr %2
 }
 
-; result = (i8*) p - 4
-define ptr @struct3(ptr %p, i64 %a) {
-; CHECK-LABEL: @struct3(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 -4
-; CHECK-NEXT:    ret ptr [[TMP1]]
-;
-  %1 = getelementptr inbounds i8, ptr %p, i64 -128
-  %2 = getelementptr inbounds %struct.A, ptr %1, i64 0, i32 1
-  ret ptr %2
-}
-; result = ((struct.C*) p + 1).member2
-define ptr @struct4(ptr %p, i64 %a) {
-; CHECK-LABEL: @struct4(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 1
-; CHECK-NEXT:    ret ptr [[TMP2]]
-;
-  %1 = getelementptr inbounds i64, ptr %p, i64 1
-  %2 = getelementptr inbounds %struct.C, ptr %1, i64 1
-  ret ptr %2
-}
-
 ; result = (i8*) &((struct.B) p)[0].member2.member0 + 7
 define ptr @structStruct(ptr %p) {
 ; CHECK-LABEL: @structStruct(
@@ -150,73 +115,33 @@ define ptr @structStruct(ptr %p) {
 ; First GEP offset is not divisible by last GEP's source element size, but first
 ; GEP points to an array such that the last GEP offset is divisible by the
 ; array's element size, so the first GEP can be rewritten with an extra index.
-; result = (i16*) &((struct.B*) p)[0].member1 + 2
-define ptr @appendIndex(ptr %p) {
+; result = (i16*) &((struct.B*) p)[i].member1 + 2
+define ptr @appendIndex(ptr %p, i64 %i) {
 ; CHECK-LABEL: @appendIndex(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 0, i32 1, i64 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[P:%.*]], i64 [[I:%.*]], i32 1, i64 2
 ; CHECK-NEXT:    ret ptr [[TMP1]]
 ;
-  %1 = getelementptr inbounds %struct.B, ptr %p, i64 0, i32 1
+  %1 = getelementptr inbounds %struct.B, ptr %p, i64 %i, i32 1
   %2 = getelementptr inbounds i32, ptr %1, i64 1
   ret ptr %2
 }
 
-; result = (i8*) &((struct.A*) &((struct.B*) p)[0].member2).member0 + 2
-define ptr @appendIndexReverse(ptr %p) {
-; CHECK-LABEL: @appendIndexReverse(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_B:%.*]], ptr [[TMP1]], i64 0, i32 1
-; CHECK-NEXT:    ret ptr [[TMP2]]
-;
-  %1 = getelementptr inbounds i64, ptr %p, i64 1
-  %2 = getelementptr inbounds %struct.B, ptr %1, i64 0, i32 1
-  ret ptr %2
-}
-
-; Constant-indexed GEP can be merged if the sum of offsets aliases a member's
-; address of one of the GEP instructions.
-; result = &((struct.C*) p + 2).member1
-define ptr @structMemberAliasing(ptr %p, i64 %a) {
-; CHECK-LABEL: @structMemberAliasing(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i64, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 1, i32 2
-; CHECK-NEXT:    ret ptr [[TMP2]]
-;
-  %1 = getelementptr inbounds i64, ptr %p, i64 1
-  %2 = getelementptr inbounds %struct.C, ptr %1, i64 1, i32 2
-  ret ptr %2
-}
-
-; Negative test. Offset of either GEP is not divisible by the other's size.
+; Offset of either GEP is not divisible by the other's size, converted to i8*
+; and merged.
 ; Here i24 is 8-bit aligned.
+; result = (i8*) p + 7
 define ptr @notDivisible(ptr %p) {
 ; CHECK-LABEL: @notDivisible(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i24, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 1
-; CHECK-NEXT:    ret ptr [[TMP2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 7
+; CHECK-NEXT:    ret ptr [[TMP1]]
 ;
   %1 = getelementptr inbounds i24, ptr %p, i64 1
   %2 = getelementptr inbounds i32, ptr %1, i64 1
   ret ptr %2
 }
 
-; Two GEP instructions can be merged if one is constant-indexed and the other
-; is a sequential type with a constant last index, and the constant offset is
-; divisible by the sequential type size.
-; result = (i32*) (([4 x i32]*) p + a) + 3
-define ptr @partialConstant1(ptr %p, i64 %a) {
-; CHECK-LABEL: @partialConstant1(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [4 x i32], ptr [[TMP1]], i64 [[A:%.*]], i64 2
-; CHECK-NEXT:    ret ptr [[TMP2]]
-;
-  %1 = getelementptr inbounds i32, ptr %p, i64 1
-  %2 = getelementptr inbounds [4 x i32], ptr %1, i64 %a, i64 2
-  ret ptr %2
-}
-
-; Negative test. Similar to above, but two GEP should not be merged if the
-; constant offset is not divisible.
+; Negative test. Two GEP should not be merged if not both offsets are constant
+; or divisible by the other's size.
 define ptr @partialConstant2(ptr %p, i64 %a) {
 ; CHECK-LABEL: @partialConstant2(
 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
@@ -228,8 +153,8 @@ define ptr @partialConstant2(ptr %p, i64 %a) {
   ret ptr %2
 }
 
-; Negative test. Similar to above, but two GEP should not be merged if there is
-; another use of the first GEP by the second GEP.
+; Negative test. Two GEP should not be merged if there is another use of the
+; first GEP by the second GEP.
 define ptr @partialConstant3(ptr %p) {
 ; CHECK-LABEL: @partialConstant3(
 ; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
@@ -249,12 +174,11 @@ define ptr @partialConstant3(ptr %p) {
 ; result = &((struct.C*) p + a).member2
 define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
 ; CHECK-LABEL: @partialConstantMemberAliasing1(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 [[A:%.*]], i32 1
-; CHECK-NEXT:    ret ptr [[TMP2]]
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
+; CHECK-NEXT:    ret ptr [[TMP1]]
 ;
-  %1 = getelementptr inbounds i32, ptr %p, i64 1
-  %2 = getelementptr inbounds %struct.C, ptr %1, i64 %a, i32 1
+  %1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
+  %2 = getelementptr inbounds i32, ptr %1, i64 1
   ret ptr %2
 }
 
@@ -262,12 +186,12 @@ define ptr @partialConstantMemberAliasing1(ptr %p, i64 %a) {
 ; address of another member.
 define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
 ; CHECK-LABEL: @partialConstantMemberAliasing2(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 [[A:%.*]], i32 1
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 1
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 1
 ; CHECK-NEXT:    ret ptr [[TMP2]]
 ;
-  %1 = getelementptr inbounds i8, ptr %p, i64 1
-  %2 = getelementptr inbounds %struct.C, ptr %1, i64 %a, i32 1
+  %1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 1
+  %2 = getelementptr inbounds i8, ptr %1, i64 1
   ret ptr %2
 }
 
@@ -275,11 +199,11 @@ define ptr @partialConstantMemberAliasing2(ptr %p, i64 %a) {
 ; range of the object currently pointed by the non-constant GEP.
 define ptr @partialConstantMemberAliasing3(ptr %p, i64 %a) {
 ; CHECK-LABEL: @partialConstantMemberAliasing3(
-; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
-; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[TMP1]], i64 [[A:%.*]], i32 2
+; CHECK-NEXT:    [[TMP1:%.*]] = getelementptr inbounds [[STRUCT_C:%.*]], ptr [[P:%.*]], i64 [[A:%.*]], i32 2
+; CHECK-NEXT:    [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 1
 ; CHECK-NEXT:    ret ptr [[TMP2]]
 ;
-  %1 = getelementptr inbounds i32, ptr %p, i64 1
-  %2 = getelementptr inbounds %struct.C, ptr %1, i64 %a, i32 2
+  %1 = getelementptr inbounds %struct.C, ptr %p, i64 %a, i32 2
+  %2 = getelementptr inbounds i32, ptr %1, i64 1
   ret ptr %2
 }

diff  --git a/llvm/test/Transforms/InstCombine/opaque-ptr.ll b/llvm/test/Transforms/InstCombine/opaque-ptr.ll
index c842dcb16c41..c1dec5e82d17 100644
--- a/llvm/test/Transforms/InstCombine/opaque-ptr.ll
+++ b/llvm/test/Transforms/InstCombine/opaque-ptr.ll
@@ -211,8 +211,7 @@ define ptr @geps_combinable_
diff erent_elem_type3(ptr %a) {
 
 define ptr @geps_combinable_
diff erent_elem_type4(ptr %a) {
 ; CHECK-LABEL: @geps_combinable_
diff erent_elem_type4(
-; CHECK-NEXT:    [[A2:%.*]] = getelementptr { i32, i32 }, ptr [[A:%.*]], i64 0, i32 1
-; CHECK-NEXT:    [[A3:%.*]] = getelementptr i8, ptr [[A2]], i64 10
+; CHECK-NEXT:    [[A3:%.*]] = getelementptr i8, ptr [[A:%.*]], i64 14
 ; CHECK-NEXT:    ret ptr [[A3]]
 ;
   %a2 = getelementptr { i32, i32 }, ptr %a, i32 0, i32 1


        


More information about the llvm-commits mailing list