xref: /llvm-project/llvm/unittests/Analysis/VectorUtilsTest.cpp (revision 38818b60c58c76ba89b990978cdfd2d7b6799260)
1 //===- VectorUtilsTest.cpp - VectorUtils 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/VectorUtils.h"
10 #include "llvm/Analysis/ValueTracking.h"
11 #include "llvm/AsmParser/Parser.h"
12 #include "llvm/IR/Function.h"
13 #include "llvm/IR/InstIterator.h"
14 #include "llvm/IR/IRBuilder.h"
15 #include "llvm/IR/LLVMContext.h"
16 #include "llvm/IR/Module.h"
17 #include "llvm/IR/NoFolder.h"
18 #include "llvm/Support/ErrorHandling.h"
19 #include "llvm/Support/SourceMgr.h"
20 #include "llvm/Support/KnownBits.h"
21 #include "gtest/gtest.h"
22 
23 using namespace llvm;
24 
25 namespace {
26 
27 class VectorUtilsTest : public testing::Test {
28 protected:
29   void parseAssembly(const char *Assembly) {
30     SMDiagnostic Error;
31     M = parseAssemblyString(Assembly, Error, Context);
32 
33     std::string errMsg;
34     raw_string_ostream os(errMsg);
35     Error.print("", os);
36 
37     // A failure here means that the test itself is buggy.
38     if (!M)
39       report_fatal_error(Twine(os.str()));
40 
41     Function *F = M->getFunction("test");
42     if (F == nullptr)
43       report_fatal_error("Test must have a function named @test");
44 
45     A = nullptr;
46     for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
47       if (I->hasName()) {
48         if (I->getName() == "A")
49           A = &*I;
50       }
51     }
52     if (A == nullptr)
53       report_fatal_error("@test must have an instruction %A");
54   }
55 
56   LLVMContext Context;
57   std::unique_ptr<Module> M;
58   Instruction *A;
59 };
60 
61 struct BasicTest : public testing::Test {
62   LLVMContext Ctx;
63   std::unique_ptr<Module> M;
64   Function *F;
65   BasicBlock *BB;
66   IRBuilder<NoFolder> IRB;
67 
68   BasicTest()
69       : M(new Module("VectorUtils", Ctx)),
70         F(Function::Create(
71             FunctionType::get(Type::getVoidTy(Ctx), /* IsVarArg */ false),
72             Function::ExternalLinkage, "f", M.get())),
73         BB(BasicBlock::Create(Ctx, "entry", F)), IRB(BB) {}
74 };
75 
76 
77 } // namespace
78 
79 TEST_F(BasicTest, isSplat) {
80   Value *UndefVec = UndefValue::get(FixedVectorType::get(IRB.getInt8Ty(), 4));
81   EXPECT_TRUE(isSplatValue(UndefVec));
82 
83   Constant *UndefScalar = UndefValue::get(IRB.getInt8Ty());
84   EXPECT_FALSE(isSplatValue(UndefScalar));
85 
86   Constant *ScalarC = IRB.getInt8(42);
87   EXPECT_FALSE(isSplatValue(ScalarC));
88 
89   Constant *OtherScalarC = IRB.getInt8(-42);
90   Constant *NonSplatC = ConstantVector::get({ScalarC, OtherScalarC});
91   EXPECT_FALSE(isSplatValue(NonSplatC));
92 
93   Value *SplatC = IRB.CreateVectorSplat(5, ScalarC);
94   EXPECT_TRUE(isSplatValue(SplatC));
95 
96   Value *SplatC_SVE =
97       IRB.CreateVectorSplat(ElementCount::getScalable(5), ScalarC);
98   EXPECT_TRUE(isSplatValue(SplatC_SVE));
99 
100   // FIXME: Constant splat analysis does not allow undef elements.
101   Constant *SplatWithUndefC = ConstantVector::get({ScalarC, UndefScalar});
102   EXPECT_FALSE(isSplatValue(SplatWithUndefC));
103 }
104 
105 TEST_F(BasicTest, narrowShuffleMaskElts) {
106   SmallVector<int, 16> ScaledMask;
107   narrowShuffleMaskElts(1, {3,2,0,-2}, ScaledMask);
108   EXPECT_EQ(ArrayRef(ScaledMask), ArrayRef({3, 2, 0, -2}));
109   narrowShuffleMaskElts(4, {3,2,0,-1}, ScaledMask);
110   EXPECT_EQ(ArrayRef(ScaledMask), ArrayRef({12, 13, 14, 15, 8, 9, 10, 11, 0, 1,
111                                             2, 3, -1, -1, -1, -1}));
112 }
113 
114 TEST_F(BasicTest, widenShuffleMaskElts) {
115   SmallVector<int, 16> WideMask;
116   SmallVector<int, 16> NarrowMask;
117 
118   // scale == 1 is a copy
119   EXPECT_TRUE(widenShuffleMaskElts(1, {3,2,0,-1}, WideMask));
120   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({3, 2, 0, -1}));
121 
122   // back to original mask
123   narrowShuffleMaskElts(1, ArrayRef(WideMask), NarrowMask);
124   EXPECT_EQ(ArrayRef(NarrowMask), ArrayRef({3, 2, 0, -1}));
125 
126   // can't widen non-consecutive 3/2
127   EXPECT_FALSE(widenShuffleMaskElts(2, {3,2,0,-1}, WideMask));
128 
129   // can't widen if not evenly divisible
130   EXPECT_FALSE(widenShuffleMaskElts(2, {0,1,2}, WideMask));
131 
132   // can always widen identity to single element
133   EXPECT_TRUE(widenShuffleMaskElts(3, {0,1,2}, WideMask));
134   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({0}));
135 
136   // back to original mask
137   narrowShuffleMaskElts(3, ArrayRef(WideMask), NarrowMask);
138   EXPECT_EQ(ArrayRef(NarrowMask), ArrayRef({0, 1, 2}));
139 
140   // groups of 4 must be consecutive/undef
141   EXPECT_TRUE(widenShuffleMaskElts(4, {12,13,14,15,8,9,10,11,0,1,2,3,-1,-1,-1,-1}, WideMask));
142   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({3, 2, 0, -1}));
143 
144   // back to original mask
145   narrowShuffleMaskElts(4, ArrayRef(WideMask), NarrowMask);
146   EXPECT_EQ(ArrayRef(NarrowMask), ArrayRef({12, 13, 14, 15, 8, 9, 10, 11, 0, 1,
147                                             2, 3, -1, -1, -1, -1}));
148 
149   // groups of 2 must be consecutive/undef
150   EXPECT_FALSE(widenShuffleMaskElts(2, {12,12,14,15,8,9,10,11,0,1,2,3,-1,-1,-1,-1}, WideMask));
151 
152   // groups of 3 must be consecutive/undef
153   EXPECT_TRUE(widenShuffleMaskElts(3, {6,7,8,0,1,2,-1,-1,-1}, WideMask));
154   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({2, 0, -1}));
155 
156   // back to original mask
157   narrowShuffleMaskElts(3, ArrayRef(WideMask), NarrowMask);
158   EXPECT_EQ(ArrayRef(NarrowMask), ArrayRef({6, 7, 8, 0, 1, 2, -1, -1, -1}));
159 
160   // groups of 3 must be consecutive/undef (partial undefs are not ok)
161   EXPECT_FALSE(widenShuffleMaskElts(3, {-1,7,8,0,-1,2,-1,-1,-1}, WideMask));
162 
163   // negative indexes must match across a wide element
164   EXPECT_FALSE(widenShuffleMaskElts(2, {-1,-2,-1,-1}, WideMask));
165 
166   // negative indexes must match across a wide element
167   EXPECT_TRUE(widenShuffleMaskElts(2, {-2,-2,-3,-3}, WideMask));
168   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({-2, -3}));
169 }
170 
171 TEST_F(BasicTest, getShuffleMaskWithWidestElts) {
172   SmallVector<int, 16> WideMask;
173 
174   // can not widen anything here.
175   getShuffleMaskWithWidestElts({3, 2, 0, -1}, WideMask);
176   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({3, 2, 0, -1}));
177 
178   // can't widen non-consecutive 3/2
179   getShuffleMaskWithWidestElts({3, 2, 0, -1}, WideMask);
180   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({3, 2, 0, -1}));
181 
182   // can always widen identity to single element
183   getShuffleMaskWithWidestElts({0, 1, 2}, WideMask);
184   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({0}));
185 
186   // groups of 4 must be consecutive/undef
187   getShuffleMaskWithWidestElts(
188       {12, 13, 14, 15, 8, 9, 10, 11, 0, 1, 2, 3, -1, -1, -1, -1}, WideMask);
189   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({3, 2, 0, -1}));
190 
191   // groups of 2 must be consecutive/undef
192   getShuffleMaskWithWidestElts(
193       {12, 12, 14, 15, 8, 9, 10, 11, 0, 1, 2, 3, -1, -1, -1, -1}, WideMask);
194   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({12, 12, 14, 15, 8, 9, 10, 11, 0, 1, 2,
195                                           3, -1, -1, -1, -1}));
196 
197   // groups of 3 must be consecutive/undef
198   getShuffleMaskWithWidestElts({6, 7, 8, 0, 1, 2, -1, -1, -1}, WideMask);
199   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({2, 0, -1}));
200 
201   // groups of 3 must be consecutive/undef (partial undefs are not ok)
202   getShuffleMaskWithWidestElts({-1, 7, 8, 0, -1, 2, -1, -1, -1}, WideMask);
203   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({-1, 7, 8, 0, -1, 2, -1, -1, -1}));
204 
205   // negative indexes must match across a wide element
206   getShuffleMaskWithWidestElts({-1, -2, -1, -1}, WideMask);
207   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({-1, -2, -1, -1}));
208 
209   // negative indexes must match across a wide element
210   getShuffleMaskWithWidestElts({-2, -2, -3, -3}, WideMask);
211   EXPECT_EQ(ArrayRef(WideMask), ArrayRef({-2, -3}));
212 }
213 
214 TEST_F(BasicTest, getShuffleDemandedElts) {
215   APInt LHS, RHS;
216 
217   // broadcast zero
218   EXPECT_TRUE(getShuffleDemandedElts(4, {0, 0, 0, 0}, APInt(4,0xf), LHS, RHS));
219   EXPECT_EQ(LHS.getZExtValue(), 0x1U);
220   EXPECT_EQ(RHS.getZExtValue(), 0x0U);
221 
222   // broadcast zero (with non-permitted undefs)
223   EXPECT_FALSE(getShuffleDemandedElts(2, {0, -1}, APInt(2, 0x3), LHS, RHS));
224 
225   // broadcast zero (with permitted undefs)
226   EXPECT_TRUE(getShuffleDemandedElts(3, {0, 0, -1}, APInt(3, 0x7), LHS, RHS, true));
227   EXPECT_EQ(LHS.getZExtValue(), 0x1U);
228   EXPECT_EQ(RHS.getZExtValue(), 0x0U);
229 
230   // broadcast one in demanded
231   EXPECT_TRUE(getShuffleDemandedElts(4, {1, 1, 1, -1}, APInt(4, 0x7), LHS, RHS));
232   EXPECT_EQ(LHS.getZExtValue(), 0x2U);
233   EXPECT_EQ(RHS.getZExtValue(), 0x0U);
234 
235   // broadcast 7 in demanded
236   EXPECT_TRUE(getShuffleDemandedElts(4, {7, 0, 7, 7}, APInt(4, 0xd), LHS, RHS));
237   EXPECT_EQ(LHS.getZExtValue(), 0x0U);
238   EXPECT_EQ(RHS.getZExtValue(), 0x8U);
239 
240   // general test
241   EXPECT_TRUE(getShuffleDemandedElts(4, {4, 2, 7, 3}, APInt(4, 0xf), LHS, RHS));
242   EXPECT_EQ(LHS.getZExtValue(), 0xcU);
243   EXPECT_EQ(RHS.getZExtValue(), 0x9U);
244 }
245 
246 TEST_F(BasicTest, getSplatIndex) {
247   EXPECT_EQ(getSplatIndex({0,0,0}), 0);
248   EXPECT_EQ(getSplatIndex({1,0,0}), -1);     // no splat
249   EXPECT_EQ(getSplatIndex({0,1,1}), -1);     // no splat
250   EXPECT_EQ(getSplatIndex({42,42,42}), 42);  // array size is independent of splat index
251   EXPECT_EQ(getSplatIndex({42,42,-1}), 42);  // ignore negative
252   EXPECT_EQ(getSplatIndex({-1,42,-1}), 42);  // ignore negatives
253   EXPECT_EQ(getSplatIndex({-4,42,-42}), 42); // ignore all negatives
254   EXPECT_EQ(getSplatIndex({-4,-1,-42}), -1); // all negative values map to -1
255 }
256 
257 TEST_F(VectorUtilsTest, isSplatValue_00) {
258   parseAssembly(
259       "define <2 x i8> @test(<2 x i8> %x) {\n"
260       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> zeroinitializer\n"
261       "  ret <2 x i8> %A\n"
262       "}\n");
263   EXPECT_TRUE(isSplatValue(A));
264 }
265 
266 TEST_F(VectorUtilsTest, isSplatValue_00_index0) {
267   parseAssembly(
268       "define <2 x i8> @test(<2 x i8> %x) {\n"
269       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> zeroinitializer\n"
270       "  ret <2 x i8> %A\n"
271       "}\n");
272   EXPECT_TRUE(isSplatValue(A, 0));
273 }
274 
275 TEST_F(VectorUtilsTest, isSplatValue_00_index1) {
276   parseAssembly(
277       "define <2 x i8> @test(<2 x i8> %x) {\n"
278       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> zeroinitializer\n"
279       "  ret <2 x i8> %A\n"
280       "}\n");
281   EXPECT_FALSE(isSplatValue(A, 1));
282 }
283 
284 TEST_F(VectorUtilsTest, isSplatValue_11) {
285   parseAssembly(
286       "define <2 x i8> @test(<2 x i8> %x) {\n"
287       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
288       "  ret <2 x i8> %A\n"
289       "}\n");
290   EXPECT_TRUE(isSplatValue(A));
291 }
292 
293 TEST_F(VectorUtilsTest, isSplatValue_11_index0) {
294   parseAssembly(
295       "define <2 x i8> @test(<2 x i8> %x) {\n"
296       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
297       "  ret <2 x i8> %A\n"
298       "}\n");
299   EXPECT_FALSE(isSplatValue(A, 0));
300 }
301 
302 TEST_F(VectorUtilsTest, isSplatValue_11_index1) {
303   parseAssembly(
304       "define <2 x i8> @test(<2 x i8> %x) {\n"
305       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
306       "  ret <2 x i8> %A\n"
307       "}\n");
308   EXPECT_TRUE(isSplatValue(A, 1));
309 }
310 
311 TEST_F(VectorUtilsTest, isSplatValue_01) {
312   parseAssembly(
313       "define <2 x i8> @test(<2 x i8> %x) {\n"
314       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 1>\n"
315       "  ret <2 x i8> %A\n"
316       "}\n");
317   EXPECT_FALSE(isSplatValue(A));
318 }
319 
320 TEST_F(VectorUtilsTest, isSplatValue_01_index0) {
321   parseAssembly(
322       "define <2 x i8> @test(<2 x i8> %x) {\n"
323       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 1>\n"
324       "  ret <2 x i8> %A\n"
325       "}\n");
326   EXPECT_FALSE(isSplatValue(A, 0));
327 }
328 
329 TEST_F(VectorUtilsTest, isSplatValue_01_index1) {
330   parseAssembly(
331       "define <2 x i8> @test(<2 x i8> %x) {\n"
332       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 1>\n"
333       "  ret <2 x i8> %A\n"
334       "}\n");
335   EXPECT_FALSE(isSplatValue(A, 1));
336 }
337 
338 // FIXME: Allow undef matching with Constant (mask) splat analysis.
339 
340 TEST_F(VectorUtilsTest, isSplatValue_0u) {
341   parseAssembly(
342       "define <2 x i8> @test(<2 x i8> %x) {\n"
343       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 undef>\n"
344       "  ret <2 x i8> %A\n"
345       "}\n");
346   EXPECT_FALSE(isSplatValue(A));
347 }
348 
349 // FIXME: Allow undef matching with Constant (mask) splat analysis.
350 
351 TEST_F(VectorUtilsTest, isSplatValue_0u_index0) {
352   parseAssembly(
353       "define <2 x i8> @test(<2 x i8> %x) {\n"
354       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 undef>\n"
355       "  ret <2 x i8> %A\n"
356       "}\n");
357   EXPECT_FALSE(isSplatValue(A, 0));
358 }
359 
360 TEST_F(VectorUtilsTest, isSplatValue_0u_index1) {
361   parseAssembly(
362       "define <2 x i8> @test(<2 x i8> %x) {\n"
363       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 undef>\n"
364       "  ret <2 x i8> %A\n"
365       "}\n");
366   EXPECT_FALSE(isSplatValue(A, 1));
367 }
368 
369 TEST_F(VectorUtilsTest, isSplatValue_Binop) {
370   parseAssembly(
371       "define <2 x i8> @test(<2 x i8> %x) {\n"
372       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
373       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
374       "  %A = udiv <2 x i8> %v0, %v1\n"
375       "  ret <2 x i8> %A\n"
376       "}\n");
377   EXPECT_TRUE(isSplatValue(A));
378 }
379 
380 TEST_F(VectorUtilsTest, isSplatValue_Binop_index0) {
381   parseAssembly(
382       "define <2 x i8> @test(<2 x i8> %x) {\n"
383       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
384       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
385       "  %A = udiv <2 x i8> %v0, %v1\n"
386       "  ret <2 x i8> %A\n"
387       "}\n");
388   EXPECT_FALSE(isSplatValue(A, 0));
389 }
390 
391 TEST_F(VectorUtilsTest, isSplatValue_Binop_index1) {
392   parseAssembly(
393       "define <2 x i8> @test(<2 x i8> %x) {\n"
394       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
395       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
396       "  %A = udiv <2 x i8> %v0, %v1\n"
397       "  ret <2 x i8> %A\n"
398       "}\n");
399   EXPECT_FALSE(isSplatValue(A, 1));
400 }
401 
402 TEST_F(VectorUtilsTest, isSplatValue_Binop_ConstantOp0) {
403   parseAssembly(
404       "define <2 x i8> @test(<2 x i8> %x) {\n"
405       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
406       "  %A = ashr <2 x i8> <i8 42, i8 42>, %v1\n"
407       "  ret <2 x i8> %A\n"
408       "}\n");
409   EXPECT_TRUE(isSplatValue(A));
410 }
411 
412 TEST_F(VectorUtilsTest, isSplatValue_Binop_ConstantOp0_index0) {
413   parseAssembly(
414       "define <2 x i8> @test(<2 x i8> %x) {\n"
415       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
416       "  %A = ashr <2 x i8> <i8 42, i8 42>, %v1\n"
417       "  ret <2 x i8> %A\n"
418       "}\n");
419   EXPECT_FALSE(isSplatValue(A, 0));
420 }
421 
422 TEST_F(VectorUtilsTest, isSplatValue_Binop_ConstantOp0_index1) {
423   parseAssembly(
424       "define <2 x i8> @test(<2 x i8> %x) {\n"
425       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
426       "  %A = ashr <2 x i8> <i8 42, i8 42>, %v1\n"
427       "  ret <2 x i8> %A\n"
428       "}\n");
429   EXPECT_TRUE(isSplatValue(A, 1));
430 }
431 
432 TEST_F(VectorUtilsTest, isSplatValue_Binop_Not_Op0) {
433   parseAssembly(
434       "define <2 x i8> @test(<2 x i8> %x) {\n"
435       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 0>\n"
436       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
437       "  %A = add <2 x i8> %v0, %v1\n"
438       "  ret <2 x i8> %A\n"
439       "}\n");
440   EXPECT_FALSE(isSplatValue(A));
441 }
442 
443 TEST_F(VectorUtilsTest, isSplatValue_Binop_Not_Op1) {
444   parseAssembly(
445       "define <2 x i8> @test(<2 x i8> %x) {\n"
446       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
447       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 1>\n"
448       "  %A = shl <2 x i8> %v0, %v1\n"
449       "  ret <2 x i8> %A\n"
450       "}\n");
451   EXPECT_FALSE(isSplatValue(A));
452 }
453 
454 TEST_F(VectorUtilsTest, isSplatValue_Select) {
455   parseAssembly(
456       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
457       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
458       "  %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
459       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
460       "  %A = select <2 x i1> %v0, <2 x i8> %v1, <2 x i8> %v2\n"
461       "  ret <2 x i8> %A\n"
462       "}\n");
463   EXPECT_TRUE(isSplatValue(A));
464 }
465 
466 TEST_F(VectorUtilsTest, isSplatValue_Select_ConstantOp) {
467   parseAssembly(
468       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
469       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
470       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
471       "  %A = select <2 x i1> %v0, <2 x i8> <i8 42, i8 42>, <2 x i8> %v2\n"
472       "  ret <2 x i8> %A\n"
473       "}\n");
474   EXPECT_TRUE(isSplatValue(A));
475 }
476 
477 TEST_F(VectorUtilsTest, isSplatValue_Select_NotCond) {
478   parseAssembly(
479       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
480       "  %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
481       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
482       "  %A = select <2 x i1> %x, <2 x i8> %v1, <2 x i8> %v2\n"
483       "  ret <2 x i8> %A\n"
484       "}\n");
485   EXPECT_FALSE(isSplatValue(A));
486 }
487 
488 TEST_F(VectorUtilsTest, isSplatValue_Select_NotOp1) {
489   parseAssembly(
490       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
491       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
492       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
493       "  %A = select <2 x i1> %v0, <2 x i8> %y, <2 x i8> %v2\n"
494       "  ret <2 x i8> %A\n"
495       "}\n");
496   EXPECT_FALSE(isSplatValue(A));
497 }
498 
499 TEST_F(VectorUtilsTest, isSplatValue_Select_NotOp2) {
500   parseAssembly(
501       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
502       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
503       "  %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
504       "  %A = select <2 x i1> %v0, <2 x i8> %v1, <2 x i8> %z\n"
505       "  ret <2 x i8> %A\n"
506       "}\n");
507   EXPECT_FALSE(isSplatValue(A));
508 }
509 
510 TEST_F(VectorUtilsTest, isSplatValue_SelectBinop) {
511   parseAssembly(
512       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
513       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
514       "  %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
515       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
516       "  %bo = xor <2 x i8> %v1, %v2\n"
517       "  %A = select <2 x i1> %v0, <2 x i8> %bo, <2 x i8> %v2\n"
518       "  ret <2 x i8> %A\n"
519       "}\n");
520   EXPECT_TRUE(isSplatValue(A));
521 }
522 
523 TEST_F(VectorUtilsTest, getSplatValueElt0) {
524   parseAssembly(
525       "define <2 x i8> @test(i8 %x) {\n"
526       "  %ins = insertelement <2 x i8> undef, i8 %x, i32 0\n"
527       "  %A = shufflevector <2 x i8> %ins, <2 x i8> undef, <2 x i32> zeroinitializer\n"
528       "  ret <2 x i8> %A\n"
529       "}\n");
530   EXPECT_EQ(getSplatValue(A)->getName(), "x");
531 }
532 
533 TEST_F(VectorUtilsTest, getSplatValueEltMismatch) {
534   parseAssembly(
535       "define <2 x i8> @test(i8 %x) {\n"
536       "  %ins = insertelement <2 x i8> undef, i8 %x, i32 1\n"
537       "  %A = shufflevector <2 x i8> %ins, <2 x i8> undef, <2 x i32> zeroinitializer\n"
538       "  ret <2 x i8> %A\n"
539       "}\n");
540   EXPECT_EQ(getSplatValue(A), nullptr);
541 }
542 
543 // TODO: This is a splat, but we don't recognize it.
544 
545 TEST_F(VectorUtilsTest, getSplatValueElt1) {
546   parseAssembly(
547       "define <2 x i8> @test(i8 %x) {\n"
548       "  %ins = insertelement <2 x i8> undef, i8 %x, i32 1\n"
549       "  %A = shufflevector <2 x i8> %ins, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
550       "  ret <2 x i8> %A\n"
551       "}\n");
552   EXPECT_EQ(getSplatValue(A), nullptr);
553 }
554 
555 ////////////////////////////////////////////////////////////////////////////////
556 // VFShape API tests.
557 ////////////////////////////////////////////////////////////////////////////////
558 
559 class VFShapeAPITest : public testing::Test {
560 protected:
561   void SetUp() override {
562     M = parseAssemblyString(IR, Err, Ctx);
563     // Get the only call instruction in the block, which is the first
564     // instruction.
565     CI = dyn_cast<CallInst>(&*(instructions(M->getFunction("f")).begin()));
566   }
567 
568   const char *IR = "define i32 @f(i32 %a, i64 %b, double %c) {\n"
569                    " %1 = call i32 @g(i32 %a, i64 %b, double %c)\n"
570                    "  ret i32 %1\n"
571                    "}\n"
572                    "declare i32 @g(i32, i64, double)\n";
573   LLVMContext Ctx;
574   SMDiagnostic Err;
575   std::unique_ptr<Module> M;
576   CallInst *CI;
577   // Dummy shape with no parameters, overwritten by buildShape when invoked.
578   VFShape Shape = {/*VF*/ ElementCount::getFixed(2), /*Parameters*/ {}};
579   VFShape Expected;
580   SmallVector<VFParameter, 8> &ExpectedParams = Expected.Parameters;
581 
582   void buildShape(ElementCount VF, bool HasGlobalPred) {
583     Shape = VFShape::get(*CI, VF, HasGlobalPred);
584   }
585 
586   bool validParams(ArrayRef<VFParameter> Parameters) {
587     Shape.Parameters =
588         SmallVector<VFParameter, 8>(Parameters.begin(), Parameters.end());
589     return Shape.hasValidParameterList();
590   }
591 };
592 
593 TEST_F(VFShapeAPITest, API_buildVFShape) {
594   buildShape(/*VF*/ ElementCount::getFixed(2), /*HasGlobalPred*/ false);
595   Expected = {/*VF*/ ElementCount::getFixed(2), /*Parameters*/ {
596                   {0, VFParamKind::Vector},
597                   {1, VFParamKind::Vector},
598                   {2, VFParamKind::Vector},
599               }};
600   EXPECT_EQ(Shape, Expected);
601 
602   buildShape(/*VF*/ ElementCount::getFixed(4), /*HasGlobalPred*/ true);
603   Expected = {/*VF*/ ElementCount::getFixed(4), /*Parameters*/ {
604                   {0, VFParamKind::Vector},
605                   {1, VFParamKind::Vector},
606                   {2, VFParamKind::Vector},
607                   {3, VFParamKind::GlobalPredicate},
608               }};
609   EXPECT_EQ(Shape, Expected);
610 
611   buildShape(/*VF*/ ElementCount::getScalable(16), /*HasGlobalPred*/ false);
612   Expected = {/*VF*/ ElementCount::getScalable(16), /*Parameters*/ {
613                   {0, VFParamKind::Vector},
614                   {1, VFParamKind::Vector},
615                   {2, VFParamKind::Vector},
616               }};
617   EXPECT_EQ(Shape, Expected);
618 }
619 
620 TEST_F(VFShapeAPITest, API_getScalarShape) {
621   buildShape(/*VF*/ ElementCount::getFixed(1), /*HasGlobalPred*/ false);
622   EXPECT_EQ(VFShape::getScalarShape(*CI), Shape);
623 }
624 
625 TEST_F(VFShapeAPITest, API_getVectorizedFunction) {
626   VFShape ScalarShape = VFShape::getScalarShape(*CI);
627   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(ScalarShape),
628             M->getFunction("g"));
629 
630   buildShape(/*VF*/ ElementCount::getScalable(1), /*HasGlobalPred*/ false);
631   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(Shape), nullptr);
632   buildShape(/*VF*/ ElementCount::getFixed(1), /*HasGlobalPred*/ true);
633   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(Shape), nullptr);
634   buildShape(/*VF*/ ElementCount::getScalable(1), /*HasGlobalPred*/ true);
635   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(Shape), nullptr);
636 }
637 
638 TEST_F(VFShapeAPITest, API_updateVFShape) {
639 
640   buildShape(/*VF*/ ElementCount::getFixed(2), /*HasGlobalPred*/ false);
641   Shape.updateParam({0 /*Pos*/, VFParamKind::OMP_Linear, 1, Align(4)});
642   Expected = {/*VF*/ ElementCount::getFixed(2), /*Parameters*/ {
643                   {0, VFParamKind::OMP_Linear, 1, Align(4)},
644                   {1, VFParamKind::Vector},
645                   {2, VFParamKind::Vector},
646               }};
647   EXPECT_EQ(Shape, Expected);
648 
649   // From this point on, we update only the parameters of the VFShape,
650   // so we update only the reference of the expected Parameters.
651   Shape.updateParam({1 /*Pos*/, VFParamKind::OMP_Uniform});
652   ExpectedParams = {
653       {0, VFParamKind::OMP_Linear, 1, Align(4)},
654       {1, VFParamKind::OMP_Uniform},
655       {2, VFParamKind::Vector},
656   };
657   EXPECT_EQ(Shape, Expected);
658 
659   Shape.updateParam({2 /*Pos*/, VFParamKind::OMP_LinearRefPos, 1});
660   ExpectedParams = {
661       {0, VFParamKind::OMP_Linear, 1, Align(4)},
662       {1, VFParamKind::OMP_Uniform},
663       {2, VFParamKind::OMP_LinearRefPos, 1},
664   };
665   EXPECT_EQ(Shape, Expected);
666 }
667 
668 TEST_F(VFShapeAPITest, API_updateVFShape_GlobalPredicate) {
669 
670   buildShape(/*VF*/ ElementCount::getScalable(2), /*HasGlobalPred*/ true);
671   Shape.updateParam({1 /*Pos*/, VFParamKind::OMP_Uniform});
672   Expected = {/*VF*/ ElementCount::getScalable(2),
673               /*Parameters*/ {{0, VFParamKind::Vector},
674                               {1, VFParamKind::OMP_Uniform},
675                               {2, VFParamKind::Vector},
676                               {3, VFParamKind::GlobalPredicate}}};
677   EXPECT_EQ(Shape, Expected);
678 }
679 
680 TEST_F(VFShapeAPITest, Parameters_Valid) {
681   // ParamPos in order.
682   EXPECT_TRUE(validParams({{0, VFParamKind::Vector}}));
683   EXPECT_TRUE(
684       validParams({{0, VFParamKind::Vector}, {1, VFParamKind::Vector}}));
685   EXPECT_TRUE(validParams({{0, VFParamKind::Vector},
686                            {1, VFParamKind::Vector},
687                            {2, VFParamKind::Vector}}));
688 
689   // GlocalPredicate is unique.
690   EXPECT_TRUE(validParams({{0, VFParamKind::Vector},
691                            {1, VFParamKind::Vector},
692                            {2, VFParamKind::Vector},
693                            {3, VFParamKind::GlobalPredicate}}));
694 
695   EXPECT_TRUE(validParams({{0, VFParamKind::Vector},
696                            {1, VFParamKind::GlobalPredicate},
697                            {2, VFParamKind::Vector}}));
698 }
699 
700 TEST_F(VFShapeAPITest, Parameters_ValidOpenMPLinear) {
701 // Valid linear constant step (>0).
702 #define __BUILD_PARAMETERS(Kind, Val)                                          \
703   {                                                                            \
704     { 0, Kind, Val }                                                           \
705   }
706   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_Linear, 1)));
707   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRef, 2)));
708   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearVal, 4)));
709   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUVal, 33)));
710 #undef __BUILD_PARAMETERS
711 
712 // Valid linear runtime step (the step parameter is marked uniform).
713 #define __BUILD_PARAMETERS(Kind)                                               \
714   {                                                                            \
715     {0, VFParamKind::OMP_Uniform}, {1, VFParamKind::Vector}, { 2, Kind, 0 }    \
716   }
717   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
718   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
719   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
720   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
721 #undef __BUILD_PARAMETERS
722 }
723 
724 TEST_F(VFShapeAPITest, Parameters_Invalid) {
725 #ifndef NDEBUG
726   // Wrong order is checked by an assertion: make sure that the
727   // assertion is not removed.
728   EXPECT_DEATH(validParams({{1, VFParamKind::Vector}}),
729                "Broken parameter list.");
730   EXPECT_DEATH(
731       validParams({{1, VFParamKind::Vector}, {0, VFParamKind::Vector}}),
732       "Broken parameter list.");
733 #endif
734 
735   // GlobalPredicate is not unique
736   EXPECT_FALSE(validParams({{0, VFParamKind::Vector},
737                             {1, VFParamKind::GlobalPredicate},
738                             {2, VFParamKind::GlobalPredicate}}));
739   EXPECT_FALSE(validParams({{0, VFParamKind::GlobalPredicate},
740                             {1, VFParamKind::Vector},
741                             {2, VFParamKind::GlobalPredicate}}));
742 }
743 
744 TEST_F(VFShapeAPITest, Parameters_InvalidOpenMPLinear) {
745 // Compile time linear steps must be non-zero (compile time invariant).
746 #define __BUILD_PARAMETERS(Kind)                                               \
747   {                                                                            \
748     { 0, Kind, 0 }                                                             \
749   }
750   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_Linear)));
751   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRef)));
752   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearVal)));
753   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUVal)));
754 #undef __BUILD_PARAMETERS
755 
756 // The step of a runtime linear parameter must be marked
757 // as uniform (runtime invariant).
758 #define __BUILD_PARAMETERS(Kind)                                               \
759   {                                                                            \
760     {0, VFParamKind::OMP_Uniform}, {1, VFParamKind::Vector}, { 2, Kind, 1 }    \
761   }
762   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
763   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
764   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
765   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
766 #undef __BUILD_PARAMETERS
767 
768 // The linear step parameter can't point at itself.
769 #define __BUILD_PARAMETERS(Kind)                                               \
770   {                                                                            \
771     {0, VFParamKind::Vector}, {1, VFParamKind::Vector}, { 2, Kind, 2 }         \
772   }
773   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
774   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
775   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
776   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
777 #undef __BUILD_PARAMETERS
778 
779 // Linear parameter (runtime) is out of range.
780 #define __BUILD_PARAMETERS(Kind)                                               \
781   {                                                                            \
782     {0, VFParamKind::Vector}, {1, VFParamKind::Vector}, { 2, Kind, 3 }         \
783   }
784   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
785   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
786   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
787   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
788 #undef __BUILD_PARAMETERS
789 }
790