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