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