Skip to content

Commit 78c0d75

Browse files
committed
[Tests] Add tests for D62939 (miscompiles around dead pointer IVs)
Flesh out a collection of tests for switching to a dead IV within LFTR, both for the current miscompile, and for some cases which we should be able to handle via simple reasoning. llvm-svn: 362976
1 parent a9633d5 commit 78c0d75

File tree

1 file changed

+228
-0
lines changed

1 file changed

+228
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -S -indvars < %s | FileCheck %s
3+
4+
; Tests in this file are specifically about correctly handling possibly poison
5+
; producing flags when converting from one IV to another. In particular, there
6+
; is a risk that the IV we chose to switch to is dynamically dead (i.e. there
7+
; is no side effect which dependents on the computation thereof). Such an IV
8+
; can produce poison on one or more iterations without triggering UB. When we
9+
; add an additional use to such an IV, we need to ensure that our new use does
10+
; not trigger UB where none existed in the original program.
11+
12+
; Provide legal integer types.
13+
target datalayout = "n8:16:32:64"
14+
15+
@data = common global [240 x i8] zeroinitializer, align 16
16+
17+
;; In this example, the pointer IV is dynamicaly dead. As such, the fact that
18+
;; inbounds produces poison *does not* trigger UB in the original loop. As
19+
;; such, the pointer IV can be poison and adding a new use of the pointer
20+
;; IV which dependends on that poison computation in a manner which might
21+
;; trigger UB would be incorrect.
22+
;; FIXME: This currently shows a miscompile!
23+
define void @neg_dynamically_dead_inbounds(i8* %a, i8** %x, i1 %always_false) #0 {
24+
; CHECK-LABEL: @neg_dynamically_dead_inbounds(
25+
; CHECK-NEXT: entry:
26+
; CHECK-NEXT: br label [[LOOP:%.*]]
27+
; CHECK: loop:
28+
; CHECK-NEXT: [[P_0:%.*]] = phi i8* [ getelementptr inbounds ([240 x i8], [240 x i8]* @data, i64 0, i64 0), [[ENTRY:%.*]] ], [ [[TMP3:%.*]], [[CONT:%.*]] ]
29+
; CHECK-NEXT: [[TMP3]] = getelementptr inbounds i8, i8* [[P_0]], i64 1
30+
; CHECK-NEXT: br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_EXECUTED:%.*]], label [[CONT]]
31+
; CHECK: never_executed:
32+
; CHECK-NEXT: store volatile i8 0, i8* [[TMP3]]
33+
; CHECK-NEXT: br label [[CONT]]
34+
; CHECK: cont:
35+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i8* [[TMP3]], getelementptr (i8, i8* getelementptr inbounds ([240 x i8], [240 x i8]* @data, i64 0, i64 0), i64 246)
36+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
37+
; CHECK: exit:
38+
; CHECK-NEXT: ret void
39+
;
40+
entry:
41+
br label %loop
42+
43+
loop:
44+
%i.0 = phi i8 [ 0, %entry ], [ %tmp4, %cont ]
45+
%p.0 = phi i8* [ getelementptr inbounds ([240 x i8], [240 x i8]* @data, i64 0, i64 0), %entry ], [ %tmp3, %cont ]
46+
%tmp3 = getelementptr inbounds i8, i8* %p.0, i64 1
47+
br i1 %always_false, label %never_executed, label %cont
48+
49+
never_executed:
50+
store volatile i8 0, i8* %tmp3
51+
br label %cont
52+
53+
cont:
54+
%tmp4 = add i8 %i.0, 1
55+
%tmp5 = icmp ult i8 %tmp4, -10
56+
br i1 %tmp5, label %loop, label %exit
57+
58+
exit:
59+
ret void
60+
}
61+
62+
; Similiar to above, but shows how we currently guard non-constant
63+
; memory operands in a manner which hides the latent miscompile.
64+
define void @neg_dynamically_dead_inbounds2(i8* %a, i1 %always_false) #0 {
65+
; CHECK-LABEL: @neg_dynamically_dead_inbounds2(
66+
; CHECK-NEXT: entry:
67+
; CHECK-NEXT: br label [[LOOP:%.*]]
68+
; CHECK: loop:
69+
; CHECK-NEXT: [[I_0:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[TMP4:%.*]], [[CONT:%.*]] ]
70+
; CHECK-NEXT: [[P_0:%.*]] = phi i8* [ [[A:%.*]], [[ENTRY]] ], [ [[TMP3:%.*]], [[CONT]] ]
71+
; CHECK-NEXT: [[TMP3]] = getelementptr inbounds i8, i8* [[P_0]], i64 1
72+
; CHECK-NEXT: br i1 [[ALWAYS_FALSE:%.*]], label [[NEVER_EXECUTED:%.*]], label [[CONT]]
73+
; CHECK: never_executed:
74+
; CHECK-NEXT: store volatile i8 0, i8* [[TMP3]]
75+
; CHECK-NEXT: br label [[CONT]]
76+
; CHECK: cont:
77+
; CHECK-NEXT: [[TMP4]] = add nuw i8 [[I_0]], 1
78+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i8 [[TMP4]], -10
79+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
80+
; CHECK: exit:
81+
; CHECK-NEXT: ret void
82+
;
83+
entry:
84+
br label %loop
85+
86+
loop:
87+
%i.0 = phi i8 [ 0, %entry ], [ %tmp4, %cont ]
88+
%p.0 = phi i8* [ %a, %entry ], [ %tmp3, %cont ]
89+
%tmp3 = getelementptr inbounds i8, i8* %p.0, i64 1
90+
br i1 %always_false, label %never_executed, label %cont
91+
92+
never_executed:
93+
store volatile i8 0, i8* %tmp3
94+
br label %cont
95+
96+
cont:
97+
%tmp4 = add i8 %i.0, 1
98+
%tmp5 = icmp ult i8 %tmp4, -10
99+
br i1 %tmp5, label %loop, label %exit
100+
101+
exit:
102+
ret void
103+
}
104+
105+
define void @dom_store(i8* %a) #0 {
106+
; CHECK-LABEL: @dom_store(
107+
; CHECK-NEXT: entry:
108+
; CHECK-NEXT: br label [[LOOP:%.*]]
109+
; CHECK: loop:
110+
; CHECK-NEXT: [[I_0:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[TMP4:%.*]], [[LOOP]] ]
111+
; CHECK-NEXT: [[P_0:%.*]] = phi i8* [ [[A:%.*]], [[ENTRY]] ], [ [[TMP3:%.*]], [[LOOP]] ]
112+
; CHECK-NEXT: [[TMP3]] = getelementptr inbounds i8, i8* [[P_0]], i64 1
113+
; CHECK-NEXT: store volatile i8 0, i8* [[TMP3]]
114+
; CHECK-NEXT: [[TMP4]] = add nuw i8 [[I_0]], 1
115+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i8 [[TMP4]], -10
116+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
117+
; CHECK: exit:
118+
; CHECK-NEXT: ret void
119+
;
120+
entry:
121+
br label %loop
122+
123+
loop:
124+
%i.0 = phi i8 [ 0, %entry ], [ %tmp4, %loop ]
125+
%p.0 = phi i8* [ %a, %entry ], [ %tmp3, %loop ]
126+
%tmp3 = getelementptr inbounds i8, i8* %p.0, i64 1
127+
store volatile i8 0, i8* %tmp3
128+
%tmp4 = add i8 %i.0, 1
129+
%tmp5 = icmp ult i8 %tmp4, -10
130+
br i1 %tmp5, label %loop, label %exit
131+
132+
exit:
133+
ret void
134+
}
135+
136+
define i8 @dom_load(i8* %a) #0 {
137+
; CHECK-LABEL: @dom_load(
138+
; CHECK-NEXT: entry:
139+
; CHECK-NEXT: br label [[LOOP:%.*]]
140+
; CHECK: loop:
141+
; CHECK-NEXT: [[I_0:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[TMP4:%.*]], [[LOOP]] ]
142+
; CHECK-NEXT: [[P_0:%.*]] = phi i8* [ [[A:%.*]], [[ENTRY]] ], [ [[TMP3:%.*]], [[LOOP]] ]
143+
; CHECK-NEXT: [[TMP3]] = getelementptr inbounds i8, i8* [[P_0]], i64 1
144+
; CHECK-NEXT: [[V:%.*]] = load i8, i8* [[TMP3]]
145+
; CHECK-NEXT: [[TMP4]] = add nuw i8 [[I_0]], 1
146+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i8 [[TMP4]], -10
147+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
148+
; CHECK: exit:
149+
; CHECK-NEXT: [[V_LCSSA:%.*]] = phi i8 [ [[V]], [[LOOP]] ]
150+
; CHECK-NEXT: ret i8 [[V_LCSSA]]
151+
;
152+
entry:
153+
br label %loop
154+
155+
loop:
156+
%i.0 = phi i8 [ 0, %entry ], [ %tmp4, %loop ]
157+
%p.0 = phi i8* [ %a, %entry ], [ %tmp3, %loop ]
158+
%tmp3 = getelementptr inbounds i8, i8* %p.0, i64 1
159+
%v = load i8, i8* %tmp3
160+
%tmp4 = add i8 %i.0, 1
161+
%tmp5 = icmp ult i8 %tmp4, -10
162+
br i1 %tmp5, label %loop, label %exit
163+
164+
exit:
165+
ret i8 %v
166+
}
167+
168+
define i64 @dom_div(i64 %a) #0 {
169+
; CHECK-LABEL: @dom_div(
170+
; CHECK-NEXT: entry:
171+
; CHECK-NEXT: br label [[LOOP:%.*]]
172+
; CHECK: loop:
173+
; CHECK-NEXT: [[I_0:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[TMP4:%.*]], [[LOOP]] ]
174+
; CHECK-NEXT: [[I_1:%.*]] = phi i64 [ [[A:%.*]], [[ENTRY]] ], [ [[TMP3:%.*]], [[LOOP]] ]
175+
; CHECK-NEXT: [[TMP3]] = add nuw nsw i64 [[I_1]], 1
176+
; CHECK-NEXT: [[V:%.*]] = udiv i64 5, [[TMP3]]
177+
; CHECK-NEXT: [[TMP4]] = add nuw i8 [[I_0]], 1
178+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i8 [[TMP4]], -10
179+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
180+
; CHECK: exit:
181+
; CHECK-NEXT: [[V_LCSSA:%.*]] = phi i64 [ [[V]], [[LOOP]] ]
182+
; CHECK-NEXT: ret i64 [[V_LCSSA]]
183+
;
184+
entry:
185+
br label %loop
186+
187+
loop:
188+
%i.0 = phi i8 [ 0, %entry ], [ %tmp4, %loop ]
189+
%i.1 = phi i64 [ %a, %entry ], [ %tmp3, %loop ]
190+
%tmp3 = add nsw nuw i64 %i.1, 1
191+
%v = udiv i64 5, %tmp3
192+
%tmp4 = add i8 %i.0, 1
193+
%tmp5 = icmp ult i8 %tmp4, -10
194+
br i1 %tmp5, label %loop, label %exit
195+
196+
exit:
197+
ret i64 %v
198+
}
199+
200+
; For integer IVs, we handle this trigger case by stripping the problematic
201+
; flags which removes the potential introduction of UB.
202+
define void @neg_dead_int_iv(i64 %a) #0 {
203+
; CHECK-LABEL: @neg_dead_int_iv(
204+
; CHECK-NEXT: entry:
205+
; CHECK-NEXT: br label [[LOOP:%.*]]
206+
; CHECK: loop:
207+
; CHECK-NEXT: [[I_1:%.*]] = phi i64 [ -2, [[ENTRY:%.*]] ], [ [[TMP3:%.*]], [[LOOP]] ]
208+
; CHECK-NEXT: [[TMP3]] = add nsw i64 [[I_1]], 1
209+
; CHECK-NEXT: [[EXITCOND:%.*]] = icmp ne i64 [[TMP3]], 244
210+
; CHECK-NEXT: br i1 [[EXITCOND]], label [[LOOP]], label [[EXIT:%.*]]
211+
; CHECK: exit:
212+
; CHECK-NEXT: ret void
213+
;
214+
entry:
215+
br label %loop
216+
217+
loop:
218+
%i.0 = phi i8 [ 0, %entry ], [ %tmp4, %loop ]
219+
%i.1 = phi i64 [ -2, %entry ], [ %tmp3, %loop ]
220+
%tmp3 = add nsw nuw i64 %i.1, 1
221+
%tmp4 = add i8 %i.0, 1
222+
%tmp5 = icmp ult i8 %tmp4, -10
223+
br i1 %tmp5, label %loop, label %exit
224+
225+
exit:
226+
ret void
227+
}
228+

0 commit comments

Comments
 (0)