1; RUN: opt < %s -jump-threading -dce -S | FileCheck %s
2
3declare void @llvm.experimental.guard(i1, ...)
4
5declare i32 @f1()
6declare i32 @f2()
7
8define i32 @branch_implies_guard(i32 %a) {
9; CHECK-LABEL: @branch_implies_guard(
10  %cond = icmp slt i32 %a, 10
11  br i1 %cond, label %T1, label %F1
12
13T1:
14; CHECK:       T1.split
15; CHECK:         %v1 = call i32 @f1()
16; CHECK-NEXT:    %retVal
17; CHECK-NEXT:    br label %Merge
18  %v1 = call i32 @f1()
19  br label %Merge
20
21F1:
22; CHECK:       F1.split
23; CHECK:         %v2 = call i32 @f2()
24; CHECK-NEXT:    %retVal
25; CHECK-NEXT:    %condGuard
26; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
27; CHECK-NEXT:    br label %Merge
28  %v2 = call i32 @f2()
29  br label %Merge
30
31Merge:
32; CHECK:       Merge
33; CHECK-NOT:     call void(i1, ...) @llvm.experimental.guard(
34  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
35  %retVal = add i32 %retPhi, 10
36  %condGuard = icmp slt i32 %a, 20
37  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
38  ret i32 %retVal
39}
40
41define i32 @not_branch_implies_guard(i32 %a) {
42; CHECK-LABEL: @not_branch_implies_guard(
43  %cond = icmp slt i32 %a, 20
44  br i1 %cond, label %T1, label %F1
45
46T1:
47; CHECK:       T1.split:
48; CHECK-NEXT:    %v1 = call i32 @f1()
49; CHECK-NEXT:    %retVal
50; CHECK-NEXT:    %condGuard
51; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard
52; CHECK-NEXT:    br label %Merge
53  %v1 = call i32 @f1()
54  br label %Merge
55
56F1:
57; CHECK:       F1.split:
58; CHECK-NEXT:   %v2 = call i32 @f2()
59; CHECK-NEXT:   %retVal
60; CHECK-NEXT:   br label %Merge
61  %v2 = call i32 @f2()
62  br label %Merge
63
64Merge:
65; CHECK:       Merge
66; CHECK-NOT:     call void(i1, ...) @llvm.experimental.guard(
67  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
68  %retVal = add i32 %retPhi, 10
69  %condGuard = icmp sgt i32 %a, 10
70  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
71  ret i32 %retVal
72}
73
74define i32 @branch_overlaps_guard(i32 %a) {
75; CHECK-LABEL: @branch_overlaps_guard(
76  %cond = icmp slt i32 %a, 20
77  br i1 %cond, label %T1, label %F1
78
79T1:
80; CHECK:        T1:
81; CHECK-NEXT:      %v1 = call i32 @f1()
82; CHECK-NEXT:      br label %Merge
83  %v1 = call i32 @f1()
84  br label %Merge
85
86F1:
87; CHECK:        F1:
88; CHECK-NEXT:     %v2 = call i32 @f2()
89; CHECK-NEXT:     br label %Merge
90  %v2 = call i32 @f2()
91  br label %Merge
92
93Merge:
94; CHECK:       Merge
95; CHECK:         %condGuard = icmp slt i32 %a, 10
96; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
97  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
98  %retVal = add i32 %retPhi, 10
99  %condGuard = icmp slt i32 %a, 10
100  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
101  ret i32 %retVal
102}
103
104define i32 @branch_doesnt_overlap_guard(i32 %a) {
105; CHECK-LABEL: @branch_doesnt_overlap_guard(
106  %cond = icmp slt i32 %a, 10
107  br i1 %cond, label %T1, label %F1
108
109T1:
110; CHECK:        T1:
111; CHECK-NEXT:      %v1 = call i32 @f1()
112; CHECK-NEXT:      br label %Merge
113  %v1 = call i32 @f1()
114  br label %Merge
115
116F1:
117; CHECK:        F1:
118; CHECK-NEXT:     %v2 = call i32 @f2()
119; CHECK-NEXT:     br label %Merge
120  %v2 = call i32 @f2()
121  br label %Merge
122
123Merge:
124; CHECK:       Merge
125; CHECK:         %condGuard = icmp sgt i32 %a, 20
126; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
127  %retPhi = phi i32 [ %v1, %T1 ], [ %v2, %F1 ]
128  %retVal = add i32 %retPhi, 10
129  %condGuard = icmp sgt i32 %a, 20
130  call void(i1, ...) @llvm.experimental.guard(i1 %condGuard) [ "deopt"() ]
131  ret i32 %retVal
132}
133
134define i32 @not_a_diamond1(i32 %a, i1 %cond1) {
135; CHECK-LABEL: @not_a_diamond1(
136  br i1 %cond1, label %Pred, label %Exit
137
138Pred:
139; CHECK:       Pred:
140; CHECK-NEXT:    switch i32 %a, label %Exit
141  switch i32 %a, label %Exit [
142    i32 10, label %Merge
143    i32 20, label %Merge
144  ]
145
146Merge:
147; CHECK:       Merge:
148; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
149; CHECK-NEXT:    br label %Exit
150  call void(i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
151  br label %Exit
152
153Exit:
154; CHECK:       Exit:
155; CHECK-NEXT:    ret i32 %a
156  ret i32 %a
157}
158
159define void @not_a_diamond2(i32 %a, i1 %cond1) {
160; CHECK-LABEL: @not_a_diamond2(
161  br label %Parent
162
163Merge:
164  call void(i1, ...) @llvm.experimental.guard(i1 %cond1)[ "deopt"() ]
165  ret void
166
167Pred:
168; CHECK-NEXT:  Pred:
169; CHECK-NEXT:    switch i32 %a, label %Exit
170  switch i32 %a, label %Exit [
171    i32 10, label %Merge
172    i32 20, label %Merge
173  ]
174
175Parent:
176  br label %Pred
177
178Exit:
179; CHECK:       Merge:
180; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 %cond1) [ "deopt"() ]
181; CHECK-NEXT:    ret void
182  ret void
183}
184
185declare void @never_called(i1)
186
187; LVI uses guard to identify value of %c2 in branch as true, we cannot replace that
188; guard with guard(true & c1).
189define void @dont_fold_guard(i8* %addr, i32 %i, i32 %length) {
190; CHECK-LABEL: dont_fold_guard
191; CHECK: %wide.chk = and i1 %c1, %c2
192; CHECK-NEXT: experimental.guard(i1 %wide.chk)
193; CHECK-NEXT: call void @never_called(i1 true)
194; CHECK-NEXT: ret void
195  %c1 = icmp ult i32 %i, %length
196  %c2 = icmp eq i32 %i, 0
197  %wide.chk = and i1 %c1, %c2
198  call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]
199  br i1 %c2, label %BB1, label %BB2
200
201BB1:
202  call void @never_called(i1 %c2)
203  ret void
204
205BB2:
206  ret void
207}
208
209declare void @dummy(i1) nounwind argmemonly
210; same as dont_fold_guard1 but there's a use immediately after guard and before
211; branch. We can fold that use.
212define void @dont_fold_guard2(i8* %addr, i32 %i, i32 %length) {
213; CHECK-LABEL: dont_fold_guard2
214; CHECK: %wide.chk = and i1 %c1, %c2
215; CHECK-NEXT: experimental.guard(i1 %wide.chk)
216; CHECK-NEXT: dummy(i1 true)
217; CHECK-NEXT: call void @never_called(i1 true)
218; CHECK-NEXT: ret void
219  %c1 = icmp ult i32 %i, %length
220  %c2 = icmp eq i32 %i, 0
221  %wide.chk = and i1 %c1, %c2
222  call void(i1, ...) @llvm.experimental.guard(i1 %wide.chk) [ "deopt"() ]
223  call void @dummy(i1 %c2)
224  br i1 %c2, label %BB1, label %BB2
225
226BB1:
227  call void @never_called(i1 %c2)
228  ret void
229
230BB2:
231  ret void
232}
233
234; same as dont_fold_guard1 but condition %cmp is not an instruction.
235; We cannot fold the guard under any circumstance.
236; FIXME: We can merge unreachableBB2 into not_zero.
237define void @dont_fold_guard3(i8* %addr, i1 %cmp, i32 %i, i32 %length) {
238; CHECK-LABEL: dont_fold_guard3
239; CHECK: guard(i1 %cmp)
240  call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
241  br i1 %cmp, label %BB1, label %BB2
242
243BB1:
244  call void @never_called(i1 %cmp)
245  ret void
246
247BB2:
248  ret void
249}
250
251declare void @f(i1)
252; Same as dont_fold_guard1 but use switch instead of branch.
253; triggers source code `ProcessThreadableEdges`.
254define void @dont_fold_guard4(i1 %cmp1, i32 %i) nounwind {
255; CHECK-LABEL: dont_fold_guard4
256; CHECK-LABEL: L2:
257; CHECK-NEXT: %cmp = icmp eq i32 %i, 0
258; CHECK-NEXT: guard(i1 %cmp)
259; CHECK-NEXT: dummy(i1 true)
260; CHECK-NEXT: @f(i1 true)
261; CHECK-NEXT: ret void
262entry:
263  br i1 %cmp1, label %L0, label %L3
264L0:
265  %cmp = icmp eq i32 %i, 0
266  call void(i1, ...) @llvm.experimental.guard(i1 %cmp) [ "deopt"() ]
267  call void @dummy(i1 %cmp)
268  switch i1 %cmp, label %L3 [
269    i1 false, label %L1
270    i1 true, label %L2
271    ]
272
273L1:
274  ret void
275L2:
276  call void @f(i1 %cmp)
277  ret void
278L3:
279  ret void
280}
281