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