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(
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
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
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(
; 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
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
; 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
}
; 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
}
; 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
}