1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -passes=instcombine -opaque-pointers -S | FileCheck %s
4 ; Constant-indexed GEP instructions in a chain of GEP instructions should be
5 ; swapped to the end whenever such transformation is valid. This allows them to
11 ; The constant-indexed GEP instruction should be swapped to the end, even
13 ; result = (((i32*) p + a) + b) + 1
14 define ptr @basic(ptr %p, i64 %a, i64 %b) {
15 ; CHECK-LABEL: @basic(
16 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
17 ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[A:%.*]]
18 ; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 [[B:%.*]]
19 ; CHECK-NEXT: ret ptr [[TMP3]]
21 %1 = getelementptr inbounds i32, ptr %p, i64 1
22 %2 = getelementptr inbounds i32, ptr %1, i64 %a
23 %3 = getelementptr inbounds i32, ptr %2, i64 %b
27 ; GEP with the last index being a constant should also be swapped.
28 define ptr @partialConstant1(ptr %p, i64 %a, i64 %b) {
29 ; CHECK-LABEL: @partialConstant1(
30 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[B:%.*]]
31 ; CHECK-NEXT: ret ptr [[TMP1]]
33 %1 = getelementptr inbounds [4 x i32], ptr %p, i64 %a, i64 1
34 %2 = getelementptr inbounds i32, ptr %p, i64 %b
38 ; Negative test. GEP should not be swapped if the last index is not a constant.
39 define ptr @partialConstant2(ptr %p, i64 %a, i64 %b) {
40 ; CHECK-LABEL: @partialConstant2(
41 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 [[B:%.*]]
42 ; CHECK-NEXT: ret ptr [[TMP1]]
44 %1 = getelementptr inbounds [4 x i32], ptr %p, i64 1, i64 %a
45 %2 = getelementptr inbounds i32, ptr %p, i64 %b
49 ; Constant-indexed GEP are merged after swawpping.
50 ; result = ((i32*) p + a) + 3
51 define ptr @merge(ptr %p, i64 %a) {
52 ; CHECK-LABEL: @merge(
53 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
54 ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[A:%.*]]
55 ; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 2
56 ; CHECK-NEXT: ret ptr [[TMP3]]
58 %1 = getelementptr inbounds i32, ptr %p, i64 1
59 %2 = getelementptr inbounds i32, ptr %1, i64 %a
60 %3 = getelementptr inbounds i32, ptr %2, i64 2
64 ; Multiple constant-indexed GEP. Note that the first two cannot be merged at
65 ; first, but after the second and third are merged, the result can be merged
66 ; with the first one on the next pass.
67 ; result = (<3 x i32>*) ((i16*) ((i8*) ptr + a) + (a * b)) + 9
68 define ptr @nested(ptr %p, i64 %a, i64 %b) {
69 ; CHECK-LABEL: @nested(
70 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds <3 x i32>, ptr [[P:%.*]], i64 1
71 ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i8, ptr [[TMP1]], i64 [[A:%.*]]
72 ; CHECK-NEXT: [[TMP3:%.*]] = mul i64 [[A]], [[B:%.*]]
73 ; CHECK-NEXT: [[TMP4:%.*]] = getelementptr inbounds <5 x i32>, ptr [[TMP2]], i64 4
74 ; CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds i16, ptr [[TMP4]], i64 [[TMP3]]
75 ; CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds <4 x i32>, ptr [[TMP5]], i64 1
76 ; CHECK-NEXT: ret ptr [[TMP6]]
78 %1 = getelementptr inbounds <3 x i32>, ptr %p, i64 1
79 %2 = getelementptr inbounds i8, ptr %1, i64 %a
81 %4 = getelementptr inbounds <5 x i32>, ptr %2, i64 4
82 %5 = getelementptr inbounds i16, ptr %4, i64 %3
83 %6 = getelementptr inbounds <4 x i32>, ptr %5, i64 1
87 ; It is valid to swap if the source operand of the first GEP has multiple uses.
88 define ptr @multipleUses1(ptr %p) {
89 ; CHECK-LABEL: @multipleUses1(
90 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
91 ; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[P]] to i64
92 ; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[TMP2]]
93 ; CHECK-NEXT: ret ptr [[TMP3]]
95 %1 = getelementptr inbounds i32, ptr %p, i64 1
96 %2 = ptrtoint ptr %p to i64
97 %3 = getelementptr inbounds i32, ptr %1, i64 %2
101 ; It is valid to swap if the second GEP has multiple uses.
102 define ptr @multipleUses2(ptr %p, i64 %a) {
103 ; CHECK-LABEL: @multipleUses2(
104 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
105 ; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[A:%.*]]
106 ; CHECK-NEXT: call void @use(ptr nonnull [[TMP2]])
107 ; CHECK-NEXT: ret ptr [[TMP2]]
109 %1 = getelementptr inbounds i32, ptr %p, i64 1
110 %2 = getelementptr inbounds i32, ptr %1, i64 %a
111 call void @use(ptr %2)
115 ; Negative test. It is not valid to swap if the first GEP has multiple uses.
116 define ptr @multipleUses3(ptr %p) {
117 ; CHECK-LABEL: @multipleUses3(
118 ; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[P:%.*]], i64 1
119 ; CHECK-NEXT: [[TMP2:%.*]] = ptrtoint ptr [[TMP1]] to i64
120 ; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[TMP2]]
121 ; CHECK-NEXT: ret ptr [[TMP3]]
123 %1 = getelementptr inbounds i32, ptr %p, i64 1
124 %2 = ptrtoint ptr %1 to i64
125 %3 = getelementptr inbounds i32, ptr %1, i64 %2