[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / JumpThreading / assume.ll
blob08775b01d75094c07d34aea24f18827af6d38182
1 ; RUN: opt -S -jump-threading -dce < %s | FileCheck %s
2 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
3 target triple = "x86_64-unknown-linux-gnu"
5 ; Function Attrs: nounwind uwtable
6 define i32 @test1(i32 %a, i32 %b) #0 {
7 entry:
8   %cmp = icmp sgt i32 %a, 5
9   tail call void @llvm.assume(i1 %cmp)
10   %cmp1 = icmp sgt i32 %b, 1234
11   br i1 %cmp1, label %if.then, label %if.else
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
19 if.then:                                          ; preds = %entry
20   %cmp2 = icmp sgt i32 %a, 3
21   br i1 %cmp2, label %if.then3, label %return
23 if.then3:                                         ; preds = %if.then
24   tail call void (...) @bar() #1
25   br label %return
27 if.else:                                          ; preds = %entry
28   tail call void (...) @car() #1
29   br label %return
31 return:                                           ; 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
36 define i32 @test2(i32 %a) #0 {
37 entry:
38   %cmp = icmp sgt i32 %a, 5
39   tail call void @llvm.assume(i1 %cmp)
40   %cmp1 = icmp sgt i32 %a, 3
41   br i1 %cmp1, label %if.then, label %return
43 ; CHECK-LABEL: @test2
44 ; CHECK: icmp sgt i32 %a, 5
45 ; CHECK: tail call void @llvm.assume
46 ; CHECK: tail call void (...) @bar()
47 ; CHECK: ret i32 1
50 if.then:                                          ; preds = %entry
51   tail call void (...) @bar() #1
52   br label %return
54 return:                                           ; preds = %entry, %if.then
55   %retval.0 = phi i32 [ 1, %if.then ], [ 0, %entry ]
56   ret i32 %retval.0
59 @g = external global i32
61 ; Check that we do prove a fact using an assume within the block.
62 ; We can fold the assume based on the semantics of assume.
63 define void @can_fold_assume(i32* %array) {
64 ; CHECK-LABEL: @can_fold_assume
65 ; CHECK-NOT: call void @llvm.assume
66 ; CHECK-NOT: br
67 ; CHECK: ret void
68   %notnull = icmp ne i32* %array, null
69   call void @llvm.assume(i1 %notnull)
70   br i1 %notnull, label %normal, label %error
72 normal:
73   ret void
75 error:
76   store atomic i32 0, i32* @g unordered, align 4
77   ret void
80 declare void @f(i1)
81 declare void @exit()
82 ; We can fold the assume but not the uses before the assume.
83 define void @cannot_fold_use_before_assume(i32* %array) {
84 ; CHECK-LABEL:@cannot_fold_use_before_assume
85 ; CHECK: @f(i1 %notnull)
86 ; CHECK-NEXT: exit()
87 ; CHECK-NOT: assume
88 ; 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
95 normal:
96   ret void
98 error:
99   store atomic i32 0, i32* @g unordered, align 4
100   ret void
103 declare void @dummy(i1) nounwind willreturn
104 define void @can_fold_some_use_before_assume(i32* %array) {
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
117 normal:
118   ret void
120 error:
121   store atomic i32 0, i32* @g unordered, align 4
122   ret void
126 ; FIXME: can fold assume and all uses before/after assume.
127 ; because the trapping exit call is after the assume.
128 define 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
142 normal:
143   %notnull2 = or i1 %notnull, false
144   call void @f(i1 %notnull2)
145   ret void
147 error:
148   store atomic i32 0, i32* @g unordered, align 4
149   ret void
152 declare 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.
155 define void @can_fold_assume2(i32* %array) {
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
172 normal:
173   call void @f(i1 %notnull)
174   call void @fz(i8 %znotnull)
175   ret void
177 error:
178   store atomic i32 0, i32* @g unordered, align 4
179   ret void
182 declare 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.
185 define void @can_fold_assume3(i32* %array){
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
202 normal:
203   call void @f(i1 %notnull)
204   call void @fz(i8 %znotnull)
205   ret void
207 error:
208   store atomic i32 0, i32* @g unordered, align 4
209   ret void
213 ; can fold all uses and remove the cond
214 define 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
225 normal:
226   ret void
228 error:
229   store atomic i32 0, i32* @g unordered, align 4
230   ret void
232 ; Function Attrs: nounwind
233 declare void @llvm.assume(i1) #1
235 declare void @bar(...)
237 declare void @car(...)
239 attributes #0 = { nounwind uwtable }
240 attributes #1 = { nounwind }