xref: /llvm-project/llvm/unittests/Analysis/VectorUtilsTest.cpp (revision 55a11b542e055744cac3beb87714fc90cacba4c0)
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(makeArrayRef(ScaledMask), makeArrayRef({3,2,0,-2}));
109   narrowShuffleMaskElts(4, {3,2,0,-1}, ScaledMask);
110   EXPECT_EQ(makeArrayRef(ScaledMask), makeArrayRef({12,13,14,15,8,9,10,11,0,1,2,3,-1,-1,-1,-1}));
111 }
112 
113 TEST_F(BasicTest, widenShuffleMaskElts) {
114   SmallVector<int, 16> WideMask;
115   SmallVector<int, 16> NarrowMask;
116 
117   // scale == 1 is a copy
118   EXPECT_TRUE(widenShuffleMaskElts(1, {3,2,0,-1}, WideMask));
119   EXPECT_EQ(makeArrayRef(WideMask), makeArrayRef({3,2,0,-1}));
120 
121   // back to original mask
122   narrowShuffleMaskElts(1, makeArrayRef(WideMask), NarrowMask);
123   EXPECT_EQ(makeArrayRef(NarrowMask), makeArrayRef({3,2,0,-1}));
124 
125   // can't widen non-consecutive 3/2
126   EXPECT_FALSE(widenShuffleMaskElts(2, {3,2,0,-1}, WideMask));
127 
128   // can't widen if not evenly divisible
129   EXPECT_FALSE(widenShuffleMaskElts(2, {0,1,2}, WideMask));
130 
131   // can always widen identity to single element
132   EXPECT_TRUE(widenShuffleMaskElts(3, {0,1,2}, WideMask));
133   EXPECT_EQ(makeArrayRef(WideMask), makeArrayRef({0}));
134 
135   // back to original mask
136   narrowShuffleMaskElts(3, makeArrayRef(WideMask), NarrowMask);
137   EXPECT_EQ(makeArrayRef(NarrowMask), makeArrayRef({0,1,2}));
138 
139   // groups of 4 must be consecutive/undef
140   EXPECT_TRUE(widenShuffleMaskElts(4, {12,13,14,15,8,9,10,11,0,1,2,3,-1,-1,-1,-1}, WideMask));
141   EXPECT_EQ(makeArrayRef(WideMask), makeArrayRef({3,2,0,-1}));
142 
143   // back to original mask
144   narrowShuffleMaskElts(4, makeArrayRef(WideMask), NarrowMask);
145   EXPECT_EQ(makeArrayRef(NarrowMask), makeArrayRef({12,13,14,15,8,9,10,11,0,1,2,3,-1,-1,-1,-1}));
146 
147   // groups of 2 must be consecutive/undef
148   EXPECT_FALSE(widenShuffleMaskElts(2, {12,12,14,15,8,9,10,11,0,1,2,3,-1,-1,-1,-1}, WideMask));
149 
150   // groups of 3 must be consecutive/undef
151   EXPECT_TRUE(widenShuffleMaskElts(3, {6,7,8,0,1,2,-1,-1,-1}, WideMask));
152   EXPECT_EQ(makeArrayRef(WideMask), makeArrayRef({2,0,-1}));
153 
154   // back to original mask
155   narrowShuffleMaskElts(3, makeArrayRef(WideMask), NarrowMask);
156   EXPECT_EQ(makeArrayRef(NarrowMask), makeArrayRef({6,7,8,0,1,2,-1,-1,-1}));
157 
158   // groups of 3 must be consecutive/undef (partial undefs are not ok)
159   EXPECT_FALSE(widenShuffleMaskElts(3, {-1,7,8,0,-1,2,-1,-1,-1}, WideMask));
160 
161   // negative indexes must match across a wide element
162   EXPECT_FALSE(widenShuffleMaskElts(2, {-1,-2,-1,-1}, WideMask));
163 
164   // negative indexes must match across a wide element
165   EXPECT_TRUE(widenShuffleMaskElts(2, {-2,-2,-3,-3}, WideMask));
166   EXPECT_EQ(makeArrayRef(WideMask), makeArrayRef({-2,-3}));
167 }
168 
169 TEST_F(BasicTest, getShuffleDemandedElts) {
170   APInt LHS, RHS;
171 
172   // broadcast zero
173   EXPECT_TRUE(getShuffleDemandedElts(4, {0, 0, 0, 0}, APInt(4,0xf), LHS, RHS));
174   EXPECT_EQ(LHS.getZExtValue(), 0x1);
175   EXPECT_EQ(RHS.getZExtValue(), 0x0);
176 
177   // broadcast zero (with non-permitted undefs)
178   EXPECT_FALSE(getShuffleDemandedElts(2, {0, -1}, APInt(2, 0x3), LHS, RHS));
179 
180   // broadcast zero (with permitted undefs)
181   EXPECT_TRUE(getShuffleDemandedElts(3, {0, 0, -1}, APInt(3, 0x7), LHS, RHS, true));
182   EXPECT_EQ(LHS.getZExtValue(), 0x1);
183   EXPECT_EQ(RHS.getZExtValue(), 0x0);
184 
185   // broadcast one in demanded
186   EXPECT_TRUE(getShuffleDemandedElts(4, {1, 1, 1, -1}, APInt(4, 0x7), LHS, RHS));
187   EXPECT_EQ(LHS.getZExtValue(), 0x2);
188   EXPECT_EQ(RHS.getZExtValue(), 0x0);
189 
190   // broadcast 7 in demanded
191   EXPECT_TRUE(getShuffleDemandedElts(4, {7, 0, 7, 7}, APInt(4, 0xd), LHS, RHS));
192   EXPECT_EQ(LHS.getZExtValue(), 0x0);
193   EXPECT_EQ(RHS.getZExtValue(), 0x8);
194 
195   // general test
196   EXPECT_TRUE(getShuffleDemandedElts(4, {4, 2, 7, 3}, APInt(4, 0xf), LHS, RHS));
197   EXPECT_EQ(LHS.getZExtValue(), 0xc);
198   EXPECT_EQ(RHS.getZExtValue(), 0x9);
199 }
200 
201 TEST_F(BasicTest, getSplatIndex) {
202   EXPECT_EQ(getSplatIndex({0,0,0}), 0);
203   EXPECT_EQ(getSplatIndex({1,0,0}), -1);     // no splat
204   EXPECT_EQ(getSplatIndex({0,1,1}), -1);     // no splat
205   EXPECT_EQ(getSplatIndex({42,42,42}), 42);  // array size is independent of splat index
206   EXPECT_EQ(getSplatIndex({42,42,-1}), 42);  // ignore negative
207   EXPECT_EQ(getSplatIndex({-1,42,-1}), 42);  // ignore negatives
208   EXPECT_EQ(getSplatIndex({-4,42,-42}), 42); // ignore all negatives
209   EXPECT_EQ(getSplatIndex({-4,-1,-42}), -1); // all negative values map to -1
210 }
211 
212 TEST_F(VectorUtilsTest, isSplatValue_00) {
213   parseAssembly(
214       "define <2 x i8> @test(<2 x i8> %x) {\n"
215       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> zeroinitializer\n"
216       "  ret <2 x i8> %A\n"
217       "}\n");
218   EXPECT_TRUE(isSplatValue(A));
219 }
220 
221 TEST_F(VectorUtilsTest, isSplatValue_00_index0) {
222   parseAssembly(
223       "define <2 x i8> @test(<2 x i8> %x) {\n"
224       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> zeroinitializer\n"
225       "  ret <2 x i8> %A\n"
226       "}\n");
227   EXPECT_TRUE(isSplatValue(A, 0));
228 }
229 
230 TEST_F(VectorUtilsTest, isSplatValue_00_index1) {
231   parseAssembly(
232       "define <2 x i8> @test(<2 x i8> %x) {\n"
233       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> zeroinitializer\n"
234       "  ret <2 x i8> %A\n"
235       "}\n");
236   EXPECT_FALSE(isSplatValue(A, 1));
237 }
238 
239 TEST_F(VectorUtilsTest, isSplatValue_11) {
240   parseAssembly(
241       "define <2 x i8> @test(<2 x i8> %x) {\n"
242       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
243       "  ret <2 x i8> %A\n"
244       "}\n");
245   EXPECT_TRUE(isSplatValue(A));
246 }
247 
248 TEST_F(VectorUtilsTest, isSplatValue_11_index0) {
249   parseAssembly(
250       "define <2 x i8> @test(<2 x i8> %x) {\n"
251       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
252       "  ret <2 x i8> %A\n"
253       "}\n");
254   EXPECT_FALSE(isSplatValue(A, 0));
255 }
256 
257 TEST_F(VectorUtilsTest, isSplatValue_11_index1) {
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> <i32 1, i32 1>\n"
261       "  ret <2 x i8> %A\n"
262       "}\n");
263   EXPECT_TRUE(isSplatValue(A, 1));
264 }
265 
266 TEST_F(VectorUtilsTest, isSplatValue_01) {
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> <i32 0, i32 1>\n"
270       "  ret <2 x i8> %A\n"
271       "}\n");
272   EXPECT_FALSE(isSplatValue(A));
273 }
274 
275 TEST_F(VectorUtilsTest, isSplatValue_01_index0) {
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> <i32 0, i32 1>\n"
279       "  ret <2 x i8> %A\n"
280       "}\n");
281   EXPECT_FALSE(isSplatValue(A, 0));
282 }
283 
284 TEST_F(VectorUtilsTest, isSplatValue_01_index1) {
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 0, i32 1>\n"
288       "  ret <2 x i8> %A\n"
289       "}\n");
290   EXPECT_FALSE(isSplatValue(A, 1));
291 }
292 
293 // FIXME: Allow undef matching with Constant (mask) splat analysis.
294 
295 TEST_F(VectorUtilsTest, isSplatValue_0u) {
296   parseAssembly(
297       "define <2 x i8> @test(<2 x i8> %x) {\n"
298       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 undef>\n"
299       "  ret <2 x i8> %A\n"
300       "}\n");
301   EXPECT_FALSE(isSplatValue(A));
302 }
303 
304 // FIXME: Allow undef matching with Constant (mask) splat analysis.
305 
306 TEST_F(VectorUtilsTest, isSplatValue_0u_index0) {
307   parseAssembly(
308       "define <2 x i8> @test(<2 x i8> %x) {\n"
309       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 undef>\n"
310       "  ret <2 x i8> %A\n"
311       "}\n");
312   EXPECT_FALSE(isSplatValue(A, 0));
313 }
314 
315 TEST_F(VectorUtilsTest, isSplatValue_0u_index1) {
316   parseAssembly(
317       "define <2 x i8> @test(<2 x i8> %x) {\n"
318       "  %A = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 undef>\n"
319       "  ret <2 x i8> %A\n"
320       "}\n");
321   EXPECT_FALSE(isSplatValue(A, 1));
322 }
323 
324 TEST_F(VectorUtilsTest, isSplatValue_Binop) {
325   parseAssembly(
326       "define <2 x i8> @test(<2 x i8> %x) {\n"
327       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
328       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
329       "  %A = udiv <2 x i8> %v0, %v1\n"
330       "  ret <2 x i8> %A\n"
331       "}\n");
332   EXPECT_TRUE(isSplatValue(A));
333 }
334 
335 TEST_F(VectorUtilsTest, isSplatValue_Binop_index0) {
336   parseAssembly(
337       "define <2 x i8> @test(<2 x i8> %x) {\n"
338       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
339       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
340       "  %A = udiv <2 x i8> %v0, %v1\n"
341       "  ret <2 x i8> %A\n"
342       "}\n");
343   EXPECT_FALSE(isSplatValue(A, 0));
344 }
345 
346 TEST_F(VectorUtilsTest, isSplatValue_Binop_index1) {
347   parseAssembly(
348       "define <2 x i8> @test(<2 x i8> %x) {\n"
349       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
350       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
351       "  %A = udiv <2 x i8> %v0, %v1\n"
352       "  ret <2 x i8> %A\n"
353       "}\n");
354   EXPECT_FALSE(isSplatValue(A, 1));
355 }
356 
357 TEST_F(VectorUtilsTest, isSplatValue_Binop_ConstantOp0) {
358   parseAssembly(
359       "define <2 x i8> @test(<2 x i8> %x) {\n"
360       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
361       "  %A = ashr <2 x i8> <i8 42, i8 42>, %v1\n"
362       "  ret <2 x i8> %A\n"
363       "}\n");
364   EXPECT_TRUE(isSplatValue(A));
365 }
366 
367 TEST_F(VectorUtilsTest, isSplatValue_Binop_ConstantOp0_index0) {
368   parseAssembly(
369       "define <2 x i8> @test(<2 x i8> %x) {\n"
370       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
371       "  %A = ashr <2 x i8> <i8 42, i8 42>, %v1\n"
372       "  ret <2 x i8> %A\n"
373       "}\n");
374   EXPECT_FALSE(isSplatValue(A, 0));
375 }
376 
377 TEST_F(VectorUtilsTest, isSplatValue_Binop_ConstantOp0_index1) {
378   parseAssembly(
379       "define <2 x i8> @test(<2 x i8> %x) {\n"
380       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
381       "  %A = ashr <2 x i8> <i8 42, i8 42>, %v1\n"
382       "  ret <2 x i8> %A\n"
383       "}\n");
384   EXPECT_TRUE(isSplatValue(A, 1));
385 }
386 
387 TEST_F(VectorUtilsTest, isSplatValue_Binop_Not_Op0) {
388   parseAssembly(
389       "define <2 x i8> @test(<2 x i8> %x) {\n"
390       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 0>\n"
391       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
392       "  %A = add <2 x i8> %v0, %v1\n"
393       "  ret <2 x i8> %A\n"
394       "}\n");
395   EXPECT_FALSE(isSplatValue(A));
396 }
397 
398 TEST_F(VectorUtilsTest, isSplatValue_Binop_Not_Op1) {
399   parseAssembly(
400       "define <2 x i8> @test(<2 x i8> %x) {\n"
401       "  %v0 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
402       "  %v1 = shufflevector <2 x i8> %x, <2 x i8> undef, <2 x i32> <i32 0, i32 1>\n"
403       "  %A = shl <2 x i8> %v0, %v1\n"
404       "  ret <2 x i8> %A\n"
405       "}\n");
406   EXPECT_FALSE(isSplatValue(A));
407 }
408 
409 TEST_F(VectorUtilsTest, isSplatValue_Select) {
410   parseAssembly(
411       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
412       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
413       "  %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
414       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
415       "  %A = select <2 x i1> %v0, <2 x i8> %v1, <2 x i8> %v2\n"
416       "  ret <2 x i8> %A\n"
417       "}\n");
418   EXPECT_TRUE(isSplatValue(A));
419 }
420 
421 TEST_F(VectorUtilsTest, isSplatValue_Select_ConstantOp) {
422   parseAssembly(
423       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
424       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
425       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
426       "  %A = select <2 x i1> %v0, <2 x i8> <i8 42, i8 42>, <2 x i8> %v2\n"
427       "  ret <2 x i8> %A\n"
428       "}\n");
429   EXPECT_TRUE(isSplatValue(A));
430 }
431 
432 TEST_F(VectorUtilsTest, isSplatValue_Select_NotCond) {
433   parseAssembly(
434       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
435       "  %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
436       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
437       "  %A = select <2 x i1> %x, <2 x i8> %v1, <2 x i8> %v2\n"
438       "  ret <2 x i8> %A\n"
439       "}\n");
440   EXPECT_FALSE(isSplatValue(A));
441 }
442 
443 TEST_F(VectorUtilsTest, isSplatValue_Select_NotOp1) {
444   parseAssembly(
445       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
446       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
447       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
448       "  %A = select <2 x i1> %v0, <2 x i8> %y, <2 x i8> %v2\n"
449       "  ret <2 x i8> %A\n"
450       "}\n");
451   EXPECT_FALSE(isSplatValue(A));
452 }
453 
454 TEST_F(VectorUtilsTest, isSplatValue_Select_NotOp2) {
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       "  %A = select <2 x i1> %v0, <2 x i8> %v1, <2 x i8> %z\n"
460       "  ret <2 x i8> %A\n"
461       "}\n");
462   EXPECT_FALSE(isSplatValue(A));
463 }
464 
465 TEST_F(VectorUtilsTest, isSplatValue_SelectBinop) {
466   parseAssembly(
467       "define <2 x i8> @test(<2 x i1> %x, <2 x i8> %y, <2 x i8> %z) {\n"
468       "  %v0 = shufflevector <2 x i1> %x, <2 x i1> undef, <2 x i32> <i32 1, i32 1>\n"
469       "  %v1 = shufflevector <2 x i8> %y, <2 x i8> undef, <2 x i32> <i32 0, i32 0>\n"
470       "  %v2 = shufflevector <2 x i8> %z, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
471       "  %bo = xor <2 x i8> %v1, %v2\n"
472       "  %A = select <2 x i1> %v0, <2 x i8> %bo, <2 x i8> %v2\n"
473       "  ret <2 x i8> %A\n"
474       "}\n");
475   EXPECT_TRUE(isSplatValue(A));
476 }
477 
478 TEST_F(VectorUtilsTest, getSplatValueElt0) {
479   parseAssembly(
480       "define <2 x i8> @test(i8 %x) {\n"
481       "  %ins = insertelement <2 x i8> undef, i8 %x, i32 0\n"
482       "  %A = shufflevector <2 x i8> %ins, <2 x i8> undef, <2 x i32> zeroinitializer\n"
483       "  ret <2 x i8> %A\n"
484       "}\n");
485   EXPECT_EQ(getSplatValue(A)->getName(), "x");
486 }
487 
488 TEST_F(VectorUtilsTest, getSplatValueEltMismatch) {
489   parseAssembly(
490       "define <2 x i8> @test(i8 %x) {\n"
491       "  %ins = insertelement <2 x i8> undef, i8 %x, i32 1\n"
492       "  %A = shufflevector <2 x i8> %ins, <2 x i8> undef, <2 x i32> zeroinitializer\n"
493       "  ret <2 x i8> %A\n"
494       "}\n");
495   EXPECT_EQ(getSplatValue(A), nullptr);
496 }
497 
498 // TODO: This is a splat, but we don't recognize it.
499 
500 TEST_F(VectorUtilsTest, getSplatValueElt1) {
501   parseAssembly(
502       "define <2 x i8> @test(i8 %x) {\n"
503       "  %ins = insertelement <2 x i8> undef, i8 %x, i32 1\n"
504       "  %A = shufflevector <2 x i8> %ins, <2 x i8> undef, <2 x i32> <i32 1, i32 1>\n"
505       "  ret <2 x i8> %A\n"
506       "}\n");
507   EXPECT_EQ(getSplatValue(A), nullptr);
508 }
509 
510 ////////////////////////////////////////////////////////////////////////////////
511 // VFShape API tests.
512 ////////////////////////////////////////////////////////////////////////////////
513 
514 class VFShapeAPITest : public testing::Test {
515 protected:
516   void SetUp() override {
517     M = parseAssemblyString(IR, Err, Ctx);
518     // Get the only call instruction in the block, which is the first
519     // instruction.
520     CI = dyn_cast<CallInst>(&*(instructions(M->getFunction("f")).begin()));
521   }
522 
523   const char *IR = "define i32 @f(i32 %a, i64 %b, double %c) {\n"
524                    " %1 = call i32 @g(i32 %a, i64 %b, double %c)\n"
525                    "  ret i32 %1\n"
526                    "}\n"
527                    "declare i32 @g(i32, i64, double)\n";
528   LLVMContext Ctx;
529   SMDiagnostic Err;
530   std::unique_ptr<Module> M;
531   CallInst *CI;
532   // Dummy shape with no parameters, overwritten by buildShape when invoked.
533   VFShape Shape = {/*VF*/ ElementCount::getFixed(2), /*Parameters*/ {}};
534   VFShape Expected;
535   SmallVector<VFParameter, 8> &ExpectedParams = Expected.Parameters;
536 
537   void buildShape(ElementCount VF, bool HasGlobalPred) {
538     Shape = VFShape::get(*CI, VF, HasGlobalPred);
539   }
540 
541   bool validParams(ArrayRef<VFParameter> Parameters) {
542     Shape.Parameters =
543         SmallVector<VFParameter, 8>(Parameters.begin(), Parameters.end());
544     return Shape.hasValidParameterList();
545   }
546 };
547 
548 TEST_F(VFShapeAPITest, API_buildVFShape) {
549   buildShape(/*VF*/ ElementCount::getFixed(2), /*HasGlobalPred*/ false);
550   Expected = {/*VF*/ ElementCount::getFixed(2), /*Parameters*/ {
551                   {0, VFParamKind::Vector},
552                   {1, VFParamKind::Vector},
553                   {2, VFParamKind::Vector},
554               }};
555   EXPECT_EQ(Shape, Expected);
556 
557   buildShape(/*VF*/ ElementCount::getFixed(4), /*HasGlobalPred*/ true);
558   Expected = {/*VF*/ ElementCount::getFixed(4), /*Parameters*/ {
559                   {0, VFParamKind::Vector},
560                   {1, VFParamKind::Vector},
561                   {2, VFParamKind::Vector},
562                   {3, VFParamKind::GlobalPredicate},
563               }};
564   EXPECT_EQ(Shape, Expected);
565 
566   buildShape(/*VF*/ ElementCount::getScalable(16), /*HasGlobalPred*/ false);
567   Expected = {/*VF*/ ElementCount::getScalable(16), /*Parameters*/ {
568                   {0, VFParamKind::Vector},
569                   {1, VFParamKind::Vector},
570                   {2, VFParamKind::Vector},
571               }};
572   EXPECT_EQ(Shape, Expected);
573 }
574 
575 TEST_F(VFShapeAPITest, API_getScalarShape) {
576   buildShape(/*VF*/ ElementCount::getFixed(1), /*HasGlobalPred*/ false);
577   EXPECT_EQ(VFShape::getScalarShape(*CI), Shape);
578 }
579 
580 TEST_F(VFShapeAPITest, API_getVectorizedFunction) {
581   VFShape ScalarShape = VFShape::getScalarShape(*CI);
582   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(ScalarShape),
583             M->getFunction("g"));
584 
585   buildShape(/*VF*/ ElementCount::getScalable(1), /*HasGlobalPred*/ false);
586   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(Shape), nullptr);
587   buildShape(/*VF*/ ElementCount::getFixed(1), /*HasGlobalPred*/ true);
588   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(Shape), nullptr);
589   buildShape(/*VF*/ ElementCount::getScalable(1), /*HasGlobalPred*/ true);
590   EXPECT_EQ(VFDatabase(*CI).getVectorizedFunction(Shape), nullptr);
591 }
592 
593 TEST_F(VFShapeAPITest, API_updateVFShape) {
594 
595   buildShape(/*VF*/ ElementCount::getFixed(2), /*HasGlobalPred*/ false);
596   Shape.updateParam({0 /*Pos*/, VFParamKind::OMP_Linear, 1, Align(4)});
597   Expected = {/*VF*/ ElementCount::getFixed(2), /*Parameters*/ {
598                   {0, VFParamKind::OMP_Linear, 1, Align(4)},
599                   {1, VFParamKind::Vector},
600                   {2, VFParamKind::Vector},
601               }};
602   EXPECT_EQ(Shape, Expected);
603 
604   // From this point on, we update only the parameters of the VFShape,
605   // so we update only the reference of the expected Parameters.
606   Shape.updateParam({1 /*Pos*/, VFParamKind::OMP_Uniform});
607   ExpectedParams = {
608       {0, VFParamKind::OMP_Linear, 1, Align(4)},
609       {1, VFParamKind::OMP_Uniform},
610       {2, VFParamKind::Vector},
611   };
612   EXPECT_EQ(Shape, Expected);
613 
614   Shape.updateParam({2 /*Pos*/, VFParamKind::OMP_LinearRefPos, 1});
615   ExpectedParams = {
616       {0, VFParamKind::OMP_Linear, 1, Align(4)},
617       {1, VFParamKind::OMP_Uniform},
618       {2, VFParamKind::OMP_LinearRefPos, 1},
619   };
620   EXPECT_EQ(Shape, Expected);
621 }
622 
623 TEST_F(VFShapeAPITest, API_updateVFShape_GlobalPredicate) {
624 
625   buildShape(/*VF*/ ElementCount::getScalable(2), /*HasGlobalPred*/ true);
626   Shape.updateParam({1 /*Pos*/, VFParamKind::OMP_Uniform});
627   Expected = {/*VF*/ ElementCount::getScalable(2),
628               /*Parameters*/ {{0, VFParamKind::Vector},
629                               {1, VFParamKind::OMP_Uniform},
630                               {2, VFParamKind::Vector},
631                               {3, VFParamKind::GlobalPredicate}}};
632   EXPECT_EQ(Shape, Expected);
633 }
634 
635 TEST_F(VFShapeAPITest, Parameters_Valid) {
636   // ParamPos in order.
637   EXPECT_TRUE(validParams({{0, VFParamKind::Vector}}));
638   EXPECT_TRUE(
639       validParams({{0, VFParamKind::Vector}, {1, VFParamKind::Vector}}));
640   EXPECT_TRUE(validParams({{0, VFParamKind::Vector},
641                            {1, VFParamKind::Vector},
642                            {2, VFParamKind::Vector}}));
643 
644   // GlocalPredicate is unique.
645   EXPECT_TRUE(validParams({{0, VFParamKind::Vector},
646                            {1, VFParamKind::Vector},
647                            {2, VFParamKind::Vector},
648                            {3, VFParamKind::GlobalPredicate}}));
649 
650   EXPECT_TRUE(validParams({{0, VFParamKind::Vector},
651                            {1, VFParamKind::GlobalPredicate},
652                            {2, VFParamKind::Vector}}));
653 }
654 
655 TEST_F(VFShapeAPITest, Parameters_ValidOpenMPLinear) {
656 // Valid linear constant step (>0).
657 #define __BUILD_PARAMETERS(Kind, Val)                                          \
658   {                                                                            \
659     { 0, Kind, Val }                                                           \
660   }
661   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_Linear, 1)));
662   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRef, 2)));
663   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearVal, 4)));
664   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUVal, 33)));
665 #undef __BUILD_PARAMETERS
666 
667 // Valid linear runtime step (the step parameter is marked uniform).
668 #define __BUILD_PARAMETERS(Kind)                                               \
669   {                                                                            \
670     {0, VFParamKind::OMP_Uniform}, {1, VFParamKind::Vector}, { 2, Kind, 0 }    \
671   }
672   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
673   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
674   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
675   EXPECT_TRUE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
676 #undef __BUILD_PARAMETERS
677 }
678 
679 TEST_F(VFShapeAPITest, Parameters_Invalid) {
680 #ifndef NDEBUG
681   // Wrong order is checked by an assertion: make sure that the
682   // assertion is not removed.
683   EXPECT_DEATH(validParams({{1, VFParamKind::Vector}}),
684                "Broken parameter list.");
685   EXPECT_DEATH(
686       validParams({{1, VFParamKind::Vector}, {0, VFParamKind::Vector}}),
687       "Broken parameter list.");
688 #endif
689 
690   // GlobalPredicate is not unique
691   EXPECT_FALSE(validParams({{0, VFParamKind::Vector},
692                             {1, VFParamKind::GlobalPredicate},
693                             {2, VFParamKind::GlobalPredicate}}));
694   EXPECT_FALSE(validParams({{0, VFParamKind::GlobalPredicate},
695                             {1, VFParamKind::Vector},
696                             {2, VFParamKind::GlobalPredicate}}));
697 }
698 
699 TEST_F(VFShapeAPITest, Parameters_InvalidOpenMPLinear) {
700 // Compile time linear steps must be non-zero (compile time invariant).
701 #define __BUILD_PARAMETERS(Kind)                                               \
702   {                                                                            \
703     { 0, Kind, 0 }                                                             \
704   }
705   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_Linear)));
706   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRef)));
707   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearVal)));
708   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUVal)));
709 #undef __BUILD_PARAMETERS
710 
711 // The step of a runtime linear parameter must be marked
712 // as uniform (runtime invariant).
713 #define __BUILD_PARAMETERS(Kind)                                               \
714   {                                                                            \
715     {0, VFParamKind::OMP_Uniform}, {1, VFParamKind::Vector}, { 2, Kind, 1 }    \
716   }
717   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
718   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
719   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
720   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
721 #undef __BUILD_PARAMETERS
722 
723 // The linear step parameter can't point at itself.
724 #define __BUILD_PARAMETERS(Kind)                                               \
725   {                                                                            \
726     {0, VFParamKind::Vector}, {1, VFParamKind::Vector}, { 2, Kind, 2 }         \
727   }
728   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
729   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
730   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
731   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
732 #undef __BUILD_PARAMETERS
733 
734 // Linear parameter (runtime) is out of range.
735 #define __BUILD_PARAMETERS(Kind)                                               \
736   {                                                                            \
737     {0, VFParamKind::Vector}, {1, VFParamKind::Vector}, { 2, Kind, 3 }         \
738   }
739   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearPos)));
740   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearRefPos)));
741   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearValPos)));
742   EXPECT_FALSE(validParams(__BUILD_PARAMETERS(VFParamKind::OMP_LinearUValPos)));
743 #undef __BUILD_PARAMETERS
744 }
745