[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