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