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