1 | //===- ValueTrackingTest.cpp - ValueTracking tests ------------------------===// |
2 | // |
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | // See https://llvm.org/LICENSE.txt for license information. |
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #include "llvm/Analysis/ValueTracking.h" |
10 | #include "llvm/Analysis/AssumptionCache.h" |
11 | #include "llvm/AsmParser/Parser.h" |
12 | #include "llvm/IR/ConstantRange.h" |
13 | #include "llvm/IR/Dominators.h" |
14 | #include "llvm/IR/Function.h" |
15 | #include "llvm/IR/IRBuilder.h" |
16 | #include "llvm/IR/InstIterator.h" |
17 | #include "llvm/IR/Instructions.h" |
18 | #include "llvm/IR/LLVMContext.h" |
19 | #include "llvm/IR/Module.h" |
20 | #include "llvm/Support/ErrorHandling.h" |
21 | #include "llvm/Support/KnownBits.h" |
22 | #include "llvm/Support/SourceMgr.h" |
23 | #include "llvm/Transforms/Utils/Local.h" |
24 | #include "gtest/gtest.h" |
25 | |
26 | using namespace llvm; |
27 | |
28 | namespace { |
29 | |
30 | static Instruction *findInstructionByNameOrNull(Function *F, StringRef Name) { |
31 | for (Instruction &I : instructions(F)) |
32 | if (I.getName() == Name) |
33 | return &I; |
34 | |
35 | return nullptr; |
36 | } |
37 | |
38 | static Instruction &findInstructionByName(Function *F, StringRef Name) { |
39 | auto *I = findInstructionByNameOrNull(F, Name); |
40 | if (I) |
41 | return *I; |
42 | |
43 | llvm_unreachable("Expected value not found" ); |
44 | } |
45 | |
46 | class ValueTrackingTest : public testing::Test { |
47 | protected: |
48 | std::unique_ptr<Module> parseModule(StringRef Assembly) { |
49 | SMDiagnostic Error; |
50 | std::unique_ptr<Module> M = parseAssemblyString(AsmString: Assembly, Err&: Error, Context); |
51 | |
52 | std::string errMsg; |
53 | raw_string_ostream os(errMsg); |
54 | Error.print(ProgName: "" , S&: os); |
55 | EXPECT_TRUE(M) << os.str(); |
56 | |
57 | return M; |
58 | } |
59 | |
60 | void parseAssembly(StringRef Assembly) { |
61 | M = parseModule(Assembly); |
62 | ASSERT_TRUE(M); |
63 | |
64 | F = M->getFunction(Name: "test" ); |
65 | ASSERT_TRUE(F) << "Test must have a function @test" ; |
66 | if (!F) |
67 | return; |
68 | |
69 | A = findInstructionByNameOrNull(F, Name: "A" ); |
70 | ASSERT_TRUE(A) << "@test must have an instruction %A" ; |
71 | A2 = findInstructionByNameOrNull(F, Name: "A2" ); |
72 | A3 = findInstructionByNameOrNull(F, Name: "A3" ); |
73 | A4 = findInstructionByNameOrNull(F, Name: "A4" ); |
74 | A5 = findInstructionByNameOrNull(F, Name: "A5" ); |
75 | A6 = findInstructionByNameOrNull(F, Name: "A6" ); |
76 | A7 = findInstructionByNameOrNull(F, Name: "A7" ); |
77 | |
78 | CxtI = findInstructionByNameOrNull(F, Name: "CxtI" ); |
79 | CxtI2 = findInstructionByNameOrNull(F, Name: "CxtI2" ); |
80 | CxtI3 = findInstructionByNameOrNull(F, Name: "CxtI3" ); |
81 | } |
82 | |
83 | LLVMContext Context; |
84 | std::unique_ptr<Module> M; |
85 | Function *F = nullptr; |
86 | Instruction *A = nullptr; |
87 | // Instructions (optional) |
88 | Instruction *A2 = nullptr, *A3 = nullptr, *A4 = nullptr, *A5 = nullptr, |
89 | *A6 = nullptr, *A7 = nullptr; |
90 | |
91 | // Context instructions (optional) |
92 | Instruction *CxtI = nullptr, *CxtI2 = nullptr, *CxtI3 = nullptr; |
93 | }; |
94 | |
95 | class MatchSelectPatternTest : public ValueTrackingTest { |
96 | protected: |
97 | void expectPattern(const SelectPatternResult &P) { |
98 | Value *LHS, *RHS; |
99 | Instruction::CastOps CastOp; |
100 | SelectPatternResult R = matchSelectPattern(V: A, LHS, RHS, CastOp: &CastOp); |
101 | EXPECT_EQ(P.Flavor, R.Flavor); |
102 | EXPECT_EQ(P.NaNBehavior, R.NaNBehavior); |
103 | EXPECT_EQ(P.Ordered, R.Ordered); |
104 | } |
105 | }; |
106 | |
107 | class ComputeKnownBitsTest : public ValueTrackingTest { |
108 | protected: |
109 | void expectKnownBits(uint64_t Zero, uint64_t One) { |
110 | auto Known = computeKnownBits(V: A, DL: M->getDataLayout()); |
111 | ASSERT_FALSE(Known.hasConflict()); |
112 | EXPECT_EQ(Known.One.getZExtValue(), One); |
113 | EXPECT_EQ(Known.Zero.getZExtValue(), Zero); |
114 | } |
115 | }; |
116 | |
117 | class ComputeKnownFPClassTest : public ValueTrackingTest { |
118 | protected: |
119 | void expectKnownFPClass(unsigned KnownTrue, std::optional<bool> SignBitKnown, |
120 | Instruction *TestVal = nullptr) { |
121 | if (!TestVal) |
122 | TestVal = A; |
123 | |
124 | KnownFPClass Known = computeKnownFPClass(V: TestVal, DL: M->getDataLayout()); |
125 | EXPECT_EQ(KnownTrue, Known.KnownFPClasses); |
126 | EXPECT_EQ(SignBitKnown, Known.SignBit); |
127 | } |
128 | }; |
129 | } |
130 | |
131 | TEST_F(MatchSelectPatternTest, SimpleFMin) { |
132 | parseAssembly( |
133 | Assembly: "define float @test(float %a) {\n" |
134 | " %1 = fcmp ult float %a, 5.0\n" |
135 | " %A = select i1 %1, float %a, float 5.0\n" |
136 | " ret float %A\n" |
137 | "}\n" ); |
138 | expectPattern(P: {.Flavor: SPF_FMINNUM, .NaNBehavior: SPNB_RETURNS_NAN, .Ordered: false}); |
139 | } |
140 | |
141 | TEST_F(MatchSelectPatternTest, SimpleFMax) { |
142 | parseAssembly( |
143 | Assembly: "define float @test(float %a) {\n" |
144 | " %1 = fcmp ogt float %a, 5.0\n" |
145 | " %A = select i1 %1, float %a, float 5.0\n" |
146 | " ret float %A\n" |
147 | "}\n" ); |
148 | expectPattern(P: {.Flavor: SPF_FMAXNUM, .NaNBehavior: SPNB_RETURNS_OTHER, .Ordered: true}); |
149 | } |
150 | |
151 | TEST_F(MatchSelectPatternTest, SwappedFMax) { |
152 | parseAssembly( |
153 | Assembly: "define float @test(float %a) {\n" |
154 | " %1 = fcmp olt float 5.0, %a\n" |
155 | " %A = select i1 %1, float %a, float 5.0\n" |
156 | " ret float %A\n" |
157 | "}\n" ); |
158 | expectPattern(P: {.Flavor: SPF_FMAXNUM, .NaNBehavior: SPNB_RETURNS_OTHER, .Ordered: false}); |
159 | } |
160 | |
161 | TEST_F(MatchSelectPatternTest, SwappedFMax2) { |
162 | parseAssembly( |
163 | Assembly: "define float @test(float %a) {\n" |
164 | " %1 = fcmp olt float %a, 5.0\n" |
165 | " %A = select i1 %1, float 5.0, float %a\n" |
166 | " ret float %A\n" |
167 | "}\n" ); |
168 | expectPattern(P: {.Flavor: SPF_FMAXNUM, .NaNBehavior: SPNB_RETURNS_NAN, .Ordered: false}); |
169 | } |
170 | |
171 | TEST_F(MatchSelectPatternTest, SwappedFMax3) { |
172 | parseAssembly( |
173 | Assembly: "define float @test(float %a) {\n" |
174 | " %1 = fcmp ult float %a, 5.0\n" |
175 | " %A = select i1 %1, float 5.0, float %a\n" |
176 | " ret float %A\n" |
177 | "}\n" ); |
178 | expectPattern(P: {.Flavor: SPF_FMAXNUM, .NaNBehavior: SPNB_RETURNS_OTHER, .Ordered: true}); |
179 | } |
180 | |
181 | TEST_F(MatchSelectPatternTest, FastFMin) { |
182 | parseAssembly( |
183 | Assembly: "define float @test(float %a) {\n" |
184 | " %1 = fcmp nnan olt float %a, 5.0\n" |
185 | " %A = select i1 %1, float %a, float 5.0\n" |
186 | " ret float %A\n" |
187 | "}\n" ); |
188 | expectPattern(P: {.Flavor: SPF_FMINNUM, .NaNBehavior: SPNB_RETURNS_ANY, .Ordered: false}); |
189 | } |
190 | |
191 | TEST_F(MatchSelectPatternTest, FMinConstantZero) { |
192 | parseAssembly( |
193 | Assembly: "define float @test(float %a) {\n" |
194 | " %1 = fcmp ole float %a, 0.0\n" |
195 | " %A = select i1 %1, float %a, float 0.0\n" |
196 | " ret float %A\n" |
197 | "}\n" ); |
198 | // This shouldn't be matched, as %a could be -0.0. |
199 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
200 | } |
201 | |
202 | TEST_F(MatchSelectPatternTest, FMinConstantZeroNsz) { |
203 | parseAssembly( |
204 | Assembly: "define float @test(float %a) {\n" |
205 | " %1 = fcmp nsz ole float %a, 0.0\n" |
206 | " %A = select i1 %1, float %a, float 0.0\n" |
207 | " ret float %A\n" |
208 | "}\n" ); |
209 | // But this should be, because we've ignored signed zeroes. |
210 | expectPattern(P: {.Flavor: SPF_FMINNUM, .NaNBehavior: SPNB_RETURNS_OTHER, .Ordered: true}); |
211 | } |
212 | |
213 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero1) { |
214 | parseAssembly( |
215 | Assembly: "define float @test(float %a) {\n" |
216 | " %1 = fcmp olt float -0.0, %a\n" |
217 | " %A = select i1 %1, float 0.0, float %a\n" |
218 | " ret float %A\n" |
219 | "}\n" ); |
220 | // The sign of zero doesn't matter in fcmp. |
221 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
222 | } |
223 | |
224 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero2) { |
225 | parseAssembly( |
226 | Assembly: "define float @test(float %a) {\n" |
227 | " %1 = fcmp ogt float %a, -0.0\n" |
228 | " %A = select i1 %1, float 0.0, float %a\n" |
229 | " ret float %A\n" |
230 | "}\n" ); |
231 | // The sign of zero doesn't matter in fcmp. |
232 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
233 | } |
234 | |
235 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero3) { |
236 | parseAssembly( |
237 | Assembly: "define float @test(float %a) {\n" |
238 | " %1 = fcmp olt float 0.0, %a\n" |
239 | " %A = select i1 %1, float -0.0, float %a\n" |
240 | " ret float %A\n" |
241 | "}\n" ); |
242 | // The sign of zero doesn't matter in fcmp. |
243 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
244 | } |
245 | |
246 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero4) { |
247 | parseAssembly( |
248 | Assembly: "define float @test(float %a) {\n" |
249 | " %1 = fcmp ogt float %a, 0.0\n" |
250 | " %A = select i1 %1, float -0.0, float %a\n" |
251 | " ret float %A\n" |
252 | "}\n" ); |
253 | // The sign of zero doesn't matter in fcmp. |
254 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
255 | } |
256 | |
257 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero5) { |
258 | parseAssembly( |
259 | Assembly: "define float @test(float %a) {\n" |
260 | " %1 = fcmp ogt float -0.0, %a\n" |
261 | " %A = select i1 %1, float %a, float 0.0\n" |
262 | " ret float %A\n" |
263 | "}\n" ); |
264 | // The sign of zero doesn't matter in fcmp. |
265 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
266 | } |
267 | |
268 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero6) { |
269 | parseAssembly( |
270 | Assembly: "define float @test(float %a) {\n" |
271 | " %1 = fcmp olt float %a, -0.0\n" |
272 | " %A = select i1 %1, float %a, float 0.0\n" |
273 | " ret float %A\n" |
274 | "}\n" ); |
275 | // The sign of zero doesn't matter in fcmp. |
276 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
277 | } |
278 | |
279 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero7) { |
280 | parseAssembly( |
281 | Assembly: "define float @test(float %a) {\n" |
282 | " %1 = fcmp ogt float 0.0, %a\n" |
283 | " %A = select i1 %1, float %a, float -0.0\n" |
284 | " ret float %A\n" |
285 | "}\n" ); |
286 | // The sign of zero doesn't matter in fcmp. |
287 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
288 | } |
289 | |
290 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZero8) { |
291 | parseAssembly( |
292 | Assembly: "define float @test(float %a) {\n" |
293 | " %1 = fcmp olt float %a, 0.0\n" |
294 | " %A = select i1 %1, float %a, float -0.0\n" |
295 | " ret float %A\n" |
296 | "}\n" ); |
297 | // The sign of zero doesn't matter in fcmp. |
298 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
299 | } |
300 | |
301 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero1) { |
302 | parseAssembly( |
303 | Assembly: "define float @test(float %a) {\n" |
304 | " %1 = fcmp ogt float -0.0, %a\n" |
305 | " %A = select i1 %1, float 0.0, float %a\n" |
306 | " ret float %A\n" |
307 | "}\n" ); |
308 | // The sign of zero doesn't matter in fcmp. |
309 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
310 | } |
311 | |
312 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero2) { |
313 | parseAssembly( |
314 | Assembly: "define float @test(float %a) {\n" |
315 | " %1 = fcmp olt float %a, -0.0\n" |
316 | " %A = select i1 %1, float 0.0, float %a\n" |
317 | " ret float %A\n" |
318 | "}\n" ); |
319 | // The sign of zero doesn't matter in fcmp. |
320 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
321 | } |
322 | |
323 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero3) { |
324 | parseAssembly( |
325 | Assembly: "define float @test(float %a) {\n" |
326 | " %1 = fcmp ogt float 0.0, %a\n" |
327 | " %A = select i1 %1, float -0.0, float %a\n" |
328 | " ret float %A\n" |
329 | "}\n" ); |
330 | // The sign of zero doesn't matter in fcmp. |
331 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
332 | } |
333 | |
334 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero4) { |
335 | parseAssembly( |
336 | Assembly: "define float @test(float %a) {\n" |
337 | " %1 = fcmp olt float %a, 0.0\n" |
338 | " %A = select i1 %1, float -0.0, float %a\n" |
339 | " ret float %A\n" |
340 | "}\n" ); |
341 | // The sign of zero doesn't matter in fcmp. |
342 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
343 | } |
344 | |
345 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero5) { |
346 | parseAssembly( |
347 | Assembly: "define float @test(float %a) {\n" |
348 | " %1 = fcmp olt float -0.0, %a\n" |
349 | " %A = select i1 %1, float %a, float 0.0\n" |
350 | " ret float %A\n" |
351 | "}\n" ); |
352 | // The sign of zero doesn't matter in fcmp. |
353 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
354 | } |
355 | |
356 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero6) { |
357 | parseAssembly( |
358 | Assembly: "define float @test(float %a) {\n" |
359 | " %1 = fcmp ogt float %a, -0.0\n" |
360 | " %A = select i1 %1, float %a, float 0.0\n" |
361 | " ret float %A\n" |
362 | "}\n" ); |
363 | // The sign of zero doesn't matter in fcmp. |
364 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
365 | } |
366 | |
367 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero7) { |
368 | parseAssembly( |
369 | Assembly: "define float @test(float %a) {\n" |
370 | " %1 = fcmp olt float 0.0, %a\n" |
371 | " %A = select i1 %1, float %a, float -0.0\n" |
372 | " ret float %A\n" |
373 | "}\n" ); |
374 | // The sign of zero doesn't matter in fcmp. |
375 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
376 | } |
377 | |
378 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZero8) { |
379 | parseAssembly( |
380 | Assembly: "define float @test(float %a) {\n" |
381 | " %1 = fcmp ogt float %a, 0.0\n" |
382 | " %A = select i1 %1, float %a, float -0.0\n" |
383 | " ret float %A\n" |
384 | "}\n" ); |
385 | // The sign of zero doesn't matter in fcmp. |
386 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
387 | } |
388 | |
389 | TEST_F(MatchSelectPatternTest, FMinMismatchConstantZeroVecUndef) { |
390 | parseAssembly( |
391 | Assembly: "define <2 x float> @test(<2 x float> %a) {\n" |
392 | " %1 = fcmp ogt <2 x float> %a, <float -0.0, float -0.0>\n" |
393 | " %A = select <2 x i1> %1, <2 x float> <float undef, float 0.0>, <2 x float> %a\n" |
394 | " ret <2 x float> %A\n" |
395 | "}\n" ); |
396 | // An undef in a vector constant can not be back-propagated for this analysis. |
397 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
398 | } |
399 | |
400 | TEST_F(MatchSelectPatternTest, FMaxMismatchConstantZeroVecUndef) { |
401 | parseAssembly( |
402 | Assembly: "define <2 x float> @test(<2 x float> %a) {\n" |
403 | " %1 = fcmp ogt <2 x float> %a, zeroinitializer\n" |
404 | " %A = select <2 x i1> %1, <2 x float> %a, <2 x float> <float -0.0, float undef>\n" |
405 | " ret <2 x float> %A\n" |
406 | "}\n" ); |
407 | // An undef in a vector constant can not be back-propagated for this analysis. |
408 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
409 | } |
410 | |
411 | TEST_F(MatchSelectPatternTest, VectorFMinimum) { |
412 | parseAssembly( |
413 | Assembly: "define <4 x float> @test(<4 x float> %a) {\n" |
414 | " %1 = fcmp ule <4 x float> %a, \n" |
415 | " <float 5.0, float 5.0, float 5.0, float 5.0>\n" |
416 | " %A = select <4 x i1> %1, <4 x float> %a,\n" |
417 | " <4 x float> <float 5.0, float 5.0, float 5.0, float 5.0>\n" |
418 | " ret <4 x float> %A\n" |
419 | "}\n" ); |
420 | // Check that pattern matching works on vectors where each lane has the same |
421 | // unordered pattern. |
422 | expectPattern(P: {.Flavor: SPF_FMINNUM, .NaNBehavior: SPNB_RETURNS_NAN, .Ordered: false}); |
423 | } |
424 | |
425 | TEST_F(MatchSelectPatternTest, VectorFMinOtherOrdered) { |
426 | parseAssembly( |
427 | Assembly: "define <4 x float> @test(<4 x float> %a) {\n" |
428 | " %1 = fcmp ole <4 x float> %a, \n" |
429 | " <float 5.0, float 5.0, float 5.0, float 5.0>\n" |
430 | " %A = select <4 x i1> %1, <4 x float> %a,\n" |
431 | " <4 x float> <float 5.0, float 5.0, float 5.0, float 5.0>\n" |
432 | " ret <4 x float> %A\n" |
433 | "}\n" ); |
434 | // Check that pattern matching works on vectors where each lane has the same |
435 | // ordered pattern. |
436 | expectPattern(P: {.Flavor: SPF_FMINNUM, .NaNBehavior: SPNB_RETURNS_OTHER, .Ordered: true}); |
437 | } |
438 | |
439 | TEST_F(MatchSelectPatternTest, VectorNotFMinimum) { |
440 | parseAssembly( |
441 | Assembly: "define <4 x float> @test(<4 x float> %a) {\n" |
442 | " %1 = fcmp ule <4 x float> %a, \n" |
443 | " <float 5.0, float 0x7ff8000000000000, float 5.0, float 5.0>\n" |
444 | " %A = select <4 x i1> %1, <4 x float> %a,\n" |
445 | " <4 x float> <float 5.0, float 0x7ff8000000000000, float 5.0, float " |
446 | "5.0>\n" |
447 | " ret <4 x float> %A\n" |
448 | "}\n" ); |
449 | // The lane that contains a NaN (0x7ff80...) behaves like a |
450 | // non-NaN-propagating min and the other lines behave like a NaN-propagating |
451 | // min, so check that neither is returned. |
452 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
453 | } |
454 | |
455 | TEST_F(MatchSelectPatternTest, VectorNotFMinZero) { |
456 | parseAssembly( |
457 | Assembly: "define <4 x float> @test(<4 x float> %a) {\n" |
458 | " %1 = fcmp ule <4 x float> %a, \n" |
459 | " <float 5.0, float -0.0, float 5.0, float 5.0>\n" |
460 | " %A = select <4 x i1> %1, <4 x float> %a,\n" |
461 | " <4 x float> <float 5.0, float 0.0, float 5.0, float 5.0>\n" |
462 | " ret <4 x float> %A\n" |
463 | "}\n" ); |
464 | // Always selects the second lane of %a if it is positive or negative zero, so |
465 | // this is stricter than a min. |
466 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
467 | } |
468 | |
469 | TEST_F(MatchSelectPatternTest, DoubleCastU) { |
470 | parseAssembly( |
471 | Assembly: "define i32 @test(i8 %a, i8 %b) {\n" |
472 | " %1 = icmp ult i8 %a, %b\n" |
473 | " %2 = zext i8 %a to i32\n" |
474 | " %3 = zext i8 %b to i32\n" |
475 | " %A = select i1 %1, i32 %2, i32 %3\n" |
476 | " ret i32 %A\n" |
477 | "}\n" ); |
478 | // We should be able to look through the situation where we cast both operands |
479 | // to the select. |
480 | expectPattern(P: {.Flavor: SPF_UMIN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
481 | } |
482 | |
483 | TEST_F(MatchSelectPatternTest, DoubleCastS) { |
484 | parseAssembly( |
485 | Assembly: "define i32 @test(i8 %a, i8 %b) {\n" |
486 | " %1 = icmp slt i8 %a, %b\n" |
487 | " %2 = sext i8 %a to i32\n" |
488 | " %3 = sext i8 %b to i32\n" |
489 | " %A = select i1 %1, i32 %2, i32 %3\n" |
490 | " ret i32 %A\n" |
491 | "}\n" ); |
492 | // We should be able to look through the situation where we cast both operands |
493 | // to the select. |
494 | expectPattern(P: {.Flavor: SPF_SMIN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
495 | } |
496 | |
497 | TEST_F(MatchSelectPatternTest, DoubleCastBad) { |
498 | parseAssembly( |
499 | Assembly: "define i32 @test(i8 %a, i8 %b) {\n" |
500 | " %1 = icmp ult i8 %a, %b\n" |
501 | " %2 = zext i8 %a to i32\n" |
502 | " %3 = sext i8 %b to i32\n" |
503 | " %A = select i1 %1, i32 %2, i32 %3\n" |
504 | " ret i32 %A\n" |
505 | "}\n" ); |
506 | // The cast types here aren't the same, so we cannot match an UMIN. |
507 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
508 | } |
509 | |
510 | TEST_F(MatchSelectPatternTest, NotNotSMin) { |
511 | parseAssembly( |
512 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
513 | " %cmp = icmp sgt i8 %a, %b\n" |
514 | " %an = xor i8 %a, -1\n" |
515 | " %bn = xor i8 %b, -1\n" |
516 | " %A = select i1 %cmp, i8 %an, i8 %bn\n" |
517 | " ret i8 %A\n" |
518 | "}\n" ); |
519 | expectPattern(P: {.Flavor: SPF_SMIN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
520 | } |
521 | |
522 | TEST_F(MatchSelectPatternTest, NotNotSMinSwap) { |
523 | parseAssembly( |
524 | Assembly: "define <2 x i8> @test(<2 x i8> %a, <2 x i8> %b) {\n" |
525 | " %cmp = icmp slt <2 x i8> %a, %b\n" |
526 | " %an = xor <2 x i8> %a, <i8 -1, i8-1>\n" |
527 | " %bn = xor <2 x i8> %b, <i8 -1, i8-1>\n" |
528 | " %A = select <2 x i1> %cmp, <2 x i8> %bn, <2 x i8> %an\n" |
529 | " ret <2 x i8> %A\n" |
530 | "}\n" ); |
531 | expectPattern(P: {.Flavor: SPF_SMIN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
532 | } |
533 | |
534 | TEST_F(MatchSelectPatternTest, NotNotSMax) { |
535 | parseAssembly( |
536 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
537 | " %cmp = icmp slt i8 %a, %b\n" |
538 | " %an = xor i8 %a, -1\n" |
539 | " %bn = xor i8 %b, -1\n" |
540 | " %A = select i1 %cmp, i8 %an, i8 %bn\n" |
541 | " ret i8 %A\n" |
542 | "}\n" ); |
543 | expectPattern(P: {.Flavor: SPF_SMAX, .NaNBehavior: SPNB_NA, .Ordered: false}); |
544 | } |
545 | |
546 | TEST_F(MatchSelectPatternTest, NotNotSMaxSwap) { |
547 | parseAssembly( |
548 | Assembly: "define <2 x i8> @test(<2 x i8> %a, <2 x i8> %b) {\n" |
549 | " %cmp = icmp sgt <2 x i8> %a, %b\n" |
550 | " %an = xor <2 x i8> %a, <i8 -1, i8-1>\n" |
551 | " %bn = xor <2 x i8> %b, <i8 -1, i8-1>\n" |
552 | " %A = select <2 x i1> %cmp, <2 x i8> %bn, <2 x i8> %an\n" |
553 | " ret <2 x i8> %A\n" |
554 | "}\n" ); |
555 | expectPattern(P: {.Flavor: SPF_SMAX, .NaNBehavior: SPNB_NA, .Ordered: false}); |
556 | } |
557 | |
558 | TEST_F(MatchSelectPatternTest, NotNotUMin) { |
559 | parseAssembly( |
560 | Assembly: "define <2 x i8> @test(<2 x i8> %a, <2 x i8> %b) {\n" |
561 | " %cmp = icmp ugt <2 x i8> %a, %b\n" |
562 | " %an = xor <2 x i8> %a, <i8 -1, i8-1>\n" |
563 | " %bn = xor <2 x i8> %b, <i8 -1, i8-1>\n" |
564 | " %A = select <2 x i1> %cmp, <2 x i8> %an, <2 x i8> %bn\n" |
565 | " ret <2 x i8> %A\n" |
566 | "}\n" ); |
567 | expectPattern(P: {.Flavor: SPF_UMIN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
568 | } |
569 | |
570 | TEST_F(MatchSelectPatternTest, NotNotUMinSwap) { |
571 | parseAssembly( |
572 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
573 | " %cmp = icmp ult i8 %a, %b\n" |
574 | " %an = xor i8 %a, -1\n" |
575 | " %bn = xor i8 %b, -1\n" |
576 | " %A = select i1 %cmp, i8 %bn, i8 %an\n" |
577 | " ret i8 %A\n" |
578 | "}\n" ); |
579 | expectPattern(P: {.Flavor: SPF_UMIN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
580 | } |
581 | |
582 | TEST_F(MatchSelectPatternTest, NotNotUMax) { |
583 | parseAssembly( |
584 | Assembly: "define <2 x i8> @test(<2 x i8> %a, <2 x i8> %b) {\n" |
585 | " %cmp = icmp ult <2 x i8> %a, %b\n" |
586 | " %an = xor <2 x i8> %a, <i8 -1, i8-1>\n" |
587 | " %bn = xor <2 x i8> %b, <i8 -1, i8-1>\n" |
588 | " %A = select <2 x i1> %cmp, <2 x i8> %an, <2 x i8> %bn\n" |
589 | " ret <2 x i8> %A\n" |
590 | "}\n" ); |
591 | expectPattern(P: {.Flavor: SPF_UMAX, .NaNBehavior: SPNB_NA, .Ordered: false}); |
592 | } |
593 | |
594 | TEST_F(MatchSelectPatternTest, NotNotUMaxSwap) { |
595 | parseAssembly( |
596 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
597 | " %cmp = icmp ugt i8 %a, %b\n" |
598 | " %an = xor i8 %a, -1\n" |
599 | " %bn = xor i8 %b, -1\n" |
600 | " %A = select i1 %cmp, i8 %bn, i8 %an\n" |
601 | " ret i8 %A\n" |
602 | "}\n" ); |
603 | expectPattern(P: {.Flavor: SPF_UMAX, .NaNBehavior: SPNB_NA, .Ordered: false}); |
604 | } |
605 | |
606 | TEST_F(MatchSelectPatternTest, NotNotEq) { |
607 | parseAssembly( |
608 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
609 | " %cmp = icmp eq i8 %a, %b\n" |
610 | " %an = xor i8 %a, -1\n" |
611 | " %bn = xor i8 %b, -1\n" |
612 | " %A = select i1 %cmp, i8 %bn, i8 %an\n" |
613 | " ret i8 %A\n" |
614 | "}\n" ); |
615 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
616 | } |
617 | |
618 | TEST_F(MatchSelectPatternTest, NotNotNe) { |
619 | parseAssembly( |
620 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
621 | " %cmp = icmp ne i8 %a, %b\n" |
622 | " %an = xor i8 %a, -1\n" |
623 | " %bn = xor i8 %b, -1\n" |
624 | " %A = select i1 %cmp, i8 %bn, i8 %an\n" |
625 | " ret i8 %A\n" |
626 | "}\n" ); |
627 | expectPattern(P: {.Flavor: SPF_UNKNOWN, .NaNBehavior: SPNB_NA, .Ordered: false}); |
628 | } |
629 | |
630 | TEST(ValueTracking, GuaranteedToTransferExecutionToSuccessor) { |
631 | StringRef Assembly = |
632 | "declare void @nounwind_readonly(ptr) nounwind readonly " |
633 | "declare void @nounwind_argmemonly(ptr) nounwind argmemonly " |
634 | "declare void @nounwind_willreturn(ptr) nounwind willreturn " |
635 | "declare void @throws_but_readonly(ptr) readonly " |
636 | "declare void @throws_but_argmemonly(ptr) argmemonly " |
637 | "declare void @throws_but_willreturn(ptr) willreturn " |
638 | " " |
639 | "declare void @unknown(ptr) " |
640 | " " |
641 | "define void @f(ptr %p) { " |
642 | " call void @nounwind_readonly(ptr %p) " |
643 | " call void @nounwind_argmemonly(ptr %p) " |
644 | " call void @nounwind_willreturn(ptr %p)" |
645 | " call void @throws_but_readonly(ptr %p) " |
646 | " call void @throws_but_argmemonly(ptr %p) " |
647 | " call void @throws_but_willreturn(ptr %p) " |
648 | " call void @unknown(ptr %p) nounwind readonly " |
649 | " call void @unknown(ptr %p) nounwind argmemonly " |
650 | " call void @unknown(ptr %p) nounwind willreturn " |
651 | " call void @unknown(ptr %p) readonly " |
652 | " call void @unknown(ptr %p) argmemonly " |
653 | " call void @unknown(ptr %p) willreturn " |
654 | " ret void " |
655 | "} " ; |
656 | |
657 | LLVMContext Context; |
658 | SMDiagnostic Error; |
659 | auto M = parseAssemblyString(AsmString: Assembly, Err&: Error, Context); |
660 | assert(M && "Bad assembly?" ); |
661 | |
662 | auto *F = M->getFunction(Name: "f" ); |
663 | assert(F && "Bad assembly?" ); |
664 | |
665 | auto &BB = F->getEntryBlock(); |
666 | bool ExpectedAnswers[] = { |
667 | false, // call void @nounwind_readonly(ptr %p) |
668 | false, // call void @nounwind_argmemonly(ptr %p) |
669 | true, // call void @nounwind_willreturn(ptr %p) |
670 | false, // call void @throws_but_readonly(ptr %p) |
671 | false, // call void @throws_but_argmemonly(ptr %p) |
672 | false, // call void @throws_but_willreturn(ptr %p) |
673 | false, // call void @unknown(ptr %p) nounwind readonly |
674 | false, // call void @unknown(ptr %p) nounwind argmemonly |
675 | true, // call void @unknown(ptr %p) nounwind willreturn |
676 | false, // call void @unknown(ptr %p) readonly |
677 | false, // call void @unknown(ptr %p) argmemonly |
678 | false, // call void @unknown(ptr %p) willreturn |
679 | false, // ret void |
680 | }; |
681 | |
682 | int Index = 0; |
683 | for (auto &I : BB) { |
684 | EXPECT_EQ(isGuaranteedToTransferExecutionToSuccessor(&I), |
685 | ExpectedAnswers[Index]) |
686 | << "Incorrect answer at instruction " << Index << " = " << I; |
687 | Index++; |
688 | } |
689 | } |
690 | |
691 | TEST_F(ValueTrackingTest, ComputeNumSignBits_PR32045) { |
692 | parseAssembly( |
693 | Assembly: "define i32 @test(i32 %a) {\n" |
694 | " %A = ashr i32 %a, -1\n" |
695 | " ret i32 %A\n" |
696 | "}\n" ); |
697 | EXPECT_EQ(ComputeNumSignBits(A, M->getDataLayout()), 32u); |
698 | } |
699 | |
700 | // No guarantees for canonical IR in this analysis, so this just bails out. |
701 | TEST_F(ValueTrackingTest, ComputeNumSignBits_Shuffle) { |
702 | parseAssembly( |
703 | Assembly: "define <2 x i32> @test() {\n" |
704 | " %A = shufflevector <2 x i32> undef, <2 x i32> undef, <2 x i32> <i32 0, i32 0>\n" |
705 | " ret <2 x i32> %A\n" |
706 | "}\n" ); |
707 | EXPECT_EQ(ComputeNumSignBits(A, M->getDataLayout()), 1u); |
708 | } |
709 | |
710 | // No guarantees for canonical IR in this analysis, so a shuffle element that |
711 | // references an undef value means this can't return any extra information. |
712 | TEST_F(ValueTrackingTest, ComputeNumSignBits_Shuffle2) { |
713 | parseAssembly( |
714 | Assembly: "define <2 x i32> @test(<2 x i1> %x) {\n" |
715 | " %sext = sext <2 x i1> %x to <2 x i32>\n" |
716 | " %A = shufflevector <2 x i32> %sext, <2 x i32> undef, <2 x i32> <i32 0, i32 2>\n" |
717 | " ret <2 x i32> %A\n" |
718 | "}\n" ); |
719 | EXPECT_EQ(ComputeNumSignBits(A, M->getDataLayout()), 1u); |
720 | } |
721 | |
722 | TEST_F(ValueTrackingTest, impliesPoisonTest_Identity) { |
723 | parseAssembly(Assembly: "define void @test(i32 %x, i32 %y) {\n" |
724 | " %A = add i32 %x, %y\n" |
725 | " ret void\n" |
726 | "}" ); |
727 | EXPECT_TRUE(impliesPoison(A, A)); |
728 | } |
729 | |
730 | TEST_F(ValueTrackingTest, impliesPoisonTest_ICmp) { |
731 | parseAssembly(Assembly: "define void @test(i32 %x) {\n" |
732 | " %A2 = icmp eq i32 %x, 0\n" |
733 | " %A = icmp eq i32 %x, 1\n" |
734 | " ret void\n" |
735 | "}" ); |
736 | EXPECT_TRUE(impliesPoison(A2, A)); |
737 | } |
738 | |
739 | TEST_F(ValueTrackingTest, impliesPoisonTest_ICmpUnknown) { |
740 | parseAssembly(Assembly: "define void @test(i32 %x, i32 %y) {\n" |
741 | " %A2 = icmp eq i32 %x, %y\n" |
742 | " %A = icmp eq i32 %x, 1\n" |
743 | " ret void\n" |
744 | "}" ); |
745 | EXPECT_FALSE(impliesPoison(A2, A)); |
746 | } |
747 | |
748 | TEST_F(ValueTrackingTest, impliesPoisonTest_AddNswOkay) { |
749 | parseAssembly(Assembly: "define void @test(i32 %x) {\n" |
750 | " %A2 = add nsw i32 %x, 1\n" |
751 | " %A = add i32 %A2, 1\n" |
752 | " ret void\n" |
753 | "}" ); |
754 | EXPECT_TRUE(impliesPoison(A2, A)); |
755 | } |
756 | |
757 | TEST_F(ValueTrackingTest, impliesPoisonTest_AddNswOkay2) { |
758 | parseAssembly(Assembly: "define void @test(i32 %x) {\n" |
759 | " %A2 = add i32 %x, 1\n" |
760 | " %A = add nsw i32 %A2, 1\n" |
761 | " ret void\n" |
762 | "}" ); |
763 | EXPECT_TRUE(impliesPoison(A2, A)); |
764 | } |
765 | |
766 | TEST_F(ValueTrackingTest, impliesPoisonTest_AddNsw) { |
767 | parseAssembly(Assembly: "define void @test(i32 %x) {\n" |
768 | " %A2 = add nsw i32 %x, 1\n" |
769 | " %A = add i32 %x, 1\n" |
770 | " ret void\n" |
771 | "}" ); |
772 | EXPECT_FALSE(impliesPoison(A2, A)); |
773 | } |
774 | |
775 | TEST_F(ValueTrackingTest, impliesPoisonTest_Cmp) { |
776 | parseAssembly(Assembly: "define void @test(i32 %x, i32 %y, i1 %c) {\n" |
777 | " %A2 = icmp eq i32 %x, %y\n" |
778 | " %A0 = icmp ult i32 %x, %y\n" |
779 | " %A = or i1 %A0, %c\n" |
780 | " ret void\n" |
781 | "}" ); |
782 | EXPECT_TRUE(impliesPoison(A2, A)); |
783 | } |
784 | |
785 | TEST_F(ValueTrackingTest, impliesPoisonTest_FCmpFMF) { |
786 | parseAssembly(Assembly: "define void @test(float %x, float %y, i1 %c) {\n" |
787 | " %A2 = fcmp nnan oeq float %x, %y\n" |
788 | " %A0 = fcmp olt float %x, %y\n" |
789 | " %A = or i1 %A0, %c\n" |
790 | " ret void\n" |
791 | "}" ); |
792 | EXPECT_FALSE(impliesPoison(A2, A)); |
793 | } |
794 | |
795 | TEST_F(ValueTrackingTest, impliesPoisonTest_AddSubSameOps) { |
796 | parseAssembly(Assembly: "define void @test(i32 %x, i32 %y, i1 %c) {\n" |
797 | " %A2 = add i32 %x, %y\n" |
798 | " %A = sub i32 %x, %y\n" |
799 | " ret void\n" |
800 | "}" ); |
801 | EXPECT_TRUE(impliesPoison(A2, A)); |
802 | } |
803 | |
804 | TEST_F(ValueTrackingTest, impliesPoisonTest_MaskCmp) { |
805 | parseAssembly(Assembly: "define void @test(i32 %x, i32 %y, i1 %c) {\n" |
806 | " %M2 = and i32 %x, 7\n" |
807 | " %A2 = icmp eq i32 %M2, 1\n" |
808 | " %M = and i32 %x, 15\n" |
809 | " %A = icmp eq i32 %M, 3\n" |
810 | " ret void\n" |
811 | "}" ); |
812 | EXPECT_TRUE(impliesPoison(A2, A)); |
813 | } |
814 | |
815 | TEST_F(ValueTrackingTest, ComputeNumSignBits_Shuffle_Pointers) { |
816 | parseAssembly( |
817 | Assembly: "define <2 x ptr> @test(<2 x ptr> %x) {\n" |
818 | " %A = shufflevector <2 x ptr> zeroinitializer, <2 x ptr> undef, <2 x i32> zeroinitializer\n" |
819 | " ret <2 x ptr> %A\n" |
820 | "}\n" ); |
821 | EXPECT_EQ(ComputeNumSignBits(A, M->getDataLayout()), 64u); |
822 | } |
823 | |
824 | TEST(ValueTracking, propagatesPoison) { |
825 | std::string AsmHead = |
826 | "declare i32 @g(i32)\n" |
827 | "define void @f(i32 %x, i32 %y, i32 %shamt, float %fx, float %fy, " |
828 | "i1 %cond, ptr %p) {\n" ; |
829 | std::string AsmTail = " ret void\n}" ; |
830 | // (propagates poison?, IR instruction) |
831 | SmallVector<std::tuple<bool, std::string, unsigned>, 32> Data = { |
832 | {true, "add i32 %x, %y" , 0}, |
833 | {true, "add i32 %x, %y" , 1}, |
834 | {true, "add nsw nuw i32 %x, %y" , 0}, |
835 | {true, "add nsw nuw i32 %x, %y" , 1}, |
836 | {true, "ashr i32 %x, %y" , 0}, |
837 | {true, "ashr i32 %x, %y" , 1}, |
838 | {true, "lshr exact i32 %x, 31" , 0}, |
839 | {true, "lshr exact i32 %x, 31" , 1}, |
840 | {true, "fadd float %fx, %fy" , 0}, |
841 | {true, "fadd float %fx, %fy" , 1}, |
842 | {true, "fsub float %fx, %fy" , 0}, |
843 | {true, "fsub float %fx, %fy" , 1}, |
844 | {true, "fmul float %fx, %fy" , 0}, |
845 | {true, "fmul float %fx, %fy" , 1}, |
846 | {true, "fdiv float %fx, %fy" , 0}, |
847 | {true, "fdiv float %fx, %fy" , 1}, |
848 | {true, "frem float %fx, %fy" , 0}, |
849 | {true, "frem float %fx, %fy" , 1}, |
850 | {true, "fneg float %fx" , 0}, |
851 | {true, "fcmp oeq float %fx, %fy" , 0}, |
852 | {true, "fcmp oeq float %fx, %fy" , 1}, |
853 | {true, "icmp eq i32 %x, %y" , 0}, |
854 | {true, "icmp eq i32 %x, %y" , 1}, |
855 | {true, "getelementptr i8, ptr %p, i32 %x" , 0}, |
856 | {true, "getelementptr i8, ptr %p, i32 %x" , 1}, |
857 | {true, "getelementptr inbounds i8, ptr %p, i32 %x" , 0}, |
858 | {true, "getelementptr inbounds i8, ptr %p, i32 %x" , 1}, |
859 | {true, "bitcast float %fx to i32" , 0}, |
860 | {true, "select i1 %cond, i32 %x, i32 %y" , 0}, |
861 | {false, "select i1 %cond, i32 %x, i32 %y" , 1}, |
862 | {false, "select i1 %cond, i32 %x, i32 %y" , 2}, |
863 | {false, "freeze i32 %x" , 0}, |
864 | {true, "udiv i32 %x, %y" , 0}, |
865 | {true, "udiv i32 %x, %y" , 1}, |
866 | {true, "urem i32 %x, %y" , 0}, |
867 | {true, "urem i32 %x, %y" , 1}, |
868 | {true, "sdiv exact i32 %x, %y" , 0}, |
869 | {true, "sdiv exact i32 %x, %y" , 1}, |
870 | {true, "srem i32 %x, %y" , 0}, |
871 | {true, "srem i32 %x, %y" , 1}, |
872 | {false, "call i32 @g(i32 %x)" , 0}, |
873 | {false, "call i32 @g(i32 %x)" , 1}, |
874 | {true, "call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)" , 0}, |
875 | {true, "call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %x, i32 %y)" , 0}, |
876 | {true, "call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 %y)" , 0}, |
877 | {true, "call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)" , 0}, |
878 | {true, "call {i32, i1} @llvm.usub.with.overflow.i32(i32 %x, i32 %y)" , 0}, |
879 | {true, "call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %y)" , 0}, |
880 | {true, "call i32 @llvm.sadd.sat.i32(i32 %x, i32 %y)" , 0}, |
881 | {true, "call i32 @llvm.ssub.sat.i32(i32 %x, i32 %y)" , 0}, |
882 | {true, "call i32 @llvm.sshl.sat.i32(i32 %x, i32 %y)" , 0}, |
883 | {true, "call i32 @llvm.uadd.sat.i32(i32 %x, i32 %y)" , 0}, |
884 | {true, "call i32 @llvm.usub.sat.i32(i32 %x, i32 %y)" , 0}, |
885 | {true, "call i32 @llvm.ushl.sat.i32(i32 %x, i32 %y)" , 0}, |
886 | {true, "call i32 @llvm.ctpop.i32(i32 %x)" , 0}, |
887 | {true, "call i32 @llvm.ctlz.i32(i32 %x, i1 true)" , 0}, |
888 | {true, "call i32 @llvm.cttz.i32(i32 %x, i1 true)" , 0}, |
889 | {true, "call i32 @llvm.abs.i32(i32 %x, i1 true)" , 0}, |
890 | {true, "call i32 @llvm.smax.i32(i32 %x, i32 %y)" , 0}, |
891 | {true, "call i32 @llvm.smin.i32(i32 %x, i32 %y)" , 0}, |
892 | {true, "call i32 @llvm.umax.i32(i32 %x, i32 %y)" , 0}, |
893 | {true, "call i32 @llvm.umin.i32(i32 %x, i32 %y)" , 0}, |
894 | {true, "call i32 @llvm.bitreverse.i32(i32 %x)" , 0}, |
895 | {true, "call i32 @llvm.bswap.i32(i32 %x)" , 0}, |
896 | {false, "call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %shamt)" , 0}, |
897 | {false, "call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %shamt)" , 1}, |
898 | {false, "call i32 @llvm.fshl.i32(i32 %x, i32 %y, i32 %shamt)" , 2}, |
899 | {false, "call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %shamt)" , 0}, |
900 | {false, "call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %shamt)" , 1}, |
901 | {false, "call i32 @llvm.fshr.i32(i32 %x, i32 %y, i32 %shamt)" , 2}, |
902 | {false, "call float @llvm.sqrt.f32(float %fx)" , 0}, |
903 | {false, "call float @llvm.powi.f32.i32(float %fx, i32 %x)" , 0}, |
904 | {false, "call float @llvm.sin.f32(float %fx)" , 0}, |
905 | {false, "call float @llvm.cos.f32(float %fx)" , 0}, |
906 | {false, "call float @llvm.pow.f32(float %fx, float %fy)" , 0}, |
907 | {false, "call float @llvm.exp.f32(float %fx)" , 0}, |
908 | {false, "call float @llvm.exp2.f32(float %fx)" , 0}, |
909 | {false, "call float @llvm.log.f32(float %fx)" , 0}, |
910 | {false, "call float @llvm.log10.f32(float %fx)" , 0}, |
911 | {false, "call float @llvm.log2.f32(float %fx)" , 0}, |
912 | {false, "call float @llvm.fma.f32(float %fx, float %fx, float %fy)" , 0}, |
913 | {false, "call float @llvm.fabs.f32(float %fx)" , 0}, |
914 | {false, "call float @llvm.minnum.f32(float %fx, float %fy)" , 0}, |
915 | {false, "call float @llvm.maxnum.f32(float %fx, float %fy)" , 0}, |
916 | {false, "call float @llvm.minimum.f32(float %fx, float %fy)" , 0}, |
917 | {false, "call float @llvm.maximum.f32(float %fx, float %fy)" , 0}, |
918 | {false, "call float @llvm.copysign.f32(float %fx, float %fy)" , 0}, |
919 | {false, "call float @llvm.floor.f32(float %fx)" , 0}, |
920 | {false, "call float @llvm.ceil.f32(float %fx)" , 0}, |
921 | {false, "call float @llvm.trunc.f32(float %fx)" , 0}, |
922 | {false, "call float @llvm.rint.f32(float %fx)" , 0}, |
923 | {false, "call float @llvm.nearbyint.f32(float %fx)" , 0}, |
924 | {false, "call float @llvm.round.f32(float %fx)" , 0}, |
925 | {false, "call float @llvm.roundeven.f32(float %fx)" , 0}, |
926 | {false, "call i32 @llvm.lround.f32(float %fx)" , 0}, |
927 | {false, "call i64 @llvm.llround.f32(float %fx)" , 0}, |
928 | {false, "call i32 @llvm.lrint.f32(float %fx)" , 0}, |
929 | {false, "call i64 @llvm.llrint.f32(float %fx)" , 0}, |
930 | {false, "call float @llvm.fmuladd.f32(float %fx, float %fx, float %fy)" , |
931 | 0}}; |
932 | |
933 | std::string AssemblyStr = AsmHead; |
934 | for (auto &Itm : Data) |
935 | AssemblyStr += std::get<1>(t&: Itm) + "\n" ; |
936 | AssemblyStr += AsmTail; |
937 | |
938 | LLVMContext Context; |
939 | SMDiagnostic Error; |
940 | auto M = parseAssemblyString(AsmString: AssemblyStr, Err&: Error, Context); |
941 | assert(M && "Bad assembly?" ); |
942 | |
943 | auto *F = M->getFunction(Name: "f" ); |
944 | assert(F && "Bad assembly?" ); |
945 | |
946 | auto &BB = F->getEntryBlock(); |
947 | |
948 | int Index = 0; |
949 | for (auto &I : BB) { |
950 | if (isa<ReturnInst>(Val: &I)) |
951 | break; |
952 | bool ExpectedVal = std::get<0>(t&: Data[Index]); |
953 | unsigned OpIdx = std::get<2>(t&: Data[Index]); |
954 | EXPECT_EQ(propagatesPoison(I.getOperandUse(OpIdx)), ExpectedVal) |
955 | << "Incorrect answer at instruction " << Index << " = " << I; |
956 | Index++; |
957 | } |
958 | } |
959 | |
960 | TEST_F(ValueTrackingTest, programUndefinedIfPoison) { |
961 | parseAssembly(Assembly: "declare i32 @any_num()" |
962 | "define void @test(i32 %mask) {\n" |
963 | " %A = call i32 @any_num()\n" |
964 | " %B = or i32 %A, %mask\n" |
965 | " udiv i32 1, %B" |
966 | " ret void\n" |
967 | "}\n" ); |
968 | // If %A was poison, udiv raises UB regardless of %mask's value |
969 | EXPECT_EQ(programUndefinedIfPoison(A), true); |
970 | } |
971 | |
972 | TEST_F(ValueTrackingTest, programUndefinedIfPoisonSelect) { |
973 | parseAssembly(Assembly: "declare i32 @any_num()" |
974 | "define void @test(i1 %Cond) {\n" |
975 | " %A = call i32 @any_num()\n" |
976 | " %B = add i32 %A, 1\n" |
977 | " %C = select i1 %Cond, i32 %A, i32 %B\n" |
978 | " udiv i32 1, %C" |
979 | " ret void\n" |
980 | "}\n" ); |
981 | // If A is poison, B is also poison, and therefore C is poison regardless of |
982 | // the value of %Cond. |
983 | EXPECT_EQ(programUndefinedIfPoison(A), true); |
984 | } |
985 | |
986 | TEST_F(ValueTrackingTest, programUndefinedIfUndefOrPoison) { |
987 | parseAssembly(Assembly: "declare i32 @any_num()" |
988 | "define void @test(i32 %mask) {\n" |
989 | " %A = call i32 @any_num()\n" |
990 | " %B = or i32 %A, %mask\n" |
991 | " udiv i32 1, %B" |
992 | " ret void\n" |
993 | "}\n" ); |
994 | // If %A was undef and %mask was 1, udiv does not raise UB |
995 | EXPECT_EQ(programUndefinedIfUndefOrPoison(A), false); |
996 | } |
997 | |
998 | TEST_F(ValueTrackingTest, isGuaranteedNotToBePoison_exploitBranchCond) { |
999 | parseAssembly(Assembly: "declare i1 @any_bool()" |
1000 | "define void @test(i1 %y) {\n" |
1001 | " %A = call i1 @any_bool()\n" |
1002 | " %cond = and i1 %A, %y\n" |
1003 | " br i1 %cond, label %BB1, label %BB2\n" |
1004 | "BB1:\n" |
1005 | " ret void\n" |
1006 | "BB2:\n" |
1007 | " ret void\n" |
1008 | "}\n" ); |
1009 | DominatorTree DT(*F); |
1010 | for (auto &BB : *F) { |
1011 | if (&BB == &F->getEntryBlock()) |
1012 | continue; |
1013 | |
1014 | EXPECT_EQ(isGuaranteedNotToBePoison(A, nullptr, BB.getTerminator(), &DT), |
1015 | true) |
1016 | << "isGuaranteedNotToBePoison does not hold at " << *BB.getTerminator(); |
1017 | } |
1018 | } |
1019 | |
1020 | TEST_F(ValueTrackingTest, isGuaranteedNotToBePoison_phi) { |
1021 | parseAssembly(Assembly: "declare i32 @any_i32(i32)" |
1022 | "define void @test() {\n" |
1023 | "ENTRY:\n" |
1024 | " br label %LOOP\n" |
1025 | "LOOP:\n" |
1026 | " %A = phi i32 [0, %ENTRY], [%A.next, %NEXT]\n" |
1027 | " %A.next = call i32 @any_i32(i32 %A)\n" |
1028 | " %cond = icmp eq i32 %A.next, 0\n" |
1029 | " br i1 %cond, label %NEXT, label %EXIT\n" |
1030 | "NEXT:\n" |
1031 | " br label %LOOP\n" |
1032 | "EXIT:\n" |
1033 | " ret void\n" |
1034 | "}\n" ); |
1035 | DominatorTree DT(*F); |
1036 | for (auto &BB : *F) { |
1037 | if (BB.getName() == "LOOP" ) { |
1038 | EXPECT_EQ(isGuaranteedNotToBePoison(A, nullptr, A, &DT), true) |
1039 | << "isGuaranteedNotToBePoison does not hold" ; |
1040 | } |
1041 | } |
1042 | } |
1043 | |
1044 | TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison) { |
1045 | parseAssembly(Assembly: "declare void @f(i32 noundef)" |
1046 | "define void @test(i32 %x) {\n" |
1047 | " %A = bitcast i32 %x to i32\n" |
1048 | " call void @f(i32 noundef %x)\n" |
1049 | " ret void\n" |
1050 | "}\n" ); |
1051 | EXPECT_EQ(isGuaranteedNotToBeUndefOrPoison(A), true); |
1052 | EXPECT_EQ(isGuaranteedNotToBeUndefOrPoison(UndefValue::get(IntegerType::get(Context, 8))), false); |
1053 | EXPECT_EQ(isGuaranteedNotToBeUndefOrPoison(PoisonValue::get(IntegerType::get(Context, 8))), false); |
1054 | EXPECT_EQ(isGuaranteedNotToBePoison(UndefValue::get(IntegerType::get(Context, 8))), true); |
1055 | EXPECT_EQ(isGuaranteedNotToBePoison(PoisonValue::get(IntegerType::get(Context, 8))), false); |
1056 | |
1057 | Type *Int32Ty = Type::getInt32Ty(C&: Context); |
1058 | Constant *CU = UndefValue::get(T: Int32Ty); |
1059 | Constant *CP = PoisonValue::get(T: Int32Ty); |
1060 | Constant *C1 = ConstantInt::get(Ty: Int32Ty, V: 1); |
1061 | Constant *C2 = ConstantInt::get(Ty: Int32Ty, V: 2); |
1062 | |
1063 | { |
1064 | Constant *V1 = ConstantVector::get(V: {C1, C2}); |
1065 | EXPECT_TRUE(isGuaranteedNotToBeUndefOrPoison(V1)); |
1066 | EXPECT_TRUE(isGuaranteedNotToBePoison(V1)); |
1067 | } |
1068 | |
1069 | { |
1070 | Constant *V2 = ConstantVector::get(V: {C1, CU}); |
1071 | EXPECT_FALSE(isGuaranteedNotToBeUndefOrPoison(V2)); |
1072 | EXPECT_TRUE(isGuaranteedNotToBePoison(V2)); |
1073 | } |
1074 | |
1075 | { |
1076 | Constant *V3 = ConstantVector::get(V: {C1, CP}); |
1077 | EXPECT_FALSE(isGuaranteedNotToBeUndefOrPoison(V3)); |
1078 | EXPECT_FALSE(isGuaranteedNotToBePoison(V3)); |
1079 | } |
1080 | } |
1081 | |
1082 | TEST_F(ValueTrackingTest, isGuaranteedNotToBeUndefOrPoison_assume) { |
1083 | parseAssembly(Assembly: "declare i1 @f_i1()\n" |
1084 | "declare i32 @f_i32()\n" |
1085 | "declare void @llvm.assume(i1)\n" |
1086 | "define void @test() {\n" |
1087 | " %A = call i32 @f_i32()\n" |
1088 | " %cond = call i1 @f_i1()\n" |
1089 | " %CxtI = add i32 0, 0\n" |
1090 | " br i1 %cond, label %BB1, label %EXIT\n" |
1091 | "BB1:\n" |
1092 | " %CxtI2 = add i32 0, 0\n" |
1093 | " %cond2 = call i1 @f_i1()\n" |
1094 | " call void @llvm.assume(i1 true) [ \"noundef\"(i32 %A) ]\n" |
1095 | " br i1 %cond2, label %BB2, label %EXIT\n" |
1096 | "BB2:\n" |
1097 | " %CxtI3 = add i32 0, 0\n" |
1098 | " ret void\n" |
1099 | "EXIT:\n" |
1100 | " ret void\n" |
1101 | "}" ); |
1102 | AssumptionCache AC(*F); |
1103 | DominatorTree DT(*F); |
1104 | EXPECT_FALSE(isGuaranteedNotToBeUndefOrPoison(A, &AC, CxtI, &DT)); |
1105 | EXPECT_FALSE(isGuaranteedNotToBeUndefOrPoison(A, &AC, CxtI2, &DT)); |
1106 | EXPECT_TRUE(isGuaranteedNotToBeUndefOrPoison(A, &AC, CxtI3, &DT)); |
1107 | } |
1108 | |
1109 | TEST(ValueTracking, canCreatePoisonOrUndef) { |
1110 | std::string AsmHead = |
1111 | "@s = external dso_local global i32, align 1\n" |
1112 | "declare i32 @g(i32)\n" |
1113 | "declare {i32, i1} @llvm.sadd.with.overflow.i32(i32 %a, i32 %b)\n" |
1114 | "declare {i32, i1} @llvm.ssub.with.overflow.i32(i32 %a, i32 %b)\n" |
1115 | "declare {i32, i1} @llvm.smul.with.overflow.i32(i32 %a, i32 %b)\n" |
1116 | "declare {i32, i1} @llvm.uadd.with.overflow.i32(i32 %a, i32 %b)\n" |
1117 | "declare {i32, i1} @llvm.usub.with.overflow.i32(i32 %a, i32 %b)\n" |
1118 | "declare {i32, i1} @llvm.umul.with.overflow.i32(i32 %a, i32 %b)\n" |
1119 | "define void @f(i32 %x, i32 %y, float %fx, float %fy, i1 %cond, " |
1120 | "<4 x i32> %vx, <4 x i32> %vx2, <vscale x 4 x i32> %svx, ptr %p) {\n" ; |
1121 | std::string AsmTail = " ret void\n}" ; |
1122 | // (can create poison?, can create undef?, IR instruction) |
1123 | SmallVector<std::pair<std::pair<bool, bool>, std::string>, 32> Data = { |
1124 | {{false, false}, "add i32 %x, %y" }, |
1125 | {{true, false}, "add nsw nuw i32 %x, %y" }, |
1126 | {{true, false}, "shl i32 %x, %y" }, |
1127 | {{true, false}, "shl <4 x i32> %vx, %vx2" }, |
1128 | {{true, false}, "shl nsw i32 %x, %y" }, |
1129 | {{true, false}, "shl nsw <4 x i32> %vx, <i32 0, i32 1, i32 2, i32 3>" }, |
1130 | {{false, false}, "shl i32 %x, 31" }, |
1131 | {{true, false}, "shl i32 %x, 32" }, |
1132 | {{false, false}, "shl <4 x i32> %vx, <i32 0, i32 1, i32 2, i32 3>" }, |
1133 | {{true, false}, "shl <4 x i32> %vx, <i32 0, i32 1, i32 2, i32 32>" }, |
1134 | {{true, false}, "ashr i32 %x, %y" }, |
1135 | {{true, false}, "ashr exact i32 %x, %y" }, |
1136 | {{false, false}, "ashr i32 %x, 31" }, |
1137 | {{true, false}, "ashr exact i32 %x, 31" }, |
1138 | {{false, false}, "ashr <4 x i32> %vx, <i32 0, i32 1, i32 2, i32 3>" }, |
1139 | {{true, false}, "ashr <4 x i32> %vx, <i32 0, i32 1, i32 2, i32 32>" }, |
1140 | {{true, false}, "ashr exact <4 x i32> %vx, <i32 0, i32 1, i32 2, i32 3>" }, |
1141 | {{true, false}, "lshr i32 %x, %y" }, |
1142 | {{true, false}, "lshr exact i32 %x, 31" }, |
1143 | {{false, false}, "udiv i32 %x, %y" }, |
1144 | {{true, false}, "udiv exact i32 %x, %y" }, |
1145 | {{false, false}, "getelementptr i8, ptr %p, i32 %x" }, |
1146 | {{true, false}, "getelementptr inbounds i8, ptr %p, i32 %x" }, |
1147 | {{true, false}, "fneg nnan float %fx" }, |
1148 | {{false, false}, "fneg float %fx" }, |
1149 | {{false, false}, "fadd float %fx, %fy" }, |
1150 | {{true, false}, "fadd nnan float %fx, %fy" }, |
1151 | {{false, false}, "urem i32 %x, %y" }, |
1152 | {{true, false}, "fptoui float %fx to i32" }, |
1153 | {{true, false}, "fptosi float %fx to i32" }, |
1154 | {{false, false}, "bitcast float %fx to i32" }, |
1155 | {{false, false}, "select i1 %cond, i32 %x, i32 %y" }, |
1156 | {{true, false}, "select nnan i1 %cond, float %fx, float %fy" }, |
1157 | {{true, false}, "extractelement <4 x i32> %vx, i32 %x" }, |
1158 | {{false, false}, "extractelement <4 x i32> %vx, i32 3" }, |
1159 | {{true, false}, "extractelement <vscale x 4 x i32> %svx, i32 4" }, |
1160 | {{true, false}, "insertelement <4 x i32> %vx, i32 %x, i32 %y" }, |
1161 | {{false, false}, "insertelement <4 x i32> %vx, i32 %x, i32 3" }, |
1162 | {{true, false}, "insertelement <vscale x 4 x i32> %svx, i32 %x, i32 4" }, |
1163 | {{false, false}, "freeze i32 %x" }, |
1164 | {{false, false}, |
1165 | "shufflevector <4 x i32> %vx, <4 x i32> %vx2, " |
1166 | "<4 x i32> <i32 0, i32 1, i32 2, i32 3>" }, |
1167 | {{true, false}, |
1168 | "shufflevector <4 x i32> %vx, <4 x i32> %vx2, " |
1169 | "<4 x i32> <i32 0, i32 1, i32 2, i32 poison>" }, |
1170 | {{true, false}, |
1171 | "shufflevector <vscale x 4 x i32> %svx, " |
1172 | "<vscale x 4 x i32> %svx, <vscale x 4 x i32> poison" }, |
1173 | {{true, false}, "call i32 @g(i32 %x)" }, |
1174 | {{false, false}, "call noundef i32 @g(i32 %x)" }, |
1175 | {{true, false}, "fcmp nnan oeq float %fx, %fy" }, |
1176 | {{false, false}, "fcmp oeq float %fx, %fy" }, |
1177 | {{true, false}, "ashr i32 %x, ptrtoint (ptr @s to i32)" }, |
1178 | {{false, false}, |
1179 | "call {i32, i1} @llvm.sadd.with.overflow.i32(i32 %x, i32 %y)" }, |
1180 | {{false, false}, |
1181 | "call {i32, i1} @llvm.ssub.with.overflow.i32(i32 %x, i32 %y)" }, |
1182 | {{false, false}, |
1183 | "call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 %y)" }, |
1184 | {{false, false}, |
1185 | "call {i32, i1} @llvm.uadd.with.overflow.i32(i32 %x, i32 %y)" }, |
1186 | {{false, false}, |
1187 | "call {i32, i1} @llvm.usub.with.overflow.i32(i32 %x, i32 %y)" }, |
1188 | {{false, false}, |
1189 | "call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 %y)" }}; |
1190 | |
1191 | std::string AssemblyStr = AsmHead; |
1192 | for (auto &Itm : Data) |
1193 | AssemblyStr += Itm.second + "\n" ; |
1194 | AssemblyStr += AsmTail; |
1195 | |
1196 | LLVMContext Context; |
1197 | SMDiagnostic Error; |
1198 | auto M = parseAssemblyString(AsmString: AssemblyStr, Err&: Error, Context); |
1199 | assert(M && "Bad assembly?" ); |
1200 | |
1201 | auto *F = M->getFunction(Name: "f" ); |
1202 | assert(F && "Bad assembly?" ); |
1203 | |
1204 | auto &BB = F->getEntryBlock(); |
1205 | |
1206 | int Index = 0; |
1207 | for (auto &I : BB) { |
1208 | if (isa<ReturnInst>(Val: &I)) |
1209 | break; |
1210 | bool Poison = Data[Index].first.first; |
1211 | bool Undef = Data[Index].first.second; |
1212 | EXPECT_EQ(canCreatePoison(cast<Operator>(&I)), Poison) |
1213 | << "Incorrect answer of canCreatePoison at instruction " << Index |
1214 | << " = " << I; |
1215 | EXPECT_EQ(canCreateUndefOrPoison(cast<Operator>(&I)), Undef || Poison) |
1216 | << "Incorrect answer of canCreateUndef at instruction " << Index |
1217 | << " = " << I; |
1218 | Index++; |
1219 | } |
1220 | } |
1221 | |
1222 | TEST_F(ValueTrackingTest, computePtrAlignment) { |
1223 | parseAssembly(Assembly: "declare i1 @f_i1()\n" |
1224 | "declare ptr @f_i8p()\n" |
1225 | "declare void @llvm.assume(i1)\n" |
1226 | "define void @test() {\n" |
1227 | " %A = call ptr @f_i8p()\n" |
1228 | " %cond = call i1 @f_i1()\n" |
1229 | " %CxtI = add i32 0, 0\n" |
1230 | " br i1 %cond, label %BB1, label %EXIT\n" |
1231 | "BB1:\n" |
1232 | " %CxtI2 = add i32 0, 0\n" |
1233 | " %cond2 = call i1 @f_i1()\n" |
1234 | " call void @llvm.assume(i1 true) [ \"align\"(ptr %A, i64 16) ]\n" |
1235 | " br i1 %cond2, label %BB2, label %EXIT\n" |
1236 | "BB2:\n" |
1237 | " %CxtI3 = add i32 0, 0\n" |
1238 | " ret void\n" |
1239 | "EXIT:\n" |
1240 | " ret void\n" |
1241 | "}" ); |
1242 | AssumptionCache AC(*F); |
1243 | DominatorTree DT(*F); |
1244 | const DataLayout &DL = M->getDataLayout(); |
1245 | EXPECT_EQ(getKnownAlignment(A, DL, CxtI, &AC, &DT), Align(1)); |
1246 | EXPECT_EQ(getKnownAlignment(A, DL, CxtI2, &AC, &DT), Align(1)); |
1247 | EXPECT_EQ(getKnownAlignment(A, DL, CxtI3, &AC, &DT), Align(16)); |
1248 | } |
1249 | |
1250 | TEST_F(ComputeKnownBitsTest, ComputeKnownBits) { |
1251 | parseAssembly( |
1252 | Assembly: "define i32 @test(i32 %a, i32 %b) {\n" |
1253 | " %ash = mul i32 %a, 8\n" |
1254 | " %aad = add i32 %ash, 7\n" |
1255 | " %aan = and i32 %aad, 4095\n" |
1256 | " %bsh = shl i32 %b, 4\n" |
1257 | " %bad = or i32 %bsh, 6\n" |
1258 | " %ban = and i32 %bad, 4095\n" |
1259 | " %A = mul i32 %aan, %ban\n" |
1260 | " ret i32 %A\n" |
1261 | "}\n" ); |
1262 | expectKnownBits(/*zero*/ Zero: 4278190085u, /*one*/ One: 10u); |
1263 | } |
1264 | |
1265 | TEST_F(ComputeKnownBitsTest, ComputeKnownMulBits) { |
1266 | parseAssembly( |
1267 | Assembly: "define i32 @test(i32 %a, i32 %b) {\n" |
1268 | " %aa = shl i32 %a, 5\n" |
1269 | " %bb = shl i32 %b, 5\n" |
1270 | " %aaa = or i32 %aa, 24\n" |
1271 | " %bbb = or i32 %bb, 28\n" |
1272 | " %A = mul i32 %aaa, %bbb\n" |
1273 | " ret i32 %A\n" |
1274 | "}\n" ); |
1275 | expectKnownBits(/*zero*/ Zero: 95u, /*one*/ One: 32u); |
1276 | } |
1277 | |
1278 | TEST_F(ComputeKnownFPClassTest, SelectPos0) { |
1279 | parseAssembly( |
1280 | Assembly: "define float @test(i1 %cond) {\n" |
1281 | " %A = select i1 %cond, float 0.0, float 0.0" |
1282 | " ret float %A\n" |
1283 | "}\n" ); |
1284 | expectKnownFPClass(KnownTrue: fcPosZero, SignBitKnown: false); |
1285 | } |
1286 | |
1287 | TEST_F(ComputeKnownFPClassTest, SelectNeg0) { |
1288 | parseAssembly( |
1289 | Assembly: "define float @test(i1 %cond) {\n" |
1290 | " %A = select i1 %cond, float -0.0, float -0.0" |
1291 | " ret float %A\n" |
1292 | "}\n" ); |
1293 | expectKnownFPClass(KnownTrue: fcNegZero, SignBitKnown: true); |
1294 | } |
1295 | |
1296 | TEST_F(ComputeKnownFPClassTest, SelectPosOrNeg0) { |
1297 | parseAssembly( |
1298 | Assembly: "define float @test(i1 %cond) {\n" |
1299 | " %A = select i1 %cond, float 0.0, float -0.0" |
1300 | " ret float %A\n" |
1301 | "}\n" ); |
1302 | expectKnownFPClass(KnownTrue: fcZero, SignBitKnown: std::nullopt); |
1303 | } |
1304 | |
1305 | TEST_F(ComputeKnownFPClassTest, SelectPosInf) { |
1306 | parseAssembly( |
1307 | Assembly: "define float @test(i1 %cond) {\n" |
1308 | " %A = select i1 %cond, float 0x7FF0000000000000, float 0x7FF0000000000000" |
1309 | " ret float %A\n" |
1310 | "}\n" ); |
1311 | expectKnownFPClass(KnownTrue: fcPosInf, SignBitKnown: false); |
1312 | } |
1313 | |
1314 | TEST_F(ComputeKnownFPClassTest, SelectNegInf) { |
1315 | parseAssembly( |
1316 | Assembly: "define float @test(i1 %cond) {\n" |
1317 | " %A = select i1 %cond, float 0xFFF0000000000000, float 0xFFF0000000000000" |
1318 | " ret float %A\n" |
1319 | "}\n" ); |
1320 | expectKnownFPClass(KnownTrue: fcNegInf, SignBitKnown: true); |
1321 | } |
1322 | |
1323 | TEST_F(ComputeKnownFPClassTest, SelectPosOrNegInf) { |
1324 | parseAssembly( |
1325 | Assembly: "define float @test(i1 %cond) {\n" |
1326 | " %A = select i1 %cond, float 0x7FF0000000000000, float 0xFFF0000000000000" |
1327 | " ret float %A\n" |
1328 | "}\n" ); |
1329 | expectKnownFPClass(KnownTrue: fcInf, SignBitKnown: std::nullopt); |
1330 | } |
1331 | |
1332 | TEST_F(ComputeKnownFPClassTest, SelectNNaN) { |
1333 | parseAssembly( |
1334 | Assembly: "define float @test(i1 %cond, float %arg0, float %arg1) {\n" |
1335 | " %A = select nnan i1 %cond, float %arg0, float %arg1" |
1336 | " ret float %A\n" |
1337 | "}\n" ); |
1338 | expectKnownFPClass(KnownTrue: ~fcNan, SignBitKnown: std::nullopt); |
1339 | } |
1340 | |
1341 | TEST_F(ComputeKnownFPClassTest, SelectNInf) { |
1342 | parseAssembly( |
1343 | Assembly: "define float @test(i1 %cond, float %arg0, float %arg1) {\n" |
1344 | " %A = select ninf i1 %cond, float %arg0, float %arg1" |
1345 | " ret float %A\n" |
1346 | "}\n" ); |
1347 | expectKnownFPClass(KnownTrue: ~fcInf, SignBitKnown: std::nullopt); |
1348 | } |
1349 | |
1350 | TEST_F(ComputeKnownFPClassTest, SelectNNaNNInf) { |
1351 | parseAssembly( |
1352 | Assembly: "define float @test(i1 %cond, float %arg0, float %arg1) {\n" |
1353 | " %A = select nnan ninf i1 %cond, float %arg0, float %arg1" |
1354 | " ret float %A\n" |
1355 | "}\n" ); |
1356 | expectKnownFPClass(KnownTrue: ~(fcNan | fcInf), SignBitKnown: std::nullopt); |
1357 | } |
1358 | |
1359 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassArgUnionAll) { |
1360 | parseAssembly( |
1361 | Assembly: "define float @test(i1 %cond, float nofpclass(snan ninf nsub pzero pnorm) %arg0, float nofpclass(qnan nnorm nzero psub pinf) %arg1) {\n" |
1362 | " %A = select i1 %cond, float %arg0, float %arg1" |
1363 | " ret float %A\n" |
1364 | "}\n" ); |
1365 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt); |
1366 | } |
1367 | |
1368 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassArgNoNan) { |
1369 | parseAssembly( |
1370 | Assembly: "define float @test(i1 %cond, float nofpclass(nan) %arg0, float nofpclass(nan) %arg1) {\n" |
1371 | " %A = select i1 %cond, float %arg0, float %arg1" |
1372 | " ret float %A\n" |
1373 | "}\n" ); |
1374 | expectKnownFPClass(KnownTrue: ~fcNan, SignBitKnown: std::nullopt); |
1375 | } |
1376 | |
1377 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassArgNoPInf) { |
1378 | parseAssembly( |
1379 | Assembly: "define float @test(i1 %cond, float nofpclass(inf) %arg0, float nofpclass(pinf) %arg1) {\n" |
1380 | " %A = select i1 %cond, float %arg0, float %arg1" |
1381 | " ret float %A\n" |
1382 | "}\n" ); |
1383 | expectKnownFPClass(KnownTrue: ~fcPosInf, SignBitKnown: std::nullopt); |
1384 | } |
1385 | |
1386 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassArgNoNInf) { |
1387 | parseAssembly( |
1388 | Assembly: "define float @test(i1 %cond, float nofpclass(ninf) %arg0, float nofpclass(inf) %arg1) {\n" |
1389 | " %A = select i1 %cond, float %arg0, float %arg1" |
1390 | " ret float %A\n" |
1391 | "}\n" ); |
1392 | expectKnownFPClass(KnownTrue: ~fcNegInf, SignBitKnown: std::nullopt); |
1393 | } |
1394 | |
1395 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassCallSiteNoNan) { |
1396 | parseAssembly( |
1397 | Assembly: "declare float @func()\n" |
1398 | "define float @test() {\n" |
1399 | " %A = call nofpclass(nan) float @func()\n" |
1400 | " ret float %A\n" |
1401 | "}\n" ); |
1402 | expectKnownFPClass(KnownTrue: ~fcNan, SignBitKnown: std::nullopt); |
1403 | } |
1404 | |
1405 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassCallSiteNoZeros) { |
1406 | parseAssembly( |
1407 | Assembly: "declare float @func()\n" |
1408 | "define float @test() {\n" |
1409 | " %A = call nofpclass(zero) float @func()\n" |
1410 | " ret float %A\n" |
1411 | "}\n" ); |
1412 | expectKnownFPClass(KnownTrue: ~fcZero, SignBitKnown: std::nullopt); |
1413 | } |
1414 | |
1415 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassDeclarationNoNan) { |
1416 | parseAssembly( |
1417 | Assembly: "declare nofpclass(nan) float @no_nans()\n" |
1418 | "define float @test() {\n" |
1419 | " %A = call float @no_nans()\n" |
1420 | " ret float %A\n" |
1421 | "}\n" ); |
1422 | expectKnownFPClass(KnownTrue: ~fcNan, SignBitKnown: std::nullopt); |
1423 | } |
1424 | |
1425 | // Check nofpclass + ninf works on a callsite |
1426 | TEST_F(ComputeKnownFPClassTest, SelectNoFPClassCallSiteNoZerosNInfFlags) { |
1427 | parseAssembly( |
1428 | Assembly: "declare float @func()\n" |
1429 | "define float @test() {\n" |
1430 | " %A = call ninf nofpclass(zero) float @func()\n" |
1431 | " ret float %A\n" |
1432 | "}\n" ); |
1433 | expectKnownFPClass(KnownTrue: ~(fcZero | fcInf), SignBitKnown: std::nullopt); |
1434 | } |
1435 | |
1436 | TEST_F(ComputeKnownFPClassTest, FNegNInf) { |
1437 | parseAssembly( |
1438 | Assembly: "define float @test(float %arg) {\n" |
1439 | " %A = fneg ninf float %arg" |
1440 | " ret float %A\n" |
1441 | "}\n" ); |
1442 | expectKnownFPClass(KnownTrue: ~fcInf, SignBitKnown: std::nullopt); |
1443 | } |
1444 | |
1445 | TEST_F(ComputeKnownFPClassTest, FabsUnknown) { |
1446 | parseAssembly( |
1447 | Assembly: "declare float @llvm.fabs.f32(float)" |
1448 | "define float @test(float %arg) {\n" |
1449 | " %A = call float @llvm.fabs.f32(float %arg)" |
1450 | " ret float %A\n" |
1451 | "}\n" ); |
1452 | expectKnownFPClass(KnownTrue: fcPositive | fcNan, SignBitKnown: false); |
1453 | } |
1454 | |
1455 | TEST_F(ComputeKnownFPClassTest, FNegFabsUnknown) { |
1456 | parseAssembly( |
1457 | Assembly: "declare float @llvm.fabs.f32(float)" |
1458 | "define float @test(float %arg) {\n" |
1459 | " %fabs = call float @llvm.fabs.f32(float %arg)" |
1460 | " %A = fneg float %fabs" |
1461 | " ret float %A\n" |
1462 | "}\n" ); |
1463 | expectKnownFPClass(KnownTrue: fcNegative | fcNan, SignBitKnown: true); |
1464 | } |
1465 | |
1466 | TEST_F(ComputeKnownFPClassTest, NegFabsNInf) { |
1467 | parseAssembly( |
1468 | Assembly: "declare float @llvm.fabs.f32(float)" |
1469 | "define float @test(float %arg) {\n" |
1470 | " %fabs = call ninf float @llvm.fabs.f32(float %arg)" |
1471 | " %A = fneg float %fabs" |
1472 | " ret float %A\n" |
1473 | "}\n" ); |
1474 | expectKnownFPClass(KnownTrue: (fcNegative & ~fcNegInf) | fcNan, SignBitKnown: true); |
1475 | } |
1476 | |
1477 | TEST_F(ComputeKnownFPClassTest, FNegFabsNNaN) { |
1478 | parseAssembly( |
1479 | Assembly: "declare float @llvm.fabs.f32(float)" |
1480 | "define float @test(float %arg) {\n" |
1481 | " %fabs = call nnan float @llvm.fabs.f32(float %arg)" |
1482 | " %A = fneg float %fabs" |
1483 | " ret float %A\n" |
1484 | "}\n" ); |
1485 | expectKnownFPClass(KnownTrue: fcNegative, SignBitKnown: true); |
1486 | } |
1487 | |
1488 | TEST_F(ComputeKnownFPClassTest, CopySignNNanSrc0) { |
1489 | parseAssembly( |
1490 | Assembly: "declare float @llvm.fabs.f32(float)\n" |
1491 | "declare float @llvm.copysign.f32(float, float)\n" |
1492 | "define float @test(float %arg0, float %arg1) {\n" |
1493 | " %fabs = call nnan float @llvm.fabs.f32(float %arg0)" |
1494 | " %A = call float @llvm.copysign.f32(float %fabs, float %arg1)" |
1495 | " ret float %A\n" |
1496 | "}\n" ); |
1497 | expectKnownFPClass(KnownTrue: ~fcNan, SignBitKnown: std::nullopt); |
1498 | } |
1499 | |
1500 | TEST_F(ComputeKnownFPClassTest, CopySignNInfSrc0_NegSign) { |
1501 | parseAssembly( |
1502 | Assembly: "declare float @llvm.log.f32(float)\n" |
1503 | "declare float @llvm.copysign.f32(float, float)\n" |
1504 | "define float @test(float %arg0, float %arg1) {\n" |
1505 | " %ninf = call ninf float @llvm.log.f32(float %arg0)" |
1506 | " %A = call float @llvm.copysign.f32(float %ninf, float -1.0)" |
1507 | " ret float %A\n" |
1508 | "}\n" ); |
1509 | expectKnownFPClass(KnownTrue: fcNegFinite | fcNan, SignBitKnown: true); |
1510 | } |
1511 | |
1512 | TEST_F(ComputeKnownFPClassTest, CopySignNInfSrc0_PosSign) { |
1513 | parseAssembly( |
1514 | Assembly: "declare float @llvm.sqrt.f32(float)\n" |
1515 | "declare float @llvm.copysign.f32(float, float)\n" |
1516 | "define float @test(float %arg0, float %arg1) {\n" |
1517 | " %ninf = call ninf float @llvm.sqrt.f32(float %arg0)" |
1518 | " %A = call float @llvm.copysign.f32(float %ninf, float 1.0)" |
1519 | " ret float %A\n" |
1520 | "}\n" ); |
1521 | expectKnownFPClass(KnownTrue: fcPosFinite | fcNan, SignBitKnown: false); |
1522 | } |
1523 | |
1524 | TEST_F(ComputeKnownFPClassTest, UIToFP) { |
1525 | parseAssembly( |
1526 | Assembly: "define float @test(i32 %arg0, i16 %arg1) {\n" |
1527 | " %A = uitofp i32 %arg0 to float" |
1528 | " %A2 = uitofp i16 %arg1 to half" |
1529 | " ret float %A\n" |
1530 | "}\n" ); |
1531 | expectKnownFPClass(KnownTrue: fcPosFinite & ~fcSubnormal, SignBitKnown: false, TestVal: A); |
1532 | expectKnownFPClass(KnownTrue: fcPositive & ~fcSubnormal, SignBitKnown: false, TestVal: A2); |
1533 | } |
1534 | |
1535 | TEST_F(ComputeKnownFPClassTest, SIToFP) { |
1536 | parseAssembly( |
1537 | Assembly: "define float @test(i32 %arg0, i16 %arg1, i17 %arg2) {\n" |
1538 | " %A = sitofp i32 %arg0 to float" |
1539 | " %A2 = sitofp i16 %arg1 to half" |
1540 | " %A3 = sitofp i17 %arg2 to half" |
1541 | " ret float %A\n" |
1542 | "}\n" ); |
1543 | expectKnownFPClass(KnownTrue: fcFinite & ~fcNegZero & ~fcSubnormal, SignBitKnown: std::nullopt, TestVal: A); |
1544 | expectKnownFPClass(KnownTrue: fcFinite & ~fcNegZero & ~fcSubnormal, SignBitKnown: std::nullopt, TestVal: A2); |
1545 | expectKnownFPClass(KnownTrue: ~(fcNan | fcNegZero | fcSubnormal), SignBitKnown: std::nullopt, TestVal: A3); |
1546 | } |
1547 | |
1548 | TEST_F(ComputeKnownFPClassTest, FAdd) { |
1549 | parseAssembly( |
1550 | Assembly: "define float @test(float nofpclass(nan inf) %nnan.ninf, float nofpclass(nan) %nnan, float nofpclass(qnan) %no.qnan, float %unknown) {\n" |
1551 | " %A = fadd float %nnan, %nnan.ninf" |
1552 | " %A2 = fadd float %nnan.ninf, %nnan" |
1553 | " %A3 = fadd float %nnan.ninf, %unknown" |
1554 | " %A4 = fadd float %nnan.ninf, %no.qnan" |
1555 | " %A5 = fadd float %nnan, %nnan" |
1556 | " ret float %A\n" |
1557 | "}\n" ); |
1558 | expectKnownFPClass(KnownTrue: fcFinite | fcInf, SignBitKnown: std::nullopt, TestVal: A); |
1559 | expectKnownFPClass(KnownTrue: fcFinite | fcInf, SignBitKnown: std::nullopt, TestVal: A2); |
1560 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A3); |
1561 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A4); |
1562 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A5); |
1563 | } |
1564 | |
1565 | TEST_F(ComputeKnownFPClassTest, FSub) { |
1566 | parseAssembly( |
1567 | Assembly: "define float @test(float nofpclass(nan inf) %nnan.ninf, float nofpclass(nan) %nnan, float nofpclass(qnan) %no.qnan, float %unknown) {\n" |
1568 | " %A = fsub float %nnan, %nnan.ninf" |
1569 | " %A2 = fsub float %nnan.ninf, %nnan" |
1570 | " %A3 = fsub float %nnan.ninf, %unknown" |
1571 | " %A4 = fsub float %nnan.ninf, %no.qnan" |
1572 | " %A5 = fsub float %nnan, %nnan" |
1573 | " ret float %A\n" |
1574 | "}\n" ); |
1575 | expectKnownFPClass(KnownTrue: fcFinite | fcInf, SignBitKnown: std::nullopt, TestVal: A); |
1576 | expectKnownFPClass(KnownTrue: fcFinite | fcInf, SignBitKnown: std::nullopt, TestVal: A2); |
1577 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A3); |
1578 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A4); |
1579 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A5); |
1580 | } |
1581 | |
1582 | TEST_F(ComputeKnownFPClassTest, FMul) { |
1583 | parseAssembly( |
1584 | Assembly: "define float @test(float nofpclass(nan inf) %nnan.ninf0, float nofpclass(nan inf) %nnan.ninf1, float nofpclass(nan) %nnan, float nofpclass(qnan) %no.qnan, float %unknown) {\n" |
1585 | " %A = fmul float %nnan.ninf0, %nnan.ninf1" |
1586 | " %A2 = fmul float %nnan.ninf0, %nnan" |
1587 | " %A3 = fmul float %nnan, %nnan.ninf0" |
1588 | " %A4 = fmul float %nnan.ninf0, %no.qnan" |
1589 | " %A5 = fmul float %nnan, %nnan" |
1590 | " ret float %A\n" |
1591 | "}\n" ); |
1592 | expectKnownFPClass(KnownTrue: fcFinite | fcInf, SignBitKnown: std::nullopt, TestVal: A); |
1593 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A2); |
1594 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A3); |
1595 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A4); |
1596 | expectKnownFPClass(KnownTrue: fcPositive | fcNan, SignBitKnown: std::nullopt, TestVal: A5); |
1597 | } |
1598 | |
1599 | TEST_F(ComputeKnownFPClassTest, FMulNoZero) { |
1600 | parseAssembly( |
1601 | Assembly: "define float @test(float nofpclass(zero) %no.zero, float nofpclass(zero nan) %no.zero.nan0, float nofpclass(zero nan) %no.zero.nan1, float nofpclass(nzero nan) %no.negzero.nan, float nofpclass(pzero nan) %no.poszero.nan, float nofpclass(inf nan) %no.inf.nan, float nofpclass(inf) %no.inf, float nofpclass(nan) %no.nan) {\n" |
1602 | " %A = fmul float %no.zero.nan0, %no.zero.nan1" |
1603 | " %A2 = fmul float %no.zero, %no.zero" |
1604 | " %A3 = fmul float %no.poszero.nan, %no.zero.nan0" |
1605 | " %A4 = fmul float %no.nan, %no.zero" |
1606 | " %A5 = fmul float %no.zero, %no.inf" |
1607 | " %A6 = fmul float %no.zero.nan0, %no.nan" |
1608 | " %A7 = fmul float %no.nan, %no.zero.nan0" |
1609 | " ret float %A\n" |
1610 | "}\n" ); |
1611 | expectKnownFPClass(KnownTrue: fcFinite | fcInf, SignBitKnown: std::nullopt, TestVal: A); |
1612 | expectKnownFPClass(KnownTrue: fcPositive | fcNan, SignBitKnown: std::nullopt, TestVal: A2); |
1613 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A3); |
1614 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A4); |
1615 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A5); |
1616 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A6); |
1617 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt, TestVal: A7); |
1618 | } |
1619 | |
1620 | TEST_F(ComputeKnownFPClassTest, Phi) { |
1621 | parseAssembly( |
1622 | Assembly: "define float @test(i1 %cond, float nofpclass(nan inf) %arg0, float nofpclass(nan) %arg1) {\n" |
1623 | "entry:\n" |
1624 | " br i1 %cond, label %bb0, label %bb1\n" |
1625 | "bb0:\n" |
1626 | " br label %ret\n" |
1627 | "bb1:\n" |
1628 | " br label %ret\n" |
1629 | "ret:\n" |
1630 | " %A = phi float [ %arg0, %bb0 ], [ %arg1, %bb1 ]\n" |
1631 | " ret float %A\n" |
1632 | "}\n" ); |
1633 | expectKnownFPClass(KnownTrue: ~fcNan, SignBitKnown: std::nullopt); |
1634 | } |
1635 | |
1636 | TEST_F(ComputeKnownFPClassTest, PhiKnownSignFalse) { |
1637 | parseAssembly( |
1638 | Assembly: "declare float @llvm.fabs.f32(float)" |
1639 | "define float @test(i1 %cond, float nofpclass(nan) %arg0, float nofpclass(nan) %arg1) {\n" |
1640 | "entry:\n" |
1641 | " br i1 %cond, label %bb0, label %bb1\n" |
1642 | "bb0:\n" |
1643 | " %fabs.arg0 = call float @llvm.fabs.f32(float %arg0)\n" |
1644 | " br label %ret\n" |
1645 | "bb1:\n" |
1646 | " %fabs.arg1 = call float @llvm.fabs.f32(float %arg1)\n" |
1647 | " br label %ret\n" |
1648 | "ret:\n" |
1649 | " %A = phi float [ %fabs.arg0, %bb0 ], [ %fabs.arg1, %bb1 ]\n" |
1650 | " ret float %A\n" |
1651 | "}\n" ); |
1652 | expectKnownFPClass(KnownTrue: fcPositive, SignBitKnown: false); |
1653 | } |
1654 | |
1655 | TEST_F(ComputeKnownFPClassTest, PhiKnownSignTrue) { |
1656 | parseAssembly( |
1657 | Assembly: "declare float @llvm.fabs.f32(float)" |
1658 | "define float @test(i1 %cond, float nofpclass(nan) %arg0, float %arg1) {\n" |
1659 | "entry:\n" |
1660 | " br i1 %cond, label %bb0, label %bb1\n" |
1661 | "bb0:\n" |
1662 | " %fabs.arg0 = call float @llvm.fabs.f32(float %arg0)\n" |
1663 | " %fneg.fabs.arg0 = fneg float %fabs.arg0\n" |
1664 | " br label %ret\n" |
1665 | "bb1:\n" |
1666 | " %fabs.arg1 = call float @llvm.fabs.f32(float %arg1)\n" |
1667 | " %fneg.fabs.arg1 = fneg float %fabs.arg1\n" |
1668 | " br label %ret\n" |
1669 | "ret:\n" |
1670 | " %A = phi float [ %fneg.fabs.arg0, %bb0 ], [ %fneg.fabs.arg1, %bb1 ]\n" |
1671 | " ret float %A\n" |
1672 | "}\n" ); |
1673 | expectKnownFPClass(KnownTrue: fcNegative | fcNan, SignBitKnown: true); |
1674 | } |
1675 | |
1676 | TEST_F(ComputeKnownFPClassTest, UnreachablePhi) { |
1677 | parseAssembly( |
1678 | Assembly: "define float @test(float %arg) {\n" |
1679 | "entry:\n" |
1680 | " ret float 0.0\n" |
1681 | "unreachable:\n" |
1682 | " %A = phi float\n" |
1683 | " ret float %A\n" |
1684 | "}\n" ); |
1685 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt); |
1686 | } |
1687 | |
1688 | TEST_F(ComputeKnownFPClassTest, SelfPhiOnly) { |
1689 | parseAssembly( |
1690 | Assembly: "define float @test(float %arg) {\n" |
1691 | "entry:\n" |
1692 | " ret float 0.0\n" |
1693 | "loop:\n" |
1694 | " %A = phi float [ %A, %loop ]\n" |
1695 | " br label %loop\n" |
1696 | "}\n" ); |
1697 | expectKnownFPClass(KnownTrue: fcAllFlags, SignBitKnown: std::nullopt); |
1698 | } |
1699 | |
1700 | TEST_F(ComputeKnownFPClassTest, SelfPhiFirstArg) { |
1701 | parseAssembly( |
1702 | Assembly: "define float @test(i1 %cond, float nofpclass(inf) %arg) {\n" |
1703 | "entry:\n" |
1704 | " br i1 %cond, label %loop, label %ret\n" |
1705 | "loop:\n" |
1706 | " %A = phi float [ %arg, %entry ], [ %A, %loop ]\n" |
1707 | " br label %loop\n" |
1708 | "ret:\n" |
1709 | " ret float %A" |
1710 | "}\n" ); |
1711 | expectKnownFPClass(KnownTrue: ~fcInf, SignBitKnown: std::nullopt); |
1712 | } |
1713 | |
1714 | TEST_F(ComputeKnownFPClassTest, SelfPhiSecondArg) { |
1715 | parseAssembly( |
1716 | Assembly: "define float @test(i1 %cond, float nofpclass(inf) %arg) {\n" |
1717 | "entry:\n" |
1718 | " br i1 %cond, label %loop, label %ret\n" |
1719 | "loop:\n" |
1720 | " %A = phi float [ %A, %loop ], [ %arg, %entry ]\n" |
1721 | " br label %loop\n" |
1722 | "ret:\n" |
1723 | " ret float %A" |
1724 | "}\n" ); |
1725 | expectKnownFPClass(KnownTrue: ~fcInf, SignBitKnown: std::nullopt); |
1726 | } |
1727 | |
1728 | TEST_F(ComputeKnownFPClassTest, CannotBeOrderedLessThanZero) { |
1729 | parseAssembly(Assembly: "define float @test(float %arg) {\n" |
1730 | " %A = fmul float %arg, %arg" |
1731 | " ret float %A\n" |
1732 | "}\n" ); |
1733 | |
1734 | Type *FPTy = Type::getDoubleTy(C&: M->getContext()); |
1735 | const DataLayout &DL = M->getDataLayout(); |
1736 | |
1737 | EXPECT_TRUE( |
1738 | computeKnownFPClass(ConstantFP::getZero(FPTy, /*Negative=*/false), DL) |
1739 | .cannotBeOrderedLessThanZero()); |
1740 | EXPECT_TRUE( |
1741 | computeKnownFPClass(ConstantFP::getZero(FPTy, /*Negative=*/true), DL) |
1742 | .cannotBeOrderedLessThanZero()); |
1743 | |
1744 | EXPECT_TRUE(computeKnownFPClass(ConstantFP::getInfinity(FPTy, false), DL) |
1745 | .cannotBeOrderedLessThanZero()); |
1746 | EXPECT_FALSE(computeKnownFPClass(ConstantFP::getInfinity(FPTy, true), DL) |
1747 | .cannotBeOrderedLessThanZero()); |
1748 | |
1749 | EXPECT_TRUE(computeKnownFPClass(ConstantFP::get(FPTy, 1.0), DL) |
1750 | .cannotBeOrderedLessThanZero()); |
1751 | EXPECT_FALSE(computeKnownFPClass(ConstantFP::get(FPTy, -1.0), DL) |
1752 | .cannotBeOrderedLessThanZero()); |
1753 | |
1754 | EXPECT_TRUE( |
1755 | computeKnownFPClass( |
1756 | ConstantFP::get(FPTy, APFloat::getSmallest(FPTy->getFltSemantics(), |
1757 | /*Negative=*/false)), |
1758 | DL) |
1759 | .cannotBeOrderedLessThanZero()); |
1760 | EXPECT_FALSE( |
1761 | computeKnownFPClass( |
1762 | ConstantFP::get(FPTy, APFloat::getSmallest(FPTy->getFltSemantics(), |
1763 | /*Negative=*/true)), |
1764 | DL) |
1765 | .cannotBeOrderedLessThanZero()); |
1766 | |
1767 | EXPECT_TRUE( |
1768 | computeKnownFPClass(ConstantFP::getQNaN(FPTy, /*Negative=*/false), DL) |
1769 | .cannotBeOrderedLessThanZero()); |
1770 | EXPECT_TRUE( |
1771 | computeKnownFPClass(ConstantFP::getQNaN(FPTy, /*Negative=*/true), DL) |
1772 | .cannotBeOrderedLessThanZero()); |
1773 | EXPECT_TRUE( |
1774 | computeKnownFPClass(ConstantFP::getSNaN(FPTy, /*Negative=*/false), DL) |
1775 | .cannotBeOrderedLessThanZero()); |
1776 | EXPECT_TRUE( |
1777 | computeKnownFPClass(ConstantFP::getSNaN(FPTy, /*Negative=*/true), DL) |
1778 | .cannotBeOrderedLessThanZero()); |
1779 | } |
1780 | |
1781 | TEST_F(ComputeKnownFPClassTest, FCmpToClassTest_OrdNan) { |
1782 | parseAssembly(Assembly: "define i1 @test(double %arg) {\n" |
1783 | " %A = fcmp ord double %arg, 0x7FF8000000000000" |
1784 | " %A2 = fcmp uno double %arg, 0x7FF8000000000000" |
1785 | " %A3 = fcmp oeq double %arg, 0x7FF8000000000000" |
1786 | " %A4 = fcmp ueq double %arg, 0x7FF8000000000000" |
1787 | " ret i1 %A\n" |
1788 | "}\n" ); |
1789 | |
1790 | auto [OrdVal, OrdClass] = fcmpToClassTest( |
1791 | Pred: CmpInst::FCMP_ORD, F: *A->getFunction(), LHS: A->getOperand(i: 0), RHS: A->getOperand(i: 1)); |
1792 | EXPECT_EQ(A->getOperand(0), OrdVal); |
1793 | EXPECT_EQ(fcNone, OrdClass); |
1794 | |
1795 | auto [UnordVal, UnordClass] = |
1796 | fcmpToClassTest(Pred: CmpInst::FCMP_UNO, F: *A2->getFunction(), LHS: A2->getOperand(i: 0), |
1797 | RHS: A2->getOperand(i: 1)); |
1798 | EXPECT_EQ(A2->getOperand(0), UnordVal); |
1799 | EXPECT_EQ(fcAllFlags, UnordClass); |
1800 | |
1801 | auto [OeqVal, OeqClass] = |
1802 | fcmpToClassTest(Pred: CmpInst::FCMP_OEQ, F: *A3->getFunction(), LHS: A3->getOperand(i: 0), |
1803 | RHS: A3->getOperand(i: 1)); |
1804 | EXPECT_EQ(A3->getOperand(0), OeqVal); |
1805 | EXPECT_EQ(fcNone, OeqClass); |
1806 | |
1807 | auto [UeqVal, UeqClass] = |
1808 | fcmpToClassTest(Pred: CmpInst::FCMP_UEQ, F: *A3->getFunction(), LHS: A3->getOperand(i: 0), |
1809 | RHS: A3->getOperand(i: 1)); |
1810 | EXPECT_EQ(A3->getOperand(0), UeqVal); |
1811 | EXPECT_EQ(fcAllFlags, UeqClass); |
1812 | } |
1813 | |
1814 | TEST_F(ComputeKnownFPClassTest, FCmpToClassTest_NInf) { |
1815 | parseAssembly(Assembly: "define i1 @test(double %arg) {\n" |
1816 | " %A = fcmp olt double %arg, 0xFFF0000000000000" |
1817 | " %A2 = fcmp uge double %arg, 0xFFF0000000000000" |
1818 | " %A3 = fcmp ogt double %arg, 0xFFF0000000000000" |
1819 | " %A4 = fcmp ule double %arg, 0xFFF0000000000000" |
1820 | " %A5 = fcmp oge double %arg, 0xFFF0000000000000" |
1821 | " %A6 = fcmp ult double %arg, 0xFFF0000000000000" |
1822 | " ret i1 %A\n" |
1823 | "}\n" ); |
1824 | |
1825 | auto [OltVal, OltClass] = fcmpToClassTest( |
1826 | Pred: CmpInst::FCMP_OLT, F: *A->getFunction(), LHS: A->getOperand(i: 0), RHS: A->getOperand(i: 1)); |
1827 | EXPECT_EQ(A->getOperand(0), OltVal); |
1828 | EXPECT_EQ(fcNone, OltClass); |
1829 | |
1830 | auto [UgeVal, UgeClass] = |
1831 | fcmpToClassTest(Pred: CmpInst::FCMP_UGE, F: *A2->getFunction(), LHS: A2->getOperand(i: 0), |
1832 | RHS: A2->getOperand(i: 1)); |
1833 | EXPECT_EQ(A2->getOperand(0), UgeVal); |
1834 | EXPECT_EQ(fcAllFlags, UgeClass); |
1835 | |
1836 | auto [OgtVal, OgtClass] = |
1837 | fcmpToClassTest(Pred: CmpInst::FCMP_OGT, F: *A3->getFunction(), LHS: A3->getOperand(i: 0), |
1838 | RHS: A3->getOperand(i: 1)); |
1839 | EXPECT_EQ(A3->getOperand(0), OgtVal); |
1840 | EXPECT_EQ(~(fcNegInf | fcNan), OgtClass); |
1841 | |
1842 | auto [UleVal, UleClass] = |
1843 | fcmpToClassTest(Pred: CmpInst::FCMP_ULE, F: *A4->getFunction(), LHS: A4->getOperand(i: 0), |
1844 | RHS: A4->getOperand(i: 1)); |
1845 | EXPECT_EQ(A4->getOperand(0), UleVal); |
1846 | EXPECT_EQ(fcNegInf | fcNan, UleClass); |
1847 | |
1848 | auto [OgeVal, OgeClass] = |
1849 | fcmpToClassTest(Pred: CmpInst::FCMP_OGE, F: *A5->getFunction(), LHS: A5->getOperand(i: 0), |
1850 | RHS: A5->getOperand(i: 1)); |
1851 | EXPECT_EQ(A5->getOperand(0), OgeVal); |
1852 | EXPECT_EQ(~fcNan, OgeClass); |
1853 | |
1854 | auto [UltVal, UltClass] = |
1855 | fcmpToClassTest(Pred: CmpInst::FCMP_ULT, F: *A6->getFunction(), LHS: A6->getOperand(i: 0), |
1856 | RHS: A6->getOperand(i: 1)); |
1857 | EXPECT_EQ(A6->getOperand(0), UltVal); |
1858 | EXPECT_EQ(fcNan, UltClass); |
1859 | } |
1860 | |
1861 | TEST_F(ComputeKnownFPClassTest, FCmpToClassTest_FabsNInf) { |
1862 | parseAssembly(Assembly: "declare double @llvm.fabs.f64(double)\n" |
1863 | "define i1 @test(double %arg) {\n" |
1864 | " %fabs.arg = call double @llvm.fabs.f64(double %arg)\n" |
1865 | " %A = fcmp olt double %fabs.arg, 0xFFF0000000000000" |
1866 | " %A2 = fcmp uge double %fabs.arg, 0xFFF0000000000000" |
1867 | " %A3 = fcmp ogt double %fabs.arg, 0xFFF0000000000000" |
1868 | " %A4 = fcmp ule double %fabs.arg, 0xFFF0000000000000" |
1869 | " %A5 = fcmp oge double %fabs.arg, 0xFFF0000000000000" |
1870 | " %A6 = fcmp ult double %fabs.arg, 0xFFF0000000000000" |
1871 | " ret i1 %A\n" |
1872 | "}\n" ); |
1873 | |
1874 | Value *ArgVal = F->getArg(i: 0); |
1875 | |
1876 | auto [OltVal, OltClass] = fcmpToClassTest( |
1877 | Pred: CmpInst::FCMP_OLT, F: *A->getFunction(), LHS: A->getOperand(i: 0), RHS: A->getOperand(i: 1)); |
1878 | EXPECT_EQ(ArgVal, OltVal); |
1879 | EXPECT_EQ(fcNone, OltClass); |
1880 | |
1881 | auto [UgeVal, UgeClass] = |
1882 | fcmpToClassTest(Pred: CmpInst::FCMP_UGE, F: *A2->getFunction(), LHS: A2->getOperand(i: 0), |
1883 | RHS: A2->getOperand(i: 1)); |
1884 | EXPECT_EQ(ArgVal, UgeVal); |
1885 | EXPECT_EQ(fcAllFlags, UgeClass); |
1886 | |
1887 | auto [OgtVal, OgtClass] = |
1888 | fcmpToClassTest(Pred: CmpInst::FCMP_OGT, F: *A3->getFunction(), LHS: A3->getOperand(i: 0), |
1889 | RHS: A3->getOperand(i: 1)); |
1890 | EXPECT_EQ(ArgVal, OgtVal); |
1891 | EXPECT_EQ(~fcNan, OgtClass); |
1892 | |
1893 | auto [UleVal, UleClass] = |
1894 | fcmpToClassTest(Pred: CmpInst::FCMP_ULE, F: *A4->getFunction(), LHS: A4->getOperand(i: 0), |
1895 | RHS: A4->getOperand(i: 1)); |
1896 | EXPECT_EQ(ArgVal, UleVal); |
1897 | EXPECT_EQ(fcNan, UleClass); |
1898 | |
1899 | auto [OgeVal, OgeClass] = |
1900 | fcmpToClassTest(Pred: CmpInst::FCMP_OGE, F: *A5->getFunction(), LHS: A5->getOperand(i: 0), |
1901 | RHS: A5->getOperand(i: 1)); |
1902 | EXPECT_EQ(ArgVal, OgeVal); |
1903 | EXPECT_EQ(~fcNan, OgeClass); |
1904 | |
1905 | auto [UltVal, UltClass] = |
1906 | fcmpToClassTest(Pred: CmpInst::FCMP_ULT, F: *A6->getFunction(), LHS: A6->getOperand(i: 0), |
1907 | RHS: A6->getOperand(i: 1)); |
1908 | EXPECT_EQ(ArgVal, UltVal); |
1909 | EXPECT_EQ(fcNan, UltClass); |
1910 | } |
1911 | |
1912 | TEST_F(ComputeKnownFPClassTest, FCmpToClassTest_PInf) { |
1913 | parseAssembly(Assembly: "define i1 @test(double %arg) {\n" |
1914 | " %A = fcmp ogt double %arg, 0x7FF0000000000000" |
1915 | " %A2 = fcmp ule double %arg, 0x7FF0000000000000" |
1916 | " %A3 = fcmp ole double %arg, 0x7FF0000000000000" |
1917 | " %A4 = fcmp ugt double %arg, 0x7FF0000000000000" |
1918 | " ret i1 %A\n" |
1919 | "}\n" ); |
1920 | |
1921 | auto [OgtVal, OgtClass] = fcmpToClassTest( |
1922 | Pred: CmpInst::FCMP_OGT, F: *A->getFunction(), LHS: A->getOperand(i: 0), RHS: A->getOperand(i: 1)); |
1923 | EXPECT_EQ(A->getOperand(0), OgtVal); |
1924 | EXPECT_EQ(fcNone, OgtClass); |
1925 | |
1926 | auto [UleVal, UleClass] = |
1927 | fcmpToClassTest(Pred: CmpInst::FCMP_ULE, F: *A2->getFunction(), LHS: A2->getOperand(i: 0), |
1928 | RHS: A2->getOperand(i: 1)); |
1929 | EXPECT_EQ(A2->getOperand(0), UleVal); |
1930 | EXPECT_EQ(fcAllFlags, UleClass); |
1931 | |
1932 | auto [OleVal, OleClass] = |
1933 | fcmpToClassTest(Pred: CmpInst::FCMP_OLE, F: *A3->getFunction(), LHS: A3->getOperand(i: 0), |
1934 | RHS: A3->getOperand(i: 1)); |
1935 | EXPECT_EQ(A->getOperand(0), OleVal); |
1936 | EXPECT_EQ(~fcNan, OleClass); |
1937 | |
1938 | auto [UgtVal, UgtClass] = |
1939 | fcmpToClassTest(Pred: CmpInst::FCMP_UGT, F: *A4->getFunction(), LHS: A4->getOperand(i: 0), |
1940 | RHS: A4->getOperand(i: 1)); |
1941 | EXPECT_EQ(A4->getOperand(0), UgtVal); |
1942 | EXPECT_EQ(fcNan, UgtClass); |
1943 | } |
1944 | |
1945 | TEST_F(ComputeKnownFPClassTest, SqrtNszSignBit) { |
1946 | parseAssembly( |
1947 | Assembly: "declare float @llvm.sqrt.f32(float)\n" |
1948 | "define float @test(float %arg, float nofpclass(nan) %arg.nnan) {\n" |
1949 | " %A = call float @llvm.sqrt.f32(float %arg)\n" |
1950 | " %A2 = call nsz float @llvm.sqrt.f32(float %arg)\n" |
1951 | " %A3 = call float @llvm.sqrt.f32(float %arg.nnan)\n" |
1952 | " %A4 = call nsz float @llvm.sqrt.f32(float %arg.nnan)\n" |
1953 | " ret float %A\n" |
1954 | "}\n" ); |
1955 | |
1956 | const FPClassTest SqrtMask = fcPositive | fcNegZero | fcNan; |
1957 | const FPClassTest NszSqrtMask = fcPositive | fcNan; |
1958 | |
1959 | { |
1960 | KnownFPClass UseInstrInfo = |
1961 | computeKnownFPClass(V: A, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
1962 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/true); |
1963 | EXPECT_EQ(SqrtMask, UseInstrInfo.KnownFPClasses); |
1964 | EXPECT_EQ(std::nullopt, UseInstrInfo.SignBit); |
1965 | |
1966 | KnownFPClass NoUseInstrInfo = |
1967 | computeKnownFPClass(V: A, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
1968 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/false); |
1969 | EXPECT_EQ(SqrtMask, NoUseInstrInfo.KnownFPClasses); |
1970 | EXPECT_EQ(std::nullopt, NoUseInstrInfo.SignBit); |
1971 | } |
1972 | |
1973 | { |
1974 | KnownFPClass UseInstrInfoNSZ = |
1975 | computeKnownFPClass(V: A2, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
1976 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/true); |
1977 | EXPECT_EQ(NszSqrtMask, UseInstrInfoNSZ.KnownFPClasses); |
1978 | EXPECT_EQ(std::nullopt, UseInstrInfoNSZ.SignBit); |
1979 | |
1980 | KnownFPClass NoUseInstrInfoNSZ = |
1981 | computeKnownFPClass(V: A2, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
1982 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/false); |
1983 | EXPECT_EQ(SqrtMask, NoUseInstrInfoNSZ.KnownFPClasses); |
1984 | EXPECT_EQ(std::nullopt, NoUseInstrInfoNSZ.SignBit); |
1985 | } |
1986 | |
1987 | { |
1988 | KnownFPClass UseInstrInfoNoNan = |
1989 | computeKnownFPClass(V: A3, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
1990 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/true); |
1991 | EXPECT_EQ(fcPositive | fcNegZero | fcQNan, |
1992 | UseInstrInfoNoNan.KnownFPClasses); |
1993 | EXPECT_EQ(std::nullopt, UseInstrInfoNoNan.SignBit); |
1994 | |
1995 | KnownFPClass NoUseInstrInfoNoNan = |
1996 | computeKnownFPClass(V: A3, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
1997 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/false); |
1998 | EXPECT_EQ(fcPositive | fcNegZero | fcQNan, |
1999 | NoUseInstrInfoNoNan.KnownFPClasses); |
2000 | EXPECT_EQ(std::nullopt, NoUseInstrInfoNoNan.SignBit); |
2001 | } |
2002 | |
2003 | { |
2004 | KnownFPClass UseInstrInfoNSZNoNan = |
2005 | computeKnownFPClass(V: A4, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
2006 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/true); |
2007 | EXPECT_EQ(fcPositive | fcQNan, UseInstrInfoNSZNoNan.KnownFPClasses); |
2008 | EXPECT_EQ(false, UseInstrInfoNSZNoNan.SignBit); |
2009 | |
2010 | KnownFPClass NoUseInstrInfoNSZNoNan = |
2011 | computeKnownFPClass(V: A4, DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, |
2012 | AC: nullptr, CxtI: nullptr, DT: nullptr, /*UseInstrInfo=*/false); |
2013 | EXPECT_EQ(fcPositive | fcNegZero | fcQNan, |
2014 | NoUseInstrInfoNSZNoNan.KnownFPClasses); |
2015 | EXPECT_EQ(std::nullopt, NoUseInstrInfoNSZNoNan.SignBit); |
2016 | } |
2017 | } |
2018 | |
2019 | TEST_F(ComputeKnownFPClassTest, Constants) { |
2020 | parseAssembly(Assembly: "declare float @func()\n" |
2021 | "define float @test() {\n" |
2022 | " %A = call float @func()\n" |
2023 | " ret float %A\n" |
2024 | "}\n" ); |
2025 | |
2026 | Type *F32 = Type::getFloatTy(C&: Context); |
2027 | Type *V4F32 = FixedVectorType::get(ElementType: F32, NumElts: 4); |
2028 | |
2029 | { |
2030 | KnownFPClass ConstAggZero = computeKnownFPClass( |
2031 | V: ConstantAggregateZero::get(Ty: V4F32), DL: M->getDataLayout(), InterestedClasses: fcAllFlags, Depth: 0, |
2032 | TLI: nullptr, AC: nullptr, CxtI: nullptr, DT: nullptr); |
2033 | |
2034 | EXPECT_EQ(fcPosZero, ConstAggZero.KnownFPClasses); |
2035 | ASSERT_TRUE(ConstAggZero.SignBit); |
2036 | EXPECT_FALSE(*ConstAggZero.SignBit); |
2037 | } |
2038 | |
2039 | { |
2040 | KnownFPClass Undef = |
2041 | computeKnownFPClass(V: UndefValue::get(T: F32), DL: M->getDataLayout(), |
2042 | InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, AC: nullptr, CxtI: nullptr, DT: nullptr); |
2043 | EXPECT_EQ(fcAllFlags, Undef.KnownFPClasses); |
2044 | EXPECT_FALSE(Undef.SignBit); |
2045 | } |
2046 | |
2047 | { |
2048 | KnownFPClass Poison = |
2049 | computeKnownFPClass(V: PoisonValue::get(T: F32), DL: M->getDataLayout(), |
2050 | InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, AC: nullptr, CxtI: nullptr, DT: nullptr); |
2051 | EXPECT_EQ(fcNone, Poison.KnownFPClasses); |
2052 | ASSERT_TRUE(Poison.SignBit); |
2053 | EXPECT_FALSE(*Poison.SignBit); |
2054 | } |
2055 | |
2056 | { |
2057 | // Assume the poison element should be 0. |
2058 | Constant *ZeroF32 = ConstantFP::getZero(Ty: F32); |
2059 | Constant *PoisonF32 = PoisonValue::get(T: F32); |
2060 | |
2061 | KnownFPClass PartiallyPoison = computeKnownFPClass( |
2062 | V: ConstantVector::get(V: {ZeroF32, PoisonF32}), DL: M->getDataLayout(), |
2063 | InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, AC: nullptr, CxtI: nullptr, DT: nullptr); |
2064 | EXPECT_EQ(fcPosZero, PartiallyPoison.KnownFPClasses); |
2065 | ASSERT_TRUE(PartiallyPoison.SignBit); |
2066 | EXPECT_FALSE(*PartiallyPoison.SignBit); |
2067 | } |
2068 | |
2069 | { |
2070 | // Assume the poison element should be 1. |
2071 | Constant *NegZeroF32 = ConstantFP::getZero(Ty: F32, Negative: true); |
2072 | Constant *PoisonF32 = PoisonValue::get(T: F32); |
2073 | |
2074 | KnownFPClass PartiallyPoison = computeKnownFPClass( |
2075 | V: ConstantVector::get(V: {NegZeroF32, PoisonF32}), DL: M->getDataLayout(), |
2076 | InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, AC: nullptr, CxtI: nullptr, DT: nullptr); |
2077 | EXPECT_EQ(fcNegZero, PartiallyPoison.KnownFPClasses); |
2078 | ASSERT_TRUE(PartiallyPoison.SignBit); |
2079 | EXPECT_TRUE(*PartiallyPoison.SignBit); |
2080 | } |
2081 | |
2082 | { |
2083 | // Assume the poison element should be 1. |
2084 | Constant *NegZeroF32 = ConstantFP::getZero(Ty: F32, Negative: true); |
2085 | Constant *PoisonF32 = PoisonValue::get(T: F32); |
2086 | |
2087 | KnownFPClass PartiallyPoison = computeKnownFPClass( |
2088 | V: ConstantVector::get(V: {PoisonF32, NegZeroF32}), DL: M->getDataLayout(), |
2089 | InterestedClasses: fcAllFlags, Depth: 0, TLI: nullptr, AC: nullptr, CxtI: nullptr, DT: nullptr); |
2090 | EXPECT_EQ(fcNegZero, PartiallyPoison.KnownFPClasses); |
2091 | EXPECT_TRUE(PartiallyPoison.SignBit); |
2092 | } |
2093 | } |
2094 | |
2095 | TEST_F(ValueTrackingTest, isNonZeroRecurrence) { |
2096 | parseAssembly(Assembly: R"( |
2097 | define i1 @test(i8 %n, i8 %r) { |
2098 | entry: |
2099 | br label %loop |
2100 | loop: |
2101 | %p = phi i8 [ -1, %entry ], [ %next, %loop ] |
2102 | %next = add nsw i8 %p, -1 |
2103 | %cmp1 = icmp eq i8 %p, %n |
2104 | br i1 %cmp1, label %exit, label %loop |
2105 | exit: |
2106 | %A = or i8 %p, %r |
2107 | %CxtI = icmp eq i8 %A, 0 |
2108 | ret i1 %CxtI |
2109 | } |
2110 | )" ); |
2111 | const DataLayout &DL = M->getDataLayout(); |
2112 | AssumptionCache AC(*F); |
2113 | EXPECT_TRUE(isKnownNonZero(A, SimplifyQuery(DL, /*DT=*/nullptr, &AC, CxtI))); |
2114 | } |
2115 | |
2116 | TEST_F(ValueTrackingTest, KnownNonZeroFromDomCond) { |
2117 | parseAssembly(Assembly: R"( |
2118 | declare ptr @f_i8() |
2119 | define void @test(i1 %c) { |
2120 | %A = call ptr @f_i8() |
2121 | %B = call ptr @f_i8() |
2122 | %c1 = icmp ne ptr %A, null |
2123 | %cond = and i1 %c1, %c |
2124 | br i1 %cond, label %T, label %Q |
2125 | T: |
2126 | %CxtI = add i32 0, 0 |
2127 | ret void |
2128 | Q: |
2129 | %CxtI2 = add i32 0, 0 |
2130 | ret void |
2131 | } |
2132 | )" ); |
2133 | AssumptionCache AC(*F); |
2134 | DominatorTree DT(*F); |
2135 | const DataLayout &DL = M->getDataLayout(); |
2136 | const SimplifyQuery SQ(DL, &DT, &AC); |
2137 | EXPECT_EQ(isKnownNonZero(A, SQ.getWithInstruction(CxtI)), true); |
2138 | EXPECT_EQ(isKnownNonZero(A, SQ.getWithInstruction(CxtI2)), false); |
2139 | } |
2140 | |
2141 | TEST_F(ValueTrackingTest, KnownNonZeroFromDomCond2) { |
2142 | parseAssembly(Assembly: R"( |
2143 | declare ptr @f_i8() |
2144 | define void @test(i1 %c) { |
2145 | %A = call ptr @f_i8() |
2146 | %B = call ptr @f_i8() |
2147 | %c1 = icmp ne ptr %A, null |
2148 | %cond = select i1 %c, i1 %c1, i1 false |
2149 | br i1 %cond, label %T, label %Q |
2150 | T: |
2151 | %CxtI = add i32 0, 0 |
2152 | ret void |
2153 | Q: |
2154 | %CxtI2 = add i32 0, 0 |
2155 | ret void |
2156 | } |
2157 | )" ); |
2158 | AssumptionCache AC(*F); |
2159 | DominatorTree DT(*F); |
2160 | const DataLayout &DL = M->getDataLayout(); |
2161 | const SimplifyQuery SQ(DL, &DT, &AC); |
2162 | EXPECT_EQ(isKnownNonZero(A, SQ.getWithInstruction(CxtI)), true); |
2163 | EXPECT_EQ(isKnownNonZero(A, SQ.getWithInstruction(CxtI2)), false); |
2164 | } |
2165 | |
2166 | TEST_F(ValueTrackingTest, IsImpliedConditionAnd) { |
2167 | parseAssembly(Assembly: R"( |
2168 | define void @test(i32 %x, i32 %y) { |
2169 | %c1 = icmp ult i32 %x, 10 |
2170 | %c2 = icmp ult i32 %y, 15 |
2171 | %A = and i1 %c1, %c2 |
2172 | ; x < 10 /\ y < 15 |
2173 | %A2 = icmp ult i32 %x, 20 |
2174 | %A3 = icmp uge i32 %y, 20 |
2175 | %A4 = icmp ult i32 %x, 5 |
2176 | ret void |
2177 | } |
2178 | )" ); |
2179 | const DataLayout &DL = M->getDataLayout(); |
2180 | EXPECT_EQ(isImpliedCondition(A, A2, DL), true); |
2181 | EXPECT_EQ(isImpliedCondition(A, A3, DL), false); |
2182 | EXPECT_EQ(isImpliedCondition(A, A4, DL), std::nullopt); |
2183 | } |
2184 | |
2185 | TEST_F(ValueTrackingTest, IsImpliedConditionAnd2) { |
2186 | parseAssembly(Assembly: R"( |
2187 | define void @test(i32 %x, i32 %y) { |
2188 | %c1 = icmp ult i32 %x, 10 |
2189 | %c2 = icmp ult i32 %y, 15 |
2190 | %A = select i1 %c1, i1 %c2, i1 false |
2191 | ; x < 10 /\ y < 15 |
2192 | %A2 = icmp ult i32 %x, 20 |
2193 | %A3 = icmp uge i32 %y, 20 |
2194 | %A4 = icmp ult i32 %x, 5 |
2195 | ret void |
2196 | } |
2197 | )" ); |
2198 | const DataLayout &DL = M->getDataLayout(); |
2199 | EXPECT_EQ(isImpliedCondition(A, A2, DL), true); |
2200 | EXPECT_EQ(isImpliedCondition(A, A3, DL), false); |
2201 | EXPECT_EQ(isImpliedCondition(A, A4, DL), std::nullopt); |
2202 | } |
2203 | |
2204 | TEST_F(ValueTrackingTest, IsImpliedConditionAndVec) { |
2205 | parseAssembly(Assembly: R"( |
2206 | define void @test(<2 x i8> %x, <2 x i8> %y) { |
2207 | %A = icmp ult <2 x i8> %x, %y |
2208 | %A2 = icmp ule <2 x i8> %x, %y |
2209 | ret void |
2210 | } |
2211 | )" ); |
2212 | const DataLayout &DL = M->getDataLayout(); |
2213 | EXPECT_EQ(isImpliedCondition(A, A2, DL), true); |
2214 | } |
2215 | |
2216 | TEST_F(ValueTrackingTest, IsImpliedConditionOr) { |
2217 | parseAssembly(Assembly: R"( |
2218 | define void @test(i32 %x, i32 %y) { |
2219 | %c1 = icmp ult i32 %x, 10 |
2220 | %c2 = icmp ult i32 %y, 15 |
2221 | %A = or i1 %c1, %c2 ; negated |
2222 | ; x >= 10 /\ y >= 15 |
2223 | %A2 = icmp ult i32 %x, 5 |
2224 | %A3 = icmp uge i32 %y, 10 |
2225 | %A4 = icmp ult i32 %x, 15 |
2226 | ret void |
2227 | } |
2228 | )" ); |
2229 | const DataLayout &DL = M->getDataLayout(); |
2230 | EXPECT_EQ(isImpliedCondition(A, A2, DL, false), false); |
2231 | EXPECT_EQ(isImpliedCondition(A, A3, DL, false), true); |
2232 | EXPECT_EQ(isImpliedCondition(A, A4, DL, false), std::nullopt); |
2233 | } |
2234 | |
2235 | TEST_F(ValueTrackingTest, IsImpliedConditionOr2) { |
2236 | parseAssembly(Assembly: R"( |
2237 | define void @test(i32 %x, i32 %y) { |
2238 | %c1 = icmp ult i32 %x, 10 |
2239 | %c2 = icmp ult i32 %y, 15 |
2240 | %A = select i1 %c1, i1 true, i1 %c2 ; negated |
2241 | ; x >= 10 /\ y >= 15 |
2242 | %A2 = icmp ult i32 %x, 5 |
2243 | %A3 = icmp uge i32 %y, 10 |
2244 | %A4 = icmp ult i32 %x, 15 |
2245 | ret void |
2246 | } |
2247 | )" ); |
2248 | const DataLayout &DL = M->getDataLayout(); |
2249 | EXPECT_EQ(isImpliedCondition(A, A2, DL, false), false); |
2250 | EXPECT_EQ(isImpliedCondition(A, A3, DL, false), true); |
2251 | EXPECT_EQ(isImpliedCondition(A, A4, DL, false), std::nullopt); |
2252 | } |
2253 | |
2254 | TEST_F(ComputeKnownBitsTest, KnownNonZeroShift) { |
2255 | // %q is known nonzero without known bits. |
2256 | // Because %q is nonzero, %A[0] is known to be zero. |
2257 | parseAssembly( |
2258 | Assembly: "define i8 @test(i8 %p, ptr %pq) {\n" |
2259 | " %q = load i8, ptr %pq, !range !0\n" |
2260 | " %A = shl i8 %p, %q\n" |
2261 | " ret i8 %A\n" |
2262 | "}\n" |
2263 | "!0 = !{ i8 1, i8 5 }\n" ); |
2264 | expectKnownBits(/*zero*/ Zero: 1u, /*one*/ One: 0u); |
2265 | } |
2266 | |
2267 | TEST_F(ComputeKnownBitsTest, ComputeKnownFshl) { |
2268 | // fshl(....1111....0000, 00..1111........, 6) |
2269 | // = 11....000000..11 |
2270 | parseAssembly( |
2271 | Assembly: "define i16 @test(i16 %a, i16 %b) {\n" |
2272 | " %aa = shl i16 %a, 4\n" |
2273 | " %bb = lshr i16 %b, 2\n" |
2274 | " %aaa = or i16 %aa, 3840\n" |
2275 | " %bbb = or i16 %bb, 3840\n" |
2276 | " %A = call i16 @llvm.fshl.i16(i16 %aaa, i16 %bbb, i16 6)\n" |
2277 | " ret i16 %A\n" |
2278 | "}\n" |
2279 | "declare i16 @llvm.fshl.i16(i16, i16, i16)\n" ); |
2280 | expectKnownBits(/*zero*/ Zero: 1008u, /*one*/ One: 49155u); |
2281 | } |
2282 | |
2283 | TEST_F(ComputeKnownBitsTest, ComputeKnownFshr) { |
2284 | // fshr(....1111....0000, 00..1111........, 26) |
2285 | // = 11....000000..11 |
2286 | parseAssembly( |
2287 | Assembly: "define i16 @test(i16 %a, i16 %b) {\n" |
2288 | " %aa = shl i16 %a, 4\n" |
2289 | " %bb = lshr i16 %b, 2\n" |
2290 | " %aaa = or i16 %aa, 3840\n" |
2291 | " %bbb = or i16 %bb, 3840\n" |
2292 | " %A = call i16 @llvm.fshr.i16(i16 %aaa, i16 %bbb, i16 26)\n" |
2293 | " ret i16 %A\n" |
2294 | "}\n" |
2295 | "declare i16 @llvm.fshr.i16(i16, i16, i16)\n" ); |
2296 | expectKnownBits(/*zero*/ Zero: 1008u, /*one*/ One: 49155u); |
2297 | } |
2298 | |
2299 | TEST_F(ComputeKnownBitsTest, ComputeKnownFshlZero) { |
2300 | // fshl(....1111....0000, 00..1111........, 0) |
2301 | // = ....1111....0000 |
2302 | parseAssembly( |
2303 | Assembly: "define i16 @test(i16 %a, i16 %b) {\n" |
2304 | " %aa = shl i16 %a, 4\n" |
2305 | " %bb = lshr i16 %b, 2\n" |
2306 | " %aaa = or i16 %aa, 3840\n" |
2307 | " %bbb = or i16 %bb, 3840\n" |
2308 | " %A = call i16 @llvm.fshl.i16(i16 %aaa, i16 %bbb, i16 0)\n" |
2309 | " ret i16 %A\n" |
2310 | "}\n" |
2311 | "declare i16 @llvm.fshl.i16(i16, i16, i16)\n" ); |
2312 | expectKnownBits(/*zero*/ Zero: 15u, /*one*/ One: 3840u); |
2313 | } |
2314 | |
2315 | TEST_F(ComputeKnownBitsTest, ComputeKnownUAddSatLeadingOnes) { |
2316 | // uadd.sat(1111...1, ........) |
2317 | // = 1111.... |
2318 | parseAssembly( |
2319 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
2320 | " %aa = or i8 %a, 241\n" |
2321 | " %A = call i8 @llvm.uadd.sat.i8(i8 %aa, i8 %b)\n" |
2322 | " ret i8 %A\n" |
2323 | "}\n" |
2324 | "declare i8 @llvm.uadd.sat.i8(i8, i8)\n" ); |
2325 | expectKnownBits(/*zero*/ Zero: 0u, /*one*/ One: 240u); |
2326 | } |
2327 | |
2328 | TEST_F(ComputeKnownBitsTest, ComputeKnownUAddSatOnesPreserved) { |
2329 | // uadd.sat(00...011, .1...110) |
2330 | // = .......1 |
2331 | parseAssembly( |
2332 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
2333 | " %aa = or i8 %a, 3\n" |
2334 | " %aaa = and i8 %aa, 59\n" |
2335 | " %bb = or i8 %b, 70\n" |
2336 | " %bbb = and i8 %bb, 254\n" |
2337 | " %A = call i8 @llvm.uadd.sat.i8(i8 %aaa, i8 %bbb)\n" |
2338 | " ret i8 %A\n" |
2339 | "}\n" |
2340 | "declare i8 @llvm.uadd.sat.i8(i8, i8)\n" ); |
2341 | expectKnownBits(/*zero*/ Zero: 0u, /*one*/ One: 1u); |
2342 | } |
2343 | |
2344 | TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatLHSLeadingZeros) { |
2345 | // usub.sat(0000...0, ........) |
2346 | // = 0000.... |
2347 | parseAssembly( |
2348 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
2349 | " %aa = and i8 %a, 14\n" |
2350 | " %A = call i8 @llvm.usub.sat.i8(i8 %aa, i8 %b)\n" |
2351 | " ret i8 %A\n" |
2352 | "}\n" |
2353 | "declare i8 @llvm.usub.sat.i8(i8, i8)\n" ); |
2354 | expectKnownBits(/*zero*/ Zero: 240u, /*one*/ One: 0u); |
2355 | } |
2356 | |
2357 | TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatRHSLeadingOnes) { |
2358 | // usub.sat(........, 1111...1) |
2359 | // = 0000.... |
2360 | parseAssembly( |
2361 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
2362 | " %bb = or i8 %a, 241\n" |
2363 | " %A = call i8 @llvm.usub.sat.i8(i8 %a, i8 %bb)\n" |
2364 | " ret i8 %A\n" |
2365 | "}\n" |
2366 | "declare i8 @llvm.usub.sat.i8(i8, i8)\n" ); |
2367 | expectKnownBits(/*zero*/ Zero: 240u, /*one*/ One: 0u); |
2368 | } |
2369 | |
2370 | TEST_F(ComputeKnownBitsTest, ComputeKnownUSubSatZerosPreserved) { |
2371 | // usub.sat(11...011, .1...110) |
2372 | // = ......0. |
2373 | parseAssembly( |
2374 | Assembly: "define i8 @test(i8 %a, i8 %b) {\n" |
2375 | " %aa = or i8 %a, 195\n" |
2376 | " %aaa = and i8 %aa, 251\n" |
2377 | " %bb = or i8 %b, 70\n" |
2378 | " %bbb = and i8 %bb, 254\n" |
2379 | " %A = call i8 @llvm.usub.sat.i8(i8 %aaa, i8 %bbb)\n" |
2380 | " ret i8 %A\n" |
2381 | "}\n" |
2382 | "declare i8 @llvm.usub.sat.i8(i8, i8)\n" ); |
2383 | expectKnownBits(/*zero*/ Zero: 2u, /*one*/ One: 0u); |
2384 | } |
2385 | |
2386 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsPtrToIntTrunc) { |
2387 | // ptrtoint truncates the pointer type. Make sure we don't crash. |
2388 | parseAssembly( |
2389 | Assembly: "define void @test(ptr %p) {\n" |
2390 | " %A = load ptr, ptr %p\n" |
2391 | " %i = ptrtoint ptr %A to i32\n" |
2392 | " %m = and i32 %i, 31\n" |
2393 | " %c = icmp eq i32 %m, 0\n" |
2394 | " call void @llvm.assume(i1 %c)\n" |
2395 | " ret void\n" |
2396 | "}\n" |
2397 | "declare void @llvm.assume(i1)\n" ); |
2398 | AssumptionCache AC(*F); |
2399 | KnownBits Known = computeKnownBits( |
2400 | V: A, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, CxtI: F->front().getTerminator()); |
2401 | EXPECT_TRUE(Known.isUnknown()); |
2402 | } |
2403 | |
2404 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsPtrToIntZext) { |
2405 | // ptrtoint zero extends the pointer type. Make sure we don't crash. |
2406 | parseAssembly( |
2407 | Assembly: "define void @test(ptr %p) {\n" |
2408 | " %A = load ptr, ptr %p\n" |
2409 | " %i = ptrtoint ptr %A to i128\n" |
2410 | " %m = and i128 %i, 31\n" |
2411 | " %c = icmp eq i128 %m, 0\n" |
2412 | " call void @llvm.assume(i1 %c)\n" |
2413 | " ret void\n" |
2414 | "}\n" |
2415 | "declare void @llvm.assume(i1)\n" ); |
2416 | AssumptionCache AC(*F); |
2417 | KnownBits Known = computeKnownBits( |
2418 | V: A, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, CxtI: F->front().getTerminator()); |
2419 | EXPECT_TRUE(Known.isUnknown()); |
2420 | } |
2421 | |
2422 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsFreeze) { |
2423 | parseAssembly(Assembly: "define void @test() {\n" |
2424 | " %m = call i32 @any_num()\n" |
2425 | " %A = freeze i32 %m\n" |
2426 | " %n = and i32 %m, 31\n" |
2427 | " %c = icmp eq i32 %n, 0\n" |
2428 | " call void @llvm.assume(i1 %c)\n" |
2429 | " ret void\n" |
2430 | "}\n" |
2431 | "declare void @llvm.assume(i1)\n" |
2432 | "declare i32 @any_num()\n" ); |
2433 | AssumptionCache AC(*F); |
2434 | KnownBits Known = computeKnownBits(V: A, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2435 | CxtI: F->front().getTerminator()); |
2436 | EXPECT_EQ(Known.Zero.getZExtValue(), 31u); |
2437 | EXPECT_EQ(Known.One.getZExtValue(), 0u); |
2438 | } |
2439 | |
2440 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsReturnedRangeConflict) { |
2441 | parseAssembly( |
2442 | Assembly: "declare i16 @foo(i16 returned)\n" |
2443 | "\n" |
2444 | "define i16 @test() {\n" |
2445 | " %A = call i16 @foo(i16 4095), !range !{i16 32, i16 33}\n" |
2446 | " ret i16 %A\n" |
2447 | "}\n" ); |
2448 | // The call returns 32 according to range metadata, but 4095 according to the |
2449 | // returned arg operand. Given the conflicting information we expect that the |
2450 | // known bits information simply is cleared. |
2451 | expectKnownBits(/*zero*/ Zero: 0u, /*one*/ One: 0u); |
2452 | } |
2453 | |
2454 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsAddWithRange) { |
2455 | parseAssembly(Assembly: "define void @test(ptr %p) {\n" |
2456 | " %A = load i64, ptr %p, !range !{i64 64, i64 65536}\n" |
2457 | " %APlus512 = add i64 %A, 512\n" |
2458 | " %c = icmp ugt i64 %APlus512, 523\n" |
2459 | " call void @llvm.assume(i1 %c)\n" |
2460 | " ret void\n" |
2461 | "}\n" |
2462 | "declare void @llvm.assume(i1)\n" ); |
2463 | AssumptionCache AC(*F); |
2464 | KnownBits Known = computeKnownBits(V: A, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2465 | CxtI: F->front().getTerminator()); |
2466 | EXPECT_EQ(Known.Zero.getZExtValue(), ~(65536llu - 1)); |
2467 | EXPECT_EQ(Known.One.getZExtValue(), 0u); |
2468 | Instruction &APlus512 = findInstructionByName(F, Name: "APlus512" ); |
2469 | Known = computeKnownBits(V: &APlus512, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2470 | CxtI: F->front().getTerminator()); |
2471 | // We know of one less zero because 512 may have produced a 1 that |
2472 | // got carried all the way to the first trailing zero. |
2473 | EXPECT_EQ(Known.Zero.getZExtValue(), (~(65536llu - 1)) << 1); |
2474 | EXPECT_EQ(Known.One.getZExtValue(), 0u); |
2475 | // The known range is not precise given computeKnownBits works |
2476 | // with the masks of zeros and ones, not the ranges. |
2477 | EXPECT_EQ(Known.getMinValue(), 0u); |
2478 | EXPECT_EQ(Known.getMaxValue(), 131071); |
2479 | } |
2480 | |
2481 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsUnknownVScale) { |
2482 | Module M("" , Context); |
2483 | IRBuilder<> Builder(Context); |
2484 | Function *TheFn = |
2485 | Intrinsic::getDeclaration(M: &M, Intrinsic::id: vscale, Tys: {Builder.getInt32Ty()}); |
2486 | CallInst *CI = Builder.CreateCall(Callee: TheFn, Args: {}, OpBundles: {}, Name: "" ); |
2487 | |
2488 | KnownBits Known = computeKnownBits(V: CI, DL: M.getDataLayout(), /* Depth */ 0); |
2489 | // There is no parent function so we cannot look up the vscale_range |
2490 | // attribute to determine the number of bits. |
2491 | EXPECT_EQ(Known.One.getZExtValue(), 0u); |
2492 | EXPECT_EQ(Known.Zero.getZExtValue(), 0u); |
2493 | |
2494 | BasicBlock *BB = BasicBlock::Create(Context); |
2495 | CI->insertInto(ParentBB: BB, It: BB->end()); |
2496 | Known = computeKnownBits(V: CI, DL: M.getDataLayout(), /* Depth */ 0); |
2497 | // There is no parent function so we cannot look up the vscale_range |
2498 | // attribute to determine the number of bits. |
2499 | EXPECT_EQ(Known.One.getZExtValue(), 0u); |
2500 | EXPECT_EQ(Known.Zero.getZExtValue(), 0u); |
2501 | |
2502 | CI->removeFromParent(); |
2503 | delete CI; |
2504 | delete BB; |
2505 | } |
2506 | |
2507 | // 512 + [32, 64) doesn't produce overlapping bits. |
2508 | // Make sure we get all the individual bits properly. |
2509 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsAddWithRangeNoOverlap) { |
2510 | parseAssembly(Assembly: "define void @test(ptr %p) {\n" |
2511 | " %A = load i64, ptr %p, !range !{i64 32, i64 64}\n" |
2512 | " %APlus512 = add i64 %A, 512\n" |
2513 | " %c = icmp ugt i64 %APlus512, 523\n" |
2514 | " call void @llvm.assume(i1 %c)\n" |
2515 | " ret void\n" |
2516 | "}\n" |
2517 | "declare void @llvm.assume(i1)\n" ); |
2518 | AssumptionCache AC(*F); |
2519 | KnownBits Known = computeKnownBits(V: A, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2520 | CxtI: F->front().getTerminator()); |
2521 | EXPECT_EQ(Known.Zero.getZExtValue(), ~(64llu - 1)); |
2522 | EXPECT_EQ(Known.One.getZExtValue(), 32u); |
2523 | Instruction &APlus512 = findInstructionByName(F, Name: "APlus512" ); |
2524 | Known = computeKnownBits(V: &APlus512, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2525 | CxtI: F->front().getTerminator()); |
2526 | EXPECT_EQ(Known.Zero.getZExtValue(), ~512llu & ~(64llu - 1)); |
2527 | EXPECT_EQ(Known.One.getZExtValue(), 512u | 32u); |
2528 | // The known range is not precise given computeKnownBits works |
2529 | // with the masks of zeros and ones, not the ranges. |
2530 | EXPECT_EQ(Known.getMinValue(), 544); |
2531 | EXPECT_EQ(Known.getMaxValue(), 575); |
2532 | } |
2533 | |
2534 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsGEPWithRange) { |
2535 | parseAssembly( |
2536 | Assembly: "define void @test(ptr %p) {\n" |
2537 | " %A = load i64, ptr %p, !range !{i64 64, i64 65536}\n" |
2538 | " %APtr = inttoptr i64 %A to float*" |
2539 | " %APtrPlus512 = getelementptr float, float* %APtr, i32 128\n" |
2540 | " %c = icmp ugt float* %APtrPlus512, inttoptr (i32 523 to float*)\n" |
2541 | " call void @llvm.assume(i1 %c)\n" |
2542 | " ret void\n" |
2543 | "}\n" |
2544 | "declare void @llvm.assume(i1)\n" ); |
2545 | AssumptionCache AC(*F); |
2546 | KnownBits Known = computeKnownBits(V: A, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2547 | CxtI: F->front().getTerminator()); |
2548 | EXPECT_EQ(Known.Zero.getZExtValue(), ~(65536llu - 1)); |
2549 | EXPECT_EQ(Known.One.getZExtValue(), 0u); |
2550 | Instruction &APtrPlus512 = findInstructionByName(F, Name: "APtrPlus512" ); |
2551 | Known = computeKnownBits(V: &APtrPlus512, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2552 | CxtI: F->front().getTerminator()); |
2553 | // We know of one less zero because 512 may have produced a 1 that |
2554 | // got carried all the way to the first trailing zero. |
2555 | EXPECT_EQ(Known.Zero.getZExtValue(), ~(65536llu - 1) << 1); |
2556 | EXPECT_EQ(Known.One.getZExtValue(), 0u); |
2557 | // The known range is not precise given computeKnownBits works |
2558 | // with the masks of zeros and ones, not the ranges. |
2559 | EXPECT_EQ(Known.getMinValue(), 0u); |
2560 | EXPECT_EQ(Known.getMaxValue(), 131071); |
2561 | } |
2562 | |
2563 | // 4*128 + [32, 64) doesn't produce overlapping bits. |
2564 | // Make sure we get all the individual bits properly. |
2565 | // This test is useful to check that we account for the scaling factor |
2566 | // in the gep. Indeed, gep float, [32,64), 128 is not 128 + [32,64). |
2567 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsGEPWithRangeNoOverlap) { |
2568 | parseAssembly( |
2569 | Assembly: "define void @test(ptr %p) {\n" |
2570 | " %A = load i64, ptr %p, !range !{i64 32, i64 64}\n" |
2571 | " %APtr = inttoptr i64 %A to float*" |
2572 | " %APtrPlus512 = getelementptr float, float* %APtr, i32 128\n" |
2573 | " %c = icmp ugt float* %APtrPlus512, inttoptr (i32 523 to float*)\n" |
2574 | " call void @llvm.assume(i1 %c)\n" |
2575 | " ret void\n" |
2576 | "}\n" |
2577 | "declare void @llvm.assume(i1)\n" ); |
2578 | AssumptionCache AC(*F); |
2579 | KnownBits Known = computeKnownBits(V: A, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2580 | CxtI: F->front().getTerminator()); |
2581 | EXPECT_EQ(Known.Zero.getZExtValue(), ~(64llu - 1)); |
2582 | EXPECT_EQ(Known.One.getZExtValue(), 32u); |
2583 | Instruction &APtrPlus512 = findInstructionByName(F, Name: "APtrPlus512" ); |
2584 | Known = computeKnownBits(V: &APtrPlus512, DL: M->getDataLayout(), /* Depth */ 0, AC: &AC, |
2585 | CxtI: F->front().getTerminator()); |
2586 | EXPECT_EQ(Known.Zero.getZExtValue(), ~512llu & ~(64llu - 1)); |
2587 | EXPECT_EQ(Known.One.getZExtValue(), 512u | 32u); |
2588 | // The known range is not precise given computeKnownBits works |
2589 | // with the masks of zeros and ones, not the ranges. |
2590 | EXPECT_EQ(Known.getMinValue(), 544); |
2591 | EXPECT_EQ(Known.getMaxValue(), 575); |
2592 | } |
2593 | |
2594 | TEST_F(ComputeKnownBitsTest, ComputeKnownBitsAbsoluteSymbol) { |
2595 | auto M = parseModule(Assembly: R"( |
2596 | @absolute_0_255 = external global [128 x i32], align 1, !absolute_symbol !0 |
2597 | @absolute_0_256 = external global [128 x i32], align 1, !absolute_symbol !1 |
2598 | @absolute_256_512 = external global [128 x i32], align 1, !absolute_symbol !2 |
2599 | @absolute_0_neg1 = external global [128 x i32], align 1, !absolute_symbol !3 |
2600 | @absolute_neg32_32 = external global [128 x i32], align 1, !absolute_symbol !4 |
2601 | @absolute_neg32_33 = external global [128 x i32], align 1, !absolute_symbol !5 |
2602 | @absolute_neg64_neg32 = external global [128 x i32], align 1, !absolute_symbol !6 |
2603 | @absolute_0_256_align8 = external global [128 x i32], align 8, !absolute_symbol !1 |
2604 | |
2605 | !0 = !{i64 0, i64 255} |
2606 | !1 = !{i64 0, i64 256} |
2607 | !2 = !{i64 256, i64 512} |
2608 | !3 = !{i64 0, i64 -1} |
2609 | !4 = !{i64 -32, i64 32} |
2610 | !5 = !{i64 -32, i64 33} |
2611 | !6 = !{i64 -64, i64 -32} |
2612 | )" ); |
2613 | |
2614 | GlobalValue *Absolute_0_255 = M->getNamedValue(Name: "absolute_0_255" ); |
2615 | GlobalValue *Absolute_0_256 = M->getNamedValue(Name: "absolute_0_256" ); |
2616 | GlobalValue *Absolute_256_512 = M->getNamedValue(Name: "absolute_256_512" ); |
2617 | GlobalValue *Absolute_0_Neg1 = M->getNamedValue(Name: "absolute_0_neg1" ); |
2618 | GlobalValue *Absolute_Neg32_32 = M->getNamedValue(Name: "absolute_neg32_32" ); |
2619 | GlobalValue *Absolute_Neg32_33 = M->getNamedValue(Name: "absolute_neg32_33" ); |
2620 | GlobalValue *Absolute_Neg64_Neg32 = M->getNamedValue(Name: "absolute_neg64_neg32" ); |
2621 | GlobalValue *Absolute_0_256_Align8 = |
2622 | M->getNamedValue(Name: "absolute_0_256_align8" ); |
2623 | |
2624 | KnownBits Known_0_255 = computeKnownBits(V: Absolute_0_255, DL: M->getDataLayout()); |
2625 | EXPECT_EQ(64u - 8u, Known_0_255.countMinLeadingZeros()); |
2626 | EXPECT_EQ(0u, Known_0_255.countMinTrailingZeros()); |
2627 | EXPECT_EQ(0u, Known_0_255.countMinLeadingOnes()); |
2628 | EXPECT_EQ(0u, Known_0_255.countMinTrailingOnes()); |
2629 | |
2630 | KnownBits Known_0_256 = computeKnownBits(V: Absolute_0_256, DL: M->getDataLayout()); |
2631 | EXPECT_EQ(64u - 8u, Known_0_256.countMinLeadingZeros()); |
2632 | EXPECT_EQ(0u, Known_0_256.countMinTrailingZeros()); |
2633 | EXPECT_EQ(0u, Known_0_256.countMinLeadingOnes()); |
2634 | EXPECT_EQ(0u, Known_0_256.countMinTrailingOnes()); |
2635 | |
2636 | KnownBits Known_256_512 = |
2637 | computeKnownBits(V: Absolute_256_512, DL: M->getDataLayout()); |
2638 | EXPECT_EQ(64u - 8u, Known_0_255.countMinLeadingZeros()); |
2639 | EXPECT_EQ(0u, Known_0_255.countMinTrailingZeros()); |
2640 | EXPECT_EQ(0u, Known_0_255.countMinLeadingOnes()); |
2641 | EXPECT_EQ(0u, Known_0_255.countMinTrailingOnes()); |
2642 | |
2643 | KnownBits Known_0_Neg1 = |
2644 | computeKnownBits(V: Absolute_0_Neg1, DL: M->getDataLayout()); |
2645 | EXPECT_EQ(0u, Known_0_Neg1.countMinLeadingZeros()); |
2646 | EXPECT_EQ(0u, Known_0_Neg1.countMinTrailingZeros()); |
2647 | EXPECT_EQ(0u, Known_0_Neg1.countMinLeadingOnes()); |
2648 | EXPECT_EQ(0u, Known_0_Neg1.countMinTrailingOnes()); |
2649 | |
2650 | KnownBits Known_Neg32_32 = |
2651 | computeKnownBits(V: Absolute_Neg32_32, DL: M->getDataLayout()); |
2652 | EXPECT_EQ(0u, Known_Neg32_32.countMinLeadingZeros()); |
2653 | EXPECT_EQ(0u, Known_Neg32_32.countMinTrailingZeros()); |
2654 | EXPECT_EQ(0u, Known_Neg32_32.countMinLeadingOnes()); |
2655 | EXPECT_EQ(0u, Known_Neg32_32.countMinTrailingOnes()); |
2656 | EXPECT_EQ(1u, Known_Neg32_32.countMinSignBits()); |
2657 | |
2658 | KnownBits Known_Neg32_33 = |
2659 | computeKnownBits(V: Absolute_Neg32_33, DL: M->getDataLayout()); |
2660 | EXPECT_EQ(0u, Known_Neg32_33.countMinLeadingZeros()); |
2661 | EXPECT_EQ(0u, Known_Neg32_33.countMinTrailingZeros()); |
2662 | EXPECT_EQ(0u, Known_Neg32_33.countMinLeadingOnes()); |
2663 | EXPECT_EQ(0u, Known_Neg32_33.countMinTrailingOnes()); |
2664 | EXPECT_EQ(1u, Known_Neg32_33.countMinSignBits()); |
2665 | |
2666 | KnownBits Known_Neg32_Neg32 = |
2667 | computeKnownBits(V: Absolute_Neg64_Neg32, DL: M->getDataLayout()); |
2668 | EXPECT_EQ(0u, Known_Neg32_Neg32.countMinLeadingZeros()); |
2669 | EXPECT_EQ(0u, Known_Neg32_Neg32.countMinTrailingZeros()); |
2670 | EXPECT_EQ(58u, Known_Neg32_Neg32.countMinLeadingOnes()); |
2671 | EXPECT_EQ(0u, Known_Neg32_Neg32.countMinTrailingOnes()); |
2672 | EXPECT_EQ(58u, Known_Neg32_Neg32.countMinSignBits()); |
2673 | |
2674 | KnownBits Known_0_256_Align8 = |
2675 | computeKnownBits(V: Absolute_0_256_Align8, DL: M->getDataLayout()); |
2676 | EXPECT_EQ(64u - 8u, Known_0_256_Align8.countMinLeadingZeros()); |
2677 | EXPECT_EQ(3u, Known_0_256_Align8.countMinTrailingZeros()); |
2678 | EXPECT_EQ(0u, Known_0_256_Align8.countMinLeadingOnes()); |
2679 | EXPECT_EQ(0u, Known_0_256_Align8.countMinTrailingOnes()); |
2680 | } |
2681 | |
2682 | TEST_F(ValueTrackingTest, HaveNoCommonBitsSet) { |
2683 | { |
2684 | // Check for an inverted mask: (X & ~M) op (Y & M). |
2685 | auto M = parseModule(Assembly: R"( |
2686 | define i32 @test(i32 %X, i32 %Y, i32 noundef %M) { |
2687 | %1 = xor i32 %M, -1 |
2688 | %LHS = and i32 %1, %X |
2689 | %RHS = and i32 %Y, %M |
2690 | %Ret = add i32 %LHS, %RHS |
2691 | ret i32 %Ret |
2692 | })" ); |
2693 | |
2694 | auto *F = M->getFunction(Name: "test" ); |
2695 | auto *LHS = findInstructionByNameOrNull(F, Name: "LHS" ); |
2696 | auto *RHS = findInstructionByNameOrNull(F, Name: "RHS" ); |
2697 | |
2698 | const DataLayout &DL = M->getDataLayout(); |
2699 | EXPECT_TRUE(haveNoCommonBitsSet(LHS, RHS, DL)); |
2700 | EXPECT_TRUE(haveNoCommonBitsSet(RHS, LHS, DL)); |
2701 | } |
2702 | { |
2703 | // Check for (A & B) and ~(A | B) |
2704 | auto M = parseModule(Assembly: R"( |
2705 | define void @test(i32 noundef %A, i32 noundef %B) { |
2706 | %LHS = and i32 %A, %B |
2707 | %or = or i32 %A, %B |
2708 | %RHS = xor i32 %or, -1 |
2709 | |
2710 | %LHS2 = and i32 %B, %A |
2711 | %or2 = or i32 %A, %B |
2712 | %RHS2 = xor i32 %or2, -1 |
2713 | |
2714 | ret void |
2715 | })" ); |
2716 | |
2717 | auto *F = M->getFunction(Name: "test" ); |
2718 | const DataLayout &DL = M->getDataLayout(); |
2719 | |
2720 | auto *LHS = findInstructionByNameOrNull(F, Name: "LHS" ); |
2721 | auto *RHS = findInstructionByNameOrNull(F, Name: "RHS" ); |
2722 | EXPECT_TRUE(haveNoCommonBitsSet(LHS, RHS, DL)); |
2723 | EXPECT_TRUE(haveNoCommonBitsSet(RHS, LHS, DL)); |
2724 | |
2725 | auto *LHS2 = findInstructionByNameOrNull(F, Name: "LHS2" ); |
2726 | auto *RHS2 = findInstructionByNameOrNull(F, Name: "RHS2" ); |
2727 | EXPECT_TRUE(haveNoCommonBitsSet(LHS2, RHS2, DL)); |
2728 | EXPECT_TRUE(haveNoCommonBitsSet(RHS2, LHS2, DL)); |
2729 | } |
2730 | { |
2731 | // Check for (A & B) and ~(A | B) in vector version |
2732 | auto M = parseModule(Assembly: R"( |
2733 | define void @test(<2 x i32> noundef %A, <2 x i32> noundef %B) { |
2734 | %LHS = and <2 x i32> %A, %B |
2735 | %or = or <2 x i32> %A, %B |
2736 | %RHS = xor <2 x i32> %or, <i32 -1, i32 -1> |
2737 | |
2738 | %LHS2 = and <2 x i32> %B, %A |
2739 | %or2 = or <2 x i32> %A, %B |
2740 | %RHS2 = xor <2 x i32> %or2, <i32 -1, i32 -1> |
2741 | |
2742 | ret void |
2743 | })" ); |
2744 | |
2745 | auto *F = M->getFunction(Name: "test" ); |
2746 | const DataLayout &DL = M->getDataLayout(); |
2747 | |
2748 | auto *LHS = findInstructionByNameOrNull(F, Name: "LHS" ); |
2749 | auto *RHS = findInstructionByNameOrNull(F, Name: "RHS" ); |
2750 | EXPECT_TRUE(haveNoCommonBitsSet(LHS, RHS, DL)); |
2751 | EXPECT_TRUE(haveNoCommonBitsSet(RHS, LHS, DL)); |
2752 | |
2753 | auto *LHS2 = findInstructionByNameOrNull(F, Name: "LHS2" ); |
2754 | auto *RHS2 = findInstructionByNameOrNull(F, Name: "RHS2" ); |
2755 | EXPECT_TRUE(haveNoCommonBitsSet(LHS2, RHS2, DL)); |
2756 | EXPECT_TRUE(haveNoCommonBitsSet(RHS2, LHS2, DL)); |
2757 | } |
2758 | } |
2759 | |
2760 | class IsBytewiseValueTest : public ValueTrackingTest, |
2761 | public ::testing::WithParamInterface< |
2762 | std::pair<const char *, const char *>> { |
2763 | protected: |
2764 | }; |
2765 | |
2766 | const std::pair<const char *, const char *> IsBytewiseValueTests[] = { |
2767 | { |
2768 | "i8 0" , |
2769 | "i48* null" , |
2770 | }, |
2771 | { |
2772 | "i8 undef" , |
2773 | "i48* undef" , |
2774 | }, |
2775 | { |
2776 | "i8 0" , |
2777 | "i8 zeroinitializer" , |
2778 | }, |
2779 | { |
2780 | "i8 0" , |
2781 | "i8 0" , |
2782 | }, |
2783 | { |
2784 | "i8 -86" , |
2785 | "i8 -86" , |
2786 | }, |
2787 | { |
2788 | "i8 -1" , |
2789 | "i8 -1" , |
2790 | }, |
2791 | { |
2792 | "i8 undef" , |
2793 | "i16 undef" , |
2794 | }, |
2795 | { |
2796 | "i8 0" , |
2797 | "i16 0" , |
2798 | }, |
2799 | { |
2800 | "" , |
2801 | "i16 7" , |
2802 | }, |
2803 | { |
2804 | "i8 -86" , |
2805 | "i16 -21846" , |
2806 | }, |
2807 | { |
2808 | "i8 -1" , |
2809 | "i16 -1" , |
2810 | }, |
2811 | { |
2812 | "i8 0" , |
2813 | "i48 0" , |
2814 | }, |
2815 | { |
2816 | "i8 -1" , |
2817 | "i48 -1" , |
2818 | }, |
2819 | { |
2820 | "i8 0" , |
2821 | "i49 0" , |
2822 | }, |
2823 | { |
2824 | "" , |
2825 | "i49 -1" , |
2826 | }, |
2827 | { |
2828 | "i8 0" , |
2829 | "half 0xH0000" , |
2830 | }, |
2831 | { |
2832 | "i8 -85" , |
2833 | "half 0xHABAB" , |
2834 | }, |
2835 | { |
2836 | "i8 0" , |
2837 | "float 0.0" , |
2838 | }, |
2839 | { |
2840 | "i8 -1" , |
2841 | "float 0xFFFFFFFFE0000000" , |
2842 | }, |
2843 | { |
2844 | "i8 0" , |
2845 | "double 0.0" , |
2846 | }, |
2847 | { |
2848 | "i8 -15" , |
2849 | "double 0xF1F1F1F1F1F1F1F1" , |
2850 | }, |
2851 | { |
2852 | "i8 undef" , |
2853 | "i16* undef" , |
2854 | }, |
2855 | { |
2856 | "i8 0" , |
2857 | "i16* inttoptr (i64 0 to i16*)" , |
2858 | }, |
2859 | { |
2860 | "i8 -1" , |
2861 | "i16* inttoptr (i64 -1 to i16*)" , |
2862 | }, |
2863 | { |
2864 | "i8 -86" , |
2865 | "i16* inttoptr (i64 -6148914691236517206 to i16*)" , |
2866 | }, |
2867 | { |
2868 | "" , |
2869 | "i16* inttoptr (i48 -1 to i16*)" , |
2870 | }, |
2871 | { |
2872 | "i8 -1" , |
2873 | "i16* inttoptr (i96 -1 to i16*)" , |
2874 | }, |
2875 | { |
2876 | "i8 undef" , |
2877 | "[0 x i8] zeroinitializer" , |
2878 | }, |
2879 | { |
2880 | "i8 undef" , |
2881 | "[0 x i8] undef" , |
2882 | }, |
2883 | { |
2884 | "i8 undef" , |
2885 | "[5 x [0 x i8]] zeroinitializer" , |
2886 | }, |
2887 | { |
2888 | "i8 undef" , |
2889 | "[5 x [0 x i8]] undef" , |
2890 | }, |
2891 | { |
2892 | "i8 0" , |
2893 | "[6 x i8] zeroinitializer" , |
2894 | }, |
2895 | { |
2896 | "i8 undef" , |
2897 | "[6 x i8] undef" , |
2898 | }, |
2899 | { |
2900 | "i8 1" , |
2901 | "[5 x i8] [i8 1, i8 1, i8 1, i8 1, i8 1]" , |
2902 | }, |
2903 | { |
2904 | "" , |
2905 | "[5 x i64] [i64 1, i64 1, i64 1, i64 1, i64 1]" , |
2906 | }, |
2907 | { |
2908 | "i8 -1" , |
2909 | "[5 x i64] [i64 -1, i64 -1, i64 -1, i64 -1, i64 -1]" , |
2910 | }, |
2911 | { |
2912 | "" , |
2913 | "[4 x i8] [i8 1, i8 2, i8 1, i8 1]" , |
2914 | }, |
2915 | { |
2916 | "i8 1" , |
2917 | "[4 x i8] [i8 1, i8 undef, i8 1, i8 1]" , |
2918 | }, |
2919 | { |
2920 | "i8 0" , |
2921 | "<6 x i8> zeroinitializer" , |
2922 | }, |
2923 | { |
2924 | "i8 undef" , |
2925 | "<6 x i8> undef" , |
2926 | }, |
2927 | { |
2928 | "i8 1" , |
2929 | "<5 x i8> <i8 1, i8 1, i8 1, i8 1, i8 1>" , |
2930 | }, |
2931 | { |
2932 | "" , |
2933 | "<5 x i64> <i64 1, i64 1, i64 1, i64 1, i64 1>" , |
2934 | }, |
2935 | { |
2936 | "i8 -1" , |
2937 | "<5 x i64> <i64 -1, i64 -1, i64 -1, i64 -1, i64 -1>" , |
2938 | }, |
2939 | { |
2940 | "" , |
2941 | "<4 x i8> <i8 1, i8 1, i8 2, i8 1>" , |
2942 | }, |
2943 | { |
2944 | "i8 5" , |
2945 | "<2 x i8> < i8 5, i8 undef >" , |
2946 | }, |
2947 | { |
2948 | "i8 0" , |
2949 | "[2 x [2 x i16]] zeroinitializer" , |
2950 | }, |
2951 | { |
2952 | "i8 undef" , |
2953 | "[2 x [2 x i16]] undef" , |
2954 | }, |
2955 | { |
2956 | "i8 -86" , |
2957 | "[2 x [2 x i16]] [[2 x i16] [i16 -21846, i16 -21846], " |
2958 | "[2 x i16] [i16 -21846, i16 -21846]]" , |
2959 | }, |
2960 | { |
2961 | "" , |
2962 | "[2 x [2 x i16]] [[2 x i16] [i16 -21846, i16 -21846], " |
2963 | "[2 x i16] [i16 -21836, i16 -21846]]" , |
2964 | }, |
2965 | { |
2966 | "i8 undef" , |
2967 | "{ } zeroinitializer" , |
2968 | }, |
2969 | { |
2970 | "i8 undef" , |
2971 | "{ } undef" , |
2972 | }, |
2973 | { |
2974 | "i8 undef" , |
2975 | "{ {}, {} } zeroinitializer" , |
2976 | }, |
2977 | { |
2978 | "i8 undef" , |
2979 | "{ {}, {} } undef" , |
2980 | }, |
2981 | { |
2982 | "i8 0" , |
2983 | "{i8, i64, i16*} zeroinitializer" , |
2984 | }, |
2985 | { |
2986 | "i8 undef" , |
2987 | "{i8, i64, i16*} undef" , |
2988 | }, |
2989 | { |
2990 | "i8 -86" , |
2991 | "{i8, i64, i16*} {i8 -86, i64 -6148914691236517206, i16* undef}" , |
2992 | }, |
2993 | { |
2994 | "" , |
2995 | "{i8, i64, i16*} {i8 86, i64 -6148914691236517206, i16* undef}" , |
2996 | }, |
2997 | }; |
2998 | |
2999 | INSTANTIATE_TEST_SUITE_P(IsBytewiseValueParamTests, IsBytewiseValueTest, |
3000 | ::testing::ValuesIn(IsBytewiseValueTests)); |
3001 | |
3002 | TEST_P(IsBytewiseValueTest, IsBytewiseValue) { |
3003 | auto M = parseModule(Assembly: std::string("@test = global " ) + GetParam().second); |
3004 | GlobalVariable *GV = dyn_cast<GlobalVariable>(Val: M->getNamedValue(Name: "test" )); |
3005 | Value *Actual = isBytewiseValue(V: GV->getInitializer(), DL: M->getDataLayout()); |
3006 | std::string Buff; |
3007 | raw_string_ostream S(Buff); |
3008 | if (Actual) |
3009 | S << *Actual; |
3010 | EXPECT_EQ(GetParam().first, S.str()); |
3011 | } |
3012 | |
3013 | TEST_F(ValueTrackingTest, ComputeConstantRange) { |
3014 | { |
3015 | // Assumptions: |
3016 | // * stride >= 5 |
3017 | // * stride < 10 |
3018 | // |
3019 | // stride = [5, 10) |
3020 | auto M = parseModule(Assembly: R"( |
3021 | declare void @llvm.assume(i1) |
3022 | |
3023 | define i32 @test(i32 %stride) { |
3024 | %gt = icmp uge i32 %stride, 5 |
3025 | call void @llvm.assume(i1 %gt) |
3026 | %lt = icmp ult i32 %stride, 10 |
3027 | call void @llvm.assume(i1 %lt) |
3028 | %stride.plus.one = add nsw nuw i32 %stride, 1 |
3029 | ret i32 %stride.plus.one |
3030 | })" ); |
3031 | Function *F = M->getFunction(Name: "test" ); |
3032 | |
3033 | AssumptionCache AC(*F); |
3034 | Value *Stride = &*F->arg_begin(); |
3035 | ConstantRange CR1 = computeConstantRange(V: Stride, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: nullptr); |
3036 | EXPECT_TRUE(CR1.isFullSet()); |
3037 | |
3038 | Instruction *I = &findInstructionByName(F, Name: "stride.plus.one" ); |
3039 | ConstantRange CR2 = computeConstantRange(V: Stride, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I); |
3040 | EXPECT_EQ(5, CR2.getLower()); |
3041 | EXPECT_EQ(10, CR2.getUpper()); |
3042 | } |
3043 | |
3044 | { |
3045 | // Assumptions: |
3046 | // * stride >= 5 |
3047 | // * stride < 200 |
3048 | // * stride == 99 |
3049 | // |
3050 | // stride = [99, 100) |
3051 | auto M = parseModule(Assembly: R"( |
3052 | declare void @llvm.assume(i1) |
3053 | |
3054 | define i32 @test(i32 %stride) { |
3055 | %gt = icmp uge i32 %stride, 5 |
3056 | call void @llvm.assume(i1 %gt) |
3057 | %lt = icmp ult i32 %stride, 200 |
3058 | call void @llvm.assume(i1 %lt) |
3059 | %eq = icmp eq i32 %stride, 99 |
3060 | call void @llvm.assume(i1 %eq) |
3061 | %stride.plus.one = add nsw nuw i32 %stride, 1 |
3062 | ret i32 %stride.plus.one |
3063 | })" ); |
3064 | Function *F = M->getFunction(Name: "test" ); |
3065 | |
3066 | AssumptionCache AC(*F); |
3067 | Value *Stride = &*F->arg_begin(); |
3068 | Instruction *I = &findInstructionByName(F, Name: "stride.plus.one" ); |
3069 | ConstantRange CR = computeConstantRange(V: Stride, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I); |
3070 | EXPECT_EQ(99, *CR.getSingleElement()); |
3071 | } |
3072 | |
3073 | { |
3074 | // Assumptions: |
3075 | // * stride >= 5 |
3076 | // * stride >= 50 |
3077 | // * stride < 100 |
3078 | // * stride < 200 |
3079 | // |
3080 | // stride = [50, 100) |
3081 | auto M = parseModule(Assembly: R"( |
3082 | declare void @llvm.assume(i1) |
3083 | |
3084 | define i32 @test(i32 %stride, i1 %cond) { |
3085 | %gt = icmp uge i32 %stride, 5 |
3086 | call void @llvm.assume(i1 %gt) |
3087 | %gt.2 = icmp uge i32 %stride, 50 |
3088 | call void @llvm.assume(i1 %gt.2) |
3089 | br i1 %cond, label %bb1, label %bb2 |
3090 | |
3091 | bb1: |
3092 | %lt = icmp ult i32 %stride, 200 |
3093 | call void @llvm.assume(i1 %lt) |
3094 | %lt.2 = icmp ult i32 %stride, 100 |
3095 | call void @llvm.assume(i1 %lt.2) |
3096 | %stride.plus.one = add nsw nuw i32 %stride, 1 |
3097 | ret i32 %stride.plus.one |
3098 | |
3099 | bb2: |
3100 | ret i32 0 |
3101 | })" ); |
3102 | Function *F = M->getFunction(Name: "test" ); |
3103 | |
3104 | AssumptionCache AC(*F); |
3105 | Value *Stride = &*F->arg_begin(); |
3106 | Instruction *GT2 = &findInstructionByName(F, Name: "gt.2" ); |
3107 | ConstantRange CR = computeConstantRange(V: Stride, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: GT2); |
3108 | EXPECT_EQ(5, CR.getLower()); |
3109 | EXPECT_EQ(0, CR.getUpper()); |
3110 | |
3111 | Instruction *I = &findInstructionByName(F, Name: "stride.plus.one" ); |
3112 | ConstantRange CR2 = computeConstantRange(V: Stride, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I); |
3113 | EXPECT_EQ(50, CR2.getLower()); |
3114 | EXPECT_EQ(100, CR2.getUpper()); |
3115 | } |
3116 | |
3117 | { |
3118 | // Assumptions: |
3119 | // * stride > 5 |
3120 | // * stride < 5 |
3121 | // |
3122 | // stride = empty range, as the assumptions contradict each other. |
3123 | auto M = parseModule(Assembly: R"( |
3124 | declare void @llvm.assume(i1) |
3125 | |
3126 | define i32 @test(i32 %stride, i1 %cond) { |
3127 | %gt = icmp ugt i32 %stride, 5 |
3128 | call void @llvm.assume(i1 %gt) |
3129 | %lt = icmp ult i32 %stride, 5 |
3130 | call void @llvm.assume(i1 %lt) |
3131 | %stride.plus.one = add nsw nuw i32 %stride, 1 |
3132 | ret i32 %stride.plus.one |
3133 | })" ); |
3134 | Function *F = M->getFunction(Name: "test" ); |
3135 | |
3136 | AssumptionCache AC(*F); |
3137 | Value *Stride = &*F->arg_begin(); |
3138 | |
3139 | Instruction *I = &findInstructionByName(F, Name: "stride.plus.one" ); |
3140 | ConstantRange CR = computeConstantRange(V: Stride, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I); |
3141 | EXPECT_TRUE(CR.isEmptySet()); |
3142 | } |
3143 | |
3144 | { |
3145 | // Assumptions: |
3146 | // * x.1 >= 5 |
3147 | // * x.2 < x.1 |
3148 | // |
3149 | // stride = [0, -1) |
3150 | auto M = parseModule(Assembly: R"( |
3151 | declare void @llvm.assume(i1) |
3152 | |
3153 | define i32 @test(i32 %x.1, i32 %x.2) { |
3154 | %gt = icmp uge i32 %x.1, 5 |
3155 | call void @llvm.assume(i1 %gt) |
3156 | %lt = icmp ult i32 %x.2, %x.1 |
3157 | call void @llvm.assume(i1 %lt) |
3158 | %stride.plus.one = add nsw nuw i32 %x.1, 1 |
3159 | ret i32 %stride.plus.one |
3160 | })" ); |
3161 | Function *F = M->getFunction(Name: "test" ); |
3162 | |
3163 | AssumptionCache AC(*F); |
3164 | Value *X1 = &*(F->arg_begin()); |
3165 | Value *X2 = &*std::next(x: F->arg_begin()); |
3166 | |
3167 | Instruction *I = &findInstructionByName(F, Name: "stride.plus.one" ); |
3168 | ConstantRange CR1 = computeConstantRange(V: X1, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I); |
3169 | ConstantRange CR2 = computeConstantRange(V: X2, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I); |
3170 | |
3171 | EXPECT_EQ(5, CR1.getLower()); |
3172 | EXPECT_EQ(0, CR1.getUpper()); |
3173 | |
3174 | EXPECT_EQ(0, CR2.getLower()); |
3175 | EXPECT_EQ(0xffffffff, CR2.getUpper()); |
3176 | |
3177 | // Check the depth cutoff results in a conservative result (full set) by |
3178 | // passing Depth == MaxDepth == 6. |
3179 | ConstantRange CR3 = computeConstantRange(V: X2, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I, DT: nullptr, Depth: 6); |
3180 | EXPECT_TRUE(CR3.isFullSet()); |
3181 | } |
3182 | { |
3183 | // Assumptions: |
3184 | // * x.2 <= x.1 |
3185 | auto M = parseModule(Assembly: R"( |
3186 | declare void @llvm.assume(i1) |
3187 | |
3188 | define i32 @test(i32 %x.1, i32 %x.2) { |
3189 | %lt = icmp ule i32 %x.2, %x.1 |
3190 | call void @llvm.assume(i1 %lt) |
3191 | %stride.plus.one = add nsw nuw i32 %x.1, 1 |
3192 | ret i32 %stride.plus.one |
3193 | })" ); |
3194 | Function *F = M->getFunction(Name: "test" ); |
3195 | |
3196 | AssumptionCache AC(*F); |
3197 | Value *X2 = &*std::next(x: F->arg_begin()); |
3198 | |
3199 | Instruction *I = &findInstructionByName(F, Name: "stride.plus.one" ); |
3200 | ConstantRange CR1 = computeConstantRange(V: X2, ForSigned: false, UseInstrInfo: true, AC: &AC, CtxI: I); |
3201 | // If we don't know the value of x.2, we don't know the value of x.1. |
3202 | EXPECT_TRUE(CR1.isFullSet()); |
3203 | } |
3204 | } |
3205 | |
3206 | struct FindAllocaForValueTestParams { |
3207 | const char *IR; |
3208 | bool AnyOffsetResult; |
3209 | bool ZeroOffsetResult; |
3210 | }; |
3211 | |
3212 | class FindAllocaForValueTest |
3213 | : public ValueTrackingTest, |
3214 | public ::testing::WithParamInterface<FindAllocaForValueTestParams> { |
3215 | protected: |
3216 | }; |
3217 | |
3218 | const FindAllocaForValueTestParams FindAllocaForValueTests[] = { |
3219 | {.IR: R"( |
3220 | define void @test() { |
3221 | %a = alloca i64 |
3222 | %r = bitcast ptr %a to ptr |
3223 | ret void |
3224 | })" , |
3225 | .AnyOffsetResult: true, .ZeroOffsetResult: true}, |
3226 | |
3227 | {.IR: R"( |
3228 | define void @test() { |
3229 | %a = alloca i32 |
3230 | %r = getelementptr i32, ptr %a, i32 1 |
3231 | ret void |
3232 | })" , |
3233 | .AnyOffsetResult: true, .ZeroOffsetResult: false}, |
3234 | |
3235 | {.IR: R"( |
3236 | define void @test() { |
3237 | %a = alloca i32 |
3238 | %r = getelementptr i32, ptr %a, i32 0 |
3239 | ret void |
3240 | })" , |
3241 | .AnyOffsetResult: true, .ZeroOffsetResult: true}, |
3242 | |
3243 | {.IR: R"( |
3244 | define void @test(i1 %cond) { |
3245 | entry: |
3246 | %a = alloca i32 |
3247 | br label %bb1 |
3248 | |
3249 | bb1: |
3250 | %r = phi ptr [ %a, %entry ], [ %r, %bb1 ] |
3251 | br i1 %cond, label %bb1, label %exit |
3252 | |
3253 | exit: |
3254 | ret void |
3255 | })" , |
3256 | .AnyOffsetResult: true, .ZeroOffsetResult: true}, |
3257 | |
3258 | {.IR: R"( |
3259 | define void @test(i1 %cond) { |
3260 | %a = alloca i32 |
3261 | %r = select i1 %cond, ptr %a, ptr %a |
3262 | ret void |
3263 | })" , |
3264 | .AnyOffsetResult: true, .ZeroOffsetResult: true}, |
3265 | |
3266 | {.IR: R"( |
3267 | define void @test(i1 %cond) { |
3268 | %a = alloca i32 |
3269 | %b = alloca i32 |
3270 | %r = select i1 %cond, ptr %a, ptr %b |
3271 | ret void |
3272 | })" , |
3273 | .AnyOffsetResult: false, .ZeroOffsetResult: false}, |
3274 | |
3275 | {.IR: R"( |
3276 | define void @test(i1 %cond) { |
3277 | entry: |
3278 | %a = alloca i64 |
3279 | %a32 = bitcast ptr %a to ptr |
3280 | br label %bb1 |
3281 | |
3282 | bb1: |
3283 | %x = phi ptr [ %a32, %entry ], [ %x, %bb1 ] |
3284 | %r = getelementptr i32, ptr %x, i32 1 |
3285 | br i1 %cond, label %bb1, label %exit |
3286 | |
3287 | exit: |
3288 | ret void |
3289 | })" , |
3290 | .AnyOffsetResult: true, .ZeroOffsetResult: false}, |
3291 | |
3292 | {.IR: R"( |
3293 | define void @test(i1 %cond) { |
3294 | entry: |
3295 | %a = alloca i64 |
3296 | %a32 = bitcast ptr %a to ptr |
3297 | br label %bb1 |
3298 | |
3299 | bb1: |
3300 | %x = phi ptr [ %a32, %entry ], [ %r, %bb1 ] |
3301 | %r = getelementptr i32, ptr %x, i32 1 |
3302 | br i1 %cond, label %bb1, label %exit |
3303 | |
3304 | exit: |
3305 | ret void |
3306 | })" , |
3307 | .AnyOffsetResult: true, .ZeroOffsetResult: false}, |
3308 | |
3309 | {.IR: R"( |
3310 | define void @test(i1 %cond, ptr %a) { |
3311 | entry: |
3312 | %r = bitcast ptr %a to ptr |
3313 | ret void |
3314 | })" , |
3315 | .AnyOffsetResult: false, .ZeroOffsetResult: false}, |
3316 | |
3317 | {.IR: R"( |
3318 | define void @test(i1 %cond) { |
3319 | entry: |
3320 | %a = alloca i32 |
3321 | %b = alloca i32 |
3322 | br label %bb1 |
3323 | |
3324 | bb1: |
3325 | %r = phi ptr [ %a, %entry ], [ %b, %bb1 ] |
3326 | br i1 %cond, label %bb1, label %exit |
3327 | |
3328 | exit: |
3329 | ret void |
3330 | })" , |
3331 | .AnyOffsetResult: false, .ZeroOffsetResult: false}, |
3332 | {.IR: R"( |
3333 | declare ptr @retptr(ptr returned) |
3334 | define void @test(i1 %cond) { |
3335 | %a = alloca i32 |
3336 | %r = call ptr @retptr(ptr %a) |
3337 | ret void |
3338 | })" , |
3339 | .AnyOffsetResult: true, .ZeroOffsetResult: true}, |
3340 | {.IR: R"( |
3341 | declare ptr @fun(ptr) |
3342 | define void @test(i1 %cond) { |
3343 | %a = alloca i32 |
3344 | %r = call ptr @fun(ptr %a) |
3345 | ret void |
3346 | })" , |
3347 | .AnyOffsetResult: false, .ZeroOffsetResult: false}, |
3348 | }; |
3349 | |
3350 | TEST_P(FindAllocaForValueTest, findAllocaForValue) { |
3351 | auto M = parseModule(Assembly: GetParam().IR); |
3352 | Function *F = M->getFunction(Name: "test" ); |
3353 | Instruction *I = &findInstructionByName(F, Name: "r" ); |
3354 | const AllocaInst *AI = findAllocaForValue(V: I); |
3355 | EXPECT_EQ(!!AI, GetParam().AnyOffsetResult); |
3356 | } |
3357 | |
3358 | TEST_P(FindAllocaForValueTest, findAllocaForValueZeroOffset) { |
3359 | auto M = parseModule(Assembly: GetParam().IR); |
3360 | Function *F = M->getFunction(Name: "test" ); |
3361 | Instruction *I = &findInstructionByName(F, Name: "r" ); |
3362 | const AllocaInst *AI = findAllocaForValue(V: I, OffsetZero: true); |
3363 | EXPECT_EQ(!!AI, GetParam().ZeroOffsetResult); |
3364 | } |
3365 | |
3366 | INSTANTIATE_TEST_SUITE_P(FindAllocaForValueTest, FindAllocaForValueTest, |
3367 | ::testing::ValuesIn(FindAllocaForValueTests)); |
3368 | |