1; RUN: opt -instcombine -S  < %s | FileCheck %s
2
3target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:32-f32:32:32-f64:32:32-v64:64:64-v128:128:128-a0:0:64"
4
5define i32 *@test1(i32* %A, i32 %Offset) {
6entry:
7  %tmp = getelementptr inbounds i32, i32* %A, i32 %Offset
8  br label %bb
9
10bb:
11  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
12  %LHS = getelementptr inbounds i32, i32* %A, i32 100
13  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
14  %cond = icmp ult i32 * %LHS, %RHS
15  br i1 %cond, label %bb2, label %bb
16
17bb2:
18  ret i32* %RHS
19
20; CHECK-LABEL: @test1(
21; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %entry ]
22; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
23; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
24; CHECK:  br i1 %cond, label %bb2, label %bb
25; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %A, i32 %[[INDEX]]
26; CHECK:  ret i32* %[[PTR]]
27}
28
29define i32 *@test2(i32 %A, i32 %Offset) {
30entry:
31  %A.ptr = inttoptr i32 %A to i32*
32  %tmp = getelementptr inbounds i32, i32* %A.ptr, i32 %Offset
33  br label %bb
34
35bb:
36  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
37  %LHS = getelementptr inbounds i32, i32* %A.ptr, i32 100
38  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
39  %cmp0 = ptrtoint i32 *%LHS to i32
40  %cmp1 = ptrtoint i32 *%RHS to i32
41  %cond = icmp ult i32 %cmp0, %cmp1
42  br i1 %cond, label %bb2, label %bb
43
44bb2:
45  ret i32* %RHS
46
47; CHECK-LABEL: @test2(
48; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %entry ]
49; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
50; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
51; CHECK:  br i1 %cond, label %bb2, label %bb
52; CHECK:  %[[TOPTR:[0-9A-Za-z.]+]] = inttoptr i32 %[[ADD:[0-9A-Za-z.]+]] to i32*
53; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %[[TOPTR]], i32 %[[INDEX]]
54; CHECK:  ret i32* %[[PTR]]
55}
56
57; Perform the transformation only if we know that the GEPs used are inbounds.
58define i32 *@test3(i32* %A, i32 %Offset) {
59entry:
60  %tmp = getelementptr i32, i32* %A, i32 %Offset
61  br label %bb
62
63bb:
64  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
65  %LHS = getelementptr i32, i32* %A, i32 100
66  %RHS.next = getelementptr i32, i32* %RHS, i64 1
67  %cond = icmp ult i32 * %LHS, %RHS
68  br i1 %cond, label %bb2, label %bb
69
70bb2:
71  ret i32* %RHS
72
73; CHECK-LABEL: @test3(
74; CHECK-NOT:  %cond = icmp sgt i32 %{{[0-9A-Za-z.]+}}, 100
75}
76
77; An inttoptr that requires an extension or truncation will be opaque when determining
78; the base pointer. In this case we can still perform the transformation by considering
79; A.ptr as being the base pointer.
80define i32 *@test4(i16 %A, i32 %Offset) {
81entry:
82  %A.ptr = inttoptr i16 %A to i32*
83  %tmp = getelementptr inbounds i32, i32* %A.ptr, i32 %Offset
84  br label %bb
85
86bb:
87  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %entry ]
88  %LHS = getelementptr inbounds i32, i32* %A.ptr, i32 100
89  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
90  %cmp0 = ptrtoint i32 *%LHS to i32
91  %cmp1 = ptrtoint i32 *%RHS to i32
92  %cond = icmp ult i32 %cmp0, %cmp1
93  br i1 %cond, label %bb2, label %bb
94
95bb2:
96  ret i32* %RHS
97
98; CHECK-LABEL: @test4(
99; CHECK:  %cond = icmp sgt i32 %{{[0-9A-Za-z.]+}}, 100
100}
101
102declare i32* @fun_ptr()
103
104define i32 *@test5(i32 %Offset) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
105entry:
106 %A = invoke i32 *@fun_ptr() to label %cont unwind label %lpad
107
108cont:
109  %tmp = getelementptr inbounds i32, i32* %A, i32 %Offset
110  br label %bb
111
112bb:
113  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %cont ]
114  %LHS = getelementptr inbounds i32, i32* %A, i32 100
115  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
116  %cond = icmp ult i32 * %LHS, %RHS
117  br i1 %cond, label %bb2, label %bb
118
119bb2:
120  ret i32* %RHS
121
122lpad:
123  %l = landingpad { i8*, i32 } cleanup
124  ret i32* null
125
126; CHECK-LABEL: @test5(
127; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %cont ]
128; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
129; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
130; CHECK:  br i1 %cond, label %bb2, label %bb
131; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %A, i32 %[[INDEX]]
132; CHECK:  ret i32* %[[PTR]]
133}
134
135declare i32 @fun_i32()
136
137define i32 *@test6(i32 %Offset) personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
138entry:
139 %A = invoke i32 @fun_i32() to label %cont unwind label %lpad
140
141cont:
142  %A.ptr = inttoptr i32 %A to i32*
143  %tmp = getelementptr inbounds i32, i32* %A.ptr, i32 %Offset
144  br label %bb
145
146bb:
147  %RHS = phi i32* [ %RHS.next, %bb ], [ %tmp, %cont ]
148  %LHS = getelementptr inbounds i32, i32* %A.ptr, i32 100
149  %RHS.next = getelementptr inbounds i32, i32* %RHS, i64 1
150  %cond = icmp ult i32 * %LHS, %RHS
151  br i1 %cond, label %bb2, label %bb
152
153bb2:
154  ret i32* %RHS
155
156lpad:
157  %l = landingpad { i8*, i32 } cleanup
158  ret i32* null
159
160; CHECK-LABEL: @test6(
161; CHECK:  %[[INDEX:[0-9A-Za-z.]+]] = phi i32 [ %[[ADD:[0-9A-Za-z.]+]], %bb ], [ %Offset, %cont ]
162; CHECK:  %[[ADD]] = add nsw i32 %[[INDEX]], 1
163; CHECK:  %cond = icmp sgt i32 %[[INDEX]], 100
164; CHECK:  br i1 %cond, label %bb2, label %bb
165; CHECK:  %[[TOPTR:[0-9A-Za-z.]+]] = inttoptr i32 %[[ADD:[0-9A-Za-z.]+]] to i32*
166; CHECK:  %[[PTR:[0-9A-Za-z.]+]] = getelementptr inbounds i32, i32* %[[TOPTR]], i32 %[[INDEX]]
167; CHECK:  ret i32* %[[PTR]]
168}
169
170declare i32 @__gxx_personality_v0(...)
171