blob: f58ee299cba0759ba39e4d4ccb2d4002768970b6 [file] [log] [blame]
Hal Finkel7e184492014-09-07 20:29:59 +00001; RUN: opt -S -jump-threading -dce < %s | FileCheck %s
2target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3target triple = "x86_64-unknown-linux-gnu"
4
5; Function Attrs: nounwind uwtable
6define i32 @test1(i32 %a, i32 %b) #0 {
7entry:
8 %cmp = icmp sgt i32 %a, 5
Daniel Jasperaec2fa32016-12-19 08:22:17 +00009 tail call void @llvm.assume(i1 %cmp)
Hal Finkel7e184492014-09-07 20:29:59 +000010 %cmp1 = icmp sgt i32 %b, 1234
11 br i1 %cmp1, label %if.then, label %if.else
12
13; CHECK-LABEL: @test1
14; CHECK: icmp sgt i32 %a, 5
15; CHECK: call void @llvm.assume
16; CHECK-NOT: icmp sgt i32 %a, 3
17; CHECK: ret i32
18
19if.then: ; preds = %entry
20 %cmp2 = icmp sgt i32 %a, 3
21 br i1 %cmp2, label %if.then3, label %return
22
23if.then3: ; preds = %if.then
David Blaikie23af6482015-04-16 23:24:18 +000024 tail call void (...) @bar() #1
Hal Finkel7e184492014-09-07 20:29:59 +000025 br label %return
26
27if.else: ; preds = %entry
David Blaikie23af6482015-04-16 23:24:18 +000028 tail call void (...) @car() #1
Hal Finkel7e184492014-09-07 20:29:59 +000029 br label %return
30
31return: ; preds = %if.else, %if.then, %if.then3
32 %retval.0 = phi i32 [ 1, %if.then3 ], [ 0, %if.then ], [ 0, %if.else ]
33 ret i32 %retval.0
34}
35
36define i32 @test2(i32 %a) #0 {
37entry:
38 %cmp = icmp sgt i32 %a, 5
Daniel Jasperaec2fa32016-12-19 08:22:17 +000039 tail call void @llvm.assume(i1 %cmp)
Hal Finkel7e184492014-09-07 20:29:59 +000040 %cmp1 = icmp sgt i32 %a, 3
41 br i1 %cmp1, label %if.then, label %return
42
43; CHECK-LABEL: @test2
44; CHECK: icmp sgt i32 %a, 5
45; CHECK: tail call void @llvm.assume
David Blaikie23af6482015-04-16 23:24:18 +000046; CHECK: tail call void (...) @bar()
Hal Finkel7e184492014-09-07 20:29:59 +000047; CHECK: ret i32 1
48
49
50if.then: ; preds = %entry
David Blaikie23af6482015-04-16 23:24:18 +000051 tail call void (...) @bar() #1
Hal Finkel7e184492014-09-07 20:29:59 +000052 br label %return
53
54return: ; preds = %entry, %if.then
55 %retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ]
56 ret i32 %retval.0
57}
58
Anna Thomas7bca5912017-05-18 13:12:18 +000059@g = external global i32
60
61; Check that we do prove a fact using an assume within the block.
Anna Thomasc07d5542017-05-23 13:36:25 +000062; We can fold the assume based on the semantics of assume.
Anna Thomas7bca5912017-05-18 13:12:18 +000063define void @can_fold_assume(i32* %array) {
Anna Thomasc07d5542017-05-23 13:36:25 +000064; CHECK-LABEL: @can_fold_assume
65; CHECK-NOT: call void @llvm.assume
66; CHECK-NOT: br
67; CHECK: ret void
Anna Thomas7bca5912017-05-18 13:12:18 +000068 %notnull = icmp ne i32* %array, null
69 call void @llvm.assume(i1 %notnull)
70 br i1 %notnull, label %normal, label %error
71
72normal:
73 ret void
74
75error:
76 store atomic i32 0, i32* @g unordered, align 4
77 ret void
78}
79
80declare void @f(i1)
81declare void @exit()
82; We can fold the assume but not the uses before the assume.
Anna Thomasc07d5542017-05-23 13:36:25 +000083define void @cannot_fold_use_before_assume(i32* %array) {
84; CHECK-LABEL:@cannot_fold_use_before_assume
Anna Thomas7bca5912017-05-18 13:12:18 +000085; CHECK: @f(i1 %notnull)
86; CHECK-NEXT: exit()
Anna Thomasc07d5542017-05-23 13:36:25 +000087; CHECK-NOT: assume
Anna Thomas7bca5912017-05-18 13:12:18 +000088; CHECK-NEXT: ret void
89 %notnull = icmp ne i32* %array, null
90 call void @f(i1 %notnull)
91 call void @exit()
92 call void @llvm.assume(i1 %notnull)
93 br i1 %notnull, label %normal, label %error
94
95normal:
96 ret void
97
98error:
99 store atomic i32 0, i32* @g unordered, align 4
100 ret void
101}
102
Anna Thomasc07d5542017-05-23 13:36:25 +0000103declare void @dummy(i1) nounwind argmemonly
104define void @can_fold_some_use_before_assume(i32* %array) {
105
106; CHECK-LABEL:@can_fold_some_use_before_assume
107; CHECK: @f(i1 %notnull)
108; CHECK-NEXT: @dummy(i1 true)
109; CHECK-NOT: assume
110; CHECK-NEXT: ret void
111 %notnull = icmp ne i32* %array, null
112 call void @f(i1 %notnull)
113 call void @dummy(i1 %notnull)
114 call void @llvm.assume(i1 %notnull)
115 br i1 %notnull, label %normal, label %error
116
117normal:
118 ret void
119
120error:
121 store atomic i32 0, i32* @g unordered, align 4
122 ret void
123
124}
125
126; FIXME: can fold assume and all uses before/after assume.
127; because the trapping exit call is after the assume.
128define void @can_fold_assume_and_all_uses(i32* %array) {
129; CHECK-LABEL:@can_fold_assume_and_all_uses
130; CHECK: @dummy(i1 %notnull)
131; CHECK-NEXT: assume(i1 %notnull)
132; CHECK-NEXT: exit()
133; CHECK-NEXT: %notnull2 = or i1 true, false
134; CHECK-NEXT: @f(i1 %notnull2)
135; CHECK-NEXT: ret void
136 %notnull = icmp ne i32* %array, null
137 call void @dummy(i1 %notnull)
138 call void @llvm.assume(i1 %notnull)
139 call void @exit()
140 br i1 %notnull, label %normal, label %error
141
142normal:
143 %notnull2 = or i1 %notnull, false
144 call void @f(i1 %notnull2)
145 ret void
146
147error:
148 store atomic i32 0, i32* @g unordered, align 4
149 ret void
150}
151
152declare void @fz(i8)
153; FIXME: We can fold assume to true, and the use after assume, but we do not do so
154; currently, because of the function call after the assume.
155define void @can_fold_assume2(i32* %array) {
156
157; CHECK-LABEL:@can_fold_assume2
158; CHECK: @f(i1 %notnull)
159; CHECK-NEXT: assume(i1 %notnull)
160; CHECK-NEXT: znotnull = zext i1 %notnull to i8
161; CHECK-NEXT: @f(i1 %notnull)
162; CHECK-NEXT: @f(i1 true)
163; CHECK-NEXT: @fz(i8 %znotnull)
164; CHECK-NEXT: ret void
165 %notnull = icmp ne i32* %array, null
166 call void @f(i1 %notnull)
167 call void @llvm.assume(i1 %notnull)
168 %znotnull = zext i1 %notnull to i8
169 call void @f(i1 %notnull)
170 br i1 %notnull, label %normal, label %error
171
172normal:
173 call void @f(i1 %notnull)
174 call void @fz(i8 %znotnull)
175 ret void
176
177error:
178 store atomic i32 0, i32* @g unordered, align 4
179 ret void
180}
181
182declare void @llvm.experimental.guard(i1, ...)
183; FIXME: We can fold assume to true, but we do not do so
184; because of the guard following the assume.
185define void @can_fold_assume3(i32* %array){
186
187; CHECK-LABEL:@can_fold_assume3
188; CHECK: @f(i1 %notnull)
189; CHECK-NEXT: assume(i1 %notnull)
190; CHECK-NEXT: guard(i1 %notnull)
191; CHECK-NEXT: znotnull = zext i1 true to i8
192; CHECK-NEXT: @f(i1 true)
193; CHECK-NEXT: @fz(i8 %znotnull)
194; CHECK-NEXT: ret void
195 %notnull = icmp ne i32* %array, null
196 call void @f(i1 %notnull)
197 call void @llvm.assume(i1 %notnull)
198 call void(i1, ...) @llvm.experimental.guard(i1 %notnull) [ "deopt"() ]
199 %znotnull = zext i1 %notnull to i8
200 br i1 %notnull, label %normal, label %error
201
202normal:
203 call void @f(i1 %notnull)
204 call void @fz(i8 %znotnull)
205 ret void
206
207error:
208 store atomic i32 0, i32* @g unordered, align 4
209 ret void
210}
211
212
213; can fold all uses and remove the cond
214define void @can_fold_assume4(i32* %array) {
215; CHECK-LABEL: can_fold_assume4
216; CHECK-NOT: notnull
217; CHECK: dummy(i1 true)
218; CHECK-NEXT: ret void
219 %notnull = icmp ne i32* %array, null
220 call void @exit()
221 call void @dummy(i1 %notnull)
222 call void @llvm.assume(i1 %notnull)
223 br i1 %notnull, label %normal, label %error
224
225normal:
226 ret void
227
228error:
229 store atomic i32 0, i32* @g unordered, align 4
230 ret void
231}
Hal Finkel7e184492014-09-07 20:29:59 +0000232; Function Attrs: nounwind
233declare void @llvm.assume(i1) #1
234
235declare void @bar(...)
236
237declare void @car(...)
238
239attributes #0 = { nounwind uwtable }
240attributes #1 = { nounwind }
241