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