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