1 //===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder 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/Frontend/OpenMP/OMPConstants.h" 10 #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" 11 #include "llvm/IR/BasicBlock.h" 12 #include "llvm/IR/DIBuilder.h" 13 #include "llvm/IR/Function.h" 14 #include "llvm/IR/InstIterator.h" 15 #include "llvm/IR/LLVMContext.h" 16 #include "llvm/IR/Module.h" 17 #include "llvm/IR/Verifier.h" 18 #include "llvm/Transforms/Utils/BasicBlockUtils.h" 19 #include "gtest/gtest.h" 20 21 using namespace llvm; 22 using namespace omp; 23 24 namespace { 25 26 /// Create an instruction that uses the values in \p Values. We use "printf" 27 /// just because it is often used for this purpose in test code, but it is never 28 /// executed here. 29 static CallInst *createPrintfCall(IRBuilder<> &Builder, StringRef FormatStr, 30 ArrayRef<Value *> Values) { 31 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 32 33 GlobalVariable *GV = Builder.CreateGlobalString(FormatStr, "", 0, M); 34 Constant *Zero = ConstantInt::get(Type::getInt32Ty(M->getContext()), 0); 35 Constant *Indices[] = {Zero, Zero}; 36 Constant *FormatStrConst = 37 ConstantExpr::getInBoundsGetElementPtr(GV->getValueType(), GV, Indices); 38 39 Function *PrintfDecl = M->getFunction("printf"); 40 if (!PrintfDecl) { 41 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 42 FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), true); 43 PrintfDecl = Function::Create(Ty, Linkage, "printf", M); 44 } 45 46 SmallVector<Value *, 4> Args; 47 Args.push_back(FormatStrConst); 48 Args.append(Values.begin(), Values.end()); 49 return Builder.CreateCall(PrintfDecl, Args); 50 } 51 52 /// Verify that blocks in \p RefOrder are corresponds to the depth-first visit 53 /// order the control flow of \p F. 54 /// 55 /// This is an easy way to verify the branching structure of the CFG without 56 /// checking every branch instruction individually. For the CFG of a 57 /// CanonicalLoopInfo, the Cond BB's terminating branch's first edge is entering 58 /// the body, i.e. the DFS order corresponds to the execution order with one 59 /// loop iteration. 60 static testing::AssertionResult 61 verifyDFSOrder(Function *F, ArrayRef<BasicBlock *> RefOrder) { 62 ArrayRef<BasicBlock *>::iterator It = RefOrder.begin(); 63 ArrayRef<BasicBlock *>::iterator E = RefOrder.end(); 64 65 df_iterator_default_set<BasicBlock *, 16> Visited; 66 auto DFS = llvm::depth_first_ext(&F->getEntryBlock(), Visited); 67 68 BasicBlock *Prev = nullptr; 69 for (BasicBlock *BB : DFS) { 70 if (It != E && BB == *It) { 71 Prev = *It; 72 ++It; 73 } 74 } 75 76 if (It == E) 77 return testing::AssertionSuccess(); 78 if (!Prev) 79 return testing::AssertionFailure() 80 << "Did not find " << (*It)->getName() << " in control flow"; 81 return testing::AssertionFailure() 82 << "Expected " << Prev->getName() << " before " << (*It)->getName() 83 << " in control flow"; 84 } 85 86 /// Verify that blocks in \p RefOrder are in the same relative order in the 87 /// linked lists of blocks in \p F. The linked list may contain additional 88 /// blocks in-between. 89 /// 90 /// While the order in the linked list is not relevant for semantics, keeping 91 /// the order roughly in execution order makes its printout easier to read. 92 static testing::AssertionResult 93 verifyListOrder(Function *F, ArrayRef<BasicBlock *> RefOrder) { 94 ArrayRef<BasicBlock *>::iterator It = RefOrder.begin(); 95 ArrayRef<BasicBlock *>::iterator E = RefOrder.end(); 96 97 BasicBlock *Prev = nullptr; 98 for (BasicBlock &BB : *F) { 99 if (It != E && &BB == *It) { 100 Prev = *It; 101 ++It; 102 } 103 } 104 105 if (It == E) 106 return testing::AssertionSuccess(); 107 if (!Prev) 108 return testing::AssertionFailure() << "Did not find " << (*It)->getName() 109 << " in function " << F->getName(); 110 return testing::AssertionFailure() 111 << "Expected " << Prev->getName() << " before " << (*It)->getName() 112 << " in function " << F->getName(); 113 } 114 115 class OpenMPIRBuilderTest : public testing::Test { 116 protected: 117 void SetUp() override { 118 M.reset(new Module("MyModule", Ctx)); 119 FunctionType *FTy = 120 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, 121 /*isVarArg=*/false); 122 F = Function::Create(FTy, Function::ExternalLinkage, "", M.get()); 123 BB = BasicBlock::Create(Ctx, "", F); 124 125 DIBuilder DIB(*M); 126 auto File = DIB.createFile("test.dbg", "/src", llvm::None, 127 Optional<StringRef>("/src/test.dbg")); 128 auto CU = 129 DIB.createCompileUnit(dwarf::DW_LANG_C, File, "llvm-C", true, "", 0); 130 auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); 131 auto SP = DIB.createFunction( 132 CU, "foo", "", File, 1, Type, 1, DINode::FlagZero, 133 DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized); 134 F->setSubprogram(SP); 135 auto Scope = DIB.createLexicalBlockFile(SP, File, 0); 136 DIB.finalize(); 137 DL = DILocation::get(Ctx, 3, 7, Scope); 138 } 139 140 void TearDown() override { 141 BB = nullptr; 142 M.reset(); 143 } 144 145 LLVMContext Ctx; 146 std::unique_ptr<Module> M; 147 Function *F; 148 BasicBlock *BB; 149 DebugLoc DL; 150 }; 151 152 class OpenMPIRBuilderTestWithParams 153 : public OpenMPIRBuilderTest, 154 public ::testing::WithParamInterface<omp::OMPScheduleType> {}; 155 156 // Returns the value stored in the given allocation. Returns null if the given 157 // value is not a result of an allocation, if no value is stored or if there is 158 // more than one store. 159 static Value *findStoredValue(Value *AllocaValue) { 160 Instruction *Alloca = dyn_cast<AllocaInst>(AllocaValue); 161 if (!Alloca) 162 return nullptr; 163 StoreInst *Store = nullptr; 164 for (Use &U : Alloca->uses()) { 165 if (auto *CandidateStore = dyn_cast<StoreInst>(U.getUser())) { 166 EXPECT_EQ(Store, nullptr); 167 Store = CandidateStore; 168 } 169 } 170 if (!Store) 171 return nullptr; 172 return Store->getValueOperand(); 173 } 174 175 TEST_F(OpenMPIRBuilderTest, CreateBarrier) { 176 OpenMPIRBuilder OMPBuilder(*M); 177 OMPBuilder.initialize(); 178 179 IRBuilder<> Builder(BB); 180 181 OMPBuilder.createBarrier({IRBuilder<>::InsertPoint()}, OMPD_for); 182 EXPECT_TRUE(M->global_empty()); 183 EXPECT_EQ(M->size(), 1U); 184 EXPECT_EQ(F->size(), 1U); 185 EXPECT_EQ(BB->size(), 0U); 186 187 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 188 OMPBuilder.createBarrier(Loc, OMPD_for); 189 EXPECT_FALSE(M->global_empty()); 190 EXPECT_EQ(M->size(), 3U); 191 EXPECT_EQ(F->size(), 1U); 192 EXPECT_EQ(BB->size(), 2U); 193 194 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 195 EXPECT_NE(GTID, nullptr); 196 EXPECT_EQ(GTID->getNumArgOperands(), 1U); 197 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 198 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 199 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 200 201 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode()); 202 EXPECT_NE(Barrier, nullptr); 203 EXPECT_EQ(Barrier->getNumArgOperands(), 2U); 204 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_barrier"); 205 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); 206 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); 207 208 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID); 209 210 Builder.CreateUnreachable(); 211 EXPECT_FALSE(verifyModule(*M, &errs())); 212 } 213 214 TEST_F(OpenMPIRBuilderTest, CreateCancel) { 215 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 216 OpenMPIRBuilder OMPBuilder(*M); 217 OMPBuilder.initialize(); 218 219 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); 220 new UnreachableInst(Ctx, CBB); 221 auto FiniCB = [&](InsertPointTy IP) { 222 ASSERT_NE(IP.getBlock(), nullptr); 223 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); 224 BranchInst::Create(CBB, IP.getBlock()); 225 }; 226 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); 227 228 IRBuilder<> Builder(BB); 229 230 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 231 auto NewIP = OMPBuilder.createCancel(Loc, nullptr, OMPD_parallel); 232 Builder.restoreIP(NewIP); 233 EXPECT_FALSE(M->global_empty()); 234 EXPECT_EQ(M->size(), 3U); 235 EXPECT_EQ(F->size(), 4U); 236 EXPECT_EQ(BB->size(), 4U); 237 238 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 239 EXPECT_NE(GTID, nullptr); 240 EXPECT_EQ(GTID->getNumArgOperands(), 1U); 241 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 242 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 243 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 244 245 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode()); 246 EXPECT_NE(Cancel, nullptr); 247 EXPECT_EQ(Cancel->getNumArgOperands(), 3U); 248 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel"); 249 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory()); 250 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory()); 251 EXPECT_EQ(Cancel->getNumUses(), 1U); 252 Instruction *CancelBBTI = Cancel->getParent()->getTerminator(); 253 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U); 254 EXPECT_EQ(CancelBBTI->getSuccessor(0), NewIP.getBlock()); 255 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U); 256 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 257 1U); 258 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), 259 CBB); 260 261 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID); 262 263 OMPBuilder.popFinalizationCB(); 264 265 Builder.CreateUnreachable(); 266 EXPECT_FALSE(verifyModule(*M, &errs())); 267 } 268 269 TEST_F(OpenMPIRBuilderTest, CreateCancelIfCond) { 270 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 271 OpenMPIRBuilder OMPBuilder(*M); 272 OMPBuilder.initialize(); 273 274 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); 275 new UnreachableInst(Ctx, CBB); 276 auto FiniCB = [&](InsertPointTy IP) { 277 ASSERT_NE(IP.getBlock(), nullptr); 278 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); 279 BranchInst::Create(CBB, IP.getBlock()); 280 }; 281 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); 282 283 IRBuilder<> Builder(BB); 284 285 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 286 auto NewIP = OMPBuilder.createCancel(Loc, Builder.getTrue(), OMPD_parallel); 287 Builder.restoreIP(NewIP); 288 EXPECT_FALSE(M->global_empty()); 289 EXPECT_EQ(M->size(), 3U); 290 EXPECT_EQ(F->size(), 7U); 291 EXPECT_EQ(BB->size(), 1U); 292 ASSERT_TRUE(isa<BranchInst>(BB->getTerminator())); 293 ASSERT_EQ(BB->getTerminator()->getNumSuccessors(), 2U); 294 BB = BB->getTerminator()->getSuccessor(0); 295 EXPECT_EQ(BB->size(), 4U); 296 297 298 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 299 EXPECT_NE(GTID, nullptr); 300 EXPECT_EQ(GTID->getNumArgOperands(), 1U); 301 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 302 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 303 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 304 305 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode()); 306 EXPECT_NE(Cancel, nullptr); 307 EXPECT_EQ(Cancel->getNumArgOperands(), 3U); 308 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel"); 309 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory()); 310 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory()); 311 EXPECT_EQ(Cancel->getNumUses(), 1U); 312 Instruction *CancelBBTI = Cancel->getParent()->getTerminator(); 313 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U); 314 EXPECT_EQ(CancelBBTI->getSuccessor(0)->size(), 1U); 315 EXPECT_EQ(CancelBBTI->getSuccessor(0)->getUniqueSuccessor(), NewIP.getBlock()); 316 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U); 317 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 318 1U); 319 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), 320 CBB); 321 322 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID); 323 324 OMPBuilder.popFinalizationCB(); 325 326 Builder.CreateUnreachable(); 327 EXPECT_FALSE(verifyModule(*M, &errs())); 328 } 329 330 TEST_F(OpenMPIRBuilderTest, CreateCancelBarrier) { 331 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 332 OpenMPIRBuilder OMPBuilder(*M); 333 OMPBuilder.initialize(); 334 335 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); 336 new UnreachableInst(Ctx, CBB); 337 auto FiniCB = [&](InsertPointTy IP) { 338 ASSERT_NE(IP.getBlock(), nullptr); 339 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); 340 BranchInst::Create(CBB, IP.getBlock()); 341 }; 342 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); 343 344 IRBuilder<> Builder(BB); 345 346 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 347 auto NewIP = OMPBuilder.createBarrier(Loc, OMPD_for); 348 Builder.restoreIP(NewIP); 349 EXPECT_FALSE(M->global_empty()); 350 EXPECT_EQ(M->size(), 3U); 351 EXPECT_EQ(F->size(), 4U); 352 EXPECT_EQ(BB->size(), 4U); 353 354 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 355 EXPECT_NE(GTID, nullptr); 356 EXPECT_EQ(GTID->getNumArgOperands(), 1U); 357 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 358 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 359 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 360 361 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode()); 362 EXPECT_NE(Barrier, nullptr); 363 EXPECT_EQ(Barrier->getNumArgOperands(), 2U); 364 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier"); 365 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); 366 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); 367 EXPECT_EQ(Barrier->getNumUses(), 1U); 368 Instruction *BarrierBBTI = Barrier->getParent()->getTerminator(); 369 EXPECT_EQ(BarrierBBTI->getNumSuccessors(), 2U); 370 EXPECT_EQ(BarrierBBTI->getSuccessor(0), NewIP.getBlock()); 371 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->size(), 1U); 372 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 373 1U); 374 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), 375 CBB); 376 377 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID); 378 379 OMPBuilder.popFinalizationCB(); 380 381 Builder.CreateUnreachable(); 382 EXPECT_FALSE(verifyModule(*M, &errs())); 383 } 384 385 TEST_F(OpenMPIRBuilderTest, DbgLoc) { 386 OpenMPIRBuilder OMPBuilder(*M); 387 OMPBuilder.initialize(); 388 F->setName("func"); 389 390 IRBuilder<> Builder(BB); 391 392 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 393 OMPBuilder.createBarrier(Loc, OMPD_for); 394 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 395 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode()); 396 EXPECT_EQ(GTID->getDebugLoc(), DL); 397 EXPECT_EQ(Barrier->getDebugLoc(), DL); 398 EXPECT_TRUE(isa<GlobalVariable>(Barrier->getOperand(0))); 399 if (!isa<GlobalVariable>(Barrier->getOperand(0))) 400 return; 401 GlobalVariable *Ident = cast<GlobalVariable>(Barrier->getOperand(0)); 402 EXPECT_TRUE(Ident->hasInitializer()); 403 if (!Ident->hasInitializer()) 404 return; 405 Constant *Initializer = Ident->getInitializer(); 406 EXPECT_TRUE( 407 isa<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts())); 408 GlobalVariable *SrcStrGlob = 409 cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts()); 410 if (!SrcStrGlob) 411 return; 412 EXPECT_TRUE(isa<ConstantDataArray>(SrcStrGlob->getInitializer())); 413 ConstantDataArray *SrcSrc = 414 dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer()); 415 if (!SrcSrc) 416 return; 417 EXPECT_EQ(SrcSrc->getAsCString(), ";/src/test.dbg;foo;3;7;;"); 418 } 419 420 TEST_F(OpenMPIRBuilderTest, ParallelSimple) { 421 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 422 OpenMPIRBuilder OMPBuilder(*M); 423 OMPBuilder.initialize(); 424 F->setName("func"); 425 IRBuilder<> Builder(BB); 426 427 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 428 429 AllocaInst *PrivAI = nullptr; 430 431 unsigned NumBodiesGenerated = 0; 432 unsigned NumPrivatizedVars = 0; 433 unsigned NumFinalizationPoints = 0; 434 435 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 436 BasicBlock &ContinuationIP) { 437 ++NumBodiesGenerated; 438 439 Builder.restoreIP(AllocaIP); 440 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 441 Builder.CreateStore(F->arg_begin(), PrivAI); 442 443 Builder.restoreIP(CodeGenIP); 444 Value *PrivLoad = Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, 445 "local.use"); 446 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 447 Instruction *ThenTerm, *ElseTerm; 448 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), 449 &ThenTerm, &ElseTerm); 450 451 Builder.SetInsertPoint(ThenTerm); 452 Builder.CreateBr(&ContinuationIP); 453 ThenTerm->eraseFromParent(); 454 }; 455 456 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 457 Value &Orig, Value &Inner, 458 Value *&ReplacementValue) -> InsertPointTy { 459 ++NumPrivatizedVars; 460 461 if (!isa<AllocaInst>(Orig)) { 462 EXPECT_EQ(&Orig, F->arg_begin()); 463 ReplacementValue = &Inner; 464 return CodeGenIP; 465 } 466 467 // Since the original value is an allocation, it has a pointer type and 468 // therefore no additional wrapping should happen. 469 EXPECT_EQ(&Orig, &Inner); 470 471 // Trivial copy (=firstprivate). 472 Builder.restoreIP(AllocaIP); 473 Type *VTy = Inner.getType()->getPointerElementType(); 474 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 475 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 476 Builder.restoreIP(CodeGenIP); 477 Builder.CreateStore(V, ReplacementValue); 478 return CodeGenIP; 479 }; 480 481 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; 482 483 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 484 F->getEntryBlock().getFirstInsertionPt()); 485 IRBuilder<>::InsertPoint AfterIP = 486 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 487 nullptr, nullptr, OMP_PROC_BIND_default, false); 488 EXPECT_EQ(NumBodiesGenerated, 1U); 489 EXPECT_EQ(NumPrivatizedVars, 1U); 490 EXPECT_EQ(NumFinalizationPoints, 1U); 491 492 Builder.restoreIP(AfterIP); 493 Builder.CreateRetVoid(); 494 495 OMPBuilder.finalize(); 496 497 EXPECT_NE(PrivAI, nullptr); 498 Function *OutlinedFn = PrivAI->getFunction(); 499 EXPECT_NE(F, OutlinedFn); 500 EXPECT_FALSE(verifyModule(*M, &errs())); 501 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoUnwind)); 502 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoRecurse)); 503 EXPECT_TRUE(OutlinedFn->hasParamAttribute(0, Attribute::NoAlias)); 504 EXPECT_TRUE(OutlinedFn->hasParamAttribute(1, Attribute::NoAlias)); 505 506 EXPECT_TRUE(OutlinedFn->hasInternalLinkage()); 507 EXPECT_EQ(OutlinedFn->arg_size(), 3U); 508 509 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent()); 510 EXPECT_EQ(OutlinedFn->getNumUses(), 1U); 511 User *Usr = OutlinedFn->user_back(); 512 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 513 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); 514 ASSERT_NE(ForkCI, nullptr); 515 516 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 517 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U); 518 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 519 EXPECT_EQ(ForkCI->getArgOperand(1), 520 ConstantInt::get(Type::getInt32Ty(Ctx), 1U)); 521 EXPECT_EQ(ForkCI->getArgOperand(2), Usr); 522 EXPECT_EQ(findStoredValue(ForkCI->getArgOperand(3)), F->arg_begin()); 523 } 524 525 TEST_F(OpenMPIRBuilderTest, ParallelNested) { 526 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 527 OpenMPIRBuilder OMPBuilder(*M); 528 OMPBuilder.initialize(); 529 F->setName("func"); 530 IRBuilder<> Builder(BB); 531 532 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 533 534 unsigned NumInnerBodiesGenerated = 0; 535 unsigned NumOuterBodiesGenerated = 0; 536 unsigned NumFinalizationPoints = 0; 537 538 auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 539 BasicBlock &ContinuationIP) { 540 ++NumInnerBodiesGenerated; 541 }; 542 543 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 544 Value &Orig, Value &Inner, 545 Value *&ReplacementValue) -> InsertPointTy { 546 // Trivial copy (=firstprivate). 547 Builder.restoreIP(AllocaIP); 548 Type *VTy = Inner.getType()->getPointerElementType(); 549 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 550 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 551 Builder.restoreIP(CodeGenIP); 552 Builder.CreateStore(V, ReplacementValue); 553 return CodeGenIP; 554 }; 555 556 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; 557 558 auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 559 BasicBlock &ContinuationIP) { 560 ++NumOuterBodiesGenerated; 561 Builder.restoreIP(CodeGenIP); 562 BasicBlock *CGBB = CodeGenIP.getBlock(); 563 BasicBlock *NewBB = SplitBlock(CGBB, &*CodeGenIP.getPoint()); 564 CGBB->getTerminator()->eraseFromParent(); 565 ; 566 567 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.createParallel( 568 InsertPointTy(CGBB, CGBB->end()), AllocaIP, InnerBodyGenCB, PrivCB, 569 FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); 570 571 Builder.restoreIP(AfterIP); 572 Builder.CreateBr(NewBB); 573 }; 574 575 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 576 F->getEntryBlock().getFirstInsertionPt()); 577 IRBuilder<>::InsertPoint AfterIP = 578 OMPBuilder.createParallel(Loc, AllocaIP, OuterBodyGenCB, PrivCB, FiniCB, 579 nullptr, nullptr, OMP_PROC_BIND_default, false); 580 581 EXPECT_EQ(NumInnerBodiesGenerated, 1U); 582 EXPECT_EQ(NumOuterBodiesGenerated, 1U); 583 EXPECT_EQ(NumFinalizationPoints, 2U); 584 585 Builder.restoreIP(AfterIP); 586 Builder.CreateRetVoid(); 587 588 OMPBuilder.finalize(); 589 590 EXPECT_EQ(M->size(), 5U); 591 for (Function &OutlinedFn : *M) { 592 if (F == &OutlinedFn || OutlinedFn.isDeclaration()) 593 continue; 594 EXPECT_FALSE(verifyModule(*M, &errs())); 595 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind)); 596 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoRecurse)); 597 EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias)); 598 EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias)); 599 600 EXPECT_TRUE(OutlinedFn.hasInternalLinkage()); 601 EXPECT_EQ(OutlinedFn.arg_size(), 2U); 602 603 EXPECT_EQ(OutlinedFn.getNumUses(), 1U); 604 User *Usr = OutlinedFn.user_back(); 605 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 606 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); 607 ASSERT_NE(ForkCI, nullptr); 608 609 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 610 EXPECT_EQ(ForkCI->getNumArgOperands(), 3U); 611 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 612 EXPECT_EQ(ForkCI->getArgOperand(1), 613 ConstantInt::get(Type::getInt32Ty(Ctx), 0U)); 614 EXPECT_EQ(ForkCI->getArgOperand(2), Usr); 615 } 616 } 617 618 TEST_F(OpenMPIRBuilderTest, ParallelNested2Inner) { 619 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 620 OpenMPIRBuilder OMPBuilder(*M); 621 OMPBuilder.initialize(); 622 F->setName("func"); 623 IRBuilder<> Builder(BB); 624 625 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 626 627 unsigned NumInnerBodiesGenerated = 0; 628 unsigned NumOuterBodiesGenerated = 0; 629 unsigned NumFinalizationPoints = 0; 630 631 auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 632 BasicBlock &ContinuationIP) { 633 ++NumInnerBodiesGenerated; 634 }; 635 636 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 637 Value &Orig, Value &Inner, 638 Value *&ReplacementValue) -> InsertPointTy { 639 // Trivial copy (=firstprivate). 640 Builder.restoreIP(AllocaIP); 641 Type *VTy = Inner.getType()->getPointerElementType(); 642 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 643 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 644 Builder.restoreIP(CodeGenIP); 645 Builder.CreateStore(V, ReplacementValue); 646 return CodeGenIP; 647 }; 648 649 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; 650 651 auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 652 BasicBlock &ContinuationIP) { 653 ++NumOuterBodiesGenerated; 654 Builder.restoreIP(CodeGenIP); 655 BasicBlock *CGBB = CodeGenIP.getBlock(); 656 BasicBlock *NewBB1 = SplitBlock(CGBB, &*CodeGenIP.getPoint()); 657 BasicBlock *NewBB2 = SplitBlock(NewBB1, &*NewBB1->getFirstInsertionPt()); 658 CGBB->getTerminator()->eraseFromParent(); 659 ; 660 NewBB1->getTerminator()->eraseFromParent(); 661 ; 662 663 IRBuilder<>::InsertPoint AfterIP1 = OMPBuilder.createParallel( 664 InsertPointTy(CGBB, CGBB->end()), AllocaIP, InnerBodyGenCB, PrivCB, 665 FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); 666 667 Builder.restoreIP(AfterIP1); 668 Builder.CreateBr(NewBB1); 669 670 IRBuilder<>::InsertPoint AfterIP2 = OMPBuilder.createParallel( 671 InsertPointTy(NewBB1, NewBB1->end()), AllocaIP, InnerBodyGenCB, PrivCB, 672 FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); 673 674 Builder.restoreIP(AfterIP2); 675 Builder.CreateBr(NewBB2); 676 }; 677 678 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 679 F->getEntryBlock().getFirstInsertionPt()); 680 IRBuilder<>::InsertPoint AfterIP = 681 OMPBuilder.createParallel(Loc, AllocaIP, OuterBodyGenCB, PrivCB, FiniCB, 682 nullptr, nullptr, OMP_PROC_BIND_default, false); 683 684 EXPECT_EQ(NumInnerBodiesGenerated, 2U); 685 EXPECT_EQ(NumOuterBodiesGenerated, 1U); 686 EXPECT_EQ(NumFinalizationPoints, 3U); 687 688 Builder.restoreIP(AfterIP); 689 Builder.CreateRetVoid(); 690 691 OMPBuilder.finalize(); 692 693 EXPECT_EQ(M->size(), 6U); 694 for (Function &OutlinedFn : *M) { 695 if (F == &OutlinedFn || OutlinedFn.isDeclaration()) 696 continue; 697 EXPECT_FALSE(verifyModule(*M, &errs())); 698 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind)); 699 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoRecurse)); 700 EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias)); 701 EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias)); 702 703 EXPECT_TRUE(OutlinedFn.hasInternalLinkage()); 704 EXPECT_EQ(OutlinedFn.arg_size(), 2U); 705 706 unsigned NumAllocas = 0; 707 for (Instruction &I : instructions(OutlinedFn)) 708 NumAllocas += isa<AllocaInst>(I); 709 EXPECT_EQ(NumAllocas, 1U); 710 711 EXPECT_EQ(OutlinedFn.getNumUses(), 1U); 712 User *Usr = OutlinedFn.user_back(); 713 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 714 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); 715 ASSERT_NE(ForkCI, nullptr); 716 717 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 718 EXPECT_EQ(ForkCI->getNumArgOperands(), 3U); 719 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 720 EXPECT_EQ(ForkCI->getArgOperand(1), 721 ConstantInt::get(Type::getInt32Ty(Ctx), 0U)); 722 EXPECT_EQ(ForkCI->getArgOperand(2), Usr); 723 } 724 } 725 726 TEST_F(OpenMPIRBuilderTest, ParallelIfCond) { 727 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 728 OpenMPIRBuilder OMPBuilder(*M); 729 OMPBuilder.initialize(); 730 F->setName("func"); 731 IRBuilder<> Builder(BB); 732 733 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 734 735 AllocaInst *PrivAI = nullptr; 736 737 unsigned NumBodiesGenerated = 0; 738 unsigned NumPrivatizedVars = 0; 739 unsigned NumFinalizationPoints = 0; 740 741 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 742 BasicBlock &ContinuationIP) { 743 ++NumBodiesGenerated; 744 745 Builder.restoreIP(AllocaIP); 746 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 747 Builder.CreateStore(F->arg_begin(), PrivAI); 748 749 Builder.restoreIP(CodeGenIP); 750 Value *PrivLoad = Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, 751 "local.use"); 752 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 753 Instruction *ThenTerm, *ElseTerm; 754 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), 755 &ThenTerm, &ElseTerm); 756 757 Builder.SetInsertPoint(ThenTerm); 758 Builder.CreateBr(&ContinuationIP); 759 ThenTerm->eraseFromParent(); 760 }; 761 762 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 763 Value &Orig, Value &Inner, 764 Value *&ReplacementValue) -> InsertPointTy { 765 ++NumPrivatizedVars; 766 767 if (!isa<AllocaInst>(Orig)) { 768 EXPECT_EQ(&Orig, F->arg_begin()); 769 ReplacementValue = &Inner; 770 return CodeGenIP; 771 } 772 773 // Since the original value is an allocation, it has a pointer type and 774 // therefore no additional wrapping should happen. 775 EXPECT_EQ(&Orig, &Inner); 776 777 // Trivial copy (=firstprivate). 778 Builder.restoreIP(AllocaIP); 779 Type *VTy = Inner.getType()->getPointerElementType(); 780 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 781 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 782 Builder.restoreIP(CodeGenIP); 783 Builder.CreateStore(V, ReplacementValue); 784 return CodeGenIP; 785 }; 786 787 auto FiniCB = [&](InsertPointTy CodeGenIP) { 788 ++NumFinalizationPoints; 789 // No destructors. 790 }; 791 792 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 793 F->getEntryBlock().getFirstInsertionPt()); 794 IRBuilder<>::InsertPoint AfterIP = 795 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 796 Builder.CreateIsNotNull(F->arg_begin()), 797 nullptr, OMP_PROC_BIND_default, false); 798 799 EXPECT_EQ(NumBodiesGenerated, 1U); 800 EXPECT_EQ(NumPrivatizedVars, 1U); 801 EXPECT_EQ(NumFinalizationPoints, 1U); 802 803 Builder.restoreIP(AfterIP); 804 Builder.CreateRetVoid(); 805 OMPBuilder.finalize(); 806 807 EXPECT_NE(PrivAI, nullptr); 808 Function *OutlinedFn = PrivAI->getFunction(); 809 EXPECT_NE(F, OutlinedFn); 810 EXPECT_FALSE(verifyModule(*M, &errs())); 811 812 EXPECT_TRUE(OutlinedFn->hasInternalLinkage()); 813 EXPECT_EQ(OutlinedFn->arg_size(), 3U); 814 815 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent()); 816 ASSERT_EQ(OutlinedFn->getNumUses(), 2U); 817 818 CallInst *DirectCI = nullptr; 819 CallInst *ForkCI = nullptr; 820 for (User *Usr : OutlinedFn->users()) { 821 if (isa<CallInst>(Usr)) { 822 ASSERT_EQ(DirectCI, nullptr); 823 DirectCI = cast<CallInst>(Usr); 824 } else { 825 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 826 ASSERT_EQ(Usr->getNumUses(), 1U); 827 ASSERT_TRUE(isa<CallInst>(Usr->user_back())); 828 ForkCI = cast<CallInst>(Usr->user_back()); 829 } 830 } 831 832 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 833 EXPECT_EQ(ForkCI->getNumArgOperands(), 4U); 834 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 835 EXPECT_EQ(ForkCI->getArgOperand(1), 836 ConstantInt::get(Type::getInt32Ty(Ctx), 1)); 837 Value *StoredForkArg = findStoredValue(ForkCI->getArgOperand(3)); 838 EXPECT_EQ(StoredForkArg, F->arg_begin()); 839 840 EXPECT_EQ(DirectCI->getCalledFunction(), OutlinedFn); 841 EXPECT_EQ(DirectCI->getNumArgOperands(), 3U); 842 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(0))); 843 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(1))); 844 Value *StoredDirectArg = findStoredValue(DirectCI->getArgOperand(2)); 845 EXPECT_EQ(StoredDirectArg, F->arg_begin()); 846 } 847 848 TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) { 849 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 850 OpenMPIRBuilder OMPBuilder(*M); 851 OMPBuilder.initialize(); 852 F->setName("func"); 853 IRBuilder<> Builder(BB); 854 855 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 856 857 unsigned NumBodiesGenerated = 0; 858 unsigned NumPrivatizedVars = 0; 859 unsigned NumFinalizationPoints = 0; 860 861 CallInst *CheckedBarrier = nullptr; 862 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 863 BasicBlock &ContinuationIP) { 864 ++NumBodiesGenerated; 865 866 Builder.restoreIP(CodeGenIP); 867 868 // Create three barriers, two cancel barriers but only one checked. 869 Function *CBFn, *BFn; 870 871 Builder.restoreIP( 872 OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel)); 873 874 CBFn = M->getFunction("__kmpc_cancel_barrier"); 875 BFn = M->getFunction("__kmpc_barrier"); 876 ASSERT_NE(CBFn, nullptr); 877 ASSERT_EQ(BFn, nullptr); 878 ASSERT_EQ(CBFn->getNumUses(), 1U); 879 ASSERT_TRUE(isa<CallInst>(CBFn->user_back())); 880 ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U); 881 CheckedBarrier = cast<CallInst>(CBFn->user_back()); 882 883 Builder.restoreIP( 884 OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel, true)); 885 CBFn = M->getFunction("__kmpc_cancel_barrier"); 886 BFn = M->getFunction("__kmpc_barrier"); 887 ASSERT_NE(CBFn, nullptr); 888 ASSERT_NE(BFn, nullptr); 889 ASSERT_EQ(CBFn->getNumUses(), 1U); 890 ASSERT_EQ(BFn->getNumUses(), 1U); 891 ASSERT_TRUE(isa<CallInst>(BFn->user_back())); 892 ASSERT_EQ(BFn->user_back()->getNumUses(), 0U); 893 894 Builder.restoreIP(OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel, 895 false, false)); 896 ASSERT_EQ(CBFn->getNumUses(), 2U); 897 ASSERT_EQ(BFn->getNumUses(), 1U); 898 ASSERT_TRUE(CBFn->user_back() != CheckedBarrier); 899 ASSERT_TRUE(isa<CallInst>(CBFn->user_back())); 900 ASSERT_EQ(CBFn->user_back()->getNumUses(), 0U); 901 }; 902 903 auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V, Value &, 904 Value *&) -> InsertPointTy { 905 ++NumPrivatizedVars; 906 llvm_unreachable("No privatization callback call expected!"); 907 }; 908 909 FunctionType *FakeDestructorTy = 910 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, 911 /*isVarArg=*/false); 912 auto *FakeDestructor = Function::Create( 913 FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get()); 914 915 auto FiniCB = [&](InsertPointTy IP) { 916 ++NumFinalizationPoints; 917 Builder.restoreIP(IP); 918 Builder.CreateCall(FakeDestructor, 919 {Builder.getInt32(NumFinalizationPoints)}); 920 }; 921 922 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 923 F->getEntryBlock().getFirstInsertionPt()); 924 IRBuilder<>::InsertPoint AfterIP = 925 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 926 Builder.CreateIsNotNull(F->arg_begin()), 927 nullptr, OMP_PROC_BIND_default, true); 928 929 EXPECT_EQ(NumBodiesGenerated, 1U); 930 EXPECT_EQ(NumPrivatizedVars, 0U); 931 EXPECT_EQ(NumFinalizationPoints, 2U); 932 EXPECT_EQ(FakeDestructor->getNumUses(), 2U); 933 934 Builder.restoreIP(AfterIP); 935 Builder.CreateRetVoid(); 936 OMPBuilder.finalize(); 937 938 EXPECT_FALSE(verifyModule(*M, &errs())); 939 940 BasicBlock *ExitBB = nullptr; 941 for (const User *Usr : FakeDestructor->users()) { 942 const CallInst *CI = dyn_cast<CallInst>(Usr); 943 ASSERT_EQ(CI->getCalledFunction(), FakeDestructor); 944 ASSERT_TRUE(isa<BranchInst>(CI->getNextNode())); 945 ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U); 946 if (ExitBB) 947 ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB); 948 else 949 ExitBB = CI->getNextNode()->getSuccessor(0); 950 ASSERT_EQ(ExitBB->size(), 1U); 951 if (!isa<ReturnInst>(ExitBB->front())) { 952 ASSERT_TRUE(isa<BranchInst>(ExitBB->front())); 953 ASSERT_EQ(cast<BranchInst>(ExitBB->front()).getNumSuccessors(), 1U); 954 ASSERT_TRUE(isa<ReturnInst>( 955 cast<BranchInst>(ExitBB->front()).getSuccessor(0)->front())); 956 } 957 } 958 } 959 960 TEST_F(OpenMPIRBuilderTest, ParallelForwardAsPointers) { 961 OpenMPIRBuilder OMPBuilder(*M); 962 OMPBuilder.initialize(); 963 F->setName("func"); 964 IRBuilder<> Builder(BB); 965 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 966 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 967 968 Type *I32Ty = Type::getInt32Ty(M->getContext()); 969 Type *I32PtrTy = Type::getInt32PtrTy(M->getContext()); 970 Type *StructTy = StructType::get(I32Ty, I32PtrTy); 971 Type *StructPtrTy = StructTy->getPointerTo(); 972 Type *VoidTy = Type::getVoidTy(M->getContext()); 973 FunctionCallee RetI32Func = M->getOrInsertFunction("ret_i32", I32Ty); 974 FunctionCallee TakeI32Func = 975 M->getOrInsertFunction("take_i32", VoidTy, I32Ty); 976 FunctionCallee RetI32PtrFunc = M->getOrInsertFunction("ret_i32ptr", I32PtrTy); 977 FunctionCallee TakeI32PtrFunc = 978 M->getOrInsertFunction("take_i32ptr", VoidTy, I32PtrTy); 979 FunctionCallee RetStructFunc = M->getOrInsertFunction("ret_struct", StructTy); 980 FunctionCallee TakeStructFunc = 981 M->getOrInsertFunction("take_struct", VoidTy, StructTy); 982 FunctionCallee RetStructPtrFunc = 983 M->getOrInsertFunction("ret_structptr", StructPtrTy); 984 FunctionCallee TakeStructPtrFunc = 985 M->getOrInsertFunction("take_structPtr", VoidTy, StructPtrTy); 986 Value *I32Val = Builder.CreateCall(RetI32Func); 987 Value *I32PtrVal = Builder.CreateCall(RetI32PtrFunc); 988 Value *StructVal = Builder.CreateCall(RetStructFunc); 989 Value *StructPtrVal = Builder.CreateCall(RetStructPtrFunc); 990 991 Instruction *Internal; 992 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 993 BasicBlock &ContinuationBB) { 994 IRBuilder<>::InsertPointGuard Guard(Builder); 995 Builder.restoreIP(CodeGenIP); 996 Internal = Builder.CreateCall(TakeI32Func, I32Val); 997 Builder.CreateCall(TakeI32PtrFunc, I32PtrVal); 998 Builder.CreateCall(TakeStructFunc, StructVal); 999 Builder.CreateCall(TakeStructPtrFunc, StructPtrVal); 1000 }; 1001 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &, 1002 Value &Inner, Value *&ReplacementValue) { 1003 ReplacementValue = &Inner; 1004 return CodeGenIP; 1005 }; 1006 auto FiniCB = [](InsertPointTy) {}; 1007 1008 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 1009 F->getEntryBlock().getFirstInsertionPt()); 1010 IRBuilder<>::InsertPoint AfterIP = 1011 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 1012 nullptr, nullptr, OMP_PROC_BIND_default, false); 1013 Builder.restoreIP(AfterIP); 1014 Builder.CreateRetVoid(); 1015 1016 OMPBuilder.finalize(); 1017 1018 EXPECT_FALSE(verifyModule(*M, &errs())); 1019 Function *OutlinedFn = Internal->getFunction(); 1020 1021 Type *Arg2Type = OutlinedFn->getArg(2)->getType(); 1022 EXPECT_TRUE(Arg2Type->isPointerTy()); 1023 EXPECT_EQ(Arg2Type->getPointerElementType(), I32Ty); 1024 1025 // Arguments that need to be passed through pointers and reloaded will get 1026 // used earlier in the functions and therefore will appear first in the 1027 // argument list after outlining. 1028 Type *Arg3Type = OutlinedFn->getArg(3)->getType(); 1029 EXPECT_TRUE(Arg3Type->isPointerTy()); 1030 EXPECT_EQ(Arg3Type->getPointerElementType(), StructTy); 1031 1032 Type *Arg4Type = OutlinedFn->getArg(4)->getType(); 1033 EXPECT_EQ(Arg4Type, I32PtrTy); 1034 1035 Type *Arg5Type = OutlinedFn->getArg(5)->getType(); 1036 EXPECT_EQ(Arg5Type, StructPtrTy); 1037 } 1038 1039 TEST_F(OpenMPIRBuilderTest, CanonicalLoopSimple) { 1040 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1041 OpenMPIRBuilder OMPBuilder(*M); 1042 OMPBuilder.initialize(); 1043 IRBuilder<> Builder(BB); 1044 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1045 Value *TripCount = F->getArg(0); 1046 1047 unsigned NumBodiesGenerated = 0; 1048 auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) { 1049 NumBodiesGenerated += 1; 1050 1051 Builder.restoreIP(CodeGenIP); 1052 1053 Value *Cmp = Builder.CreateICmpEQ(LC, TripCount); 1054 Instruction *ThenTerm, *ElseTerm; 1055 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), 1056 &ThenTerm, &ElseTerm); 1057 }; 1058 1059 CanonicalLoopInfo *Loop = 1060 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, TripCount); 1061 1062 Builder.restoreIP(Loop->getAfterIP()); 1063 ReturnInst *RetInst = Builder.CreateRetVoid(); 1064 OMPBuilder.finalize(); 1065 1066 Loop->assertOK(); 1067 EXPECT_FALSE(verifyModule(*M, &errs())); 1068 1069 EXPECT_EQ(NumBodiesGenerated, 1U); 1070 1071 // Verify control flow structure (in addition to Loop->assertOK()). 1072 EXPECT_EQ(Loop->getPreheader()->getSinglePredecessor(), &F->getEntryBlock()); 1073 EXPECT_EQ(Loop->getAfter(), Builder.GetInsertBlock()); 1074 1075 Instruction *IndVar = Loop->getIndVar(); 1076 EXPECT_TRUE(isa<PHINode>(IndVar)); 1077 EXPECT_EQ(IndVar->getType(), TripCount->getType()); 1078 EXPECT_EQ(IndVar->getParent(), Loop->getHeader()); 1079 1080 EXPECT_EQ(Loop->getTripCount(), TripCount); 1081 1082 BasicBlock *Body = Loop->getBody(); 1083 Instruction *CmpInst = &Body->getInstList().front(); 1084 EXPECT_TRUE(isa<ICmpInst>(CmpInst)); 1085 EXPECT_EQ(CmpInst->getOperand(0), IndVar); 1086 1087 BasicBlock *LatchPred = Loop->getLatch()->getSinglePredecessor(); 1088 EXPECT_TRUE(llvm::all_of(successors(Body), [=](BasicBlock *SuccBB) { 1089 return SuccBB->getSingleSuccessor() == LatchPred; 1090 })); 1091 1092 EXPECT_EQ(&Loop->getAfter()->front(), RetInst); 1093 } 1094 1095 TEST_F(OpenMPIRBuilderTest, CanonicalLoopBounds) { 1096 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1097 OpenMPIRBuilder OMPBuilder(*M); 1098 OMPBuilder.initialize(); 1099 IRBuilder<> Builder(BB); 1100 1101 // Check the trip count is computed correctly. We generate the canonical loop 1102 // but rely on the IRBuilder's constant folder to compute the final result 1103 // since all inputs are constant. To verify overflow situations, limit the 1104 // trip count / loop counter widths to 16 bits. 1105 auto EvalTripCount = [&](int64_t Start, int64_t Stop, int64_t Step, 1106 bool IsSigned, bool InclusiveStop) -> int64_t { 1107 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1108 Type *LCTy = Type::getInt16Ty(Ctx); 1109 Value *StartVal = ConstantInt::get(LCTy, Start); 1110 Value *StopVal = ConstantInt::get(LCTy, Stop); 1111 Value *StepVal = ConstantInt::get(LCTy, Step); 1112 auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) {}; 1113 CanonicalLoopInfo *Loop = 1114 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, StartVal, StopVal, 1115 StepVal, IsSigned, InclusiveStop); 1116 Loop->assertOK(); 1117 Builder.restoreIP(Loop->getAfterIP()); 1118 Value *TripCount = Loop->getTripCount(); 1119 return cast<ConstantInt>(TripCount)->getValue().getZExtValue(); 1120 }; 1121 1122 EXPECT_EQ(EvalTripCount(0, 0, 1, false, false), 0); 1123 EXPECT_EQ(EvalTripCount(0, 1, 2, false, false), 1); 1124 EXPECT_EQ(EvalTripCount(0, 42, 1, false, false), 42); 1125 EXPECT_EQ(EvalTripCount(0, 42, 2, false, false), 21); 1126 EXPECT_EQ(EvalTripCount(21, 42, 1, false, false), 21); 1127 EXPECT_EQ(EvalTripCount(0, 5, 5, false, false), 1); 1128 EXPECT_EQ(EvalTripCount(0, 9, 5, false, false), 2); 1129 EXPECT_EQ(EvalTripCount(0, 11, 5, false, false), 3); 1130 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 1, false, false), 0xFFFF); 1131 EXPECT_EQ(EvalTripCount(0xFFFF, 0, 1, false, false), 0); 1132 EXPECT_EQ(EvalTripCount(0xFFFE, 0xFFFF, 1, false, false), 1); 1133 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0x100, false, false), 0x100); 1134 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFF, false, false), 1); 1135 1136 EXPECT_EQ(EvalTripCount(0, 6, 5, false, false), 2); 1137 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFE, false, false), 2); 1138 EXPECT_EQ(EvalTripCount(0, 0, 1, false, true), 1); 1139 EXPECT_EQ(EvalTripCount(0, 0, 0xFFFF, false, true), 1); 1140 EXPECT_EQ(EvalTripCount(0, 0xFFFE, 1, false, true), 0xFFFF); 1141 EXPECT_EQ(EvalTripCount(0, 0xFFFE, 2, false, true), 0x8000); 1142 1143 EXPECT_EQ(EvalTripCount(0, 0, -1, true, false), 0); 1144 EXPECT_EQ(EvalTripCount(0, 1, -1, true, true), 0); 1145 EXPECT_EQ(EvalTripCount(20, 5, -5, true, false), 3); 1146 EXPECT_EQ(EvalTripCount(20, 5, -5, true, true), 4); 1147 EXPECT_EQ(EvalTripCount(-4, -2, 2, true, false), 1); 1148 EXPECT_EQ(EvalTripCount(-4, -3, 2, true, false), 1); 1149 EXPECT_EQ(EvalTripCount(-4, -2, 2, true, true), 2); 1150 1151 EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 1, true, false), 0x8000); 1152 EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 1, true, true), 0x8001); 1153 EXPECT_EQ(EvalTripCount(INT16_MIN, 0x7FFF, 1, true, false), 0xFFFF); 1154 EXPECT_EQ(EvalTripCount(INT16_MIN + 1, 0x7FFF, 1, true, true), 0xFFFF); 1155 EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 0x7FFF, true, false), 2); 1156 EXPECT_EQ(EvalTripCount(0x7FFF, 0, -1, true, false), 0x7FFF); 1157 EXPECT_EQ(EvalTripCount(0, INT16_MIN, -1, true, false), 0x8000); 1158 EXPECT_EQ(EvalTripCount(0, INT16_MIN, -16, true, false), 0x800); 1159 EXPECT_EQ(EvalTripCount(0x7FFF, INT16_MIN, -1, true, false), 0xFFFF); 1160 EXPECT_EQ(EvalTripCount(0x7FFF, 1, INT16_MIN, true, false), 1); 1161 EXPECT_EQ(EvalTripCount(0x7FFF, -1, INT16_MIN, true, true), 2); 1162 1163 // Finalize the function and verify it. 1164 Builder.CreateRetVoid(); 1165 OMPBuilder.finalize(); 1166 EXPECT_FALSE(verifyModule(*M, &errs())); 1167 } 1168 1169 TEST_F(OpenMPIRBuilderTest, CollapseNestedLoops) { 1170 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1171 OpenMPIRBuilder OMPBuilder(*M); 1172 OMPBuilder.initialize(); 1173 F->setName("func"); 1174 1175 IRBuilder<> Builder(BB); 1176 1177 Type *LCTy = F->getArg(0)->getType(); 1178 Constant *One = ConstantInt::get(LCTy, 1); 1179 Constant *Two = ConstantInt::get(LCTy, 2); 1180 Value *OuterTripCount = 1181 Builder.CreateAdd(F->getArg(0), Two, "tripcount.outer"); 1182 Value *InnerTripCount = 1183 Builder.CreateAdd(F->getArg(0), One, "tripcount.inner"); 1184 1185 // Fix an insertion point for ComputeIP. 1186 BasicBlock *LoopNextEnter = 1187 BasicBlock::Create(M->getContext(), "loopnest.enter", F, 1188 Builder.GetInsertBlock()->getNextNode()); 1189 BranchInst *EnterBr = Builder.CreateBr(LoopNextEnter); 1190 InsertPointTy ComputeIP{EnterBr->getParent(), EnterBr->getIterator()}; 1191 1192 Builder.SetInsertPoint(LoopNextEnter); 1193 OpenMPIRBuilder::LocationDescription OuterLoc(Builder.saveIP(), DL); 1194 1195 CanonicalLoopInfo *InnerLoop = nullptr; 1196 CallInst *InbetweenLead = nullptr; 1197 CallInst *InbetweenTrail = nullptr; 1198 CallInst *Call = nullptr; 1199 auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP, Value *OuterLC) { 1200 Builder.restoreIP(OuterCodeGenIP); 1201 InbetweenLead = 1202 createPrintfCall(Builder, "In-between lead i=%d\\n", {OuterLC}); 1203 1204 auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP, 1205 Value *InnerLC) { 1206 Builder.restoreIP(InnerCodeGenIP); 1207 Call = createPrintfCall(Builder, "body i=%d j=%d\\n", {OuterLC, InnerLC}); 1208 }; 1209 InnerLoop = OMPBuilder.createCanonicalLoop( 1210 Builder.saveIP(), InnerLoopBodyGenCB, InnerTripCount, "inner"); 1211 1212 Builder.restoreIP(InnerLoop->getAfterIP()); 1213 InbetweenTrail = 1214 createPrintfCall(Builder, "In-between trail i=%d\\n", {OuterLC}); 1215 }; 1216 CanonicalLoopInfo *OuterLoop = OMPBuilder.createCanonicalLoop( 1217 OuterLoc, OuterLoopBodyGenCB, OuterTripCount, "outer"); 1218 1219 // Finish the function. 1220 Builder.restoreIP(OuterLoop->getAfterIP()); 1221 Builder.CreateRetVoid(); 1222 1223 CanonicalLoopInfo *Collapsed = 1224 OMPBuilder.collapseLoops(DL, {OuterLoop, InnerLoop}, ComputeIP); 1225 1226 OMPBuilder.finalize(); 1227 EXPECT_FALSE(verifyModule(*M, &errs())); 1228 1229 // Verify control flow and BB order. 1230 BasicBlock *RefOrder[] = { 1231 Collapsed->getPreheader(), Collapsed->getHeader(), 1232 Collapsed->getCond(), Collapsed->getBody(), 1233 InbetweenLead->getParent(), Call->getParent(), 1234 InbetweenTrail->getParent(), Collapsed->getLatch(), 1235 Collapsed->getExit(), Collapsed->getAfter(), 1236 }; 1237 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1238 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1239 1240 // Verify the total trip count. 1241 auto *TripCount = cast<MulOperator>(Collapsed->getTripCount()); 1242 EXPECT_EQ(TripCount->getOperand(0), OuterTripCount); 1243 EXPECT_EQ(TripCount->getOperand(1), InnerTripCount); 1244 1245 // Verify the changed indvar. 1246 auto *OuterIV = cast<BinaryOperator>(Call->getOperand(1)); 1247 EXPECT_EQ(OuterIV->getOpcode(), Instruction::UDiv); 1248 EXPECT_EQ(OuterIV->getParent(), Collapsed->getBody()); 1249 EXPECT_EQ(OuterIV->getOperand(1), InnerTripCount); 1250 EXPECT_EQ(OuterIV->getOperand(0), Collapsed->getIndVar()); 1251 1252 auto *InnerIV = cast<BinaryOperator>(Call->getOperand(2)); 1253 EXPECT_EQ(InnerIV->getOpcode(), Instruction::URem); 1254 EXPECT_EQ(InnerIV->getParent(), Collapsed->getBody()); 1255 EXPECT_EQ(InnerIV->getOperand(0), Collapsed->getIndVar()); 1256 EXPECT_EQ(InnerIV->getOperand(1), InnerTripCount); 1257 1258 EXPECT_EQ(InbetweenLead->getOperand(1), OuterIV); 1259 EXPECT_EQ(InbetweenTrail->getOperand(1), OuterIV); 1260 } 1261 1262 TEST_F(OpenMPIRBuilderTest, TileSingleLoop) { 1263 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1264 OpenMPIRBuilder OMPBuilder(*M); 1265 OMPBuilder.initialize(); 1266 F->setName("func"); 1267 1268 IRBuilder<> Builder(BB); 1269 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1270 Value *TripCount = F->getArg(0); 1271 1272 BasicBlock *BodyCode = nullptr; 1273 Instruction *Call = nullptr; 1274 auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) { 1275 Builder.restoreIP(CodeGenIP); 1276 BodyCode = Builder.GetInsertBlock(); 1277 1278 // Add something that consumes the induction variable to the body. 1279 Call = createPrintfCall(Builder, "%d\\n", {LC}); 1280 }; 1281 CanonicalLoopInfo *Loop = 1282 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, TripCount); 1283 1284 // Finalize the function. 1285 Builder.restoreIP(Loop->getAfterIP()); 1286 Builder.CreateRetVoid(); 1287 1288 Instruction *OrigIndVar = Loop->getIndVar(); 1289 EXPECT_EQ(Call->getOperand(1), OrigIndVar); 1290 1291 // Tile the loop. 1292 Constant *TileSize = ConstantInt::get(Loop->getIndVarType(), APInt(32, 7)); 1293 std::vector<CanonicalLoopInfo *> GenLoops = 1294 OMPBuilder.tileLoops(DL, {Loop}, {TileSize}); 1295 1296 OMPBuilder.finalize(); 1297 EXPECT_FALSE(verifyModule(*M, &errs())); 1298 1299 EXPECT_EQ(GenLoops.size(), 2u); 1300 CanonicalLoopInfo *Floor = GenLoops[0]; 1301 CanonicalLoopInfo *Tile = GenLoops[1]; 1302 1303 BasicBlock *RefOrder[] = { 1304 Floor->getPreheader(), Floor->getHeader(), Floor->getCond(), 1305 Floor->getBody(), Tile->getPreheader(), Tile->getHeader(), 1306 Tile->getCond(), Tile->getBody(), BodyCode, 1307 Tile->getLatch(), Tile->getExit(), Tile->getAfter(), 1308 Floor->getLatch(), Floor->getExit(), Floor->getAfter(), 1309 }; 1310 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1311 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1312 1313 // Check the induction variable. 1314 EXPECT_EQ(Call->getParent(), BodyCode); 1315 auto *Shift = cast<AddOperator>(Call->getOperand(1)); 1316 EXPECT_EQ(cast<Instruction>(Shift)->getParent(), Tile->getBody()); 1317 EXPECT_EQ(Shift->getOperand(1), Tile->getIndVar()); 1318 auto *Scale = cast<MulOperator>(Shift->getOperand(0)); 1319 EXPECT_EQ(cast<Instruction>(Scale)->getParent(), Tile->getBody()); 1320 EXPECT_EQ(Scale->getOperand(0), TileSize); 1321 EXPECT_EQ(Scale->getOperand(1), Floor->getIndVar()); 1322 } 1323 1324 TEST_F(OpenMPIRBuilderTest, TileNestedLoops) { 1325 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1326 OpenMPIRBuilder OMPBuilder(*M); 1327 OMPBuilder.initialize(); 1328 F->setName("func"); 1329 1330 IRBuilder<> Builder(BB); 1331 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1332 Value *TripCount = F->getArg(0); 1333 Type *LCTy = TripCount->getType(); 1334 1335 BasicBlock *BodyCode = nullptr; 1336 CanonicalLoopInfo *InnerLoop = nullptr; 1337 auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP, 1338 llvm::Value *OuterLC) { 1339 auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP, 1340 llvm::Value *InnerLC) { 1341 Builder.restoreIP(InnerCodeGenIP); 1342 BodyCode = Builder.GetInsertBlock(); 1343 1344 // Add something that consumes the induction variables to the body. 1345 createPrintfCall(Builder, "i=%d j=%d\\n", {OuterLC, InnerLC}); 1346 }; 1347 InnerLoop = OMPBuilder.createCanonicalLoop( 1348 OuterCodeGenIP, InnerLoopBodyGenCB, TripCount, "inner"); 1349 }; 1350 CanonicalLoopInfo *OuterLoop = OMPBuilder.createCanonicalLoop( 1351 Loc, OuterLoopBodyGenCB, TripCount, "outer"); 1352 1353 // Finalize the function. 1354 Builder.restoreIP(OuterLoop->getAfterIP()); 1355 Builder.CreateRetVoid(); 1356 1357 // Tile to loop nest. 1358 Constant *OuterTileSize = ConstantInt::get(LCTy, APInt(32, 11)); 1359 Constant *InnerTileSize = ConstantInt::get(LCTy, APInt(32, 7)); 1360 std::vector<CanonicalLoopInfo *> GenLoops = OMPBuilder.tileLoops( 1361 DL, {OuterLoop, InnerLoop}, {OuterTileSize, InnerTileSize}); 1362 1363 OMPBuilder.finalize(); 1364 EXPECT_FALSE(verifyModule(*M, &errs())); 1365 1366 EXPECT_EQ(GenLoops.size(), 4u); 1367 CanonicalLoopInfo *Floor1 = GenLoops[0]; 1368 CanonicalLoopInfo *Floor2 = GenLoops[1]; 1369 CanonicalLoopInfo *Tile1 = GenLoops[2]; 1370 CanonicalLoopInfo *Tile2 = GenLoops[3]; 1371 1372 BasicBlock *RefOrder[] = { 1373 Floor1->getPreheader(), 1374 Floor1->getHeader(), 1375 Floor1->getCond(), 1376 Floor1->getBody(), 1377 Floor2->getPreheader(), 1378 Floor2->getHeader(), 1379 Floor2->getCond(), 1380 Floor2->getBody(), 1381 Tile1->getPreheader(), 1382 Tile1->getHeader(), 1383 Tile1->getCond(), 1384 Tile1->getBody(), 1385 Tile2->getPreheader(), 1386 Tile2->getHeader(), 1387 Tile2->getCond(), 1388 Tile2->getBody(), 1389 BodyCode, 1390 Tile2->getLatch(), 1391 Tile2->getExit(), 1392 Tile2->getAfter(), 1393 Tile1->getLatch(), 1394 Tile1->getExit(), 1395 Tile1->getAfter(), 1396 Floor2->getLatch(), 1397 Floor2->getExit(), 1398 Floor2->getAfter(), 1399 Floor1->getLatch(), 1400 Floor1->getExit(), 1401 Floor1->getAfter(), 1402 }; 1403 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1404 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1405 } 1406 1407 TEST_F(OpenMPIRBuilderTest, TileNestedLoopsWithBounds) { 1408 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1409 OpenMPIRBuilder OMPBuilder(*M); 1410 OMPBuilder.initialize(); 1411 F->setName("func"); 1412 1413 IRBuilder<> Builder(BB); 1414 Value *TripCount = F->getArg(0); 1415 Type *LCTy = TripCount->getType(); 1416 1417 Value *OuterStartVal = ConstantInt::get(LCTy, 2); 1418 Value *OuterStopVal = TripCount; 1419 Value *OuterStep = ConstantInt::get(LCTy, 5); 1420 Value *InnerStartVal = ConstantInt::get(LCTy, 13); 1421 Value *InnerStopVal = TripCount; 1422 Value *InnerStep = ConstantInt::get(LCTy, 3); 1423 1424 // Fix an insertion point for ComputeIP. 1425 BasicBlock *LoopNextEnter = 1426 BasicBlock::Create(M->getContext(), "loopnest.enter", F, 1427 Builder.GetInsertBlock()->getNextNode()); 1428 BranchInst *EnterBr = Builder.CreateBr(LoopNextEnter); 1429 InsertPointTy ComputeIP{EnterBr->getParent(), EnterBr->getIterator()}; 1430 1431 InsertPointTy LoopIP{LoopNextEnter, LoopNextEnter->begin()}; 1432 OpenMPIRBuilder::LocationDescription Loc({LoopIP, DL}); 1433 1434 BasicBlock *BodyCode = nullptr; 1435 CanonicalLoopInfo *InnerLoop = nullptr; 1436 CallInst *Call = nullptr; 1437 auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP, 1438 llvm::Value *OuterLC) { 1439 auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP, 1440 llvm::Value *InnerLC) { 1441 Builder.restoreIP(InnerCodeGenIP); 1442 BodyCode = Builder.GetInsertBlock(); 1443 1444 // Add something that consumes the induction variable to the body. 1445 Call = createPrintfCall(Builder, "i=%d j=%d\\n", {OuterLC, InnerLC}); 1446 }; 1447 InnerLoop = OMPBuilder.createCanonicalLoop( 1448 OuterCodeGenIP, InnerLoopBodyGenCB, InnerStartVal, InnerStopVal, 1449 InnerStep, false, false, ComputeIP, "inner"); 1450 }; 1451 CanonicalLoopInfo *OuterLoop = OMPBuilder.createCanonicalLoop( 1452 Loc, OuterLoopBodyGenCB, OuterStartVal, OuterStopVal, OuterStep, false, 1453 false, ComputeIP, "outer"); 1454 1455 // Finalize the function 1456 Builder.restoreIP(OuterLoop->getAfterIP()); 1457 Builder.CreateRetVoid(); 1458 1459 // Tile the loop nest. 1460 Constant *TileSize0 = ConstantInt::get(LCTy, APInt(32, 11)); 1461 Constant *TileSize1 = ConstantInt::get(LCTy, APInt(32, 7)); 1462 std::vector<CanonicalLoopInfo *> GenLoops = 1463 OMPBuilder.tileLoops(DL, {OuterLoop, InnerLoop}, {TileSize0, TileSize1}); 1464 1465 OMPBuilder.finalize(); 1466 EXPECT_FALSE(verifyModule(*M, &errs())); 1467 1468 EXPECT_EQ(GenLoops.size(), 4u); 1469 CanonicalLoopInfo *Floor0 = GenLoops[0]; 1470 CanonicalLoopInfo *Floor1 = GenLoops[1]; 1471 CanonicalLoopInfo *Tile0 = GenLoops[2]; 1472 CanonicalLoopInfo *Tile1 = GenLoops[3]; 1473 1474 BasicBlock *RefOrder[] = { 1475 Floor0->getPreheader(), 1476 Floor0->getHeader(), 1477 Floor0->getCond(), 1478 Floor0->getBody(), 1479 Floor1->getPreheader(), 1480 Floor1->getHeader(), 1481 Floor1->getCond(), 1482 Floor1->getBody(), 1483 Tile0->getPreheader(), 1484 Tile0->getHeader(), 1485 Tile0->getCond(), 1486 Tile0->getBody(), 1487 Tile1->getPreheader(), 1488 Tile1->getHeader(), 1489 Tile1->getCond(), 1490 Tile1->getBody(), 1491 BodyCode, 1492 Tile1->getLatch(), 1493 Tile1->getExit(), 1494 Tile1->getAfter(), 1495 Tile0->getLatch(), 1496 Tile0->getExit(), 1497 Tile0->getAfter(), 1498 Floor1->getLatch(), 1499 Floor1->getExit(), 1500 Floor1->getAfter(), 1501 Floor0->getLatch(), 1502 Floor0->getExit(), 1503 Floor0->getAfter(), 1504 }; 1505 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1506 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1507 1508 EXPECT_EQ(Call->getParent(), BodyCode); 1509 1510 auto *RangeShift0 = cast<AddOperator>(Call->getOperand(1)); 1511 EXPECT_EQ(RangeShift0->getOperand(1), OuterStartVal); 1512 auto *RangeScale0 = cast<MulOperator>(RangeShift0->getOperand(0)); 1513 EXPECT_EQ(RangeScale0->getOperand(1), OuterStep); 1514 auto *TileShift0 = cast<AddOperator>(RangeScale0->getOperand(0)); 1515 EXPECT_EQ(cast<Instruction>(TileShift0)->getParent(), Tile1->getBody()); 1516 EXPECT_EQ(TileShift0->getOperand(1), Tile0->getIndVar()); 1517 auto *TileScale0 = cast<MulOperator>(TileShift0->getOperand(0)); 1518 EXPECT_EQ(cast<Instruction>(TileScale0)->getParent(), Tile1->getBody()); 1519 EXPECT_EQ(TileScale0->getOperand(0), TileSize0); 1520 EXPECT_EQ(TileScale0->getOperand(1), Floor0->getIndVar()); 1521 1522 auto *RangeShift1 = cast<AddOperator>(Call->getOperand(2)); 1523 EXPECT_EQ(cast<Instruction>(RangeShift1)->getParent(), BodyCode); 1524 EXPECT_EQ(RangeShift1->getOperand(1), InnerStartVal); 1525 auto *RangeScale1 = cast<MulOperator>(RangeShift1->getOperand(0)); 1526 EXPECT_EQ(cast<Instruction>(RangeScale1)->getParent(), BodyCode); 1527 EXPECT_EQ(RangeScale1->getOperand(1), InnerStep); 1528 auto *TileShift1 = cast<AddOperator>(RangeScale1->getOperand(0)); 1529 EXPECT_EQ(cast<Instruction>(TileShift1)->getParent(), Tile1->getBody()); 1530 EXPECT_EQ(TileShift1->getOperand(1), Tile1->getIndVar()); 1531 auto *TileScale1 = cast<MulOperator>(TileShift1->getOperand(0)); 1532 EXPECT_EQ(cast<Instruction>(TileScale1)->getParent(), Tile1->getBody()); 1533 EXPECT_EQ(TileScale1->getOperand(0), TileSize1); 1534 EXPECT_EQ(TileScale1->getOperand(1), Floor1->getIndVar()); 1535 } 1536 1537 TEST_F(OpenMPIRBuilderTest, TileSingleLoopCounts) { 1538 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1539 OpenMPIRBuilder OMPBuilder(*M); 1540 OMPBuilder.initialize(); 1541 IRBuilder<> Builder(BB); 1542 1543 // Create a loop, tile it, and extract its trip count. All input values are 1544 // constant and IRBuilder evaluates all-constant arithmetic inplace, such that 1545 // the floor trip count itself will be a ConstantInt. Unfortunately we cannot 1546 // do the same for the tile loop. 1547 auto GetFloorCount = [&](int64_t Start, int64_t Stop, int64_t Step, 1548 bool IsSigned, bool InclusiveStop, 1549 int64_t TileSize) -> uint64_t { 1550 OpenMPIRBuilder::LocationDescription Loc(Builder.saveIP(), DL); 1551 Type *LCTy = Type::getInt16Ty(Ctx); 1552 Value *StartVal = ConstantInt::get(LCTy, Start); 1553 Value *StopVal = ConstantInt::get(LCTy, Stop); 1554 Value *StepVal = ConstantInt::get(LCTy, Step); 1555 1556 // Generate a loop. 1557 auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) {}; 1558 CanonicalLoopInfo *Loop = 1559 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, StartVal, StopVal, 1560 StepVal, IsSigned, InclusiveStop); 1561 1562 // Tile the loop. 1563 Value *TileSizeVal = ConstantInt::get(LCTy, TileSize); 1564 std::vector<CanonicalLoopInfo *> GenLoops = 1565 OMPBuilder.tileLoops(Loc.DL, {Loop}, {TileSizeVal}); 1566 1567 // Set the insertion pointer to after loop, where the next loop will be 1568 // emitted. 1569 Builder.restoreIP(Loop->getAfterIP()); 1570 1571 // Extract the trip count. 1572 CanonicalLoopInfo *FloorLoop = GenLoops[0]; 1573 Value *FloorTripCount = FloorLoop->getTripCount(); 1574 return cast<ConstantInt>(FloorTripCount)->getValue().getZExtValue(); 1575 }; 1576 1577 // Empty iteration domain. 1578 EXPECT_EQ(GetFloorCount(0, 0, 1, false, false, 7), 0u); 1579 EXPECT_EQ(GetFloorCount(0, -1, 1, false, true, 7), 0u); 1580 EXPECT_EQ(GetFloorCount(-1, -1, -1, true, false, 7), 0u); 1581 EXPECT_EQ(GetFloorCount(-1, 0, -1, true, true, 7), 0u); 1582 EXPECT_EQ(GetFloorCount(-1, -1, 3, true, false, 7), 0u); 1583 1584 // Only complete tiles. 1585 EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u); 1586 EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u); 1587 EXPECT_EQ(GetFloorCount(1, 15, 1, false, false, 7), 2u); 1588 EXPECT_EQ(GetFloorCount(0, -14, -1, true, false, 7), 2u); 1589 EXPECT_EQ(GetFloorCount(-1, -14, -1, true, true, 7), 2u); 1590 EXPECT_EQ(GetFloorCount(0, 3 * 7 * 2, 3, false, false, 7), 2u); 1591 1592 // Only a partial tile. 1593 EXPECT_EQ(GetFloorCount(0, 1, 1, false, false, 7), 1u); 1594 EXPECT_EQ(GetFloorCount(0, 6, 1, false, false, 7), 1u); 1595 EXPECT_EQ(GetFloorCount(-1, 1, 3, true, false, 7), 1u); 1596 EXPECT_EQ(GetFloorCount(-1, -2, -1, true, false, 7), 1u); 1597 EXPECT_EQ(GetFloorCount(0, 2, 3, false, false, 7), 1u); 1598 1599 // Complete and partial tiles. 1600 EXPECT_EQ(GetFloorCount(0, 13, 1, false, false, 7), 2u); 1601 EXPECT_EQ(GetFloorCount(0, 15, 1, false, false, 7), 3u); 1602 EXPECT_EQ(GetFloorCount(-1, -14, -1, true, false, 7), 2u); 1603 EXPECT_EQ(GetFloorCount(0, 3 * 7 * 5 - 1, 3, false, false, 7), 5u); 1604 EXPECT_EQ(GetFloorCount(-1, -3 * 7 * 5, -3, true, false, 7), 5u); 1605 1606 // Close to 16-bit integer range. 1607 EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 1), 0xFFFFu); 1608 EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 7), 0xFFFFu / 7 + 1); 1609 EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, true, 7), 0xFFFFu / 7 + 1); 1610 EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 7), 0xFFFFu / 7 + 1); 1611 EXPECT_EQ(GetFloorCount(-0x7FFF, 0x7FFF, 1, true, true, 7), 0xFFFFu / 7 + 1); 1612 EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, false, 0xFFFF), 1u); 1613 EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 0xFFFF), 1u); 1614 1615 // Finalize the function. 1616 Builder.CreateRetVoid(); 1617 OMPBuilder.finalize(); 1618 1619 EXPECT_FALSE(verifyModule(*M, &errs())); 1620 } 1621 1622 TEST_F(OpenMPIRBuilderTest, StaticWorkShareLoop) { 1623 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1624 OpenMPIRBuilder OMPBuilder(*M); 1625 OMPBuilder.initialize(); 1626 IRBuilder<> Builder(BB); 1627 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1628 1629 Type *LCTy = Type::getInt32Ty(Ctx); 1630 Value *StartVal = ConstantInt::get(LCTy, 10); 1631 Value *StopVal = ConstantInt::get(LCTy, 52); 1632 Value *StepVal = ConstantInt::get(LCTy, 2); 1633 auto LoopBodyGen = [&](InsertPointTy, llvm::Value *) {}; 1634 1635 CanonicalLoopInfo *CLI = OMPBuilder.createCanonicalLoop( 1636 Loc, LoopBodyGen, StartVal, StopVal, StepVal, 1637 /*IsSigned=*/false, /*InclusiveStop=*/false); 1638 1639 Builder.SetInsertPoint(BB, BB->getFirstInsertionPt()); 1640 InsertPointTy AllocaIP = Builder.saveIP(); 1641 1642 CLI = OMPBuilder.createStaticWorkshareLoop(Loc, CLI, AllocaIP, 1643 /*NeedsBarrier=*/true); 1644 auto AllocaIter = BB->begin(); 1645 ASSERT_GE(std::distance(BB->begin(), BB->end()), 4); 1646 AllocaInst *PLastIter = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1647 AllocaInst *PLowerBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1648 AllocaInst *PUpperBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1649 AllocaInst *PStride = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1650 EXPECT_NE(PLastIter, nullptr); 1651 EXPECT_NE(PLowerBound, nullptr); 1652 EXPECT_NE(PUpperBound, nullptr); 1653 EXPECT_NE(PStride, nullptr); 1654 1655 auto PreheaderIter = CLI->getPreheader()->begin(); 1656 ASSERT_GE( 1657 std::distance(CLI->getPreheader()->begin(), CLI->getPreheader()->end()), 1658 7); 1659 StoreInst *LowerBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1660 StoreInst *UpperBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1661 StoreInst *StrideStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1662 ASSERT_NE(LowerBoundStore, nullptr); 1663 ASSERT_NE(UpperBoundStore, nullptr); 1664 ASSERT_NE(StrideStore, nullptr); 1665 1666 auto *OrigLowerBound = 1667 dyn_cast<ConstantInt>(LowerBoundStore->getValueOperand()); 1668 auto *OrigUpperBound = 1669 dyn_cast<ConstantInt>(UpperBoundStore->getValueOperand()); 1670 auto *OrigStride = dyn_cast<ConstantInt>(StrideStore->getValueOperand()); 1671 ASSERT_NE(OrigLowerBound, nullptr); 1672 ASSERT_NE(OrigUpperBound, nullptr); 1673 ASSERT_NE(OrigStride, nullptr); 1674 EXPECT_EQ(OrigLowerBound->getValue(), 0); 1675 EXPECT_EQ(OrigUpperBound->getValue(), 20); 1676 EXPECT_EQ(OrigStride->getValue(), 1); 1677 1678 // Check that the loop IV is updated to account for the lower bound returned 1679 // by the OpenMP runtime call. 1680 BinaryOperator *Add = dyn_cast<BinaryOperator>(&CLI->getBody()->front()); 1681 EXPECT_EQ(Add->getOperand(0), CLI->getIndVar()); 1682 auto *LoadedLowerBound = dyn_cast<LoadInst>(Add->getOperand(1)); 1683 ASSERT_NE(LoadedLowerBound, nullptr); 1684 EXPECT_EQ(LoadedLowerBound->getPointerOperand(), PLowerBound); 1685 1686 // Check that the trip count is updated to account for the lower and upper 1687 // bounds return by the OpenMP runtime call. 1688 auto *AddOne = dyn_cast<Instruction>(CLI->getTripCount()); 1689 ASSERT_NE(AddOne, nullptr); 1690 ASSERT_TRUE(AddOne->isBinaryOp()); 1691 auto *One = dyn_cast<ConstantInt>(AddOne->getOperand(1)); 1692 ASSERT_NE(One, nullptr); 1693 EXPECT_EQ(One->getValue(), 1); 1694 auto *Difference = dyn_cast<Instruction>(AddOne->getOperand(0)); 1695 ASSERT_NE(Difference, nullptr); 1696 ASSERT_TRUE(Difference->isBinaryOp()); 1697 EXPECT_EQ(Difference->getOperand(1), LoadedLowerBound); 1698 auto *LoadedUpperBound = dyn_cast<LoadInst>(Difference->getOperand(0)); 1699 ASSERT_NE(LoadedUpperBound, nullptr); 1700 EXPECT_EQ(LoadedUpperBound->getPointerOperand(), PUpperBound); 1701 1702 // The original loop iterator should only be used in the condition, in the 1703 // increment and in the statement that adds the lower bound to it. 1704 Value *IV = CLI->getIndVar(); 1705 EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3); 1706 1707 // The exit block should contain the "fini" call and the barrier call, 1708 // plus the call to obtain the thread ID. 1709 BasicBlock *ExitBlock = CLI->getExit(); 1710 size_t NumCallsInExitBlock = 1711 count_if(*ExitBlock, [](Instruction &I) { return isa<CallInst>(I); }); 1712 EXPECT_EQ(NumCallsInExitBlock, 3u); 1713 } 1714 1715 TEST_P(OpenMPIRBuilderTestWithParams, DynamicWorkShareLoop) { 1716 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1717 OpenMPIRBuilder OMPBuilder(*M); 1718 OMPBuilder.initialize(); 1719 IRBuilder<> Builder(BB); 1720 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1721 1722 omp::OMPScheduleType SchedType = GetParam(); 1723 uint32_t ChunkSize = 1; 1724 switch (SchedType & ~omp::OMPScheduleType::ModifierMask) { 1725 case omp::OMPScheduleType::DynamicChunked: 1726 case omp::OMPScheduleType::GuidedChunked: 1727 ChunkSize = 7; 1728 break; 1729 case omp::OMPScheduleType::Auto: 1730 case omp::OMPScheduleType::Runtime: 1731 ChunkSize = 1; 1732 break; 1733 default: 1734 assert(0 && "unknown type for this test"); 1735 break; 1736 } 1737 1738 Type *LCTy = Type::getInt32Ty(Ctx); 1739 Value *StartVal = ConstantInt::get(LCTy, 10); 1740 Value *StopVal = ConstantInt::get(LCTy, 52); 1741 Value *StepVal = ConstantInt::get(LCTy, 2); 1742 Value *ChunkVal = ConstantInt::get(LCTy, ChunkSize); 1743 auto LoopBodyGen = [&](InsertPointTy, llvm::Value *) {}; 1744 1745 CanonicalLoopInfo *CLI = OMPBuilder.createCanonicalLoop( 1746 Loc, LoopBodyGen, StartVal, StopVal, StepVal, 1747 /*IsSigned=*/false, /*InclusiveStop=*/false); 1748 1749 Builder.SetInsertPoint(BB, BB->getFirstInsertionPt()); 1750 InsertPointTy AllocaIP = Builder.saveIP(); 1751 1752 // Collect all the info from CLI, as it isn't usable after the call to 1753 // createDynamicWorkshareLoop. 1754 InsertPointTy AfterIP = CLI->getAfterIP(); 1755 BasicBlock *Preheader = CLI->getPreheader(); 1756 BasicBlock *ExitBlock = CLI->getExit(); 1757 Value *IV = CLI->getIndVar(); 1758 1759 InsertPointTy EndIP = 1760 OMPBuilder.createDynamicWorkshareLoop(Loc, CLI, AllocaIP, SchedType, 1761 /*NeedsBarrier=*/true, ChunkVal); 1762 // The returned value should be the "after" point. 1763 ASSERT_EQ(EndIP.getBlock(), AfterIP.getBlock()); 1764 ASSERT_EQ(EndIP.getPoint(), AfterIP.getPoint()); 1765 1766 auto AllocaIter = BB->begin(); 1767 ASSERT_GE(std::distance(BB->begin(), BB->end()), 4); 1768 AllocaInst *PLastIter = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1769 AllocaInst *PLowerBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1770 AllocaInst *PUpperBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1771 AllocaInst *PStride = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1772 EXPECT_NE(PLastIter, nullptr); 1773 EXPECT_NE(PLowerBound, nullptr); 1774 EXPECT_NE(PUpperBound, nullptr); 1775 EXPECT_NE(PStride, nullptr); 1776 1777 auto PreheaderIter = Preheader->begin(); 1778 ASSERT_GE(std::distance(Preheader->begin(), Preheader->end()), 6); 1779 StoreInst *LowerBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1780 StoreInst *UpperBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1781 StoreInst *StrideStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1782 ASSERT_NE(LowerBoundStore, nullptr); 1783 ASSERT_NE(UpperBoundStore, nullptr); 1784 ASSERT_NE(StrideStore, nullptr); 1785 1786 CallInst *ThreadIdCall = dyn_cast<CallInst>(&*(PreheaderIter++)); 1787 ASSERT_NE(ThreadIdCall, nullptr); 1788 EXPECT_EQ(ThreadIdCall->getCalledFunction()->getName(), 1789 "__kmpc_global_thread_num"); 1790 1791 CallInst *InitCall = dyn_cast<CallInst>(&*PreheaderIter); 1792 1793 ASSERT_NE(InitCall, nullptr); 1794 EXPECT_EQ(InitCall->getCalledFunction()->getName(), 1795 "__kmpc_dispatch_init_4u"); 1796 EXPECT_EQ(InitCall->getNumArgOperands(), 7U); 1797 EXPECT_EQ(InitCall->getArgOperand(6), ConstantInt::get(LCTy, ChunkSize)); 1798 ConstantInt *SchedVal = cast<ConstantInt>(InitCall->getArgOperand(2)); 1799 EXPECT_EQ(SchedVal->getValue(), static_cast<uint64_t>(SchedType)); 1800 1801 ConstantInt *OrigLowerBound = 1802 dyn_cast<ConstantInt>(LowerBoundStore->getValueOperand()); 1803 ConstantInt *OrigUpperBound = 1804 dyn_cast<ConstantInt>(UpperBoundStore->getValueOperand()); 1805 ConstantInt *OrigStride = 1806 dyn_cast<ConstantInt>(StrideStore->getValueOperand()); 1807 ASSERT_NE(OrigLowerBound, nullptr); 1808 ASSERT_NE(OrigUpperBound, nullptr); 1809 ASSERT_NE(OrigStride, nullptr); 1810 EXPECT_EQ(OrigLowerBound->getValue(), 1); 1811 EXPECT_EQ(OrigUpperBound->getValue(), 21); 1812 EXPECT_EQ(OrigStride->getValue(), 1); 1813 1814 // The original loop iterator should only be used in the condition, in the 1815 // increment and in the statement that adds the lower bound to it. 1816 EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3); 1817 1818 // The exit block should contain the barrier call, plus the call to obtain 1819 // the thread ID. 1820 size_t NumCallsInExitBlock = 1821 count_if(*ExitBlock, [](Instruction &I) { return isa<CallInst>(I); }); 1822 EXPECT_EQ(NumCallsInExitBlock, 2u); 1823 1824 // Add a termination to our block and check that it is internally consistent. 1825 Builder.restoreIP(EndIP); 1826 Builder.CreateRetVoid(); 1827 OMPBuilder.finalize(); 1828 EXPECT_FALSE(verifyModule(*M, &errs())); 1829 } 1830 1831 INSTANTIATE_TEST_SUITE_P( 1832 OpenMPWSLoopSchedulingTypes, OpenMPIRBuilderTestWithParams, 1833 ::testing::Values(omp::OMPScheduleType::DynamicChunked, 1834 omp::OMPScheduleType::GuidedChunked, 1835 omp::OMPScheduleType::Auto, omp::OMPScheduleType::Runtime, 1836 omp::OMPScheduleType::DynamicChunked | 1837 omp::OMPScheduleType::ModifierMonotonic, 1838 omp::OMPScheduleType::DynamicChunked | 1839 omp::OMPScheduleType::ModifierNonmonotonic, 1840 omp::OMPScheduleType::GuidedChunked | 1841 omp::OMPScheduleType::ModifierMonotonic, 1842 omp::OMPScheduleType::GuidedChunked | 1843 omp::OMPScheduleType::ModifierNonmonotonic, 1844 omp::OMPScheduleType::Auto | 1845 omp::OMPScheduleType::ModifierMonotonic, 1846 omp::OMPScheduleType::Runtime | 1847 omp::OMPScheduleType::ModifierMonotonic)); 1848 1849 TEST_F(OpenMPIRBuilderTest, MasterDirective) { 1850 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1851 OpenMPIRBuilder OMPBuilder(*M); 1852 OMPBuilder.initialize(); 1853 F->setName("func"); 1854 IRBuilder<> Builder(BB); 1855 1856 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1857 1858 AllocaInst *PrivAI = nullptr; 1859 1860 BasicBlock *EntryBB = nullptr; 1861 BasicBlock *ExitBB = nullptr; 1862 BasicBlock *ThenBB = nullptr; 1863 1864 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 1865 BasicBlock &FiniBB) { 1866 if (AllocaIP.isSet()) 1867 Builder.restoreIP(AllocaIP); 1868 else 1869 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); 1870 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 1871 Builder.CreateStore(F->arg_begin(), PrivAI); 1872 1873 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 1874 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 1875 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 1876 1877 Builder.restoreIP(CodeGenIP); 1878 1879 // collect some info for checks later 1880 ExitBB = FiniBB.getUniqueSuccessor(); 1881 ThenBB = Builder.GetInsertBlock(); 1882 EntryBB = ThenBB->getUniquePredecessor(); 1883 1884 // simple instructions for body 1885 Value *PrivLoad = Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, 1886 "local.use"); 1887 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 1888 }; 1889 1890 auto FiniCB = [&](InsertPointTy IP) { 1891 BasicBlock *IPBB = IP.getBlock(); 1892 EXPECT_NE(IPBB->end(), IP.getPoint()); 1893 }; 1894 1895 Builder.restoreIP(OMPBuilder.createMaster(Builder, BodyGenCB, FiniCB)); 1896 Value *EntryBBTI = EntryBB->getTerminator(); 1897 EXPECT_NE(EntryBBTI, nullptr); 1898 EXPECT_TRUE(isa<BranchInst>(EntryBBTI)); 1899 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator()); 1900 EXPECT_TRUE(EntryBr->isConditional()); 1901 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); 1902 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); 1903 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); 1904 1905 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition()); 1906 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0))); 1907 1908 CallInst *MasterEntryCI = cast<CallInst>(CondInst->getOperand(0)); 1909 EXPECT_EQ(MasterEntryCI->getNumArgOperands(), 2U); 1910 EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master"); 1911 EXPECT_TRUE(isa<GlobalVariable>(MasterEntryCI->getArgOperand(0))); 1912 1913 CallInst *MasterEndCI = nullptr; 1914 for (auto &FI : *ThenBB) { 1915 Instruction *cur = &FI; 1916 if (isa<CallInst>(cur)) { 1917 MasterEndCI = cast<CallInst>(cur); 1918 if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master") 1919 break; 1920 MasterEndCI = nullptr; 1921 } 1922 } 1923 EXPECT_NE(MasterEndCI, nullptr); 1924 EXPECT_EQ(MasterEndCI->getNumArgOperands(), 2U); 1925 EXPECT_TRUE(isa<GlobalVariable>(MasterEndCI->getArgOperand(0))); 1926 EXPECT_EQ(MasterEndCI->getArgOperand(1), MasterEntryCI->getArgOperand(1)); 1927 } 1928 1929 TEST_F(OpenMPIRBuilderTest, MaskedDirective) { 1930 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1931 OpenMPIRBuilder OMPBuilder(*M); 1932 OMPBuilder.initialize(); 1933 F->setName("func"); 1934 IRBuilder<> Builder(BB); 1935 1936 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1937 1938 AllocaInst *PrivAI = nullptr; 1939 1940 BasicBlock *EntryBB = nullptr; 1941 BasicBlock *ExitBB = nullptr; 1942 BasicBlock *ThenBB = nullptr; 1943 1944 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 1945 BasicBlock &FiniBB) { 1946 if (AllocaIP.isSet()) 1947 Builder.restoreIP(AllocaIP); 1948 else 1949 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); 1950 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 1951 Builder.CreateStore(F->arg_begin(), PrivAI); 1952 1953 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 1954 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 1955 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 1956 1957 Builder.restoreIP(CodeGenIP); 1958 1959 // collect some info for checks later 1960 ExitBB = FiniBB.getUniqueSuccessor(); 1961 ThenBB = Builder.GetInsertBlock(); 1962 EntryBB = ThenBB->getUniquePredecessor(); 1963 1964 // simple instructions for body 1965 Value *PrivLoad = 1966 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 1967 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 1968 }; 1969 1970 auto FiniCB = [&](InsertPointTy IP) { 1971 BasicBlock *IPBB = IP.getBlock(); 1972 EXPECT_NE(IPBB->end(), IP.getPoint()); 1973 }; 1974 1975 Constant *Filter = ConstantInt::get(Type::getInt32Ty(M->getContext()), 0); 1976 Builder.restoreIP( 1977 OMPBuilder.createMasked(Builder, BodyGenCB, FiniCB, Filter)); 1978 Value *EntryBBTI = EntryBB->getTerminator(); 1979 EXPECT_NE(EntryBBTI, nullptr); 1980 EXPECT_TRUE(isa<BranchInst>(EntryBBTI)); 1981 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator()); 1982 EXPECT_TRUE(EntryBr->isConditional()); 1983 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); 1984 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); 1985 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); 1986 1987 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition()); 1988 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0))); 1989 1990 CallInst *MaskedEntryCI = cast<CallInst>(CondInst->getOperand(0)); 1991 EXPECT_EQ(MaskedEntryCI->getNumArgOperands(), 3U); 1992 EXPECT_EQ(MaskedEntryCI->getCalledFunction()->getName(), "__kmpc_masked"); 1993 EXPECT_TRUE(isa<GlobalVariable>(MaskedEntryCI->getArgOperand(0))); 1994 1995 CallInst *MaskedEndCI = nullptr; 1996 for (auto &FI : *ThenBB) { 1997 Instruction *cur = &FI; 1998 if (isa<CallInst>(cur)) { 1999 MaskedEndCI = cast<CallInst>(cur); 2000 if (MaskedEndCI->getCalledFunction()->getName() == "__kmpc_end_masked") 2001 break; 2002 MaskedEndCI = nullptr; 2003 } 2004 } 2005 EXPECT_NE(MaskedEndCI, nullptr); 2006 EXPECT_EQ(MaskedEndCI->getNumArgOperands(), 2U); 2007 EXPECT_TRUE(isa<GlobalVariable>(MaskedEndCI->getArgOperand(0))); 2008 EXPECT_EQ(MaskedEndCI->getArgOperand(1), MaskedEntryCI->getArgOperand(1)); 2009 } 2010 2011 TEST_F(OpenMPIRBuilderTest, CriticalDirective) { 2012 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2013 OpenMPIRBuilder OMPBuilder(*M); 2014 OMPBuilder.initialize(); 2015 F->setName("func"); 2016 IRBuilder<> Builder(BB); 2017 2018 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2019 2020 AllocaInst *PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2021 2022 BasicBlock *EntryBB = nullptr; 2023 2024 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2025 BasicBlock &FiniBB) { 2026 // collect some info for checks later 2027 EntryBB = FiniBB.getUniquePredecessor(); 2028 2029 // actual start for bodyCB 2030 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2031 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2032 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2033 EXPECT_EQ(EntryBB, CodeGenIPBB); 2034 2035 // body begin 2036 Builder.restoreIP(CodeGenIP); 2037 Builder.CreateStore(F->arg_begin(), PrivAI); 2038 Value *PrivLoad = Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, 2039 "local.use"); 2040 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2041 }; 2042 2043 auto FiniCB = [&](InsertPointTy IP) { 2044 BasicBlock *IPBB = IP.getBlock(); 2045 EXPECT_NE(IPBB->end(), IP.getPoint()); 2046 }; 2047 2048 Builder.restoreIP(OMPBuilder.createCritical(Builder, BodyGenCB, FiniCB, 2049 "testCRT", nullptr)); 2050 2051 Value *EntryBBTI = EntryBB->getTerminator(); 2052 EXPECT_EQ(EntryBBTI, nullptr); 2053 2054 CallInst *CriticalEntryCI = nullptr; 2055 for (auto &EI : *EntryBB) { 2056 Instruction *cur = &EI; 2057 if (isa<CallInst>(cur)) { 2058 CriticalEntryCI = cast<CallInst>(cur); 2059 if (CriticalEntryCI->getCalledFunction()->getName() == "__kmpc_critical") 2060 break; 2061 CriticalEntryCI = nullptr; 2062 } 2063 } 2064 EXPECT_NE(CriticalEntryCI, nullptr); 2065 EXPECT_EQ(CriticalEntryCI->getNumArgOperands(), 3U); 2066 EXPECT_EQ(CriticalEntryCI->getCalledFunction()->getName(), "__kmpc_critical"); 2067 EXPECT_TRUE(isa<GlobalVariable>(CriticalEntryCI->getArgOperand(0))); 2068 2069 CallInst *CriticalEndCI = nullptr; 2070 for (auto &FI : *EntryBB) { 2071 Instruction *cur = &FI; 2072 if (isa<CallInst>(cur)) { 2073 CriticalEndCI = cast<CallInst>(cur); 2074 if (CriticalEndCI->getCalledFunction()->getName() == 2075 "__kmpc_end_critical") 2076 break; 2077 CriticalEndCI = nullptr; 2078 } 2079 } 2080 EXPECT_NE(CriticalEndCI, nullptr); 2081 EXPECT_EQ(CriticalEndCI->getNumArgOperands(), 3U); 2082 EXPECT_TRUE(isa<GlobalVariable>(CriticalEndCI->getArgOperand(0))); 2083 EXPECT_EQ(CriticalEndCI->getArgOperand(1), CriticalEntryCI->getArgOperand(1)); 2084 PointerType *CriticalNamePtrTy = 2085 PointerType::getUnqual(ArrayType::get(Type::getInt32Ty(Ctx), 8)); 2086 EXPECT_EQ(CriticalEndCI->getArgOperand(2), CriticalEntryCI->getArgOperand(2)); 2087 EXPECT_EQ(CriticalEndCI->getArgOperand(2)->getType(), CriticalNamePtrTy); 2088 } 2089 2090 TEST_F(OpenMPIRBuilderTest, CopyinBlocks) { 2091 OpenMPIRBuilder OMPBuilder(*M); 2092 OMPBuilder.initialize(); 2093 F->setName("func"); 2094 IRBuilder<> Builder(BB); 2095 2096 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2097 2098 IntegerType* Int32 = Type::getInt32Ty(M->getContext()); 2099 AllocaInst* MasterAddress = Builder.CreateAlloca(Int32->getPointerTo()); 2100 AllocaInst* PrivAddress = Builder.CreateAlloca(Int32->getPointerTo()); 2101 2102 BasicBlock *EntryBB = BB; 2103 2104 OMPBuilder.createCopyinClauseBlocks(Builder.saveIP(), MasterAddress, 2105 PrivAddress, Int32, /*BranchtoEnd*/ true); 2106 2107 BranchInst* EntryBr = dyn_cast_or_null<BranchInst>(EntryBB->getTerminator()); 2108 2109 EXPECT_NE(EntryBr, nullptr); 2110 EXPECT_TRUE(EntryBr->isConditional()); 2111 2112 BasicBlock* NotMasterBB = EntryBr->getSuccessor(0); 2113 BasicBlock* CopyinEnd = EntryBr->getSuccessor(1); 2114 CmpInst* CMP = dyn_cast_or_null<CmpInst>(EntryBr->getCondition()); 2115 2116 EXPECT_NE(CMP, nullptr); 2117 EXPECT_NE(NotMasterBB, nullptr); 2118 EXPECT_NE(CopyinEnd, nullptr); 2119 2120 BranchInst* NotMasterBr = dyn_cast_or_null<BranchInst>(NotMasterBB->getTerminator()); 2121 EXPECT_NE(NotMasterBr, nullptr); 2122 EXPECT_FALSE(NotMasterBr->isConditional()); 2123 EXPECT_EQ(CopyinEnd,NotMasterBr->getSuccessor(0)); 2124 } 2125 2126 TEST_F(OpenMPIRBuilderTest, SingleDirective) { 2127 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2128 OpenMPIRBuilder OMPBuilder(*M); 2129 OMPBuilder.initialize(); 2130 F->setName("func"); 2131 IRBuilder<> Builder(BB); 2132 2133 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2134 2135 AllocaInst *PrivAI = nullptr; 2136 2137 BasicBlock *EntryBB = nullptr; 2138 BasicBlock *ExitBB = nullptr; 2139 BasicBlock *ThenBB = nullptr; 2140 2141 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2142 BasicBlock &FiniBB) { 2143 if (AllocaIP.isSet()) 2144 Builder.restoreIP(AllocaIP); 2145 else 2146 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); 2147 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2148 Builder.CreateStore(F->arg_begin(), PrivAI); 2149 2150 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2151 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2152 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2153 2154 Builder.restoreIP(CodeGenIP); 2155 2156 // collect some info for checks later 2157 ExitBB = FiniBB.getUniqueSuccessor(); 2158 ThenBB = Builder.GetInsertBlock(); 2159 EntryBB = ThenBB->getUniquePredecessor(); 2160 2161 // simple instructions for body 2162 Value *PrivLoad = Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, 2163 "local.use"); 2164 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2165 }; 2166 2167 auto FiniCB = [&](InsertPointTy IP) { 2168 BasicBlock *IPBB = IP.getBlock(); 2169 EXPECT_NE(IPBB->end(), IP.getPoint()); 2170 }; 2171 2172 Builder.restoreIP( 2173 OMPBuilder.createSingle(Builder, BodyGenCB, FiniCB, /*DidIt*/ nullptr)); 2174 Value *EntryBBTI = EntryBB->getTerminator(); 2175 EXPECT_NE(EntryBBTI, nullptr); 2176 EXPECT_TRUE(isa<BranchInst>(EntryBBTI)); 2177 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator()); 2178 EXPECT_TRUE(EntryBr->isConditional()); 2179 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); 2180 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); 2181 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); 2182 2183 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition()); 2184 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0))); 2185 2186 CallInst *SingleEntryCI = cast<CallInst>(CondInst->getOperand(0)); 2187 EXPECT_EQ(SingleEntryCI->getNumArgOperands(), 2U); 2188 EXPECT_EQ(SingleEntryCI->getCalledFunction()->getName(), "__kmpc_single"); 2189 EXPECT_TRUE(isa<GlobalVariable>(SingleEntryCI->getArgOperand(0))); 2190 2191 CallInst *SingleEndCI = nullptr; 2192 for (auto &FI : *ThenBB) { 2193 Instruction *cur = &FI; 2194 if (isa<CallInst>(cur)) { 2195 SingleEndCI = cast<CallInst>(cur); 2196 if (SingleEndCI->getCalledFunction()->getName() == "__kmpc_end_single") 2197 break; 2198 SingleEndCI = nullptr; 2199 } 2200 } 2201 EXPECT_NE(SingleEndCI, nullptr); 2202 EXPECT_EQ(SingleEndCI->getNumArgOperands(), 2U); 2203 EXPECT_TRUE(isa<GlobalVariable>(SingleEndCI->getArgOperand(0))); 2204 EXPECT_EQ(SingleEndCI->getArgOperand(1), SingleEntryCI->getArgOperand(1)); 2205 } 2206 2207 TEST_F(OpenMPIRBuilderTest, OMPAtomicReadFlt) { 2208 OpenMPIRBuilder OMPBuilder(*M); 2209 OMPBuilder.initialize(); 2210 F->setName("func"); 2211 IRBuilder<> Builder(BB); 2212 2213 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2214 2215 Type *Float32 = Type::getFloatTy(M->getContext()); 2216 AllocaInst *XVal = Builder.CreateAlloca(Float32); 2217 XVal->setName("AtomicVar"); 2218 AllocaInst *VVal = Builder.CreateAlloca(Float32); 2219 VVal->setName("AtomicRead"); 2220 AtomicOrdering AO = AtomicOrdering::Monotonic; 2221 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2222 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2223 2224 Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO)); 2225 2226 IntegerType *IntCastTy = 2227 IntegerType::get(M->getContext(), Float32->getScalarSizeInBits()); 2228 2229 BitCastInst *CastFrmFlt = cast<BitCastInst>(VVal->getNextNode()); 2230 EXPECT_EQ(CastFrmFlt->getSrcTy(), Float32->getPointerTo()); 2231 EXPECT_EQ(CastFrmFlt->getDestTy(), IntCastTy->getPointerTo()); 2232 EXPECT_EQ(CastFrmFlt->getOperand(0), XVal); 2233 2234 LoadInst *AtomicLoad = cast<LoadInst>(CastFrmFlt->getNextNode()); 2235 EXPECT_TRUE(AtomicLoad->isAtomic()); 2236 EXPECT_EQ(AtomicLoad->getPointerOperand(), CastFrmFlt); 2237 2238 BitCastInst *CastToFlt = cast<BitCastInst>(AtomicLoad->getNextNode()); 2239 EXPECT_EQ(CastToFlt->getSrcTy(), IntCastTy); 2240 EXPECT_EQ(CastToFlt->getDestTy(), Float32); 2241 EXPECT_EQ(CastToFlt->getOperand(0), AtomicLoad); 2242 2243 StoreInst *StoreofAtomic = cast<StoreInst>(CastToFlt->getNextNode()); 2244 EXPECT_EQ(StoreofAtomic->getValueOperand(), CastToFlt); 2245 EXPECT_EQ(StoreofAtomic->getPointerOperand(), VVal); 2246 2247 Builder.CreateRetVoid(); 2248 OMPBuilder.finalize(); 2249 EXPECT_FALSE(verifyModule(*M, &errs())); 2250 } 2251 2252 TEST_F(OpenMPIRBuilderTest, OMPAtomicReadInt) { 2253 OpenMPIRBuilder OMPBuilder(*M); 2254 OMPBuilder.initialize(); 2255 F->setName("func"); 2256 IRBuilder<> Builder(BB); 2257 2258 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2259 2260 IntegerType *Int32 = Type::getInt32Ty(M->getContext()); 2261 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2262 XVal->setName("AtomicVar"); 2263 AllocaInst *VVal = Builder.CreateAlloca(Int32); 2264 VVal->setName("AtomicRead"); 2265 AtomicOrdering AO = AtomicOrdering::Monotonic; 2266 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2267 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2268 2269 BasicBlock *EntryBB = BB; 2270 2271 Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO)); 2272 LoadInst *AtomicLoad = nullptr; 2273 StoreInst *StoreofAtomic = nullptr; 2274 2275 for (Instruction &Cur : *EntryBB) { 2276 if (isa<LoadInst>(Cur)) { 2277 AtomicLoad = cast<LoadInst>(&Cur); 2278 if (AtomicLoad->getPointerOperand() == XVal) 2279 continue; 2280 AtomicLoad = nullptr; 2281 } else if (isa<StoreInst>(Cur)) { 2282 StoreofAtomic = cast<StoreInst>(&Cur); 2283 if (StoreofAtomic->getPointerOperand() == VVal) 2284 continue; 2285 StoreofAtomic = nullptr; 2286 } 2287 } 2288 2289 EXPECT_NE(AtomicLoad, nullptr); 2290 EXPECT_TRUE(AtomicLoad->isAtomic()); 2291 2292 EXPECT_NE(StoreofAtomic, nullptr); 2293 EXPECT_EQ(StoreofAtomic->getValueOperand(), AtomicLoad); 2294 2295 Builder.CreateRetVoid(); 2296 OMPBuilder.finalize(); 2297 2298 EXPECT_FALSE(verifyModule(*M, &errs())); 2299 } 2300 2301 TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteFlt) { 2302 OpenMPIRBuilder OMPBuilder(*M); 2303 OMPBuilder.initialize(); 2304 F->setName("func"); 2305 IRBuilder<> Builder(BB); 2306 2307 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2308 2309 LLVMContext &Ctx = M->getContext(); 2310 Type *Float32 = Type::getFloatTy(Ctx); 2311 AllocaInst *XVal = Builder.CreateAlloca(Float32); 2312 XVal->setName("AtomicVar"); 2313 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2314 AtomicOrdering AO = AtomicOrdering::Monotonic; 2315 Constant *ValToWrite = ConstantFP::get(Float32, 1.0); 2316 2317 Builder.restoreIP(OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO)); 2318 2319 IntegerType *IntCastTy = 2320 IntegerType::get(M->getContext(), Float32->getScalarSizeInBits()); 2321 2322 BitCastInst *CastFrmFlt = cast<BitCastInst>(XVal->getNextNode()); 2323 EXPECT_EQ(CastFrmFlt->getSrcTy(), Float32->getPointerTo()); 2324 EXPECT_EQ(CastFrmFlt->getDestTy(), IntCastTy->getPointerTo()); 2325 EXPECT_EQ(CastFrmFlt->getOperand(0), XVal); 2326 2327 Value *ExprCast = Builder.CreateBitCast(ValToWrite, IntCastTy); 2328 2329 StoreInst *StoreofAtomic = cast<StoreInst>(CastFrmFlt->getNextNode()); 2330 EXPECT_EQ(StoreofAtomic->getValueOperand(), ExprCast); 2331 EXPECT_EQ(StoreofAtomic->getPointerOperand(), CastFrmFlt); 2332 EXPECT_TRUE(StoreofAtomic->isAtomic()); 2333 2334 Builder.CreateRetVoid(); 2335 OMPBuilder.finalize(); 2336 EXPECT_FALSE(verifyModule(*M, &errs())); 2337 } 2338 2339 TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteInt) { 2340 OpenMPIRBuilder OMPBuilder(*M); 2341 OMPBuilder.initialize(); 2342 F->setName("func"); 2343 IRBuilder<> Builder(BB); 2344 2345 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2346 2347 LLVMContext &Ctx = M->getContext(); 2348 IntegerType *Int32 = Type::getInt32Ty(Ctx); 2349 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2350 XVal->setName("AtomicVar"); 2351 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2352 AtomicOrdering AO = AtomicOrdering::Monotonic; 2353 ConstantInt *ValToWrite = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2354 2355 BasicBlock *EntryBB = BB; 2356 2357 Builder.restoreIP(OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO)); 2358 2359 StoreInst *StoreofAtomic = nullptr; 2360 2361 for (Instruction &Cur : *EntryBB) { 2362 if (isa<StoreInst>(Cur)) { 2363 StoreofAtomic = cast<StoreInst>(&Cur); 2364 if (StoreofAtomic->getPointerOperand() == XVal) 2365 continue; 2366 StoreofAtomic = nullptr; 2367 } 2368 } 2369 2370 EXPECT_NE(StoreofAtomic, nullptr); 2371 EXPECT_TRUE(StoreofAtomic->isAtomic()); 2372 EXPECT_EQ(StoreofAtomic->getValueOperand(), ValToWrite); 2373 2374 Builder.CreateRetVoid(); 2375 OMPBuilder.finalize(); 2376 EXPECT_FALSE(verifyModule(*M, &errs())); 2377 } 2378 2379 TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdate) { 2380 OpenMPIRBuilder OMPBuilder(*M); 2381 OMPBuilder.initialize(); 2382 F->setName("func"); 2383 IRBuilder<> Builder(BB); 2384 2385 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2386 2387 IntegerType *Int32 = Type::getInt32Ty(M->getContext()); 2388 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2389 XVal->setName("AtomicVar"); 2390 Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal); 2391 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2392 AtomicOrdering AO = AtomicOrdering::Monotonic; 2393 ConstantInt *ConstVal = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2394 Value *Expr = nullptr; 2395 AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Sub; 2396 bool IsXLHSInRHSPart = false; 2397 2398 BasicBlock *EntryBB = BB; 2399 Instruction *AllocIP = EntryBB->getFirstNonPHI(); 2400 Value *Sub = nullptr; 2401 2402 auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) { 2403 Sub = IRB.CreateSub(ConstVal, Atomic); 2404 return Sub; 2405 }; 2406 Builder.restoreIP(OMPBuilder.createAtomicUpdate( 2407 Builder, AllocIP, X, Expr, AO, RMWOp, UpdateOp, IsXLHSInRHSPart)); 2408 BasicBlock *ContBB = EntryBB->getSingleSuccessor(); 2409 BranchInst *ContTI = dyn_cast<BranchInst>(ContBB->getTerminator()); 2410 EXPECT_NE(ContTI, nullptr); 2411 BasicBlock *EndBB = ContTI->getSuccessor(0); 2412 EXPECT_TRUE(ContTI->isConditional()); 2413 EXPECT_EQ(ContTI->getSuccessor(1), ContBB); 2414 EXPECT_NE(EndBB, nullptr); 2415 2416 PHINode *Phi = dyn_cast<PHINode>(&ContBB->front()); 2417 EXPECT_NE(Phi, nullptr); 2418 EXPECT_EQ(Phi->getNumIncomingValues(), 2U); 2419 EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB); 2420 EXPECT_EQ(Phi->getIncomingBlock(1), ContBB); 2421 2422 EXPECT_EQ(Sub->getNumUses(), 1U); 2423 StoreInst *St = dyn_cast<StoreInst>(Sub->user_back()); 2424 AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand()); 2425 2426 ExtractValueInst *ExVI1 = 2427 dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB)); 2428 EXPECT_NE(ExVI1, nullptr); 2429 AtomicCmpXchgInst *CmpExchg = 2430 dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand()); 2431 EXPECT_NE(CmpExchg, nullptr); 2432 EXPECT_EQ(CmpExchg->getPointerOperand(), XVal); 2433 EXPECT_EQ(CmpExchg->getCompareOperand(), Phi); 2434 EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic); 2435 2436 LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand()); 2437 EXPECT_NE(Ld, nullptr); 2438 EXPECT_EQ(UpdateTemp, Ld->getPointerOperand()); 2439 2440 Builder.CreateRetVoid(); 2441 OMPBuilder.finalize(); 2442 EXPECT_FALSE(verifyModule(*M, &errs())); 2443 } 2444 2445 TEST_F(OpenMPIRBuilderTest, OMPAtomicCapture) { 2446 OpenMPIRBuilder OMPBuilder(*M); 2447 OMPBuilder.initialize(); 2448 F->setName("func"); 2449 IRBuilder<> Builder(BB); 2450 2451 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2452 2453 LLVMContext &Ctx = M->getContext(); 2454 IntegerType *Int32 = Type::getInt32Ty(Ctx); 2455 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2456 XVal->setName("AtomicVar"); 2457 AllocaInst *VVal = Builder.CreateAlloca(Int32); 2458 VVal->setName("AtomicCapTar"); 2459 StoreInst *Init = 2460 Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal); 2461 2462 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2463 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2464 AtomicOrdering AO = AtomicOrdering::Monotonic; 2465 ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2466 AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Add; 2467 bool IsXLHSInRHSPart = true; 2468 bool IsPostfixUpdate = true; 2469 bool UpdateExpr = true; 2470 2471 BasicBlock *EntryBB = BB; 2472 Instruction *AllocIP = EntryBB->getFirstNonPHI(); 2473 2474 // integer update - not used 2475 auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) { return nullptr; }; 2476 2477 Builder.restoreIP(OMPBuilder.createAtomicCapture( 2478 Builder, AllocIP, X, V, Expr, AO, RMWOp, UpdateOp, UpdateExpr, 2479 IsPostfixUpdate, IsXLHSInRHSPart)); 2480 EXPECT_EQ(EntryBB->getParent()->size(), 1U); 2481 AtomicRMWInst *ARWM = dyn_cast<AtomicRMWInst>(Init->getNextNode()); 2482 EXPECT_NE(ARWM, nullptr); 2483 EXPECT_EQ(ARWM->getPointerOperand(), XVal); 2484 EXPECT_EQ(ARWM->getOperation(), RMWOp); 2485 StoreInst *St = dyn_cast<StoreInst>(ARWM->user_back()); 2486 EXPECT_NE(St, nullptr); 2487 EXPECT_EQ(St->getPointerOperand(), VVal); 2488 2489 Builder.CreateRetVoid(); 2490 OMPBuilder.finalize(); 2491 EXPECT_FALSE(verifyModule(*M, &errs())); 2492 } 2493 2494 TEST_F(OpenMPIRBuilderTest, CreateSections) { 2495 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2496 using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy; 2497 OpenMPIRBuilder OMPBuilder(*M); 2498 OMPBuilder.initialize(); 2499 F->setName("func"); 2500 IRBuilder<> Builder(BB); 2501 2502 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2503 llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector; 2504 llvm::SmallVector<BasicBlock *, 4> CaseBBs; 2505 2506 BasicBlock *SwitchBB = nullptr; 2507 BasicBlock *ForExitBB = nullptr; 2508 BasicBlock *ForIncBB = nullptr; 2509 AllocaInst *PrivAI = nullptr; 2510 SwitchInst *Switch = nullptr; 2511 2512 unsigned NumBodiesGenerated = 0; 2513 unsigned NumFiniCBCalls = 0; 2514 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2515 2516 auto FiniCB = [&](InsertPointTy IP) { 2517 ++NumFiniCBCalls; 2518 BasicBlock *IPBB = IP.getBlock(); 2519 EXPECT_NE(IPBB->end(), IP.getPoint()); 2520 }; 2521 2522 auto SectionCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2523 BasicBlock &FiniBB) { 2524 ++NumBodiesGenerated; 2525 CaseBBs.push_back(CodeGenIP.getBlock()); 2526 SwitchBB = CodeGenIP.getBlock()->getSinglePredecessor(); 2527 Builder.restoreIP(CodeGenIP); 2528 Builder.CreateStore(F->arg_begin(), PrivAI); 2529 Value *PrivLoad = 2530 Builder.CreateLoad(F->arg_begin()->getType(), PrivAI, "local.alloca"); 2531 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2532 Builder.CreateBr(&FiniBB); 2533 ForIncBB = 2534 CodeGenIP.getBlock()->getSinglePredecessor()->getSingleSuccessor(); 2535 }; 2536 auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2537 llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) { 2538 // TODO: Privatization not implemented yet 2539 return CodeGenIP; 2540 }; 2541 2542 SectionCBVector.push_back(SectionCB); 2543 SectionCBVector.push_back(SectionCB); 2544 2545 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 2546 F->getEntryBlock().getFirstInsertionPt()); 2547 Builder.restoreIP(OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector, 2548 PrivCB, FiniCB, false, false)); 2549 Builder.CreateRetVoid(); // Required at the end of the function 2550 2551 // Switch BB's predecessor is loop condition BB, whose successor at index 1 is 2552 // loop's exit BB 2553 ForExitBB = 2554 SwitchBB->getSinglePredecessor()->getTerminator()->getSuccessor(1); 2555 EXPECT_NE(ForExitBB, nullptr); 2556 2557 EXPECT_NE(PrivAI, nullptr); 2558 Function *OutlinedFn = PrivAI->getFunction(); 2559 EXPECT_EQ(F, OutlinedFn); 2560 EXPECT_FALSE(verifyModule(*M, &errs())); 2561 EXPECT_EQ(OutlinedFn->arg_size(), 1U); 2562 EXPECT_EQ(OutlinedFn->getBasicBlockList().size(), size_t(11)); 2563 2564 BasicBlock *LoopPreheaderBB = 2565 OutlinedFn->getEntryBlock().getSingleSuccessor(); 2566 // loop variables are 5 - lower bound, upper bound, stride, islastiter, and 2567 // iterator/counter 2568 bool FoundForInit = false; 2569 for (Instruction &Inst : *LoopPreheaderBB) { 2570 if (isa<CallInst>(Inst)) { 2571 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 2572 "__kmpc_for_static_init_4u") { 2573 FoundForInit = true; 2574 } 2575 } 2576 } 2577 EXPECT_EQ(FoundForInit, true); 2578 2579 bool FoundForExit = false; 2580 bool FoundBarrier = false; 2581 for (Instruction &Inst : *ForExitBB) { 2582 if (isa<CallInst>(Inst)) { 2583 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 2584 "__kmpc_for_static_fini") { 2585 FoundForExit = true; 2586 } 2587 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 2588 "__kmpc_barrier") { 2589 FoundBarrier = true; 2590 } 2591 if (FoundForExit && FoundBarrier) 2592 break; 2593 } 2594 } 2595 EXPECT_EQ(FoundForExit, true); 2596 EXPECT_EQ(FoundBarrier, true); 2597 2598 EXPECT_NE(SwitchBB, nullptr); 2599 EXPECT_NE(SwitchBB->getTerminator(), nullptr); 2600 EXPECT_EQ(isa<SwitchInst>(SwitchBB->getTerminator()), true); 2601 Switch = cast<SwitchInst>(SwitchBB->getTerminator()); 2602 EXPECT_EQ(Switch->getNumCases(), 2U); 2603 EXPECT_NE(ForIncBB, nullptr); 2604 EXPECT_EQ(Switch->getSuccessor(0), ForIncBB); 2605 2606 EXPECT_EQ(CaseBBs.size(), 2U); 2607 for (auto *&CaseBB : CaseBBs) { 2608 EXPECT_EQ(CaseBB->getParent(), OutlinedFn); 2609 EXPECT_EQ(CaseBB->getSingleSuccessor(), ForExitBB); 2610 } 2611 2612 ASSERT_EQ(NumBodiesGenerated, 2U); 2613 ASSERT_EQ(NumFiniCBCalls, 1U); 2614 } 2615 2616 TEST_F(OpenMPIRBuilderTest, CreateOffloadMaptypes) { 2617 OpenMPIRBuilder OMPBuilder(*M); 2618 OMPBuilder.initialize(); 2619 2620 IRBuilder<> Builder(BB); 2621 2622 SmallVector<uint64_t> Mappings = {0, 1}; 2623 GlobalVariable *OffloadMaptypesGlobal = 2624 OMPBuilder.createOffloadMaptypes(Mappings, "offload_maptypes"); 2625 EXPECT_FALSE(M->global_empty()); 2626 EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_maptypes"); 2627 EXPECT_TRUE(OffloadMaptypesGlobal->isConstant()); 2628 EXPECT_TRUE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr()); 2629 EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage()); 2630 EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer()); 2631 Constant *Initializer = OffloadMaptypesGlobal->getInitializer(); 2632 EXPECT_TRUE(isa<ConstantDataArray>(Initializer)); 2633 ConstantDataArray *MappingInit = dyn_cast<ConstantDataArray>(Initializer); 2634 EXPECT_EQ(MappingInit->getNumElements(), Mappings.size()); 2635 EXPECT_TRUE(MappingInit->getType()->getElementType()->isIntegerTy(64)); 2636 Constant *CA = ConstantDataArray::get(Builder.getContext(), Mappings); 2637 EXPECT_EQ(MappingInit, CA); 2638 } 2639 2640 TEST_F(OpenMPIRBuilderTest, CreateOffloadMapnames) { 2641 OpenMPIRBuilder OMPBuilder(*M); 2642 OMPBuilder.initialize(); 2643 2644 IRBuilder<> Builder(BB); 2645 2646 Constant *Cst1 = OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5); 2647 Constant *Cst2 = OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5); 2648 SmallVector<llvm::Constant *> Names = {Cst1, Cst2}; 2649 2650 GlobalVariable *OffloadMaptypesGlobal = 2651 OMPBuilder.createOffloadMapnames(Names, "offload_mapnames"); 2652 EXPECT_FALSE(M->global_empty()); 2653 EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_mapnames"); 2654 EXPECT_TRUE(OffloadMaptypesGlobal->isConstant()); 2655 EXPECT_FALSE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr()); 2656 EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage()); 2657 EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer()); 2658 Constant *Initializer = OffloadMaptypesGlobal->getInitializer(); 2659 EXPECT_TRUE(isa<Constant>(Initializer->getOperand(0)->stripPointerCasts())); 2660 EXPECT_TRUE(isa<Constant>(Initializer->getOperand(1)->stripPointerCasts())); 2661 2662 GlobalVariable *Name1Gbl = 2663 cast<GlobalVariable>(Initializer->getOperand(0)->stripPointerCasts()); 2664 EXPECT_TRUE(isa<ConstantDataArray>(Name1Gbl->getInitializer())); 2665 ConstantDataArray *Name1GblCA = 2666 dyn_cast<ConstantDataArray>(Name1Gbl->getInitializer()); 2667 EXPECT_EQ(Name1GblCA->getAsCString(), ";file1;array1;2;5;;"); 2668 2669 GlobalVariable *Name2Gbl = 2670 cast<GlobalVariable>(Initializer->getOperand(1)->stripPointerCasts()); 2671 EXPECT_TRUE(isa<ConstantDataArray>(Name2Gbl->getInitializer())); 2672 ConstantDataArray *Name2GblCA = 2673 dyn_cast<ConstantDataArray>(Name2Gbl->getInitializer()); 2674 EXPECT_EQ(Name2GblCA->getAsCString(), ";file1;array2;3;5;;"); 2675 2676 EXPECT_TRUE(Initializer->getType()->getArrayElementType()->isPointerTy()); 2677 EXPECT_EQ(Initializer->getType()->getArrayNumElements(), Names.size()); 2678 } 2679 2680 } // namespace 2681