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