Follow up to d0858bffa11, add missing REQUIRES x86
[llvm-project.git] / llvm / test / Transforms / GuardWidening / posion.ll
blob3623f014413e80006883ab39e7b672e43b04d622
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt -S -passes=guard-widening,dce < %s | FileCheck %s
4 declare void @llvm.experimental.guard(i1,...)
5 declare i1 @dummy()
7 ; This tests shows the incorrect behavior of guard widening in terms of
8 ; interaction with poison values.
10 ; Let x incoming parameter is used for rane checks.
11 ; Test generates 5 checks. One of them (c2) is used to get the corretness
12 ; of nuw/nsw flags for x3 and x5. Others are used in guards and represent
13 ; the checks x + 10 u< L, x + 15 u< L, x + 20 u< L and x + 3 u< L.
14 ; The first two checks are in the first basic block and guard widening
15 ; considers them as profitable to combine.
16 ; When c4 and c3 are considered, number of check becomes more than two
17 ; and combineRangeCheck consider them as profitable even if they are in
18 ; different basic blocks.
19 ; Accoding to algorithm of combineRangeCheck it detects that c3 and c4
20 ; are enough to cover c1 and c5, so it ends up with guard of c3 && c4
21 ; while both of them are poison at entry. This is a bug.
23 define void @combine_range_checks(i32 %x) {
24 ; CHECK-LABEL: @combine_range_checks(
25 ; CHECK-NEXT:  entry:
26 ; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
27 ; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X_GW_FR]], 0
28 ; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[X2]], 200
29 ; CHECK-NEXT:    [[X3:%.*]] = add i32 [[X_GW_FR]], 3
30 ; CHECK-NEXT:    [[C3:%.*]] = icmp ult i32 [[X3]], 100
31 ; CHECK-NEXT:    [[X4:%.*]] = add i32 [[X_GW_FR]], 20
32 ; CHECK-NEXT:    [[C4:%.*]] = icmp ult i32 [[X4]], 100
33 ; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]]
34 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ]
35 ; CHECK-NEXT:    br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]]
36 ; CHECK:       ok:
37 ; CHECK-NEXT:    br label [[OUT]]
38 ; CHECK:       out:
39 ; CHECK-NEXT:    ret void
41 entry:
42   %x1 = add i32 %x, 10
43   %c1 = icmp ult i32 %x1, 100
44   %x2 = add i32 %x, 0
45   %c2 = icmp ult i32 %x2, 200
46   %x3 = add nuw nsw i32 %x, 3
47   %c3 = icmp ult i32 %x3, 100
48   %x4 = add nuw nsw i32 %x, 20
49   %c4 = icmp ult i32 %x4, 100
50   %x5 = add i32 %x, 15
51   %c5 = icmp ult i32 %x5, 100
52   call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ]
53   call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ]
54   br i1 %c2, label %ok, label %out
55 ok:
56   call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ]
57   call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ]
58   br label %out
59 out:
60   ret void
63 ; This is similar to @combine_range_checks but shows that simple freeze
64 ; over c3 and c4 will not help due to with X = SMAX_INT, guard with c1 will
65 ; go to deoptimization. But after guard widening freeze of c3 and c4 may return
66 ; true due to c3 and c4 are poisons and we pass guard executing side effect store
67 ; which never been executed in original program.
68 define void @combine_range_checks_with_side_effect(i32 %x, ptr %p) {
69 ; CHECK-LABEL: @combine_range_checks_with_side_effect(
70 ; CHECK-NEXT:  entry:
71 ; CHECK-NEXT:    [[X_GW_FR:%.*]] = freeze i32 [[X:%.*]]
72 ; CHECK-NEXT:    [[X2:%.*]] = add i32 [[X_GW_FR]], 0
73 ; CHECK-NEXT:    [[C2:%.*]] = icmp ult i32 [[X2]], 200
74 ; CHECK-NEXT:    [[X3:%.*]] = add i32 [[X_GW_FR]], 3
75 ; CHECK-NEXT:    [[C3:%.*]] = icmp ult i32 [[X3]], 100
76 ; CHECK-NEXT:    [[X4:%.*]] = add i32 [[X_GW_FR]], 20
77 ; CHECK-NEXT:    [[C4:%.*]] = icmp ult i32 [[X4]], 100
78 ; CHECK-NEXT:    [[WIDE_CHK2:%.*]] = and i1 [[C4]], [[C3]]
79 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK2]]) [ "deopt"(i64 1) ]
80 ; CHECK-NEXT:    store i32 0, ptr [[P:%.*]], align 4
81 ; CHECK-NEXT:    br i1 [[C2]], label [[OK:%.*]], label [[OUT:%.*]]
82 ; CHECK:       ok:
83 ; CHECK-NEXT:    br label [[OUT]]
84 ; CHECK:       out:
85 ; CHECK-NEXT:    ret void
87 entry:
88   %x1 = add i32 %x, 10
89   %c1 = icmp ult i32 %x1, 100
90   %x2 = add i32 %x, 0
91   %c2 = icmp ult i32 %x2, 200
92   %x3 = add nuw nsw i32 %x, 3
93   %c3 = icmp ult i32 %x3, 100
94   %x4 = add nuw nsw i32 %x, 20
95   %c4 = icmp ult i32 %x4, 100
96   %x5 = add i32 %x, 15
97   %c5 = icmp ult i32 %x5, 100
98   call void(i1, ...) @llvm.experimental.guard(i1 %c1) [ "deopt"(i64 1) ]
99   call void(i1, ...) @llvm.experimental.guard(i1 %c5) [ "deopt"(i64 5) ]
100   store i32 0, ptr %p
101   br i1 %c2, label %ok, label %out
103   call void(i1, ...) @llvm.experimental.guard(i1 %c4) [ "deopt"(i64 4) ]
104   call void(i1, ...) @llvm.experimental.guard(i1 %c3) [ "deopt"(i64 3) ]
105   br label %out
106 out:
107   ret void
111 ; The test shows the bug in guard widening. Critical pieces.
112 ; There is a %cond_1 check which provides the correctness of nuw nsw in %b.shift.
113 ; %b.shift and %cond_2 are poisons and after guard widening it leads to UB
114 ; for both arithmetic and logcal and.
115 define void @simple_case(i32 %a, i32 %b, i1 %cnd) {
116 ; CHECK-LABEL: @simple_case(
117 ; CHECK-NEXT:  entry:
118 ; CHECK-NEXT:    [[B_GW_FR:%.*]] = freeze i32 [[B:%.*]]
119 ; CHECK-NEXT:    [[COND_0:%.*]] = icmp ult i32 [[A:%.*]], 10
120 ; CHECK-NEXT:    [[B_SHIFT:%.*]] = add i32 [[B_GW_FR]], 5
121 ; CHECK-NEXT:    [[COND_2:%.*]] = icmp ult i32 [[B_SHIFT]], 10
122 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[COND_0]], [[COND_2]]
123 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
124 ; CHECK-NEXT:    br label [[LOOP:%.*]]
125 ; CHECK:       loop:
126 ; CHECK-NEXT:    [[COND_1:%.*]] = icmp ult i32 [[B_GW_FR]], 10
127 ; CHECK-NEXT:    br i1 [[COND_1]], label [[OK:%.*]], label [[LEAVE_LOOPEXIT:%.*]]
128 ; CHECK:       ok:
129 ; CHECK-NEXT:    br i1 [[CND:%.*]], label [[LOOP]], label [[LEAVE_LOOPEXIT]]
130 ; CHECK:       leave.loopexit:
131 ; CHECK-NEXT:    br label [[LEAVE:%.*]]
132 ; CHECK:       leave:
133 ; CHECK-NEXT:    ret void
135 entry:
136   %cond_0 = icmp ult i32 %a, 10
137   %b.shift = add nuw nsw i32 %b, 5
138   %cond_2 = icmp ult i32 %b.shift, 10
139   call void (i1, ...) @llvm.experimental.guard(i1 %cond_0) [ "deopt"() ]
140   br label %loop
142 loop:
143   %cond_1 = icmp ult i32 %b, 10
144   br i1 %cond_1, label %ok, label %leave.loopexit
146   call void (i1, ...) @llvm.experimental.guard(i1 %cond_2) [ "deopt"() ]
147   br i1 %cnd, label %loop, label %leave.loopexit
149 leave.loopexit:
150   br label %leave
152 leave:
153   ret void
156 declare ptr @fake_personality_function()
158 define void @case_with_invoke(i1 %c, i1 %gc) personality ptr @fake_personality_function {
159 ; CHECK-LABEL: @case_with_invoke(
160 ; CHECK-NEXT:  entry:
161 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[NORMAL:%.*]], label [[INVOK:%.*]]
162 ; CHECK:       invok:
163 ; CHECK-NEXT:    [[INVOKE_RESULT:%.*]] = invoke i1 @dummy()
164 ; CHECK-NEXT:    to label [[NORMAL]] unwind label [[EXCEPTION:%.*]]
165 ; CHECK:       normal:
166 ; CHECK-NEXT:    [[PHI_C:%.*]] = phi i1 [ true, [[ENTRY:%.*]] ], [ [[INVOKE_RESULT]], [[INVOK]] ]
167 ; CHECK-NEXT:    [[PHI_C_GW_FR:%.*]] = freeze i1 [[PHI_C]]
168 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[GC:%.*]], [[PHI_C_GW_FR]]
169 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
170 ; CHECK-NEXT:    ret void
171 ; CHECK:       exception:
172 ; CHECK-NEXT:    [[LANDING_PAD:%.*]] = landingpad { ptr, i32 }
173 ; CHECK-NEXT:    cleanup
174 ; CHECK-NEXT:    ret void
176 entry:
177   br i1 %c, label %normal, label %invok
179 invok:
180   %invoke.result = invoke i1 @dummy() to label %normal unwind label %exception
182 normal:
183   %phi.c = phi i1 [true, %entry], [%invoke.result, %invok]
184   call void (i1, ...) @llvm.experimental.guard(i1 %gc) [ "deopt"() ]
185   call void (i1, ...) @llvm.experimental.guard(i1 %phi.c) [ "deopt"() ]
186   ret void
188 exception:
189   %landing_pad = landingpad { ptr, i32 } cleanup
190   ret void
193 define void @case_with_invoke_in_latch(i1 %c, i1 %gc) personality ptr @fake_personality_function {
194 ; CHECK-LABEL: @case_with_invoke_in_latch(
195 ; CHECK-NEXT:  entry:
196 ; CHECK-NEXT:    br label [[HEADER:%.*]]
197 ; CHECK:       header:
198 ; CHECK-NEXT:    [[PHI_C:%.*]] = phi i1 [ false, [[ENTRY:%.*]] ], [ [[INVOKE_RESULT:%.*]], [[HEADER]] ]
199 ; CHECK-NEXT:    [[PHI_C_GW_FR:%.*]] = freeze i1 [[PHI_C]]
200 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[GC:%.*]], [[PHI_C_GW_FR]]
201 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
202 ; CHECK-NEXT:    [[INVOKE_RESULT]] = invoke i1 @dummy()
203 ; CHECK-NEXT:    to label [[HEADER]] unwind label [[EXCEPTION:%.*]]
204 ; CHECK:       exception:
205 ; CHECK-NEXT:    [[LANDING_PAD:%.*]] = landingpad { ptr, i32 }
206 ; CHECK-NEXT:    cleanup
207 ; CHECK-NEXT:    ret void
209 entry:
210   br label %header
212 header:
213   %phi.c = phi i1 [false, %entry], [%invoke.result, %header]
214   call void (i1, ...) @llvm.experimental.guard(i1 %gc) [ "deopt"() ]
215   call void (i1, ...) @llvm.experimental.guard(i1 %phi.c) [ "deopt"() ]
216   %invoke.result = invoke i1 @dummy() to label %header unwind label %exception
218 exception:
219   %landing_pad = landingpad { ptr, i32 } cleanup
220   ret void
223 declare void @dummy_vec(<4 x i1> %arg)
225 define void @freeze_poison(i1 %c, i1 %g) {
226 ; CHECK-LABEL: @freeze_poison(
227 ; CHECK-NEXT:  entry:
228 ; CHECK-NEXT:    [[DOTGW_FR:%.*]] = freeze i1 poison
229 ; CHECK-NEXT:    br i1 [[C:%.*]], label [[LEFT:%.*]], label [[RIGHT:%.*]]
230 ; CHECK:       left:
231 ; CHECK-NEXT:    call void @dummy_vec(<4 x i1> <i1 false, i1 poison, i1 poison, i1 poison>)
232 ; CHECK-NEXT:    ret void
233 ; CHECK:       right:
234 ; CHECK-NEXT:    [[WIDE_CHK:%.*]] = and i1 [[G:%.*]], [[DOTGW_FR]]
235 ; CHECK-NEXT:    call void (i1, ...) @llvm.experimental.guard(i1 [[WIDE_CHK]]) [ "deopt"() ]
236 ; CHECK-NEXT:    ret void
238 entry:
239   br i1 %c, label %left, label %right
241 left:
242   call void @dummy_vec(<4 x i1> <i1 0, i1 poison, i1 poison, i1 poison>)
243   ret void
246 right:
247   call void (i1, ...) @llvm.experimental.guard(i1 %g) [ "deopt"() ]
248   call void (i1, ...) @llvm.experimental.guard(i1 poison) [ "deopt"() ]
249   ret void