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