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/Passes/PassBuilder.h" 19 #include "llvm/Transforms/Utils/BasicBlockUtils.h" 20 #include "gtest/gtest.h" 21 22 using namespace llvm; 23 using namespace omp; 24 25 namespace { 26 27 /// Create an instruction that uses the values in \p Values. We use "printf" 28 /// just because it is often used for this purpose in test code, but it is never 29 /// executed here. 30 static CallInst *createPrintfCall(IRBuilder<> &Builder, StringRef FormatStr, 31 ArrayRef<Value *> Values) { 32 Module *M = Builder.GetInsertBlock()->getParent()->getParent(); 33 34 GlobalVariable *GV = Builder.CreateGlobalString(FormatStr, "", 0, M); 35 Constant *Zero = ConstantInt::get(Type::getInt32Ty(M->getContext()), 0); 36 Constant *Indices[] = {Zero, Zero}; 37 Constant *FormatStrConst = 38 ConstantExpr::getInBoundsGetElementPtr(GV->getValueType(), GV, Indices); 39 40 Function *PrintfDecl = M->getFunction("printf"); 41 if (!PrintfDecl) { 42 GlobalValue::LinkageTypes Linkage = Function::ExternalLinkage; 43 FunctionType *Ty = FunctionType::get(Builder.getInt32Ty(), true); 44 PrintfDecl = Function::Create(Ty, Linkage, "printf", M); 45 } 46 47 SmallVector<Value *, 4> Args; 48 Args.push_back(FormatStrConst); 49 Args.append(Values.begin(), Values.end()); 50 return Builder.CreateCall(PrintfDecl, Args); 51 } 52 53 /// Verify that blocks in \p RefOrder are corresponds to the depth-first visit 54 /// order the control flow of \p F. 55 /// 56 /// This is an easy way to verify the branching structure of the CFG without 57 /// checking every branch instruction individually. For the CFG of a 58 /// CanonicalLoopInfo, the Cond BB's terminating branch's first edge is entering 59 /// the body, i.e. the DFS order corresponds to the execution order with one 60 /// loop iteration. 61 static testing::AssertionResult 62 verifyDFSOrder(Function *F, ArrayRef<BasicBlock *> RefOrder) { 63 ArrayRef<BasicBlock *>::iterator It = RefOrder.begin(); 64 ArrayRef<BasicBlock *>::iterator E = RefOrder.end(); 65 66 df_iterator_default_set<BasicBlock *, 16> Visited; 67 auto DFS = llvm::depth_first_ext(&F->getEntryBlock(), Visited); 68 69 BasicBlock *Prev = nullptr; 70 for (BasicBlock *BB : DFS) { 71 if (It != E && BB == *It) { 72 Prev = *It; 73 ++It; 74 } 75 } 76 77 if (It == E) 78 return testing::AssertionSuccess(); 79 if (!Prev) 80 return testing::AssertionFailure() 81 << "Did not find " << (*It)->getName() << " in control flow"; 82 return testing::AssertionFailure() 83 << "Expected " << Prev->getName() << " before " << (*It)->getName() 84 << " in control flow"; 85 } 86 87 /// Verify that blocks in \p RefOrder are in the same relative order in the 88 /// linked lists of blocks in \p F. The linked list may contain additional 89 /// blocks in-between. 90 /// 91 /// While the order in the linked list is not relevant for semantics, keeping 92 /// the order roughly in execution order makes its printout easier to read. 93 static testing::AssertionResult 94 verifyListOrder(Function *F, ArrayRef<BasicBlock *> RefOrder) { 95 ArrayRef<BasicBlock *>::iterator It = RefOrder.begin(); 96 ArrayRef<BasicBlock *>::iterator E = RefOrder.end(); 97 98 BasicBlock *Prev = nullptr; 99 for (BasicBlock &BB : *F) { 100 if (It != E && &BB == *It) { 101 Prev = *It; 102 ++It; 103 } 104 } 105 106 if (It == E) 107 return testing::AssertionSuccess(); 108 if (!Prev) 109 return testing::AssertionFailure() << "Did not find " << (*It)->getName() 110 << " in function " << F->getName(); 111 return testing::AssertionFailure() 112 << "Expected " << Prev->getName() << " before " << (*It)->getName() 113 << " in function " << F->getName(); 114 } 115 116 class OpenMPIRBuilderTest : public testing::Test { 117 protected: 118 void SetUp() override { 119 M.reset(new Module("MyModule", Ctx)); 120 FunctionType *FTy = 121 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, 122 /*isVarArg=*/false); 123 F = Function::Create(FTy, Function::ExternalLinkage, "", M.get()); 124 BB = BasicBlock::Create(Ctx, "", F); 125 126 DIBuilder DIB(*M); 127 auto File = DIB.createFile("test.dbg", "/src", llvm::None, 128 Optional<StringRef>("/src/test.dbg")); 129 auto CU = 130 DIB.createCompileUnit(dwarf::DW_LANG_C, File, "llvm-C", true, "", 0); 131 auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); 132 auto SP = DIB.createFunction( 133 CU, "foo", "", File, 1, Type, 1, DINode::FlagZero, 134 DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized); 135 F->setSubprogram(SP); 136 auto Scope = DIB.createLexicalBlockFile(SP, File, 0); 137 DIB.finalize(); 138 DL = DILocation::get(Ctx, 3, 7, Scope); 139 } 140 141 void TearDown() override { 142 BB = nullptr; 143 M.reset(); 144 } 145 146 /// Create a function with a simple loop that calls printf using the logical 147 /// loop counter for use with tests that need a CanonicalLoopInfo object. 148 CanonicalLoopInfo *buildSingleLoopFunction(DebugLoc DL, 149 OpenMPIRBuilder &OMPBuilder, 150 Instruction **Call = nullptr, 151 BasicBlock **BodyCode = nullptr) { 152 OMPBuilder.initialize(); 153 F->setName("func"); 154 155 IRBuilder<> Builder(BB); 156 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 157 Value *TripCount = F->getArg(0); 158 159 auto LoopBodyGenCB = [&](OpenMPIRBuilder::InsertPointTy CodeGenIP, 160 llvm::Value *LC) { 161 Builder.restoreIP(CodeGenIP); 162 if (BodyCode) 163 *BodyCode = Builder.GetInsertBlock(); 164 165 // Add something that consumes the induction variable to the body. 166 CallInst *CallInst = createPrintfCall(Builder, "%d\\n", {LC}); 167 if (Call) 168 *Call = CallInst; 169 }; 170 CanonicalLoopInfo *Loop = 171 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, TripCount); 172 173 // Finalize the function. 174 Builder.restoreIP(Loop->getAfterIP()); 175 Builder.CreateRetVoid(); 176 177 return Loop; 178 } 179 180 LLVMContext Ctx; 181 std::unique_ptr<Module> M; 182 Function *F; 183 BasicBlock *BB; 184 DebugLoc DL; 185 }; 186 187 class OpenMPIRBuilderTestWithParams 188 : public OpenMPIRBuilderTest, 189 public ::testing::WithParamInterface<omp::OMPScheduleType> {}; 190 191 // Returns the value stored in the given allocation. Returns null if the given 192 // value is not a result of an InstTy instruction, if no value is stored or if 193 // there is more than one store. 194 template <typename InstTy> static Value *findStoredValue(Value *AllocaValue) { 195 Instruction *Inst = dyn_cast<InstTy>(AllocaValue); 196 if (!Inst) 197 return nullptr; 198 StoreInst *Store = nullptr; 199 for (Use &U : Inst->uses()) { 200 if (auto *CandidateStore = dyn_cast<StoreInst>(U.getUser())) { 201 EXPECT_EQ(Store, nullptr); 202 Store = CandidateStore; 203 } 204 } 205 if (!Store) 206 return nullptr; 207 return Store->getValueOperand(); 208 } 209 210 TEST_F(OpenMPIRBuilderTest, CreateBarrier) { 211 OpenMPIRBuilder OMPBuilder(*M); 212 OMPBuilder.initialize(); 213 214 IRBuilder<> Builder(BB); 215 216 OMPBuilder.createBarrier({IRBuilder<>::InsertPoint()}, OMPD_for); 217 EXPECT_TRUE(M->global_empty()); 218 EXPECT_EQ(M->size(), 1U); 219 EXPECT_EQ(F->size(), 1U); 220 EXPECT_EQ(BB->size(), 0U); 221 222 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 223 OMPBuilder.createBarrier(Loc, OMPD_for); 224 EXPECT_FALSE(M->global_empty()); 225 EXPECT_EQ(M->size(), 3U); 226 EXPECT_EQ(F->size(), 1U); 227 EXPECT_EQ(BB->size(), 2U); 228 229 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 230 EXPECT_NE(GTID, nullptr); 231 EXPECT_EQ(GTID->arg_size(), 1U); 232 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 233 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 234 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 235 236 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode()); 237 EXPECT_NE(Barrier, nullptr); 238 EXPECT_EQ(Barrier->arg_size(), 2U); 239 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_barrier"); 240 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); 241 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); 242 243 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID); 244 245 Builder.CreateUnreachable(); 246 EXPECT_FALSE(verifyModule(*M, &errs())); 247 } 248 249 TEST_F(OpenMPIRBuilderTest, CreateCancel) { 250 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 251 OpenMPIRBuilder OMPBuilder(*M); 252 OMPBuilder.initialize(); 253 254 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); 255 new UnreachableInst(Ctx, CBB); 256 auto FiniCB = [&](InsertPointTy IP) { 257 ASSERT_NE(IP.getBlock(), nullptr); 258 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); 259 BranchInst::Create(CBB, IP.getBlock()); 260 }; 261 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); 262 263 IRBuilder<> Builder(BB); 264 265 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 266 auto NewIP = OMPBuilder.createCancel(Loc, nullptr, OMPD_parallel); 267 Builder.restoreIP(NewIP); 268 EXPECT_FALSE(M->global_empty()); 269 EXPECT_EQ(M->size(), 4U); 270 EXPECT_EQ(F->size(), 4U); 271 EXPECT_EQ(BB->size(), 4U); 272 273 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 274 EXPECT_NE(GTID, nullptr); 275 EXPECT_EQ(GTID->arg_size(), 1U); 276 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 277 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 278 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 279 280 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode()); 281 EXPECT_NE(Cancel, nullptr); 282 EXPECT_EQ(Cancel->arg_size(), 3U); 283 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel"); 284 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory()); 285 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory()); 286 EXPECT_EQ(Cancel->getNumUses(), 1U); 287 Instruction *CancelBBTI = Cancel->getParent()->getTerminator(); 288 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U); 289 EXPECT_EQ(CancelBBTI->getSuccessor(0), NewIP.getBlock()); 290 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 3U); 291 CallInst *GTID1 = dyn_cast<CallInst>(&CancelBBTI->getSuccessor(1)->front()); 292 EXPECT_NE(GTID1, nullptr); 293 EXPECT_EQ(GTID1->arg_size(), 1U); 294 EXPECT_EQ(GTID1->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 295 EXPECT_FALSE(GTID1->getCalledFunction()->doesNotAccessMemory()); 296 EXPECT_FALSE(GTID1->getCalledFunction()->doesNotFreeMemory()); 297 CallInst *Barrier = dyn_cast<CallInst>(GTID1->getNextNode()); 298 EXPECT_NE(Barrier, nullptr); 299 EXPECT_EQ(Barrier->arg_size(), 2U); 300 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier"); 301 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); 302 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); 303 EXPECT_EQ(Barrier->getNumUses(), 0U); 304 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 305 1U); 306 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), CBB); 307 308 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID); 309 310 OMPBuilder.popFinalizationCB(); 311 312 Builder.CreateUnreachable(); 313 EXPECT_FALSE(verifyModule(*M, &errs())); 314 } 315 316 TEST_F(OpenMPIRBuilderTest, CreateCancelIfCond) { 317 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 318 OpenMPIRBuilder OMPBuilder(*M); 319 OMPBuilder.initialize(); 320 321 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); 322 new UnreachableInst(Ctx, CBB); 323 auto FiniCB = [&](InsertPointTy IP) { 324 ASSERT_NE(IP.getBlock(), nullptr); 325 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); 326 BranchInst::Create(CBB, IP.getBlock()); 327 }; 328 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); 329 330 IRBuilder<> Builder(BB); 331 332 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 333 auto NewIP = OMPBuilder.createCancel(Loc, Builder.getTrue(), OMPD_parallel); 334 Builder.restoreIP(NewIP); 335 EXPECT_FALSE(M->global_empty()); 336 EXPECT_EQ(M->size(), 4U); 337 EXPECT_EQ(F->size(), 7U); 338 EXPECT_EQ(BB->size(), 1U); 339 ASSERT_TRUE(isa<BranchInst>(BB->getTerminator())); 340 ASSERT_EQ(BB->getTerminator()->getNumSuccessors(), 2U); 341 BB = BB->getTerminator()->getSuccessor(0); 342 EXPECT_EQ(BB->size(), 4U); 343 344 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 345 EXPECT_NE(GTID, nullptr); 346 EXPECT_EQ(GTID->arg_size(), 1U); 347 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 348 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 349 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 350 351 CallInst *Cancel = dyn_cast<CallInst>(GTID->getNextNode()); 352 EXPECT_NE(Cancel, nullptr); 353 EXPECT_EQ(Cancel->arg_size(), 3U); 354 EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel"); 355 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory()); 356 EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory()); 357 EXPECT_EQ(Cancel->getNumUses(), 1U); 358 Instruction *CancelBBTI = Cancel->getParent()->getTerminator(); 359 EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U); 360 EXPECT_EQ(CancelBBTI->getSuccessor(0)->size(), 1U); 361 EXPECT_EQ(CancelBBTI->getSuccessor(0)->getUniqueSuccessor(), 362 NewIP.getBlock()); 363 EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 3U); 364 CallInst *GTID1 = dyn_cast<CallInst>(&CancelBBTI->getSuccessor(1)->front()); 365 EXPECT_NE(GTID1, nullptr); 366 EXPECT_EQ(GTID1->arg_size(), 1U); 367 EXPECT_EQ(GTID1->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 368 EXPECT_FALSE(GTID1->getCalledFunction()->doesNotAccessMemory()); 369 EXPECT_FALSE(GTID1->getCalledFunction()->doesNotFreeMemory()); 370 CallInst *Barrier = dyn_cast<CallInst>(GTID1->getNextNode()); 371 EXPECT_NE(Barrier, nullptr); 372 EXPECT_EQ(Barrier->arg_size(), 2U); 373 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier"); 374 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); 375 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); 376 EXPECT_EQ(Barrier->getNumUses(), 0U); 377 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 378 1U); 379 EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), CBB); 380 381 EXPECT_EQ(cast<CallInst>(Cancel)->getArgOperand(1), GTID); 382 383 OMPBuilder.popFinalizationCB(); 384 385 Builder.CreateUnreachable(); 386 EXPECT_FALSE(verifyModule(*M, &errs())); 387 } 388 389 TEST_F(OpenMPIRBuilderTest, CreateCancelBarrier) { 390 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 391 OpenMPIRBuilder OMPBuilder(*M); 392 OMPBuilder.initialize(); 393 394 BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); 395 new UnreachableInst(Ctx, CBB); 396 auto FiniCB = [&](InsertPointTy IP) { 397 ASSERT_NE(IP.getBlock(), nullptr); 398 ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); 399 BranchInst::Create(CBB, IP.getBlock()); 400 }; 401 OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); 402 403 IRBuilder<> Builder(BB); 404 405 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); 406 auto NewIP = OMPBuilder.createBarrier(Loc, OMPD_for); 407 Builder.restoreIP(NewIP); 408 EXPECT_FALSE(M->global_empty()); 409 EXPECT_EQ(M->size(), 3U); 410 EXPECT_EQ(F->size(), 4U); 411 EXPECT_EQ(BB->size(), 4U); 412 413 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 414 EXPECT_NE(GTID, nullptr); 415 EXPECT_EQ(GTID->arg_size(), 1U); 416 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 417 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 418 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 419 420 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode()); 421 EXPECT_NE(Barrier, nullptr); 422 EXPECT_EQ(Barrier->arg_size(), 2U); 423 EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier"); 424 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); 425 EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); 426 EXPECT_EQ(Barrier->getNumUses(), 1U); 427 Instruction *BarrierBBTI = Barrier->getParent()->getTerminator(); 428 EXPECT_EQ(BarrierBBTI->getNumSuccessors(), 2U); 429 EXPECT_EQ(BarrierBBTI->getSuccessor(0), NewIP.getBlock()); 430 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->size(), 1U); 431 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 432 1U); 433 EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), 434 CBB); 435 436 EXPECT_EQ(cast<CallInst>(Barrier)->getArgOperand(1), GTID); 437 438 OMPBuilder.popFinalizationCB(); 439 440 Builder.CreateUnreachable(); 441 EXPECT_FALSE(verifyModule(*M, &errs())); 442 } 443 444 TEST_F(OpenMPIRBuilderTest, DbgLoc) { 445 OpenMPIRBuilder OMPBuilder(*M); 446 OMPBuilder.initialize(); 447 F->setName("func"); 448 449 IRBuilder<> Builder(BB); 450 451 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 452 OMPBuilder.createBarrier(Loc, OMPD_for); 453 CallInst *GTID = dyn_cast<CallInst>(&BB->front()); 454 CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode()); 455 EXPECT_EQ(GTID->getDebugLoc(), DL); 456 EXPECT_EQ(Barrier->getDebugLoc(), DL); 457 EXPECT_TRUE(isa<GlobalVariable>(Barrier->getOperand(0))); 458 if (!isa<GlobalVariable>(Barrier->getOperand(0))) 459 return; 460 GlobalVariable *Ident = cast<GlobalVariable>(Barrier->getOperand(0)); 461 EXPECT_TRUE(Ident->hasInitializer()); 462 if (!Ident->hasInitializer()) 463 return; 464 Constant *Initializer = Ident->getInitializer(); 465 EXPECT_TRUE( 466 isa<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts())); 467 GlobalVariable *SrcStrGlob = 468 cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts()); 469 if (!SrcStrGlob) 470 return; 471 EXPECT_TRUE(isa<ConstantDataArray>(SrcStrGlob->getInitializer())); 472 ConstantDataArray *SrcSrc = 473 dyn_cast<ConstantDataArray>(SrcStrGlob->getInitializer()); 474 if (!SrcSrc) 475 return; 476 EXPECT_EQ(SrcSrc->getAsCString(), ";/src/test.dbg;foo;3;7;;"); 477 } 478 479 TEST_F(OpenMPIRBuilderTest, ParallelSimple) { 480 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 481 OpenMPIRBuilder OMPBuilder(*M); 482 OMPBuilder.initialize(); 483 F->setName("func"); 484 IRBuilder<> Builder(BB); 485 486 BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F); 487 Builder.CreateBr(EnterBB); 488 Builder.SetInsertPoint(EnterBB); 489 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 490 491 AllocaInst *PrivAI = nullptr; 492 493 unsigned NumBodiesGenerated = 0; 494 unsigned NumPrivatizedVars = 0; 495 unsigned NumFinalizationPoints = 0; 496 497 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 498 BasicBlock &ContinuationIP) { 499 ++NumBodiesGenerated; 500 501 Builder.restoreIP(AllocaIP); 502 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 503 Builder.CreateStore(F->arg_begin(), PrivAI); 504 505 Builder.restoreIP(CodeGenIP); 506 Value *PrivLoad = 507 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 508 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 509 Instruction *ThenTerm, *ElseTerm; 510 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), 511 &ThenTerm, &ElseTerm); 512 513 Builder.SetInsertPoint(ThenTerm); 514 Builder.CreateBr(&ContinuationIP); 515 ThenTerm->eraseFromParent(); 516 }; 517 518 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 519 Value &Orig, Value &Inner, 520 Value *&ReplacementValue) -> InsertPointTy { 521 ++NumPrivatizedVars; 522 523 if (!isa<AllocaInst>(Orig)) { 524 EXPECT_EQ(&Orig, F->arg_begin()); 525 ReplacementValue = &Inner; 526 return CodeGenIP; 527 } 528 529 // Since the original value is an allocation, it has a pointer type and 530 // therefore no additional wrapping should happen. 531 EXPECT_EQ(&Orig, &Inner); 532 533 // Trivial copy (=firstprivate). 534 Builder.restoreIP(AllocaIP); 535 Type *VTy = Inner.getType()->getPointerElementType(); 536 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 537 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 538 Builder.restoreIP(CodeGenIP); 539 Builder.CreateStore(V, ReplacementValue); 540 return CodeGenIP; 541 }; 542 543 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; 544 545 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 546 F->getEntryBlock().getFirstInsertionPt()); 547 IRBuilder<>::InsertPoint AfterIP = 548 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 549 nullptr, nullptr, OMP_PROC_BIND_default, false); 550 EXPECT_EQ(NumBodiesGenerated, 1U); 551 EXPECT_EQ(NumPrivatizedVars, 1U); 552 EXPECT_EQ(NumFinalizationPoints, 1U); 553 554 Builder.restoreIP(AfterIP); 555 Builder.CreateRetVoid(); 556 557 OMPBuilder.finalize(); 558 559 EXPECT_NE(PrivAI, nullptr); 560 Function *OutlinedFn = PrivAI->getFunction(); 561 EXPECT_NE(F, OutlinedFn); 562 EXPECT_FALSE(verifyModule(*M, &errs())); 563 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoUnwind)); 564 EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoRecurse)); 565 EXPECT_TRUE(OutlinedFn->hasParamAttribute(0, Attribute::NoAlias)); 566 EXPECT_TRUE(OutlinedFn->hasParamAttribute(1, Attribute::NoAlias)); 567 568 EXPECT_TRUE(OutlinedFn->hasInternalLinkage()); 569 EXPECT_EQ(OutlinedFn->arg_size(), 3U); 570 571 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent()); 572 EXPECT_EQ(OutlinedFn->getNumUses(), 1U); 573 User *Usr = OutlinedFn->user_back(); 574 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 575 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); 576 ASSERT_NE(ForkCI, nullptr); 577 578 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 579 EXPECT_EQ(ForkCI->arg_size(), 4U); 580 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 581 EXPECT_EQ(ForkCI->getArgOperand(1), 582 ConstantInt::get(Type::getInt32Ty(Ctx), 1U)); 583 EXPECT_EQ(ForkCI->getArgOperand(2), Usr); 584 EXPECT_EQ(findStoredValue<AllocaInst>(ForkCI->getArgOperand(3)), 585 F->arg_begin()); 586 } 587 588 TEST_F(OpenMPIRBuilderTest, ParallelNested) { 589 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 590 OpenMPIRBuilder OMPBuilder(*M); 591 OMPBuilder.initialize(); 592 F->setName("func"); 593 IRBuilder<> Builder(BB); 594 595 BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F); 596 Builder.CreateBr(EnterBB); 597 Builder.SetInsertPoint(EnterBB); 598 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 599 600 unsigned NumInnerBodiesGenerated = 0; 601 unsigned NumOuterBodiesGenerated = 0; 602 unsigned NumFinalizationPoints = 0; 603 604 auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 605 BasicBlock &ContinuationIP) { 606 ++NumInnerBodiesGenerated; 607 }; 608 609 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 610 Value &Orig, Value &Inner, 611 Value *&ReplacementValue) -> InsertPointTy { 612 // Trivial copy (=firstprivate). 613 Builder.restoreIP(AllocaIP); 614 Type *VTy = Inner.getType()->getPointerElementType(); 615 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 616 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 617 Builder.restoreIP(CodeGenIP); 618 Builder.CreateStore(V, ReplacementValue); 619 return CodeGenIP; 620 }; 621 622 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; 623 624 auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 625 BasicBlock &ContinuationIP) { 626 ++NumOuterBodiesGenerated; 627 Builder.restoreIP(CodeGenIP); 628 BasicBlock *CGBB = CodeGenIP.getBlock(); 629 BasicBlock *NewBB = SplitBlock(CGBB, &*CodeGenIP.getPoint()); 630 CGBB->getTerminator()->eraseFromParent(); 631 ; 632 633 IRBuilder<>::InsertPoint AfterIP = OMPBuilder.createParallel( 634 InsertPointTy(CGBB, CGBB->end()), AllocaIP, InnerBodyGenCB, PrivCB, 635 FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); 636 637 Builder.restoreIP(AfterIP); 638 Builder.CreateBr(NewBB); 639 }; 640 641 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 642 F->getEntryBlock().getFirstInsertionPt()); 643 IRBuilder<>::InsertPoint AfterIP = 644 OMPBuilder.createParallel(Loc, AllocaIP, OuterBodyGenCB, PrivCB, FiniCB, 645 nullptr, nullptr, OMP_PROC_BIND_default, false); 646 647 EXPECT_EQ(NumInnerBodiesGenerated, 1U); 648 EXPECT_EQ(NumOuterBodiesGenerated, 1U); 649 EXPECT_EQ(NumFinalizationPoints, 2U); 650 651 Builder.restoreIP(AfterIP); 652 Builder.CreateRetVoid(); 653 654 OMPBuilder.finalize(); 655 656 EXPECT_EQ(M->size(), 5U); 657 for (Function &OutlinedFn : *M) { 658 if (F == &OutlinedFn || OutlinedFn.isDeclaration()) 659 continue; 660 EXPECT_FALSE(verifyModule(*M, &errs())); 661 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind)); 662 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoRecurse)); 663 EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias)); 664 EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias)); 665 666 EXPECT_TRUE(OutlinedFn.hasInternalLinkage()); 667 EXPECT_EQ(OutlinedFn.arg_size(), 2U); 668 669 EXPECT_EQ(OutlinedFn.getNumUses(), 1U); 670 User *Usr = OutlinedFn.user_back(); 671 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 672 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); 673 ASSERT_NE(ForkCI, nullptr); 674 675 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 676 EXPECT_EQ(ForkCI->arg_size(), 3U); 677 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 678 EXPECT_EQ(ForkCI->getArgOperand(1), 679 ConstantInt::get(Type::getInt32Ty(Ctx), 0U)); 680 EXPECT_EQ(ForkCI->getArgOperand(2), Usr); 681 } 682 } 683 684 TEST_F(OpenMPIRBuilderTest, ParallelNested2Inner) { 685 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 686 OpenMPIRBuilder OMPBuilder(*M); 687 OMPBuilder.initialize(); 688 F->setName("func"); 689 IRBuilder<> Builder(BB); 690 691 BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F); 692 Builder.CreateBr(EnterBB); 693 Builder.SetInsertPoint(EnterBB); 694 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 695 696 unsigned NumInnerBodiesGenerated = 0; 697 unsigned NumOuterBodiesGenerated = 0; 698 unsigned NumFinalizationPoints = 0; 699 700 auto InnerBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 701 BasicBlock &ContinuationIP) { 702 ++NumInnerBodiesGenerated; 703 }; 704 705 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 706 Value &Orig, Value &Inner, 707 Value *&ReplacementValue) -> InsertPointTy { 708 // Trivial copy (=firstprivate). 709 Builder.restoreIP(AllocaIP); 710 Type *VTy = Inner.getType()->getPointerElementType(); 711 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 712 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 713 Builder.restoreIP(CodeGenIP); 714 Builder.CreateStore(V, ReplacementValue); 715 return CodeGenIP; 716 }; 717 718 auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; 719 720 auto OuterBodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 721 BasicBlock &ContinuationIP) { 722 ++NumOuterBodiesGenerated; 723 Builder.restoreIP(CodeGenIP); 724 BasicBlock *CGBB = CodeGenIP.getBlock(); 725 BasicBlock *NewBB1 = SplitBlock(CGBB, &*CodeGenIP.getPoint()); 726 BasicBlock *NewBB2 = SplitBlock(NewBB1, &*NewBB1->getFirstInsertionPt()); 727 CGBB->getTerminator()->eraseFromParent(); 728 ; 729 NewBB1->getTerminator()->eraseFromParent(); 730 ; 731 732 IRBuilder<>::InsertPoint AfterIP1 = OMPBuilder.createParallel( 733 InsertPointTy(CGBB, CGBB->end()), AllocaIP, InnerBodyGenCB, PrivCB, 734 FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); 735 736 Builder.restoreIP(AfterIP1); 737 Builder.CreateBr(NewBB1); 738 739 IRBuilder<>::InsertPoint AfterIP2 = OMPBuilder.createParallel( 740 InsertPointTy(NewBB1, NewBB1->end()), AllocaIP, InnerBodyGenCB, PrivCB, 741 FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); 742 743 Builder.restoreIP(AfterIP2); 744 Builder.CreateBr(NewBB2); 745 }; 746 747 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 748 F->getEntryBlock().getFirstInsertionPt()); 749 IRBuilder<>::InsertPoint AfterIP = 750 OMPBuilder.createParallel(Loc, AllocaIP, OuterBodyGenCB, PrivCB, FiniCB, 751 nullptr, nullptr, OMP_PROC_BIND_default, false); 752 753 EXPECT_EQ(NumInnerBodiesGenerated, 2U); 754 EXPECT_EQ(NumOuterBodiesGenerated, 1U); 755 EXPECT_EQ(NumFinalizationPoints, 3U); 756 757 Builder.restoreIP(AfterIP); 758 Builder.CreateRetVoid(); 759 760 OMPBuilder.finalize(); 761 762 EXPECT_EQ(M->size(), 6U); 763 for (Function &OutlinedFn : *M) { 764 if (F == &OutlinedFn || OutlinedFn.isDeclaration()) 765 continue; 766 EXPECT_FALSE(verifyModule(*M, &errs())); 767 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoUnwind)); 768 EXPECT_TRUE(OutlinedFn.hasFnAttribute(Attribute::NoRecurse)); 769 EXPECT_TRUE(OutlinedFn.hasParamAttribute(0, Attribute::NoAlias)); 770 EXPECT_TRUE(OutlinedFn.hasParamAttribute(1, Attribute::NoAlias)); 771 772 EXPECT_TRUE(OutlinedFn.hasInternalLinkage()); 773 EXPECT_EQ(OutlinedFn.arg_size(), 2U); 774 775 unsigned NumAllocas = 0; 776 for (Instruction &I : instructions(OutlinedFn)) 777 NumAllocas += isa<AllocaInst>(I); 778 EXPECT_EQ(NumAllocas, 1U); 779 780 EXPECT_EQ(OutlinedFn.getNumUses(), 1U); 781 User *Usr = OutlinedFn.user_back(); 782 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 783 CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back()); 784 ASSERT_NE(ForkCI, nullptr); 785 786 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 787 EXPECT_EQ(ForkCI->arg_size(), 3U); 788 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 789 EXPECT_EQ(ForkCI->getArgOperand(1), 790 ConstantInt::get(Type::getInt32Ty(Ctx), 0U)); 791 EXPECT_EQ(ForkCI->getArgOperand(2), Usr); 792 } 793 } 794 795 TEST_F(OpenMPIRBuilderTest, ParallelIfCond) { 796 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 797 OpenMPIRBuilder OMPBuilder(*M); 798 OMPBuilder.initialize(); 799 F->setName("func"); 800 IRBuilder<> Builder(BB); 801 802 BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F); 803 Builder.CreateBr(EnterBB); 804 Builder.SetInsertPoint(EnterBB); 805 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 806 807 AllocaInst *PrivAI = nullptr; 808 809 unsigned NumBodiesGenerated = 0; 810 unsigned NumPrivatizedVars = 0; 811 unsigned NumFinalizationPoints = 0; 812 813 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 814 BasicBlock &ContinuationIP) { 815 ++NumBodiesGenerated; 816 817 Builder.restoreIP(AllocaIP); 818 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 819 Builder.CreateStore(F->arg_begin(), PrivAI); 820 821 Builder.restoreIP(CodeGenIP); 822 Value *PrivLoad = 823 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 824 Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 825 Instruction *ThenTerm, *ElseTerm; 826 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), 827 &ThenTerm, &ElseTerm); 828 829 Builder.SetInsertPoint(ThenTerm); 830 Builder.CreateBr(&ContinuationIP); 831 ThenTerm->eraseFromParent(); 832 }; 833 834 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 835 Value &Orig, Value &Inner, 836 Value *&ReplacementValue) -> InsertPointTy { 837 ++NumPrivatizedVars; 838 839 if (!isa<AllocaInst>(Orig)) { 840 EXPECT_EQ(&Orig, F->arg_begin()); 841 ReplacementValue = &Inner; 842 return CodeGenIP; 843 } 844 845 // Since the original value is an allocation, it has a pointer type and 846 // therefore no additional wrapping should happen. 847 EXPECT_EQ(&Orig, &Inner); 848 849 // Trivial copy (=firstprivate). 850 Builder.restoreIP(AllocaIP); 851 Type *VTy = Inner.getType()->getPointerElementType(); 852 Value *V = Builder.CreateLoad(VTy, &Inner, Orig.getName() + ".reload"); 853 ReplacementValue = Builder.CreateAlloca(VTy, 0, Orig.getName() + ".copy"); 854 Builder.restoreIP(CodeGenIP); 855 Builder.CreateStore(V, ReplacementValue); 856 return CodeGenIP; 857 }; 858 859 auto FiniCB = [&](InsertPointTy CodeGenIP) { 860 ++NumFinalizationPoints; 861 // No destructors. 862 }; 863 864 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 865 F->getEntryBlock().getFirstInsertionPt()); 866 IRBuilder<>::InsertPoint AfterIP = 867 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 868 Builder.CreateIsNotNull(F->arg_begin()), 869 nullptr, OMP_PROC_BIND_default, false); 870 871 EXPECT_EQ(NumBodiesGenerated, 1U); 872 EXPECT_EQ(NumPrivatizedVars, 1U); 873 EXPECT_EQ(NumFinalizationPoints, 1U); 874 875 Builder.restoreIP(AfterIP); 876 Builder.CreateRetVoid(); 877 OMPBuilder.finalize(); 878 879 EXPECT_NE(PrivAI, nullptr); 880 Function *OutlinedFn = PrivAI->getFunction(); 881 EXPECT_NE(F, OutlinedFn); 882 EXPECT_FALSE(verifyModule(*M, &errs())); 883 884 EXPECT_TRUE(OutlinedFn->hasInternalLinkage()); 885 EXPECT_EQ(OutlinedFn->arg_size(), 3U); 886 887 EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent()); 888 ASSERT_EQ(OutlinedFn->getNumUses(), 2U); 889 890 CallInst *DirectCI = nullptr; 891 CallInst *ForkCI = nullptr; 892 for (User *Usr : OutlinedFn->users()) { 893 if (isa<CallInst>(Usr)) { 894 ASSERT_EQ(DirectCI, nullptr); 895 DirectCI = cast<CallInst>(Usr); 896 } else { 897 ASSERT_TRUE(isa<ConstantExpr>(Usr)); 898 ASSERT_EQ(Usr->getNumUses(), 1U); 899 ASSERT_TRUE(isa<CallInst>(Usr->user_back())); 900 ForkCI = cast<CallInst>(Usr->user_back()); 901 } 902 } 903 904 EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); 905 EXPECT_EQ(ForkCI->arg_size(), 4U); 906 EXPECT_TRUE(isa<GlobalVariable>(ForkCI->getArgOperand(0))); 907 EXPECT_EQ(ForkCI->getArgOperand(1), 908 ConstantInt::get(Type::getInt32Ty(Ctx), 1)); 909 Value *StoredForkArg = findStoredValue<AllocaInst>(ForkCI->getArgOperand(3)); 910 EXPECT_EQ(StoredForkArg, F->arg_begin()); 911 912 EXPECT_EQ(DirectCI->getCalledFunction(), OutlinedFn); 913 EXPECT_EQ(DirectCI->arg_size(), 3U); 914 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(0))); 915 EXPECT_TRUE(isa<AllocaInst>(DirectCI->getArgOperand(1))); 916 Value *StoredDirectArg = 917 findStoredValue<AllocaInst>(DirectCI->getArgOperand(2)); 918 EXPECT_EQ(StoredDirectArg, F->arg_begin()); 919 } 920 921 TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) { 922 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 923 OpenMPIRBuilder OMPBuilder(*M); 924 OMPBuilder.initialize(); 925 F->setName("func"); 926 IRBuilder<> Builder(BB); 927 928 BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F); 929 Builder.CreateBr(EnterBB); 930 Builder.SetInsertPoint(EnterBB); 931 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 932 933 unsigned NumBodiesGenerated = 0; 934 unsigned NumPrivatizedVars = 0; 935 unsigned NumFinalizationPoints = 0; 936 937 CallInst *CheckedBarrier = nullptr; 938 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 939 BasicBlock &ContinuationIP) { 940 ++NumBodiesGenerated; 941 942 Builder.restoreIP(CodeGenIP); 943 944 // Create three barriers, two cancel barriers but only one checked. 945 Function *CBFn, *BFn; 946 947 Builder.restoreIP( 948 OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel)); 949 950 CBFn = M->getFunction("__kmpc_cancel_barrier"); 951 BFn = M->getFunction("__kmpc_barrier"); 952 ASSERT_NE(CBFn, nullptr); 953 ASSERT_EQ(BFn, nullptr); 954 ASSERT_EQ(CBFn->getNumUses(), 1U); 955 ASSERT_TRUE(isa<CallInst>(CBFn->user_back())); 956 ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U); 957 CheckedBarrier = cast<CallInst>(CBFn->user_back()); 958 959 Builder.restoreIP( 960 OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel, true)); 961 CBFn = M->getFunction("__kmpc_cancel_barrier"); 962 BFn = M->getFunction("__kmpc_barrier"); 963 ASSERT_NE(CBFn, nullptr); 964 ASSERT_NE(BFn, nullptr); 965 ASSERT_EQ(CBFn->getNumUses(), 1U); 966 ASSERT_EQ(BFn->getNumUses(), 1U); 967 ASSERT_TRUE(isa<CallInst>(BFn->user_back())); 968 ASSERT_EQ(BFn->user_back()->getNumUses(), 0U); 969 970 Builder.restoreIP(OMPBuilder.createBarrier(Builder.saveIP(), OMPD_parallel, 971 false, false)); 972 ASSERT_EQ(CBFn->getNumUses(), 2U); 973 ASSERT_EQ(BFn->getNumUses(), 1U); 974 ASSERT_TRUE(CBFn->user_back() != CheckedBarrier); 975 ASSERT_TRUE(isa<CallInst>(CBFn->user_back())); 976 ASSERT_EQ(CBFn->user_back()->getNumUses(), 0U); 977 }; 978 979 auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V, Value &, 980 Value *&) -> InsertPointTy { 981 ++NumPrivatizedVars; 982 llvm_unreachable("No privatization callback call expected!"); 983 }; 984 985 FunctionType *FakeDestructorTy = 986 FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, 987 /*isVarArg=*/false); 988 auto *FakeDestructor = Function::Create( 989 FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get()); 990 991 auto FiniCB = [&](InsertPointTy IP) { 992 ++NumFinalizationPoints; 993 Builder.restoreIP(IP); 994 Builder.CreateCall(FakeDestructor, 995 {Builder.getInt32(NumFinalizationPoints)}); 996 }; 997 998 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 999 F->getEntryBlock().getFirstInsertionPt()); 1000 IRBuilder<>::InsertPoint AfterIP = 1001 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 1002 Builder.CreateIsNotNull(F->arg_begin()), 1003 nullptr, OMP_PROC_BIND_default, true); 1004 1005 EXPECT_EQ(NumBodiesGenerated, 1U); 1006 EXPECT_EQ(NumPrivatizedVars, 0U); 1007 EXPECT_EQ(NumFinalizationPoints, 2U); 1008 EXPECT_EQ(FakeDestructor->getNumUses(), 2U); 1009 1010 Builder.restoreIP(AfterIP); 1011 Builder.CreateRetVoid(); 1012 OMPBuilder.finalize(); 1013 1014 EXPECT_FALSE(verifyModule(*M, &errs())); 1015 1016 BasicBlock *ExitBB = nullptr; 1017 for (const User *Usr : FakeDestructor->users()) { 1018 const CallInst *CI = dyn_cast<CallInst>(Usr); 1019 ASSERT_EQ(CI->getCalledFunction(), FakeDestructor); 1020 ASSERT_TRUE(isa<BranchInst>(CI->getNextNode())); 1021 ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U); 1022 if (ExitBB) 1023 ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB); 1024 else 1025 ExitBB = CI->getNextNode()->getSuccessor(0); 1026 ASSERT_EQ(ExitBB->size(), 1U); 1027 if (!isa<ReturnInst>(ExitBB->front())) { 1028 ASSERT_TRUE(isa<BranchInst>(ExitBB->front())); 1029 ASSERT_EQ(cast<BranchInst>(ExitBB->front()).getNumSuccessors(), 1U); 1030 ASSERT_TRUE(isa<ReturnInst>( 1031 cast<BranchInst>(ExitBB->front()).getSuccessor(0)->front())); 1032 } 1033 } 1034 } 1035 1036 TEST_F(OpenMPIRBuilderTest, ParallelForwardAsPointers) { 1037 OpenMPIRBuilder OMPBuilder(*M); 1038 OMPBuilder.initialize(); 1039 F->setName("func"); 1040 IRBuilder<> Builder(BB); 1041 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1042 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1043 1044 Type *I32Ty = Type::getInt32Ty(M->getContext()); 1045 Type *I32PtrTy = Type::getInt32PtrTy(M->getContext()); 1046 Type *StructTy = StructType::get(I32Ty, I32PtrTy); 1047 Type *StructPtrTy = StructTy->getPointerTo(); 1048 Type *VoidTy = Type::getVoidTy(M->getContext()); 1049 FunctionCallee RetI32Func = M->getOrInsertFunction("ret_i32", I32Ty); 1050 FunctionCallee TakeI32Func = 1051 M->getOrInsertFunction("take_i32", VoidTy, I32Ty); 1052 FunctionCallee RetI32PtrFunc = M->getOrInsertFunction("ret_i32ptr", I32PtrTy); 1053 FunctionCallee TakeI32PtrFunc = 1054 M->getOrInsertFunction("take_i32ptr", VoidTy, I32PtrTy); 1055 FunctionCallee RetStructFunc = M->getOrInsertFunction("ret_struct", StructTy); 1056 FunctionCallee TakeStructFunc = 1057 M->getOrInsertFunction("take_struct", VoidTy, StructTy); 1058 FunctionCallee RetStructPtrFunc = 1059 M->getOrInsertFunction("ret_structptr", StructPtrTy); 1060 FunctionCallee TakeStructPtrFunc = 1061 M->getOrInsertFunction("take_structPtr", VoidTy, StructPtrTy); 1062 Value *I32Val = Builder.CreateCall(RetI32Func); 1063 Value *I32PtrVal = Builder.CreateCall(RetI32PtrFunc); 1064 Value *StructVal = Builder.CreateCall(RetStructFunc); 1065 Value *StructPtrVal = Builder.CreateCall(RetStructPtrFunc); 1066 1067 Instruction *Internal; 1068 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 1069 BasicBlock &ContinuationBB) { 1070 IRBuilder<>::InsertPointGuard Guard(Builder); 1071 Builder.restoreIP(CodeGenIP); 1072 Internal = Builder.CreateCall(TakeI32Func, I32Val); 1073 Builder.CreateCall(TakeI32PtrFunc, I32PtrVal); 1074 Builder.CreateCall(TakeStructFunc, StructVal); 1075 Builder.CreateCall(TakeStructPtrFunc, StructPtrVal); 1076 }; 1077 auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &, 1078 Value &Inner, Value *&ReplacementValue) { 1079 ReplacementValue = &Inner; 1080 return CodeGenIP; 1081 }; 1082 auto FiniCB = [](InsertPointTy) {}; 1083 1084 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 1085 F->getEntryBlock().getFirstInsertionPt()); 1086 IRBuilder<>::InsertPoint AfterIP = 1087 OMPBuilder.createParallel(Loc, AllocaIP, BodyGenCB, PrivCB, FiniCB, 1088 nullptr, nullptr, OMP_PROC_BIND_default, false); 1089 Builder.restoreIP(AfterIP); 1090 Builder.CreateRetVoid(); 1091 1092 OMPBuilder.finalize(); 1093 1094 EXPECT_FALSE(verifyModule(*M, &errs())); 1095 Function *OutlinedFn = Internal->getFunction(); 1096 1097 Type *Arg2Type = OutlinedFn->getArg(2)->getType(); 1098 EXPECT_TRUE(Arg2Type->isPointerTy()); 1099 EXPECT_EQ(Arg2Type->getPointerElementType(), I32Ty); 1100 1101 // Arguments that need to be passed through pointers and reloaded will get 1102 // used earlier in the functions and therefore will appear first in the 1103 // argument list after outlining. 1104 Type *Arg3Type = OutlinedFn->getArg(3)->getType(); 1105 EXPECT_TRUE(Arg3Type->isPointerTy()); 1106 EXPECT_EQ(Arg3Type->getPointerElementType(), StructTy); 1107 1108 Type *Arg4Type = OutlinedFn->getArg(4)->getType(); 1109 EXPECT_EQ(Arg4Type, I32PtrTy); 1110 1111 Type *Arg5Type = OutlinedFn->getArg(5)->getType(); 1112 EXPECT_EQ(Arg5Type, StructPtrTy); 1113 } 1114 1115 TEST_F(OpenMPIRBuilderTest, CanonicalLoopSimple) { 1116 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1117 OpenMPIRBuilder OMPBuilder(*M); 1118 OMPBuilder.initialize(); 1119 IRBuilder<> Builder(BB); 1120 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1121 Value *TripCount = F->getArg(0); 1122 1123 unsigned NumBodiesGenerated = 0; 1124 auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) { 1125 NumBodiesGenerated += 1; 1126 1127 Builder.restoreIP(CodeGenIP); 1128 1129 Value *Cmp = Builder.CreateICmpEQ(LC, TripCount); 1130 Instruction *ThenTerm, *ElseTerm; 1131 SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), 1132 &ThenTerm, &ElseTerm); 1133 }; 1134 1135 CanonicalLoopInfo *Loop = 1136 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, TripCount); 1137 1138 Builder.restoreIP(Loop->getAfterIP()); 1139 ReturnInst *RetInst = Builder.CreateRetVoid(); 1140 OMPBuilder.finalize(); 1141 1142 Loop->assertOK(); 1143 EXPECT_FALSE(verifyModule(*M, &errs())); 1144 1145 EXPECT_EQ(NumBodiesGenerated, 1U); 1146 1147 // Verify control flow structure (in addition to Loop->assertOK()). 1148 EXPECT_EQ(Loop->getPreheader()->getSinglePredecessor(), &F->getEntryBlock()); 1149 EXPECT_EQ(Loop->getAfter(), Builder.GetInsertBlock()); 1150 1151 Instruction *IndVar = Loop->getIndVar(); 1152 EXPECT_TRUE(isa<PHINode>(IndVar)); 1153 EXPECT_EQ(IndVar->getType(), TripCount->getType()); 1154 EXPECT_EQ(IndVar->getParent(), Loop->getHeader()); 1155 1156 EXPECT_EQ(Loop->getTripCount(), TripCount); 1157 1158 BasicBlock *Body = Loop->getBody(); 1159 Instruction *CmpInst = &Body->getInstList().front(); 1160 EXPECT_TRUE(isa<ICmpInst>(CmpInst)); 1161 EXPECT_EQ(CmpInst->getOperand(0), IndVar); 1162 1163 BasicBlock *LatchPred = Loop->getLatch()->getSinglePredecessor(); 1164 EXPECT_TRUE(llvm::all_of(successors(Body), [=](BasicBlock *SuccBB) { 1165 return SuccBB->getSingleSuccessor() == LatchPred; 1166 })); 1167 1168 EXPECT_EQ(&Loop->getAfter()->front(), RetInst); 1169 } 1170 1171 TEST_F(OpenMPIRBuilderTest, CanonicalLoopBounds) { 1172 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1173 OpenMPIRBuilder OMPBuilder(*M); 1174 OMPBuilder.initialize(); 1175 IRBuilder<> Builder(BB); 1176 1177 // Check the trip count is computed correctly. We generate the canonical loop 1178 // but rely on the IRBuilder's constant folder to compute the final result 1179 // since all inputs are constant. To verify overflow situations, limit the 1180 // trip count / loop counter widths to 16 bits. 1181 auto EvalTripCount = [&](int64_t Start, int64_t Stop, int64_t Step, 1182 bool IsSigned, bool InclusiveStop) -> int64_t { 1183 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1184 Type *LCTy = Type::getInt16Ty(Ctx); 1185 Value *StartVal = ConstantInt::get(LCTy, Start); 1186 Value *StopVal = ConstantInt::get(LCTy, Stop); 1187 Value *StepVal = ConstantInt::get(LCTy, Step); 1188 auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) {}; 1189 CanonicalLoopInfo *Loop = 1190 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, StartVal, StopVal, 1191 StepVal, IsSigned, InclusiveStop); 1192 Loop->assertOK(); 1193 Builder.restoreIP(Loop->getAfterIP()); 1194 Value *TripCount = Loop->getTripCount(); 1195 return cast<ConstantInt>(TripCount)->getValue().getZExtValue(); 1196 }; 1197 1198 EXPECT_EQ(EvalTripCount(0, 0, 1, false, false), 0); 1199 EXPECT_EQ(EvalTripCount(0, 1, 2, false, false), 1); 1200 EXPECT_EQ(EvalTripCount(0, 42, 1, false, false), 42); 1201 EXPECT_EQ(EvalTripCount(0, 42, 2, false, false), 21); 1202 EXPECT_EQ(EvalTripCount(21, 42, 1, false, false), 21); 1203 EXPECT_EQ(EvalTripCount(0, 5, 5, false, false), 1); 1204 EXPECT_EQ(EvalTripCount(0, 9, 5, false, false), 2); 1205 EXPECT_EQ(EvalTripCount(0, 11, 5, false, false), 3); 1206 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 1, false, false), 0xFFFF); 1207 EXPECT_EQ(EvalTripCount(0xFFFF, 0, 1, false, false), 0); 1208 EXPECT_EQ(EvalTripCount(0xFFFE, 0xFFFF, 1, false, false), 1); 1209 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0x100, false, false), 0x100); 1210 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFF, false, false), 1); 1211 1212 EXPECT_EQ(EvalTripCount(0, 6, 5, false, false), 2); 1213 EXPECT_EQ(EvalTripCount(0, 0xFFFF, 0xFFFE, false, false), 2); 1214 EXPECT_EQ(EvalTripCount(0, 0, 1, false, true), 1); 1215 EXPECT_EQ(EvalTripCount(0, 0, 0xFFFF, false, true), 1); 1216 EXPECT_EQ(EvalTripCount(0, 0xFFFE, 1, false, true), 0xFFFF); 1217 EXPECT_EQ(EvalTripCount(0, 0xFFFE, 2, false, true), 0x8000); 1218 1219 EXPECT_EQ(EvalTripCount(0, 0, -1, true, false), 0); 1220 EXPECT_EQ(EvalTripCount(0, 1, -1, true, true), 0); 1221 EXPECT_EQ(EvalTripCount(20, 5, -5, true, false), 3); 1222 EXPECT_EQ(EvalTripCount(20, 5, -5, true, true), 4); 1223 EXPECT_EQ(EvalTripCount(-4, -2, 2, true, false), 1); 1224 EXPECT_EQ(EvalTripCount(-4, -3, 2, true, false), 1); 1225 EXPECT_EQ(EvalTripCount(-4, -2, 2, true, true), 2); 1226 1227 EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 1, true, false), 0x8000); 1228 EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 1, true, true), 0x8001); 1229 EXPECT_EQ(EvalTripCount(INT16_MIN, 0x7FFF, 1, true, false), 0xFFFF); 1230 EXPECT_EQ(EvalTripCount(INT16_MIN + 1, 0x7FFF, 1, true, true), 0xFFFF); 1231 EXPECT_EQ(EvalTripCount(INT16_MIN, 0, 0x7FFF, true, false), 2); 1232 EXPECT_EQ(EvalTripCount(0x7FFF, 0, -1, true, false), 0x7FFF); 1233 EXPECT_EQ(EvalTripCount(0, INT16_MIN, -1, true, false), 0x8000); 1234 EXPECT_EQ(EvalTripCount(0, INT16_MIN, -16, true, false), 0x800); 1235 EXPECT_EQ(EvalTripCount(0x7FFF, INT16_MIN, -1, true, false), 0xFFFF); 1236 EXPECT_EQ(EvalTripCount(0x7FFF, 1, INT16_MIN, true, false), 1); 1237 EXPECT_EQ(EvalTripCount(0x7FFF, -1, INT16_MIN, true, true), 2); 1238 1239 // Finalize the function and verify it. 1240 Builder.CreateRetVoid(); 1241 OMPBuilder.finalize(); 1242 EXPECT_FALSE(verifyModule(*M, &errs())); 1243 } 1244 1245 TEST_F(OpenMPIRBuilderTest, CollapseNestedLoops) { 1246 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1247 OpenMPIRBuilder OMPBuilder(*M); 1248 OMPBuilder.initialize(); 1249 F->setName("func"); 1250 1251 IRBuilder<> Builder(BB); 1252 1253 Type *LCTy = F->getArg(0)->getType(); 1254 Constant *One = ConstantInt::get(LCTy, 1); 1255 Constant *Two = ConstantInt::get(LCTy, 2); 1256 Value *OuterTripCount = 1257 Builder.CreateAdd(F->getArg(0), Two, "tripcount.outer"); 1258 Value *InnerTripCount = 1259 Builder.CreateAdd(F->getArg(0), One, "tripcount.inner"); 1260 1261 // Fix an insertion point for ComputeIP. 1262 BasicBlock *LoopNextEnter = 1263 BasicBlock::Create(M->getContext(), "loopnest.enter", F, 1264 Builder.GetInsertBlock()->getNextNode()); 1265 BranchInst *EnterBr = Builder.CreateBr(LoopNextEnter); 1266 InsertPointTy ComputeIP{EnterBr->getParent(), EnterBr->getIterator()}; 1267 1268 Builder.SetInsertPoint(LoopNextEnter); 1269 OpenMPIRBuilder::LocationDescription OuterLoc(Builder.saveIP(), DL); 1270 1271 CanonicalLoopInfo *InnerLoop = nullptr; 1272 CallInst *InbetweenLead = nullptr; 1273 CallInst *InbetweenTrail = nullptr; 1274 CallInst *Call = nullptr; 1275 auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP, Value *OuterLC) { 1276 Builder.restoreIP(OuterCodeGenIP); 1277 InbetweenLead = 1278 createPrintfCall(Builder, "In-between lead i=%d\\n", {OuterLC}); 1279 1280 auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP, 1281 Value *InnerLC) { 1282 Builder.restoreIP(InnerCodeGenIP); 1283 Call = createPrintfCall(Builder, "body i=%d j=%d\\n", {OuterLC, InnerLC}); 1284 }; 1285 InnerLoop = OMPBuilder.createCanonicalLoop( 1286 Builder.saveIP(), InnerLoopBodyGenCB, InnerTripCount, "inner"); 1287 1288 Builder.restoreIP(InnerLoop->getAfterIP()); 1289 InbetweenTrail = 1290 createPrintfCall(Builder, "In-between trail i=%d\\n", {OuterLC}); 1291 }; 1292 CanonicalLoopInfo *OuterLoop = OMPBuilder.createCanonicalLoop( 1293 OuterLoc, OuterLoopBodyGenCB, OuterTripCount, "outer"); 1294 1295 // Finish the function. 1296 Builder.restoreIP(OuterLoop->getAfterIP()); 1297 Builder.CreateRetVoid(); 1298 1299 CanonicalLoopInfo *Collapsed = 1300 OMPBuilder.collapseLoops(DL, {OuterLoop, InnerLoop}, ComputeIP); 1301 1302 OMPBuilder.finalize(); 1303 EXPECT_FALSE(verifyModule(*M, &errs())); 1304 1305 // Verify control flow and BB order. 1306 BasicBlock *RefOrder[] = { 1307 Collapsed->getPreheader(), Collapsed->getHeader(), 1308 Collapsed->getCond(), Collapsed->getBody(), 1309 InbetweenLead->getParent(), Call->getParent(), 1310 InbetweenTrail->getParent(), Collapsed->getLatch(), 1311 Collapsed->getExit(), Collapsed->getAfter(), 1312 }; 1313 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1314 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1315 1316 // Verify the total trip count. 1317 auto *TripCount = cast<MulOperator>(Collapsed->getTripCount()); 1318 EXPECT_EQ(TripCount->getOperand(0), OuterTripCount); 1319 EXPECT_EQ(TripCount->getOperand(1), InnerTripCount); 1320 1321 // Verify the changed indvar. 1322 auto *OuterIV = cast<BinaryOperator>(Call->getOperand(1)); 1323 EXPECT_EQ(OuterIV->getOpcode(), Instruction::UDiv); 1324 EXPECT_EQ(OuterIV->getParent(), Collapsed->getBody()); 1325 EXPECT_EQ(OuterIV->getOperand(1), InnerTripCount); 1326 EXPECT_EQ(OuterIV->getOperand(0), Collapsed->getIndVar()); 1327 1328 auto *InnerIV = cast<BinaryOperator>(Call->getOperand(2)); 1329 EXPECT_EQ(InnerIV->getOpcode(), Instruction::URem); 1330 EXPECT_EQ(InnerIV->getParent(), Collapsed->getBody()); 1331 EXPECT_EQ(InnerIV->getOperand(0), Collapsed->getIndVar()); 1332 EXPECT_EQ(InnerIV->getOperand(1), InnerTripCount); 1333 1334 EXPECT_EQ(InbetweenLead->getOperand(1), OuterIV); 1335 EXPECT_EQ(InbetweenTrail->getOperand(1), OuterIV); 1336 } 1337 1338 TEST_F(OpenMPIRBuilderTest, TileSingleLoop) { 1339 OpenMPIRBuilder OMPBuilder(*M); 1340 Instruction *Call; 1341 BasicBlock *BodyCode; 1342 CanonicalLoopInfo *Loop = 1343 buildSingleLoopFunction(DL, OMPBuilder, &Call, &BodyCode); 1344 1345 Instruction *OrigIndVar = Loop->getIndVar(); 1346 EXPECT_EQ(Call->getOperand(1), OrigIndVar); 1347 1348 // Tile the loop. 1349 Constant *TileSize = ConstantInt::get(Loop->getIndVarType(), APInt(32, 7)); 1350 std::vector<CanonicalLoopInfo *> GenLoops = 1351 OMPBuilder.tileLoops(DL, {Loop}, {TileSize}); 1352 1353 OMPBuilder.finalize(); 1354 EXPECT_FALSE(verifyModule(*M, &errs())); 1355 1356 EXPECT_EQ(GenLoops.size(), 2u); 1357 CanonicalLoopInfo *Floor = GenLoops[0]; 1358 CanonicalLoopInfo *Tile = GenLoops[1]; 1359 1360 BasicBlock *RefOrder[] = { 1361 Floor->getPreheader(), Floor->getHeader(), Floor->getCond(), 1362 Floor->getBody(), Tile->getPreheader(), Tile->getHeader(), 1363 Tile->getCond(), Tile->getBody(), BodyCode, 1364 Tile->getLatch(), Tile->getExit(), Tile->getAfter(), 1365 Floor->getLatch(), Floor->getExit(), Floor->getAfter(), 1366 }; 1367 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1368 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1369 1370 // Check the induction variable. 1371 EXPECT_EQ(Call->getParent(), BodyCode); 1372 auto *Shift = cast<AddOperator>(Call->getOperand(1)); 1373 EXPECT_EQ(cast<Instruction>(Shift)->getParent(), Tile->getBody()); 1374 EXPECT_EQ(Shift->getOperand(1), Tile->getIndVar()); 1375 auto *Scale = cast<MulOperator>(Shift->getOperand(0)); 1376 EXPECT_EQ(cast<Instruction>(Scale)->getParent(), Tile->getBody()); 1377 EXPECT_EQ(Scale->getOperand(0), TileSize); 1378 EXPECT_EQ(Scale->getOperand(1), Floor->getIndVar()); 1379 } 1380 1381 TEST_F(OpenMPIRBuilderTest, TileNestedLoops) { 1382 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1383 OpenMPIRBuilder OMPBuilder(*M); 1384 OMPBuilder.initialize(); 1385 F->setName("func"); 1386 1387 IRBuilder<> Builder(BB); 1388 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1389 Value *TripCount = F->getArg(0); 1390 Type *LCTy = TripCount->getType(); 1391 1392 BasicBlock *BodyCode = nullptr; 1393 CanonicalLoopInfo *InnerLoop = nullptr; 1394 auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP, 1395 llvm::Value *OuterLC) { 1396 auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP, 1397 llvm::Value *InnerLC) { 1398 Builder.restoreIP(InnerCodeGenIP); 1399 BodyCode = Builder.GetInsertBlock(); 1400 1401 // Add something that consumes the induction variables to the body. 1402 createPrintfCall(Builder, "i=%d j=%d\\n", {OuterLC, InnerLC}); 1403 }; 1404 InnerLoop = OMPBuilder.createCanonicalLoop( 1405 OuterCodeGenIP, InnerLoopBodyGenCB, TripCount, "inner"); 1406 }; 1407 CanonicalLoopInfo *OuterLoop = OMPBuilder.createCanonicalLoop( 1408 Loc, OuterLoopBodyGenCB, TripCount, "outer"); 1409 1410 // Finalize the function. 1411 Builder.restoreIP(OuterLoop->getAfterIP()); 1412 Builder.CreateRetVoid(); 1413 1414 // Tile to loop nest. 1415 Constant *OuterTileSize = ConstantInt::get(LCTy, APInt(32, 11)); 1416 Constant *InnerTileSize = ConstantInt::get(LCTy, APInt(32, 7)); 1417 std::vector<CanonicalLoopInfo *> GenLoops = OMPBuilder.tileLoops( 1418 DL, {OuterLoop, InnerLoop}, {OuterTileSize, InnerTileSize}); 1419 1420 OMPBuilder.finalize(); 1421 EXPECT_FALSE(verifyModule(*M, &errs())); 1422 1423 EXPECT_EQ(GenLoops.size(), 4u); 1424 CanonicalLoopInfo *Floor1 = GenLoops[0]; 1425 CanonicalLoopInfo *Floor2 = GenLoops[1]; 1426 CanonicalLoopInfo *Tile1 = GenLoops[2]; 1427 CanonicalLoopInfo *Tile2 = GenLoops[3]; 1428 1429 BasicBlock *RefOrder[] = { 1430 Floor1->getPreheader(), 1431 Floor1->getHeader(), 1432 Floor1->getCond(), 1433 Floor1->getBody(), 1434 Floor2->getPreheader(), 1435 Floor2->getHeader(), 1436 Floor2->getCond(), 1437 Floor2->getBody(), 1438 Tile1->getPreheader(), 1439 Tile1->getHeader(), 1440 Tile1->getCond(), 1441 Tile1->getBody(), 1442 Tile2->getPreheader(), 1443 Tile2->getHeader(), 1444 Tile2->getCond(), 1445 Tile2->getBody(), 1446 BodyCode, 1447 Tile2->getLatch(), 1448 Tile2->getExit(), 1449 Tile2->getAfter(), 1450 Tile1->getLatch(), 1451 Tile1->getExit(), 1452 Tile1->getAfter(), 1453 Floor2->getLatch(), 1454 Floor2->getExit(), 1455 Floor2->getAfter(), 1456 Floor1->getLatch(), 1457 Floor1->getExit(), 1458 Floor1->getAfter(), 1459 }; 1460 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1461 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1462 } 1463 1464 TEST_F(OpenMPIRBuilderTest, TileNestedLoopsWithBounds) { 1465 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1466 OpenMPIRBuilder OMPBuilder(*M); 1467 OMPBuilder.initialize(); 1468 F->setName("func"); 1469 1470 IRBuilder<> Builder(BB); 1471 Value *TripCount = F->getArg(0); 1472 Type *LCTy = TripCount->getType(); 1473 1474 Value *OuterStartVal = ConstantInt::get(LCTy, 2); 1475 Value *OuterStopVal = TripCount; 1476 Value *OuterStep = ConstantInt::get(LCTy, 5); 1477 Value *InnerStartVal = ConstantInt::get(LCTy, 13); 1478 Value *InnerStopVal = TripCount; 1479 Value *InnerStep = ConstantInt::get(LCTy, 3); 1480 1481 // Fix an insertion point for ComputeIP. 1482 BasicBlock *LoopNextEnter = 1483 BasicBlock::Create(M->getContext(), "loopnest.enter", F, 1484 Builder.GetInsertBlock()->getNextNode()); 1485 BranchInst *EnterBr = Builder.CreateBr(LoopNextEnter); 1486 InsertPointTy ComputeIP{EnterBr->getParent(), EnterBr->getIterator()}; 1487 1488 InsertPointTy LoopIP{LoopNextEnter, LoopNextEnter->begin()}; 1489 OpenMPIRBuilder::LocationDescription Loc({LoopIP, DL}); 1490 1491 BasicBlock *BodyCode = nullptr; 1492 CanonicalLoopInfo *InnerLoop = nullptr; 1493 CallInst *Call = nullptr; 1494 auto OuterLoopBodyGenCB = [&](InsertPointTy OuterCodeGenIP, 1495 llvm::Value *OuterLC) { 1496 auto InnerLoopBodyGenCB = [&](InsertPointTy InnerCodeGenIP, 1497 llvm::Value *InnerLC) { 1498 Builder.restoreIP(InnerCodeGenIP); 1499 BodyCode = Builder.GetInsertBlock(); 1500 1501 // Add something that consumes the induction variable to the body. 1502 Call = createPrintfCall(Builder, "i=%d j=%d\\n", {OuterLC, InnerLC}); 1503 }; 1504 InnerLoop = OMPBuilder.createCanonicalLoop( 1505 OuterCodeGenIP, InnerLoopBodyGenCB, InnerStartVal, InnerStopVal, 1506 InnerStep, false, false, ComputeIP, "inner"); 1507 }; 1508 CanonicalLoopInfo *OuterLoop = OMPBuilder.createCanonicalLoop( 1509 Loc, OuterLoopBodyGenCB, OuterStartVal, OuterStopVal, OuterStep, false, 1510 false, ComputeIP, "outer"); 1511 1512 // Finalize the function 1513 Builder.restoreIP(OuterLoop->getAfterIP()); 1514 Builder.CreateRetVoid(); 1515 1516 // Tile the loop nest. 1517 Constant *TileSize0 = ConstantInt::get(LCTy, APInt(32, 11)); 1518 Constant *TileSize1 = ConstantInt::get(LCTy, APInt(32, 7)); 1519 std::vector<CanonicalLoopInfo *> GenLoops = 1520 OMPBuilder.tileLoops(DL, {OuterLoop, InnerLoop}, {TileSize0, TileSize1}); 1521 1522 OMPBuilder.finalize(); 1523 EXPECT_FALSE(verifyModule(*M, &errs())); 1524 1525 EXPECT_EQ(GenLoops.size(), 4u); 1526 CanonicalLoopInfo *Floor0 = GenLoops[0]; 1527 CanonicalLoopInfo *Floor1 = GenLoops[1]; 1528 CanonicalLoopInfo *Tile0 = GenLoops[2]; 1529 CanonicalLoopInfo *Tile1 = GenLoops[3]; 1530 1531 BasicBlock *RefOrder[] = { 1532 Floor0->getPreheader(), 1533 Floor0->getHeader(), 1534 Floor0->getCond(), 1535 Floor0->getBody(), 1536 Floor1->getPreheader(), 1537 Floor1->getHeader(), 1538 Floor1->getCond(), 1539 Floor1->getBody(), 1540 Tile0->getPreheader(), 1541 Tile0->getHeader(), 1542 Tile0->getCond(), 1543 Tile0->getBody(), 1544 Tile1->getPreheader(), 1545 Tile1->getHeader(), 1546 Tile1->getCond(), 1547 Tile1->getBody(), 1548 BodyCode, 1549 Tile1->getLatch(), 1550 Tile1->getExit(), 1551 Tile1->getAfter(), 1552 Tile0->getLatch(), 1553 Tile0->getExit(), 1554 Tile0->getAfter(), 1555 Floor1->getLatch(), 1556 Floor1->getExit(), 1557 Floor1->getAfter(), 1558 Floor0->getLatch(), 1559 Floor0->getExit(), 1560 Floor0->getAfter(), 1561 }; 1562 EXPECT_TRUE(verifyDFSOrder(F, RefOrder)); 1563 EXPECT_TRUE(verifyListOrder(F, RefOrder)); 1564 1565 EXPECT_EQ(Call->getParent(), BodyCode); 1566 1567 auto *RangeShift0 = cast<AddOperator>(Call->getOperand(1)); 1568 EXPECT_EQ(RangeShift0->getOperand(1), OuterStartVal); 1569 auto *RangeScale0 = cast<MulOperator>(RangeShift0->getOperand(0)); 1570 EXPECT_EQ(RangeScale0->getOperand(1), OuterStep); 1571 auto *TileShift0 = cast<AddOperator>(RangeScale0->getOperand(0)); 1572 EXPECT_EQ(cast<Instruction>(TileShift0)->getParent(), Tile1->getBody()); 1573 EXPECT_EQ(TileShift0->getOperand(1), Tile0->getIndVar()); 1574 auto *TileScale0 = cast<MulOperator>(TileShift0->getOperand(0)); 1575 EXPECT_EQ(cast<Instruction>(TileScale0)->getParent(), Tile1->getBody()); 1576 EXPECT_EQ(TileScale0->getOperand(0), TileSize0); 1577 EXPECT_EQ(TileScale0->getOperand(1), Floor0->getIndVar()); 1578 1579 auto *RangeShift1 = cast<AddOperator>(Call->getOperand(2)); 1580 EXPECT_EQ(cast<Instruction>(RangeShift1)->getParent(), BodyCode); 1581 EXPECT_EQ(RangeShift1->getOperand(1), InnerStartVal); 1582 auto *RangeScale1 = cast<MulOperator>(RangeShift1->getOperand(0)); 1583 EXPECT_EQ(cast<Instruction>(RangeScale1)->getParent(), BodyCode); 1584 EXPECT_EQ(RangeScale1->getOperand(1), InnerStep); 1585 auto *TileShift1 = cast<AddOperator>(RangeScale1->getOperand(0)); 1586 EXPECT_EQ(cast<Instruction>(TileShift1)->getParent(), Tile1->getBody()); 1587 EXPECT_EQ(TileShift1->getOperand(1), Tile1->getIndVar()); 1588 auto *TileScale1 = cast<MulOperator>(TileShift1->getOperand(0)); 1589 EXPECT_EQ(cast<Instruction>(TileScale1)->getParent(), Tile1->getBody()); 1590 EXPECT_EQ(TileScale1->getOperand(0), TileSize1); 1591 EXPECT_EQ(TileScale1->getOperand(1), Floor1->getIndVar()); 1592 } 1593 1594 TEST_F(OpenMPIRBuilderTest, TileSingleLoopCounts) { 1595 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1596 OpenMPIRBuilder OMPBuilder(*M); 1597 OMPBuilder.initialize(); 1598 IRBuilder<> Builder(BB); 1599 1600 // Create a loop, tile it, and extract its trip count. All input values are 1601 // constant and IRBuilder evaluates all-constant arithmetic inplace, such that 1602 // the floor trip count itself will be a ConstantInt. Unfortunately we cannot 1603 // do the same for the tile loop. 1604 auto GetFloorCount = [&](int64_t Start, int64_t Stop, int64_t Step, 1605 bool IsSigned, bool InclusiveStop, 1606 int64_t TileSize) -> uint64_t { 1607 OpenMPIRBuilder::LocationDescription Loc(Builder.saveIP(), DL); 1608 Type *LCTy = Type::getInt16Ty(Ctx); 1609 Value *StartVal = ConstantInt::get(LCTy, Start); 1610 Value *StopVal = ConstantInt::get(LCTy, Stop); 1611 Value *StepVal = ConstantInt::get(LCTy, Step); 1612 1613 // Generate a loop. 1614 auto LoopBodyGenCB = [&](InsertPointTy CodeGenIP, llvm::Value *LC) {}; 1615 CanonicalLoopInfo *Loop = 1616 OMPBuilder.createCanonicalLoop(Loc, LoopBodyGenCB, StartVal, StopVal, 1617 StepVal, IsSigned, InclusiveStop); 1618 InsertPointTy AfterIP = Loop->getAfterIP(); 1619 1620 // Tile the loop. 1621 Value *TileSizeVal = ConstantInt::get(LCTy, TileSize); 1622 std::vector<CanonicalLoopInfo *> GenLoops = 1623 OMPBuilder.tileLoops(Loc.DL, {Loop}, {TileSizeVal}); 1624 1625 // Set the insertion pointer to after loop, where the next loop will be 1626 // emitted. 1627 Builder.restoreIP(AfterIP); 1628 1629 // Extract the trip count. 1630 CanonicalLoopInfo *FloorLoop = GenLoops[0]; 1631 Value *FloorTripCount = FloorLoop->getTripCount(); 1632 return cast<ConstantInt>(FloorTripCount)->getValue().getZExtValue(); 1633 }; 1634 1635 // Empty iteration domain. 1636 EXPECT_EQ(GetFloorCount(0, 0, 1, false, false, 7), 0u); 1637 EXPECT_EQ(GetFloorCount(0, -1, 1, false, true, 7), 0u); 1638 EXPECT_EQ(GetFloorCount(-1, -1, -1, true, false, 7), 0u); 1639 EXPECT_EQ(GetFloorCount(-1, 0, -1, true, true, 7), 0u); 1640 EXPECT_EQ(GetFloorCount(-1, -1, 3, true, false, 7), 0u); 1641 1642 // Only complete tiles. 1643 EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u); 1644 EXPECT_EQ(GetFloorCount(0, 14, 1, false, false, 7), 2u); 1645 EXPECT_EQ(GetFloorCount(1, 15, 1, false, false, 7), 2u); 1646 EXPECT_EQ(GetFloorCount(0, -14, -1, true, false, 7), 2u); 1647 EXPECT_EQ(GetFloorCount(-1, -14, -1, true, true, 7), 2u); 1648 EXPECT_EQ(GetFloorCount(0, 3 * 7 * 2, 3, false, false, 7), 2u); 1649 1650 // Only a partial tile. 1651 EXPECT_EQ(GetFloorCount(0, 1, 1, false, false, 7), 1u); 1652 EXPECT_EQ(GetFloorCount(0, 6, 1, false, false, 7), 1u); 1653 EXPECT_EQ(GetFloorCount(-1, 1, 3, true, false, 7), 1u); 1654 EXPECT_EQ(GetFloorCount(-1, -2, -1, true, false, 7), 1u); 1655 EXPECT_EQ(GetFloorCount(0, 2, 3, false, false, 7), 1u); 1656 1657 // Complete and partial tiles. 1658 EXPECT_EQ(GetFloorCount(0, 13, 1, false, false, 7), 2u); 1659 EXPECT_EQ(GetFloorCount(0, 15, 1, false, false, 7), 3u); 1660 EXPECT_EQ(GetFloorCount(-1, -14, -1, true, false, 7), 2u); 1661 EXPECT_EQ(GetFloorCount(0, 3 * 7 * 5 - 1, 3, false, false, 7), 5u); 1662 EXPECT_EQ(GetFloorCount(-1, -3 * 7 * 5, -3, true, false, 7), 5u); 1663 1664 // Close to 16-bit integer range. 1665 EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 1), 0xFFFFu); 1666 EXPECT_EQ(GetFloorCount(0, 0xFFFF, 1, false, false, 7), 0xFFFFu / 7 + 1); 1667 EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, true, 7), 0xFFFFu / 7 + 1); 1668 EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 7), 0xFFFFu / 7 + 1); 1669 EXPECT_EQ(GetFloorCount(-0x7FFF, 0x7FFF, 1, true, true, 7), 0xFFFFu / 7 + 1); 1670 EXPECT_EQ(GetFloorCount(0, 0xFFFE, 1, false, false, 0xFFFF), 1u); 1671 EXPECT_EQ(GetFloorCount(-0x8000, 0x7FFF, 1, true, false, 0xFFFF), 1u); 1672 1673 // Finalize the function. 1674 Builder.CreateRetVoid(); 1675 OMPBuilder.finalize(); 1676 1677 EXPECT_FALSE(verifyModule(*M, &errs())); 1678 } 1679 1680 TEST_F(OpenMPIRBuilderTest, ApplySimd) { 1681 OpenMPIRBuilder OMPBuilder(*M); 1682 1683 CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder); 1684 1685 // Simd-ize the loop. 1686 OMPBuilder.applySimd(DL, CLI); 1687 1688 OMPBuilder.finalize(); 1689 EXPECT_FALSE(verifyModule(*M, &errs())); 1690 1691 PassBuilder PB; 1692 FunctionAnalysisManager FAM; 1693 PB.registerFunctionAnalyses(FAM); 1694 LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F); 1695 1696 const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops(); 1697 EXPECT_EQ(TopLvl.size(), 1u); 1698 1699 Loop *L = TopLvl.front(); 1700 EXPECT_TRUE(findStringMetadataForLoop(L, "llvm.loop.parallel_accesses")); 1701 EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.vectorize.enable")); 1702 1703 // Check for llvm.access.group metadata attached to the printf 1704 // function in the loop body. 1705 BasicBlock *LoopBody = CLI->getBody(); 1706 EXPECT_TRUE(any_of(*LoopBody, [](Instruction &I) { 1707 return I.getMetadata("llvm.access.group") != nullptr; 1708 })); 1709 } 1710 1711 TEST_F(OpenMPIRBuilderTest, UnrollLoopFull) { 1712 OpenMPIRBuilder OMPBuilder(*M); 1713 1714 CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder); 1715 1716 // Unroll the loop. 1717 OMPBuilder.unrollLoopFull(DL, CLI); 1718 1719 OMPBuilder.finalize(); 1720 EXPECT_FALSE(verifyModule(*M, &errs())); 1721 1722 PassBuilder PB; 1723 FunctionAnalysisManager FAM; 1724 PB.registerFunctionAnalyses(FAM); 1725 LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F); 1726 1727 const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops(); 1728 EXPECT_EQ(TopLvl.size(), 1u); 1729 1730 Loop *L = TopLvl.front(); 1731 EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.unroll.enable")); 1732 EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.unroll.full")); 1733 } 1734 1735 TEST_F(OpenMPIRBuilderTest, UnrollLoopPartial) { 1736 OpenMPIRBuilder OMPBuilder(*M); 1737 CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder); 1738 1739 // Unroll the loop. 1740 CanonicalLoopInfo *UnrolledLoop = nullptr; 1741 OMPBuilder.unrollLoopPartial(DL, CLI, 5, &UnrolledLoop); 1742 ASSERT_NE(UnrolledLoop, nullptr); 1743 1744 OMPBuilder.finalize(); 1745 EXPECT_FALSE(verifyModule(*M, &errs())); 1746 UnrolledLoop->assertOK(); 1747 1748 PassBuilder PB; 1749 FunctionAnalysisManager FAM; 1750 PB.registerFunctionAnalyses(FAM); 1751 LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F); 1752 1753 const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops(); 1754 EXPECT_EQ(TopLvl.size(), 1u); 1755 Loop *Outer = TopLvl.front(); 1756 EXPECT_EQ(Outer->getHeader(), UnrolledLoop->getHeader()); 1757 EXPECT_EQ(Outer->getLoopLatch(), UnrolledLoop->getLatch()); 1758 EXPECT_EQ(Outer->getExitingBlock(), UnrolledLoop->getCond()); 1759 EXPECT_EQ(Outer->getExitBlock(), UnrolledLoop->getExit()); 1760 1761 EXPECT_EQ(Outer->getSubLoops().size(), 1u); 1762 Loop *Inner = Outer->getSubLoops().front(); 1763 1764 EXPECT_TRUE(getBooleanLoopAttribute(Inner, "llvm.loop.unroll.enable")); 1765 EXPECT_EQ(getIntLoopAttribute(Inner, "llvm.loop.unroll.count"), 5); 1766 } 1767 1768 TEST_F(OpenMPIRBuilderTest, UnrollLoopHeuristic) { 1769 OpenMPIRBuilder OMPBuilder(*M); 1770 1771 CanonicalLoopInfo *CLI = buildSingleLoopFunction(DL, OMPBuilder); 1772 1773 // Unroll the loop. 1774 OMPBuilder.unrollLoopHeuristic(DL, CLI); 1775 1776 OMPBuilder.finalize(); 1777 EXPECT_FALSE(verifyModule(*M, &errs())); 1778 1779 PassBuilder PB; 1780 FunctionAnalysisManager FAM; 1781 PB.registerFunctionAnalyses(FAM); 1782 LoopInfo &LI = FAM.getResult<LoopAnalysis>(*F); 1783 1784 const std::vector<Loop *> &TopLvl = LI.getTopLevelLoops(); 1785 EXPECT_EQ(TopLvl.size(), 1u); 1786 1787 Loop *L = TopLvl.front(); 1788 EXPECT_TRUE(getBooleanLoopAttribute(L, "llvm.loop.unroll.enable")); 1789 } 1790 1791 TEST_F(OpenMPIRBuilderTest, StaticWorkShareLoop) { 1792 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1793 OpenMPIRBuilder OMPBuilder(*M); 1794 OMPBuilder.initialize(); 1795 IRBuilder<> Builder(BB); 1796 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1797 1798 Type *LCTy = Type::getInt32Ty(Ctx); 1799 Value *StartVal = ConstantInt::get(LCTy, 10); 1800 Value *StopVal = ConstantInt::get(LCTy, 52); 1801 Value *StepVal = ConstantInt::get(LCTy, 2); 1802 auto LoopBodyGen = [&](InsertPointTy, llvm::Value *) {}; 1803 1804 CanonicalLoopInfo *CLI = OMPBuilder.createCanonicalLoop( 1805 Loc, LoopBodyGen, StartVal, StopVal, StepVal, 1806 /*IsSigned=*/false, /*InclusiveStop=*/false); 1807 BasicBlock *Preheader = CLI->getPreheader(); 1808 BasicBlock *Body = CLI->getBody(); 1809 Value *IV = CLI->getIndVar(); 1810 BasicBlock *ExitBlock = CLI->getExit(); 1811 1812 Builder.SetInsertPoint(BB, BB->getFirstInsertionPt()); 1813 InsertPointTy AllocaIP = Builder.saveIP(); 1814 1815 OMPBuilder.applyStaticWorkshareLoop(DL, CLI, AllocaIP, /*NeedsBarrier=*/true); 1816 1817 BasicBlock *Cond = Body->getSinglePredecessor(); 1818 Instruction *Cmp = &*Cond->begin(); 1819 Value *TripCount = Cmp->getOperand(1); 1820 1821 auto AllocaIter = BB->begin(); 1822 ASSERT_GE(std::distance(BB->begin(), BB->end()), 4); 1823 AllocaInst *PLastIter = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1824 AllocaInst *PLowerBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1825 AllocaInst *PUpperBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1826 AllocaInst *PStride = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1827 EXPECT_NE(PLastIter, nullptr); 1828 EXPECT_NE(PLowerBound, nullptr); 1829 EXPECT_NE(PUpperBound, nullptr); 1830 EXPECT_NE(PStride, nullptr); 1831 1832 auto PreheaderIter = Preheader->begin(); 1833 ASSERT_GE(std::distance(Preheader->begin(), Preheader->end()), 7); 1834 StoreInst *LowerBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1835 StoreInst *UpperBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1836 StoreInst *StrideStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1837 ASSERT_NE(LowerBoundStore, nullptr); 1838 ASSERT_NE(UpperBoundStore, nullptr); 1839 ASSERT_NE(StrideStore, nullptr); 1840 1841 auto *OrigLowerBound = 1842 dyn_cast<ConstantInt>(LowerBoundStore->getValueOperand()); 1843 auto *OrigUpperBound = 1844 dyn_cast<ConstantInt>(UpperBoundStore->getValueOperand()); 1845 auto *OrigStride = dyn_cast<ConstantInt>(StrideStore->getValueOperand()); 1846 ASSERT_NE(OrigLowerBound, nullptr); 1847 ASSERT_NE(OrigUpperBound, nullptr); 1848 ASSERT_NE(OrigStride, nullptr); 1849 EXPECT_EQ(OrigLowerBound->getValue(), 0); 1850 EXPECT_EQ(OrigUpperBound->getValue(), 20); 1851 EXPECT_EQ(OrigStride->getValue(), 1); 1852 1853 // Check that the loop IV is updated to account for the lower bound returned 1854 // by the OpenMP runtime call. 1855 BinaryOperator *Add = dyn_cast<BinaryOperator>(&Body->front()); 1856 EXPECT_EQ(Add->getOperand(0), IV); 1857 auto *LoadedLowerBound = dyn_cast<LoadInst>(Add->getOperand(1)); 1858 ASSERT_NE(LoadedLowerBound, nullptr); 1859 EXPECT_EQ(LoadedLowerBound->getPointerOperand(), PLowerBound); 1860 1861 // Check that the trip count is updated to account for the lower and upper 1862 // bounds return by the OpenMP runtime call. 1863 auto *AddOne = dyn_cast<Instruction>(TripCount); 1864 ASSERT_NE(AddOne, nullptr); 1865 ASSERT_TRUE(AddOne->isBinaryOp()); 1866 auto *One = dyn_cast<ConstantInt>(AddOne->getOperand(1)); 1867 ASSERT_NE(One, nullptr); 1868 EXPECT_EQ(One->getValue(), 1); 1869 auto *Difference = dyn_cast<Instruction>(AddOne->getOperand(0)); 1870 ASSERT_NE(Difference, nullptr); 1871 ASSERT_TRUE(Difference->isBinaryOp()); 1872 EXPECT_EQ(Difference->getOperand(1), LoadedLowerBound); 1873 auto *LoadedUpperBound = dyn_cast<LoadInst>(Difference->getOperand(0)); 1874 ASSERT_NE(LoadedUpperBound, nullptr); 1875 EXPECT_EQ(LoadedUpperBound->getPointerOperand(), PUpperBound); 1876 1877 // The original loop iterator should only be used in the condition, in the 1878 // increment and in the statement that adds the lower bound to it. 1879 EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3); 1880 1881 // The exit block should contain the "fini" call and the barrier call, 1882 // plus the call to obtain the thread ID. 1883 size_t NumCallsInExitBlock = 1884 count_if(*ExitBlock, [](Instruction &I) { return isa<CallInst>(I); }); 1885 EXPECT_EQ(NumCallsInExitBlock, 3u); 1886 } 1887 1888 TEST_P(OpenMPIRBuilderTestWithParams, DynamicWorkShareLoop) { 1889 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 1890 OpenMPIRBuilder OMPBuilder(*M); 1891 OMPBuilder.initialize(); 1892 IRBuilder<> Builder(BB); 1893 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 1894 1895 omp::OMPScheduleType SchedType = GetParam(); 1896 uint32_t ChunkSize = 1; 1897 switch (SchedType & ~omp::OMPScheduleType::ModifierMask) { 1898 case omp::OMPScheduleType::DynamicChunked: 1899 case omp::OMPScheduleType::GuidedChunked: 1900 ChunkSize = 7; 1901 break; 1902 case omp::OMPScheduleType::Auto: 1903 case omp::OMPScheduleType::Runtime: 1904 ChunkSize = 1; 1905 break; 1906 default: 1907 assert(0 && "unknown type for this test"); 1908 break; 1909 } 1910 1911 Type *LCTy = Type::getInt32Ty(Ctx); 1912 Value *StartVal = ConstantInt::get(LCTy, 10); 1913 Value *StopVal = ConstantInt::get(LCTy, 52); 1914 Value *StepVal = ConstantInt::get(LCTy, 2); 1915 Value *ChunkVal = ConstantInt::get(LCTy, ChunkSize); 1916 auto LoopBodyGen = [&](InsertPointTy, llvm::Value *) {}; 1917 1918 CanonicalLoopInfo *CLI = OMPBuilder.createCanonicalLoop( 1919 Loc, LoopBodyGen, StartVal, StopVal, StepVal, 1920 /*IsSigned=*/false, /*InclusiveStop=*/false); 1921 1922 Builder.SetInsertPoint(BB, BB->getFirstInsertionPt()); 1923 InsertPointTy AllocaIP = Builder.saveIP(); 1924 1925 // Collect all the info from CLI, as it isn't usable after the call to 1926 // createDynamicWorkshareLoop. 1927 InsertPointTy AfterIP = CLI->getAfterIP(); 1928 BasicBlock *Preheader = CLI->getPreheader(); 1929 BasicBlock *ExitBlock = CLI->getExit(); 1930 Value *IV = CLI->getIndVar(); 1931 1932 InsertPointTy EndIP = 1933 OMPBuilder.applyDynamicWorkshareLoop(DL, CLI, AllocaIP, SchedType, 1934 /*NeedsBarrier=*/true, ChunkVal); 1935 // The returned value should be the "after" point. 1936 ASSERT_EQ(EndIP.getBlock(), AfterIP.getBlock()); 1937 ASSERT_EQ(EndIP.getPoint(), AfterIP.getPoint()); 1938 1939 auto AllocaIter = BB->begin(); 1940 ASSERT_GE(std::distance(BB->begin(), BB->end()), 4); 1941 AllocaInst *PLastIter = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1942 AllocaInst *PLowerBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1943 AllocaInst *PUpperBound = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1944 AllocaInst *PStride = dyn_cast<AllocaInst>(&*(AllocaIter++)); 1945 EXPECT_NE(PLastIter, nullptr); 1946 EXPECT_NE(PLowerBound, nullptr); 1947 EXPECT_NE(PUpperBound, nullptr); 1948 EXPECT_NE(PStride, nullptr); 1949 1950 auto PreheaderIter = Preheader->begin(); 1951 ASSERT_GE(std::distance(Preheader->begin(), Preheader->end()), 6); 1952 StoreInst *LowerBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1953 StoreInst *UpperBoundStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1954 StoreInst *StrideStore = dyn_cast<StoreInst>(&*(PreheaderIter++)); 1955 ASSERT_NE(LowerBoundStore, nullptr); 1956 ASSERT_NE(UpperBoundStore, nullptr); 1957 ASSERT_NE(StrideStore, nullptr); 1958 1959 CallInst *ThreadIdCall = dyn_cast<CallInst>(&*(PreheaderIter++)); 1960 ASSERT_NE(ThreadIdCall, nullptr); 1961 EXPECT_EQ(ThreadIdCall->getCalledFunction()->getName(), 1962 "__kmpc_global_thread_num"); 1963 1964 CallInst *InitCall = dyn_cast<CallInst>(&*PreheaderIter); 1965 1966 ASSERT_NE(InitCall, nullptr); 1967 EXPECT_EQ(InitCall->getCalledFunction()->getName(), 1968 "__kmpc_dispatch_init_4u"); 1969 EXPECT_EQ(InitCall->arg_size(), 7U); 1970 EXPECT_EQ(InitCall->getArgOperand(6), ConstantInt::get(LCTy, ChunkSize)); 1971 ConstantInt *SchedVal = cast<ConstantInt>(InitCall->getArgOperand(2)); 1972 EXPECT_EQ(SchedVal->getValue(), static_cast<uint64_t>(SchedType)); 1973 1974 ConstantInt *OrigLowerBound = 1975 dyn_cast<ConstantInt>(LowerBoundStore->getValueOperand()); 1976 ConstantInt *OrigUpperBound = 1977 dyn_cast<ConstantInt>(UpperBoundStore->getValueOperand()); 1978 ConstantInt *OrigStride = 1979 dyn_cast<ConstantInt>(StrideStore->getValueOperand()); 1980 ASSERT_NE(OrigLowerBound, nullptr); 1981 ASSERT_NE(OrigUpperBound, nullptr); 1982 ASSERT_NE(OrigStride, nullptr); 1983 EXPECT_EQ(OrigLowerBound->getValue(), 1); 1984 EXPECT_EQ(OrigUpperBound->getValue(), 21); 1985 EXPECT_EQ(OrigStride->getValue(), 1); 1986 1987 // The original loop iterator should only be used in the condition, in the 1988 // increment and in the statement that adds the lower bound to it. 1989 EXPECT_EQ(std::distance(IV->use_begin(), IV->use_end()), 3); 1990 1991 // The exit block should contain the barrier call, plus the call to obtain 1992 // the thread ID. 1993 size_t NumCallsInExitBlock = 1994 count_if(*ExitBlock, [](Instruction &I) { return isa<CallInst>(I); }); 1995 EXPECT_EQ(NumCallsInExitBlock, 2u); 1996 1997 // Add a termination to our block and check that it is internally consistent. 1998 Builder.restoreIP(EndIP); 1999 Builder.CreateRetVoid(); 2000 OMPBuilder.finalize(); 2001 EXPECT_FALSE(verifyModule(*M, &errs())); 2002 } 2003 2004 INSTANTIATE_TEST_SUITE_P( 2005 OpenMPWSLoopSchedulingTypes, OpenMPIRBuilderTestWithParams, 2006 ::testing::Values(omp::OMPScheduleType::DynamicChunked, 2007 omp::OMPScheduleType::GuidedChunked, 2008 omp::OMPScheduleType::Auto, omp::OMPScheduleType::Runtime, 2009 omp::OMPScheduleType::DynamicChunked | 2010 omp::OMPScheduleType::ModifierMonotonic, 2011 omp::OMPScheduleType::DynamicChunked | 2012 omp::OMPScheduleType::ModifierNonmonotonic, 2013 omp::OMPScheduleType::GuidedChunked | 2014 omp::OMPScheduleType::ModifierMonotonic, 2015 omp::OMPScheduleType::GuidedChunked | 2016 omp::OMPScheduleType::ModifierNonmonotonic, 2017 omp::OMPScheduleType::Auto | 2018 omp::OMPScheduleType::ModifierMonotonic, 2019 omp::OMPScheduleType::Runtime | 2020 omp::OMPScheduleType::ModifierMonotonic)); 2021 2022 TEST_F(OpenMPIRBuilderTest, MasterDirective) { 2023 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2024 OpenMPIRBuilder OMPBuilder(*M); 2025 OMPBuilder.initialize(); 2026 F->setName("func"); 2027 IRBuilder<> Builder(BB); 2028 2029 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2030 2031 AllocaInst *PrivAI = nullptr; 2032 2033 BasicBlock *EntryBB = nullptr; 2034 BasicBlock *ExitBB = nullptr; 2035 BasicBlock *ThenBB = nullptr; 2036 2037 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2038 BasicBlock &FiniBB) { 2039 if (AllocaIP.isSet()) 2040 Builder.restoreIP(AllocaIP); 2041 else 2042 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); 2043 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2044 Builder.CreateStore(F->arg_begin(), PrivAI); 2045 2046 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2047 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2048 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2049 2050 Builder.restoreIP(CodeGenIP); 2051 2052 // collect some info for checks later 2053 ExitBB = FiniBB.getUniqueSuccessor(); 2054 ThenBB = Builder.GetInsertBlock(); 2055 EntryBB = ThenBB->getUniquePredecessor(); 2056 2057 // simple instructions for body 2058 Value *PrivLoad = 2059 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2060 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2061 }; 2062 2063 auto FiniCB = [&](InsertPointTy IP) { 2064 BasicBlock *IPBB = IP.getBlock(); 2065 EXPECT_NE(IPBB->end(), IP.getPoint()); 2066 }; 2067 2068 Builder.restoreIP(OMPBuilder.createMaster(Builder, BodyGenCB, FiniCB)); 2069 Value *EntryBBTI = EntryBB->getTerminator(); 2070 EXPECT_NE(EntryBBTI, nullptr); 2071 EXPECT_TRUE(isa<BranchInst>(EntryBBTI)); 2072 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator()); 2073 EXPECT_TRUE(EntryBr->isConditional()); 2074 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); 2075 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); 2076 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); 2077 2078 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition()); 2079 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0))); 2080 2081 CallInst *MasterEntryCI = cast<CallInst>(CondInst->getOperand(0)); 2082 EXPECT_EQ(MasterEntryCI->arg_size(), 2U); 2083 EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master"); 2084 EXPECT_TRUE(isa<GlobalVariable>(MasterEntryCI->getArgOperand(0))); 2085 2086 CallInst *MasterEndCI = nullptr; 2087 for (auto &FI : *ThenBB) { 2088 Instruction *cur = &FI; 2089 if (isa<CallInst>(cur)) { 2090 MasterEndCI = cast<CallInst>(cur); 2091 if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master") 2092 break; 2093 MasterEndCI = nullptr; 2094 } 2095 } 2096 EXPECT_NE(MasterEndCI, nullptr); 2097 EXPECT_EQ(MasterEndCI->arg_size(), 2U); 2098 EXPECT_TRUE(isa<GlobalVariable>(MasterEndCI->getArgOperand(0))); 2099 EXPECT_EQ(MasterEndCI->getArgOperand(1), MasterEntryCI->getArgOperand(1)); 2100 } 2101 2102 TEST_F(OpenMPIRBuilderTest, MaskedDirective) { 2103 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2104 OpenMPIRBuilder OMPBuilder(*M); 2105 OMPBuilder.initialize(); 2106 F->setName("func"); 2107 IRBuilder<> Builder(BB); 2108 2109 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2110 2111 AllocaInst *PrivAI = nullptr; 2112 2113 BasicBlock *EntryBB = nullptr; 2114 BasicBlock *ExitBB = nullptr; 2115 BasicBlock *ThenBB = nullptr; 2116 2117 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2118 BasicBlock &FiniBB) { 2119 if (AllocaIP.isSet()) 2120 Builder.restoreIP(AllocaIP); 2121 else 2122 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); 2123 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2124 Builder.CreateStore(F->arg_begin(), PrivAI); 2125 2126 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2127 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2128 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2129 2130 Builder.restoreIP(CodeGenIP); 2131 2132 // collect some info for checks later 2133 ExitBB = FiniBB.getUniqueSuccessor(); 2134 ThenBB = Builder.GetInsertBlock(); 2135 EntryBB = ThenBB->getUniquePredecessor(); 2136 2137 // simple instructions for body 2138 Value *PrivLoad = 2139 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2140 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2141 }; 2142 2143 auto FiniCB = [&](InsertPointTy IP) { 2144 BasicBlock *IPBB = IP.getBlock(); 2145 EXPECT_NE(IPBB->end(), IP.getPoint()); 2146 }; 2147 2148 Constant *Filter = ConstantInt::get(Type::getInt32Ty(M->getContext()), 0); 2149 Builder.restoreIP( 2150 OMPBuilder.createMasked(Builder, BodyGenCB, FiniCB, Filter)); 2151 Value *EntryBBTI = EntryBB->getTerminator(); 2152 EXPECT_NE(EntryBBTI, nullptr); 2153 EXPECT_TRUE(isa<BranchInst>(EntryBBTI)); 2154 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator()); 2155 EXPECT_TRUE(EntryBr->isConditional()); 2156 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); 2157 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); 2158 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); 2159 2160 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition()); 2161 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0))); 2162 2163 CallInst *MaskedEntryCI = cast<CallInst>(CondInst->getOperand(0)); 2164 EXPECT_EQ(MaskedEntryCI->arg_size(), 3U); 2165 EXPECT_EQ(MaskedEntryCI->getCalledFunction()->getName(), "__kmpc_masked"); 2166 EXPECT_TRUE(isa<GlobalVariable>(MaskedEntryCI->getArgOperand(0))); 2167 2168 CallInst *MaskedEndCI = nullptr; 2169 for (auto &FI : *ThenBB) { 2170 Instruction *cur = &FI; 2171 if (isa<CallInst>(cur)) { 2172 MaskedEndCI = cast<CallInst>(cur); 2173 if (MaskedEndCI->getCalledFunction()->getName() == "__kmpc_end_masked") 2174 break; 2175 MaskedEndCI = nullptr; 2176 } 2177 } 2178 EXPECT_NE(MaskedEndCI, nullptr); 2179 EXPECT_EQ(MaskedEndCI->arg_size(), 2U); 2180 EXPECT_TRUE(isa<GlobalVariable>(MaskedEndCI->getArgOperand(0))); 2181 EXPECT_EQ(MaskedEndCI->getArgOperand(1), MaskedEntryCI->getArgOperand(1)); 2182 } 2183 2184 TEST_F(OpenMPIRBuilderTest, CriticalDirective) { 2185 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2186 OpenMPIRBuilder OMPBuilder(*M); 2187 OMPBuilder.initialize(); 2188 F->setName("func"); 2189 IRBuilder<> Builder(BB); 2190 2191 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2192 2193 AllocaInst *PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2194 2195 BasicBlock *EntryBB = nullptr; 2196 2197 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2198 BasicBlock &FiniBB) { 2199 // collect some info for checks later 2200 EntryBB = FiniBB.getUniquePredecessor(); 2201 2202 // actual start for bodyCB 2203 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2204 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2205 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2206 EXPECT_EQ(EntryBB, CodeGenIPBB); 2207 2208 // body begin 2209 Builder.restoreIP(CodeGenIP); 2210 Builder.CreateStore(F->arg_begin(), PrivAI); 2211 Value *PrivLoad = 2212 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2213 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2214 }; 2215 2216 auto FiniCB = [&](InsertPointTy IP) { 2217 BasicBlock *IPBB = IP.getBlock(); 2218 EXPECT_NE(IPBB->end(), IP.getPoint()); 2219 }; 2220 2221 Builder.restoreIP(OMPBuilder.createCritical(Builder, BodyGenCB, FiniCB, 2222 "testCRT", nullptr)); 2223 2224 Value *EntryBBTI = EntryBB->getTerminator(); 2225 EXPECT_EQ(EntryBBTI, nullptr); 2226 2227 CallInst *CriticalEntryCI = nullptr; 2228 for (auto &EI : *EntryBB) { 2229 Instruction *cur = &EI; 2230 if (isa<CallInst>(cur)) { 2231 CriticalEntryCI = cast<CallInst>(cur); 2232 if (CriticalEntryCI->getCalledFunction()->getName() == "__kmpc_critical") 2233 break; 2234 CriticalEntryCI = nullptr; 2235 } 2236 } 2237 EXPECT_NE(CriticalEntryCI, nullptr); 2238 EXPECT_EQ(CriticalEntryCI->arg_size(), 3U); 2239 EXPECT_EQ(CriticalEntryCI->getCalledFunction()->getName(), "__kmpc_critical"); 2240 EXPECT_TRUE(isa<GlobalVariable>(CriticalEntryCI->getArgOperand(0))); 2241 2242 CallInst *CriticalEndCI = nullptr; 2243 for (auto &FI : *EntryBB) { 2244 Instruction *cur = &FI; 2245 if (isa<CallInst>(cur)) { 2246 CriticalEndCI = cast<CallInst>(cur); 2247 if (CriticalEndCI->getCalledFunction()->getName() == 2248 "__kmpc_end_critical") 2249 break; 2250 CriticalEndCI = nullptr; 2251 } 2252 } 2253 EXPECT_NE(CriticalEndCI, nullptr); 2254 EXPECT_EQ(CriticalEndCI->arg_size(), 3U); 2255 EXPECT_TRUE(isa<GlobalVariable>(CriticalEndCI->getArgOperand(0))); 2256 EXPECT_EQ(CriticalEndCI->getArgOperand(1), CriticalEntryCI->getArgOperand(1)); 2257 PointerType *CriticalNamePtrTy = 2258 PointerType::getUnqual(ArrayType::get(Type::getInt32Ty(Ctx), 8)); 2259 EXPECT_EQ(CriticalEndCI->getArgOperand(2), CriticalEntryCI->getArgOperand(2)); 2260 EXPECT_EQ(CriticalEndCI->getArgOperand(2)->getType(), CriticalNamePtrTy); 2261 } 2262 2263 TEST_F(OpenMPIRBuilderTest, OrderedDirectiveDependSource) { 2264 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2265 OpenMPIRBuilder OMPBuilder(*M); 2266 OMPBuilder.initialize(); 2267 F->setName("func"); 2268 IRBuilder<> Builder(BB); 2269 LLVMContext &Ctx = M->getContext(); 2270 2271 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2272 2273 InsertPointTy AllocaIP(&F->getEntryBlock(), 2274 F->getEntryBlock().getFirstInsertionPt()); 2275 2276 unsigned NumLoops = 2; 2277 SmallVector<Value *, 2> StoreValues; 2278 Type *LCTy = Type::getInt64Ty(Ctx); 2279 StoreValues.emplace_back(ConstantInt::get(LCTy, 1)); 2280 StoreValues.emplace_back(ConstantInt::get(LCTy, 2)); 2281 2282 // Test for "#omp ordered depend(source)" 2283 Builder.restoreIP(OMPBuilder.createOrderedDepend(Builder, AllocaIP, NumLoops, 2284 StoreValues, ".cnt.addr", 2285 /*IsDependSource=*/true)); 2286 2287 Builder.CreateRetVoid(); 2288 OMPBuilder.finalize(); 2289 EXPECT_FALSE(verifyModule(*M, &errs())); 2290 2291 AllocaInst *AllocInst = dyn_cast<AllocaInst>(&BB->front()); 2292 ASSERT_NE(AllocInst, nullptr); 2293 ArrayType *ArrType = dyn_cast<ArrayType>(AllocInst->getAllocatedType()); 2294 EXPECT_EQ(ArrType->getNumElements(), NumLoops); 2295 EXPECT_TRUE( 2296 AllocInst->getAllocatedType()->getArrayElementType()->isIntegerTy(64)); 2297 2298 Instruction *IterInst = dyn_cast<Instruction>(AllocInst); 2299 for (unsigned Iter = 0; Iter < NumLoops; Iter++) { 2300 GetElementPtrInst *DependAddrGEPIter = 2301 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2302 ASSERT_NE(DependAddrGEPIter, nullptr); 2303 EXPECT_EQ(DependAddrGEPIter->getPointerOperand(), AllocInst); 2304 EXPECT_EQ(DependAddrGEPIter->getNumIndices(), (unsigned)2); 2305 auto *FirstIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(1)); 2306 auto *SecondIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(2)); 2307 ASSERT_NE(FirstIdx, nullptr); 2308 ASSERT_NE(SecondIdx, nullptr); 2309 EXPECT_EQ(FirstIdx->getValue(), 0); 2310 EXPECT_EQ(SecondIdx->getValue(), Iter); 2311 StoreInst *StoreValue = 2312 dyn_cast<StoreInst>(DependAddrGEPIter->getNextNode()); 2313 ASSERT_NE(StoreValue, nullptr); 2314 EXPECT_EQ(StoreValue->getValueOperand(), StoreValues[Iter]); 2315 EXPECT_EQ(StoreValue->getPointerOperand(), DependAddrGEPIter); 2316 EXPECT_EQ(StoreValue->getAlignment(), 8UL); 2317 IterInst = dyn_cast<Instruction>(StoreValue); 2318 } 2319 2320 GetElementPtrInst *DependBaseAddrGEP = 2321 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2322 ASSERT_NE(DependBaseAddrGEP, nullptr); 2323 EXPECT_EQ(DependBaseAddrGEP->getPointerOperand(), AllocInst); 2324 EXPECT_EQ(DependBaseAddrGEP->getNumIndices(), (unsigned)2); 2325 auto *FirstIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(1)); 2326 auto *SecondIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(2)); 2327 ASSERT_NE(FirstIdx, nullptr); 2328 ASSERT_NE(SecondIdx, nullptr); 2329 EXPECT_EQ(FirstIdx->getValue(), 0); 2330 EXPECT_EQ(SecondIdx->getValue(), 0); 2331 2332 CallInst *GTID = dyn_cast<CallInst>(DependBaseAddrGEP->getNextNode()); 2333 ASSERT_NE(GTID, nullptr); 2334 EXPECT_EQ(GTID->arg_size(), 1U); 2335 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 2336 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 2337 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 2338 2339 CallInst *Depend = dyn_cast<CallInst>(GTID->getNextNode()); 2340 ASSERT_NE(Depend, nullptr); 2341 EXPECT_EQ(Depend->arg_size(), 3U); 2342 EXPECT_EQ(Depend->getCalledFunction()->getName(), "__kmpc_doacross_post"); 2343 EXPECT_TRUE(isa<GlobalVariable>(Depend->getArgOperand(0))); 2344 EXPECT_EQ(Depend->getArgOperand(1), GTID); 2345 EXPECT_EQ(Depend->getArgOperand(2), DependBaseAddrGEP); 2346 } 2347 2348 TEST_F(OpenMPIRBuilderTest, OrderedDirectiveDependSink) { 2349 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2350 OpenMPIRBuilder OMPBuilder(*M); 2351 OMPBuilder.initialize(); 2352 F->setName("func"); 2353 IRBuilder<> Builder(BB); 2354 LLVMContext &Ctx = M->getContext(); 2355 2356 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2357 2358 InsertPointTy AllocaIP(&F->getEntryBlock(), 2359 F->getEntryBlock().getFirstInsertionPt()); 2360 2361 unsigned NumLoops = 2; 2362 SmallVector<Value *, 2> StoreValues; 2363 Type *LCTy = Type::getInt64Ty(Ctx); 2364 StoreValues.emplace_back(ConstantInt::get(LCTy, 1)); 2365 StoreValues.emplace_back(ConstantInt::get(LCTy, 2)); 2366 2367 // Test for "#omp ordered depend(sink: vec)" 2368 Builder.restoreIP(OMPBuilder.createOrderedDepend(Builder, AllocaIP, NumLoops, 2369 StoreValues, ".cnt.addr", 2370 /*IsDependSource=*/false)); 2371 2372 Builder.CreateRetVoid(); 2373 OMPBuilder.finalize(); 2374 EXPECT_FALSE(verifyModule(*M, &errs())); 2375 2376 AllocaInst *AllocInst = dyn_cast<AllocaInst>(&BB->front()); 2377 ASSERT_NE(AllocInst, nullptr); 2378 ArrayType *ArrType = dyn_cast<ArrayType>(AllocInst->getAllocatedType()); 2379 EXPECT_EQ(ArrType->getNumElements(), NumLoops); 2380 EXPECT_TRUE( 2381 AllocInst->getAllocatedType()->getArrayElementType()->isIntegerTy(64)); 2382 2383 Instruction *IterInst = dyn_cast<Instruction>(AllocInst); 2384 for (unsigned Iter = 0; Iter < NumLoops; Iter++) { 2385 GetElementPtrInst *DependAddrGEPIter = 2386 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2387 ASSERT_NE(DependAddrGEPIter, nullptr); 2388 EXPECT_EQ(DependAddrGEPIter->getPointerOperand(), AllocInst); 2389 EXPECT_EQ(DependAddrGEPIter->getNumIndices(), (unsigned)2); 2390 auto *FirstIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(1)); 2391 auto *SecondIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(2)); 2392 ASSERT_NE(FirstIdx, nullptr); 2393 ASSERT_NE(SecondIdx, nullptr); 2394 EXPECT_EQ(FirstIdx->getValue(), 0); 2395 EXPECT_EQ(SecondIdx->getValue(), Iter); 2396 StoreInst *StoreValue = 2397 dyn_cast<StoreInst>(DependAddrGEPIter->getNextNode()); 2398 ASSERT_NE(StoreValue, nullptr); 2399 EXPECT_EQ(StoreValue->getValueOperand(), StoreValues[Iter]); 2400 EXPECT_EQ(StoreValue->getPointerOperand(), DependAddrGEPIter); 2401 EXPECT_EQ(StoreValue->getAlignment(), 8UL); 2402 IterInst = dyn_cast<Instruction>(StoreValue); 2403 } 2404 2405 GetElementPtrInst *DependBaseAddrGEP = 2406 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2407 ASSERT_NE(DependBaseAddrGEP, nullptr); 2408 EXPECT_EQ(DependBaseAddrGEP->getPointerOperand(), AllocInst); 2409 EXPECT_EQ(DependBaseAddrGEP->getNumIndices(), (unsigned)2); 2410 auto *FirstIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(1)); 2411 auto *SecondIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(2)); 2412 ASSERT_NE(FirstIdx, nullptr); 2413 ASSERT_NE(SecondIdx, nullptr); 2414 EXPECT_EQ(FirstIdx->getValue(), 0); 2415 EXPECT_EQ(SecondIdx->getValue(), 0); 2416 2417 CallInst *GTID = dyn_cast<CallInst>(DependBaseAddrGEP->getNextNode()); 2418 ASSERT_NE(GTID, nullptr); 2419 EXPECT_EQ(GTID->arg_size(), 1U); 2420 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 2421 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 2422 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 2423 2424 CallInst *Depend = dyn_cast<CallInst>(GTID->getNextNode()); 2425 ASSERT_NE(Depend, nullptr); 2426 EXPECT_EQ(Depend->arg_size(), 3U); 2427 EXPECT_EQ(Depend->getCalledFunction()->getName(), "__kmpc_doacross_wait"); 2428 EXPECT_TRUE(isa<GlobalVariable>(Depend->getArgOperand(0))); 2429 EXPECT_EQ(Depend->getArgOperand(1), GTID); 2430 EXPECT_EQ(Depend->getArgOperand(2), DependBaseAddrGEP); 2431 } 2432 2433 TEST_F(OpenMPIRBuilderTest, OrderedDirectiveThreads) { 2434 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2435 OpenMPIRBuilder OMPBuilder(*M); 2436 OMPBuilder.initialize(); 2437 F->setName("func"); 2438 IRBuilder<> Builder(BB); 2439 2440 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2441 2442 AllocaInst *PrivAI = 2443 Builder.CreateAlloca(F->arg_begin()->getType(), nullptr, "priv.inst"); 2444 2445 BasicBlock *EntryBB = nullptr; 2446 2447 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2448 BasicBlock &FiniBB) { 2449 EntryBB = FiniBB.getUniquePredecessor(); 2450 2451 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2452 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2453 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2454 EXPECT_EQ(EntryBB, CodeGenIPBB); 2455 2456 Builder.restoreIP(CodeGenIP); 2457 Builder.CreateStore(F->arg_begin(), PrivAI); 2458 Value *PrivLoad = 2459 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2460 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2461 }; 2462 2463 auto FiniCB = [&](InsertPointTy IP) { 2464 BasicBlock *IPBB = IP.getBlock(); 2465 EXPECT_NE(IPBB->end(), IP.getPoint()); 2466 }; 2467 2468 // Test for "#omp ordered [threads]" 2469 Builder.restoreIP( 2470 OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, true)); 2471 2472 Builder.CreateRetVoid(); 2473 OMPBuilder.finalize(); 2474 EXPECT_FALSE(verifyModule(*M, &errs())); 2475 2476 EXPECT_NE(EntryBB->getTerminator(), nullptr); 2477 2478 CallInst *OrderedEntryCI = nullptr; 2479 for (auto &EI : *EntryBB) { 2480 Instruction *Cur = &EI; 2481 if (isa<CallInst>(Cur)) { 2482 OrderedEntryCI = cast<CallInst>(Cur); 2483 if (OrderedEntryCI->getCalledFunction()->getName() == "__kmpc_ordered") 2484 break; 2485 OrderedEntryCI = nullptr; 2486 } 2487 } 2488 EXPECT_NE(OrderedEntryCI, nullptr); 2489 EXPECT_EQ(OrderedEntryCI->arg_size(), 2U); 2490 EXPECT_EQ(OrderedEntryCI->getCalledFunction()->getName(), "__kmpc_ordered"); 2491 EXPECT_TRUE(isa<GlobalVariable>(OrderedEntryCI->getArgOperand(0))); 2492 2493 CallInst *OrderedEndCI = nullptr; 2494 for (auto &FI : *EntryBB) { 2495 Instruction *Cur = &FI; 2496 if (isa<CallInst>(Cur)) { 2497 OrderedEndCI = cast<CallInst>(Cur); 2498 if (OrderedEndCI->getCalledFunction()->getName() == "__kmpc_end_ordered") 2499 break; 2500 OrderedEndCI = nullptr; 2501 } 2502 } 2503 EXPECT_NE(OrderedEndCI, nullptr); 2504 EXPECT_EQ(OrderedEndCI->arg_size(), 2U); 2505 EXPECT_TRUE(isa<GlobalVariable>(OrderedEndCI->getArgOperand(0))); 2506 EXPECT_EQ(OrderedEndCI->getArgOperand(1), OrderedEntryCI->getArgOperand(1)); 2507 } 2508 2509 TEST_F(OpenMPIRBuilderTest, OrderedDirectiveSimd) { 2510 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2511 OpenMPIRBuilder OMPBuilder(*M); 2512 OMPBuilder.initialize(); 2513 F->setName("func"); 2514 IRBuilder<> Builder(BB); 2515 2516 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2517 2518 AllocaInst *PrivAI = 2519 Builder.CreateAlloca(F->arg_begin()->getType(), nullptr, "priv.inst"); 2520 2521 BasicBlock *EntryBB = nullptr; 2522 2523 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2524 BasicBlock &FiniBB) { 2525 EntryBB = FiniBB.getUniquePredecessor(); 2526 2527 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2528 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2529 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2530 EXPECT_EQ(EntryBB, CodeGenIPBB); 2531 2532 Builder.restoreIP(CodeGenIP); 2533 Builder.CreateStore(F->arg_begin(), PrivAI); 2534 Value *PrivLoad = 2535 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2536 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2537 }; 2538 2539 auto FiniCB = [&](InsertPointTy IP) { 2540 BasicBlock *IPBB = IP.getBlock(); 2541 EXPECT_NE(IPBB->end(), IP.getPoint()); 2542 }; 2543 2544 // Test for "#omp ordered simd" 2545 Builder.restoreIP( 2546 OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, false)); 2547 2548 Builder.CreateRetVoid(); 2549 OMPBuilder.finalize(); 2550 EXPECT_FALSE(verifyModule(*M, &errs())); 2551 2552 EXPECT_NE(EntryBB->getTerminator(), nullptr); 2553 2554 CallInst *OrderedEntryCI = nullptr; 2555 for (auto &EI : *EntryBB) { 2556 Instruction *Cur = &EI; 2557 if (isa<CallInst>(Cur)) { 2558 OrderedEntryCI = cast<CallInst>(Cur); 2559 if (OrderedEntryCI->getCalledFunction()->getName() == "__kmpc_ordered") 2560 break; 2561 OrderedEntryCI = nullptr; 2562 } 2563 } 2564 EXPECT_EQ(OrderedEntryCI, nullptr); 2565 2566 CallInst *OrderedEndCI = nullptr; 2567 for (auto &FI : *EntryBB) { 2568 Instruction *Cur = &FI; 2569 if (isa<CallInst>(Cur)) { 2570 OrderedEndCI = cast<CallInst>(Cur); 2571 if (OrderedEndCI->getCalledFunction()->getName() == "__kmpc_end_ordered") 2572 break; 2573 OrderedEndCI = nullptr; 2574 } 2575 } 2576 EXPECT_EQ(OrderedEndCI, nullptr); 2577 } 2578 2579 TEST_F(OpenMPIRBuilderTest, CopyinBlocks) { 2580 OpenMPIRBuilder OMPBuilder(*M); 2581 OMPBuilder.initialize(); 2582 F->setName("func"); 2583 IRBuilder<> Builder(BB); 2584 2585 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2586 2587 IntegerType *Int32 = Type::getInt32Ty(M->getContext()); 2588 AllocaInst *MasterAddress = Builder.CreateAlloca(Int32->getPointerTo()); 2589 AllocaInst *PrivAddress = Builder.CreateAlloca(Int32->getPointerTo()); 2590 2591 BasicBlock *EntryBB = BB; 2592 2593 OMPBuilder.createCopyinClauseBlocks(Builder.saveIP(), MasterAddress, 2594 PrivAddress, Int32, /*BranchtoEnd*/ true); 2595 2596 BranchInst *EntryBr = dyn_cast_or_null<BranchInst>(EntryBB->getTerminator()); 2597 2598 EXPECT_NE(EntryBr, nullptr); 2599 EXPECT_TRUE(EntryBr->isConditional()); 2600 2601 BasicBlock *NotMasterBB = EntryBr->getSuccessor(0); 2602 BasicBlock *CopyinEnd = EntryBr->getSuccessor(1); 2603 CmpInst *CMP = dyn_cast_or_null<CmpInst>(EntryBr->getCondition()); 2604 2605 EXPECT_NE(CMP, nullptr); 2606 EXPECT_NE(NotMasterBB, nullptr); 2607 EXPECT_NE(CopyinEnd, nullptr); 2608 2609 BranchInst *NotMasterBr = 2610 dyn_cast_or_null<BranchInst>(NotMasterBB->getTerminator()); 2611 EXPECT_NE(NotMasterBr, nullptr); 2612 EXPECT_FALSE(NotMasterBr->isConditional()); 2613 EXPECT_EQ(CopyinEnd, NotMasterBr->getSuccessor(0)); 2614 } 2615 2616 TEST_F(OpenMPIRBuilderTest, SingleDirective) { 2617 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2618 OpenMPIRBuilder OMPBuilder(*M); 2619 OMPBuilder.initialize(); 2620 F->setName("func"); 2621 IRBuilder<> Builder(BB); 2622 2623 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2624 2625 AllocaInst *PrivAI = nullptr; 2626 2627 BasicBlock *EntryBB = nullptr; 2628 BasicBlock *ExitBB = nullptr; 2629 BasicBlock *ThenBB = nullptr; 2630 2631 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2632 BasicBlock &FiniBB) { 2633 if (AllocaIP.isSet()) 2634 Builder.restoreIP(AllocaIP); 2635 else 2636 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); 2637 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2638 Builder.CreateStore(F->arg_begin(), PrivAI); 2639 2640 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2641 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2642 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2643 2644 Builder.restoreIP(CodeGenIP); 2645 2646 // collect some info for checks later 2647 ExitBB = FiniBB.getUniqueSuccessor(); 2648 ThenBB = Builder.GetInsertBlock(); 2649 EntryBB = ThenBB->getUniquePredecessor(); 2650 2651 // simple instructions for body 2652 Value *PrivLoad = 2653 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2654 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2655 }; 2656 2657 auto FiniCB = [&](InsertPointTy IP) { 2658 BasicBlock *IPBB = IP.getBlock(); 2659 EXPECT_NE(IPBB->end(), IP.getPoint()); 2660 }; 2661 2662 Builder.restoreIP( 2663 OMPBuilder.createSingle(Builder, BodyGenCB, FiniCB, /*DidIt*/ nullptr)); 2664 Value *EntryBBTI = EntryBB->getTerminator(); 2665 EXPECT_NE(EntryBBTI, nullptr); 2666 EXPECT_TRUE(isa<BranchInst>(EntryBBTI)); 2667 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator()); 2668 EXPECT_TRUE(EntryBr->isConditional()); 2669 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); 2670 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); 2671 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); 2672 2673 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition()); 2674 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0))); 2675 2676 CallInst *SingleEntryCI = cast<CallInst>(CondInst->getOperand(0)); 2677 EXPECT_EQ(SingleEntryCI->arg_size(), 2U); 2678 EXPECT_EQ(SingleEntryCI->getCalledFunction()->getName(), "__kmpc_single"); 2679 EXPECT_TRUE(isa<GlobalVariable>(SingleEntryCI->getArgOperand(0))); 2680 2681 CallInst *SingleEndCI = nullptr; 2682 for (auto &FI : *ThenBB) { 2683 Instruction *cur = &FI; 2684 if (isa<CallInst>(cur)) { 2685 SingleEndCI = cast<CallInst>(cur); 2686 if (SingleEndCI->getCalledFunction()->getName() == "__kmpc_end_single") 2687 break; 2688 SingleEndCI = nullptr; 2689 } 2690 } 2691 EXPECT_NE(SingleEndCI, nullptr); 2692 EXPECT_EQ(SingleEndCI->arg_size(), 2U); 2693 EXPECT_TRUE(isa<GlobalVariable>(SingleEndCI->getArgOperand(0))); 2694 EXPECT_EQ(SingleEndCI->getArgOperand(1), SingleEntryCI->getArgOperand(1)); 2695 } 2696 2697 TEST_F(OpenMPIRBuilderTest, OMPAtomicReadFlt) { 2698 OpenMPIRBuilder OMPBuilder(*M); 2699 OMPBuilder.initialize(); 2700 F->setName("func"); 2701 IRBuilder<> Builder(BB); 2702 2703 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2704 2705 Type *Float32 = Type::getFloatTy(M->getContext()); 2706 AllocaInst *XVal = Builder.CreateAlloca(Float32); 2707 XVal->setName("AtomicVar"); 2708 AllocaInst *VVal = Builder.CreateAlloca(Float32); 2709 VVal->setName("AtomicRead"); 2710 AtomicOrdering AO = AtomicOrdering::Monotonic; 2711 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2712 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2713 2714 Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO)); 2715 2716 IntegerType *IntCastTy = 2717 IntegerType::get(M->getContext(), Float32->getScalarSizeInBits()); 2718 2719 BitCastInst *CastFrmFlt = cast<BitCastInst>(VVal->getNextNode()); 2720 EXPECT_EQ(CastFrmFlt->getSrcTy(), Float32->getPointerTo()); 2721 EXPECT_EQ(CastFrmFlt->getDestTy(), IntCastTy->getPointerTo()); 2722 EXPECT_EQ(CastFrmFlt->getOperand(0), XVal); 2723 2724 LoadInst *AtomicLoad = cast<LoadInst>(CastFrmFlt->getNextNode()); 2725 EXPECT_TRUE(AtomicLoad->isAtomic()); 2726 EXPECT_EQ(AtomicLoad->getPointerOperand(), CastFrmFlt); 2727 2728 BitCastInst *CastToFlt = cast<BitCastInst>(AtomicLoad->getNextNode()); 2729 EXPECT_EQ(CastToFlt->getSrcTy(), IntCastTy); 2730 EXPECT_EQ(CastToFlt->getDestTy(), Float32); 2731 EXPECT_EQ(CastToFlt->getOperand(0), AtomicLoad); 2732 2733 StoreInst *StoreofAtomic = cast<StoreInst>(CastToFlt->getNextNode()); 2734 EXPECT_EQ(StoreofAtomic->getValueOperand(), CastToFlt); 2735 EXPECT_EQ(StoreofAtomic->getPointerOperand(), VVal); 2736 2737 Builder.CreateRetVoid(); 2738 OMPBuilder.finalize(); 2739 EXPECT_FALSE(verifyModule(*M, &errs())); 2740 } 2741 2742 TEST_F(OpenMPIRBuilderTest, OMPAtomicReadInt) { 2743 OpenMPIRBuilder OMPBuilder(*M); 2744 OMPBuilder.initialize(); 2745 F->setName("func"); 2746 IRBuilder<> Builder(BB); 2747 2748 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2749 2750 IntegerType *Int32 = Type::getInt32Ty(M->getContext()); 2751 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2752 XVal->setName("AtomicVar"); 2753 AllocaInst *VVal = Builder.CreateAlloca(Int32); 2754 VVal->setName("AtomicRead"); 2755 AtomicOrdering AO = AtomicOrdering::Monotonic; 2756 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2757 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2758 2759 BasicBlock *EntryBB = BB; 2760 2761 Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO)); 2762 LoadInst *AtomicLoad = nullptr; 2763 StoreInst *StoreofAtomic = nullptr; 2764 2765 for (Instruction &Cur : *EntryBB) { 2766 if (isa<LoadInst>(Cur)) { 2767 AtomicLoad = cast<LoadInst>(&Cur); 2768 if (AtomicLoad->getPointerOperand() == XVal) 2769 continue; 2770 AtomicLoad = nullptr; 2771 } else if (isa<StoreInst>(Cur)) { 2772 StoreofAtomic = cast<StoreInst>(&Cur); 2773 if (StoreofAtomic->getPointerOperand() == VVal) 2774 continue; 2775 StoreofAtomic = nullptr; 2776 } 2777 } 2778 2779 EXPECT_NE(AtomicLoad, nullptr); 2780 EXPECT_TRUE(AtomicLoad->isAtomic()); 2781 2782 EXPECT_NE(StoreofAtomic, nullptr); 2783 EXPECT_EQ(StoreofAtomic->getValueOperand(), AtomicLoad); 2784 2785 Builder.CreateRetVoid(); 2786 OMPBuilder.finalize(); 2787 2788 EXPECT_FALSE(verifyModule(*M, &errs())); 2789 } 2790 2791 TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteFlt) { 2792 OpenMPIRBuilder OMPBuilder(*M); 2793 OMPBuilder.initialize(); 2794 F->setName("func"); 2795 IRBuilder<> Builder(BB); 2796 2797 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2798 2799 LLVMContext &Ctx = M->getContext(); 2800 Type *Float32 = Type::getFloatTy(Ctx); 2801 AllocaInst *XVal = Builder.CreateAlloca(Float32); 2802 XVal->setName("AtomicVar"); 2803 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2804 AtomicOrdering AO = AtomicOrdering::Monotonic; 2805 Constant *ValToWrite = ConstantFP::get(Float32, 1.0); 2806 2807 Builder.restoreIP(OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO)); 2808 2809 IntegerType *IntCastTy = 2810 IntegerType::get(M->getContext(), Float32->getScalarSizeInBits()); 2811 2812 BitCastInst *CastFrmFlt = cast<BitCastInst>(XVal->getNextNode()); 2813 EXPECT_EQ(CastFrmFlt->getSrcTy(), Float32->getPointerTo()); 2814 EXPECT_EQ(CastFrmFlt->getDestTy(), IntCastTy->getPointerTo()); 2815 EXPECT_EQ(CastFrmFlt->getOperand(0), XVal); 2816 2817 Value *ExprCast = Builder.CreateBitCast(ValToWrite, IntCastTy); 2818 2819 StoreInst *StoreofAtomic = cast<StoreInst>(CastFrmFlt->getNextNode()); 2820 EXPECT_EQ(StoreofAtomic->getValueOperand(), ExprCast); 2821 EXPECT_EQ(StoreofAtomic->getPointerOperand(), CastFrmFlt); 2822 EXPECT_TRUE(StoreofAtomic->isAtomic()); 2823 2824 Builder.CreateRetVoid(); 2825 OMPBuilder.finalize(); 2826 EXPECT_FALSE(verifyModule(*M, &errs())); 2827 } 2828 2829 TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteInt) { 2830 OpenMPIRBuilder OMPBuilder(*M); 2831 OMPBuilder.initialize(); 2832 F->setName("func"); 2833 IRBuilder<> Builder(BB); 2834 2835 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2836 2837 LLVMContext &Ctx = M->getContext(); 2838 IntegerType *Int32 = Type::getInt32Ty(Ctx); 2839 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2840 XVal->setName("AtomicVar"); 2841 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2842 AtomicOrdering AO = AtomicOrdering::Monotonic; 2843 ConstantInt *ValToWrite = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2844 2845 BasicBlock *EntryBB = BB; 2846 2847 Builder.restoreIP(OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO)); 2848 2849 StoreInst *StoreofAtomic = nullptr; 2850 2851 for (Instruction &Cur : *EntryBB) { 2852 if (isa<StoreInst>(Cur)) { 2853 StoreofAtomic = cast<StoreInst>(&Cur); 2854 if (StoreofAtomic->getPointerOperand() == XVal) 2855 continue; 2856 StoreofAtomic = nullptr; 2857 } 2858 } 2859 2860 EXPECT_NE(StoreofAtomic, nullptr); 2861 EXPECT_TRUE(StoreofAtomic->isAtomic()); 2862 EXPECT_EQ(StoreofAtomic->getValueOperand(), ValToWrite); 2863 2864 Builder.CreateRetVoid(); 2865 OMPBuilder.finalize(); 2866 EXPECT_FALSE(verifyModule(*M, &errs())); 2867 } 2868 2869 TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdate) { 2870 OpenMPIRBuilder OMPBuilder(*M); 2871 OMPBuilder.initialize(); 2872 F->setName("func"); 2873 IRBuilder<> Builder(BB); 2874 2875 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2876 2877 IntegerType *Int32 = Type::getInt32Ty(M->getContext()); 2878 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2879 XVal->setName("AtomicVar"); 2880 Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal); 2881 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2882 AtomicOrdering AO = AtomicOrdering::Monotonic; 2883 ConstantInt *ConstVal = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2884 Value *Expr = nullptr; 2885 AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Sub; 2886 bool IsXLHSInRHSPart = false; 2887 2888 BasicBlock *EntryBB = BB; 2889 Instruction *AllocIP = EntryBB->getFirstNonPHI(); 2890 Value *Sub = nullptr; 2891 2892 auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) { 2893 Sub = IRB.CreateSub(ConstVal, Atomic); 2894 return Sub; 2895 }; 2896 Builder.restoreIP(OMPBuilder.createAtomicUpdate( 2897 Builder, AllocIP, X, Expr, AO, RMWOp, UpdateOp, IsXLHSInRHSPart)); 2898 BasicBlock *ContBB = EntryBB->getSingleSuccessor(); 2899 BranchInst *ContTI = dyn_cast<BranchInst>(ContBB->getTerminator()); 2900 EXPECT_NE(ContTI, nullptr); 2901 BasicBlock *EndBB = ContTI->getSuccessor(0); 2902 EXPECT_TRUE(ContTI->isConditional()); 2903 EXPECT_EQ(ContTI->getSuccessor(1), ContBB); 2904 EXPECT_NE(EndBB, nullptr); 2905 2906 PHINode *Phi = dyn_cast<PHINode>(&ContBB->front()); 2907 EXPECT_NE(Phi, nullptr); 2908 EXPECT_EQ(Phi->getNumIncomingValues(), 2U); 2909 EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB); 2910 EXPECT_EQ(Phi->getIncomingBlock(1), ContBB); 2911 2912 EXPECT_EQ(Sub->getNumUses(), 1U); 2913 StoreInst *St = dyn_cast<StoreInst>(Sub->user_back()); 2914 AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand()); 2915 2916 ExtractValueInst *ExVI1 = 2917 dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB)); 2918 EXPECT_NE(ExVI1, nullptr); 2919 AtomicCmpXchgInst *CmpExchg = 2920 dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand()); 2921 EXPECT_NE(CmpExchg, nullptr); 2922 EXPECT_EQ(CmpExchg->getPointerOperand(), XVal); 2923 EXPECT_EQ(CmpExchg->getCompareOperand(), Phi); 2924 EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic); 2925 2926 LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand()); 2927 EXPECT_NE(Ld, nullptr); 2928 EXPECT_EQ(UpdateTemp, Ld->getPointerOperand()); 2929 2930 Builder.CreateRetVoid(); 2931 OMPBuilder.finalize(); 2932 EXPECT_FALSE(verifyModule(*M, &errs())); 2933 } 2934 2935 TEST_F(OpenMPIRBuilderTest, OMPAtomicCapture) { 2936 OpenMPIRBuilder OMPBuilder(*M); 2937 OMPBuilder.initialize(); 2938 F->setName("func"); 2939 IRBuilder<> Builder(BB); 2940 2941 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2942 2943 LLVMContext &Ctx = M->getContext(); 2944 IntegerType *Int32 = Type::getInt32Ty(Ctx); 2945 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2946 XVal->setName("AtomicVar"); 2947 AllocaInst *VVal = Builder.CreateAlloca(Int32); 2948 VVal->setName("AtomicCapTar"); 2949 StoreInst *Init = 2950 Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal); 2951 2952 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2953 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2954 AtomicOrdering AO = AtomicOrdering::Monotonic; 2955 ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2956 AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Add; 2957 bool IsXLHSInRHSPart = true; 2958 bool IsPostfixUpdate = true; 2959 bool UpdateExpr = true; 2960 2961 BasicBlock *EntryBB = BB; 2962 Instruction *AllocIP = EntryBB->getFirstNonPHI(); 2963 2964 // integer update - not used 2965 auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) { return nullptr; }; 2966 2967 Builder.restoreIP(OMPBuilder.createAtomicCapture( 2968 Builder, AllocIP, X, V, Expr, AO, RMWOp, UpdateOp, UpdateExpr, 2969 IsPostfixUpdate, IsXLHSInRHSPart)); 2970 EXPECT_EQ(EntryBB->getParent()->size(), 1U); 2971 AtomicRMWInst *ARWM = dyn_cast<AtomicRMWInst>(Init->getNextNode()); 2972 EXPECT_NE(ARWM, nullptr); 2973 EXPECT_EQ(ARWM->getPointerOperand(), XVal); 2974 EXPECT_EQ(ARWM->getOperation(), RMWOp); 2975 StoreInst *St = dyn_cast<StoreInst>(ARWM->user_back()); 2976 EXPECT_NE(St, nullptr); 2977 EXPECT_EQ(St->getPointerOperand(), VVal); 2978 2979 Builder.CreateRetVoid(); 2980 OMPBuilder.finalize(); 2981 EXPECT_FALSE(verifyModule(*M, &errs())); 2982 } 2983 2984 /// Returns the single instruction of InstTy type in BB that uses the value V. 2985 /// If there is more than one such instruction, returns null. 2986 template <typename InstTy> 2987 static InstTy *findSingleUserInBlock(Value *V, BasicBlock *BB) { 2988 InstTy *Result = nullptr; 2989 for (User *U : V->users()) { 2990 auto *Inst = dyn_cast<InstTy>(U); 2991 if (!Inst || Inst->getParent() != BB) 2992 continue; 2993 if (Result) 2994 return nullptr; 2995 Result = Inst; 2996 } 2997 return Result; 2998 } 2999 3000 /// Returns true if BB contains a simple binary reduction that loads a value 3001 /// from Accum, performs some binary operation with it, and stores it back to 3002 /// Accum. 3003 static bool isSimpleBinaryReduction(Value *Accum, BasicBlock *BB, 3004 Instruction::BinaryOps *OpCode = nullptr) { 3005 StoreInst *Store = findSingleUserInBlock<StoreInst>(Accum, BB); 3006 if (!Store) 3007 return false; 3008 auto *Stored = dyn_cast<BinaryOperator>(Store->getOperand(0)); 3009 if (!Stored) 3010 return false; 3011 if (OpCode && *OpCode != Stored->getOpcode()) 3012 return false; 3013 auto *Load = dyn_cast<LoadInst>(Stored->getOperand(0)); 3014 return Load && Load->getOperand(0) == Accum; 3015 } 3016 3017 /// Returns true if BB contains a binary reduction that reduces V using a binary 3018 /// operator into an accumulator that is a function argument. 3019 static bool isValueReducedToFuncArg(Value *V, BasicBlock *BB) { 3020 auto *ReductionOp = findSingleUserInBlock<BinaryOperator>(V, BB); 3021 if (!ReductionOp) 3022 return false; 3023 3024 auto *GlobalLoad = dyn_cast<LoadInst>(ReductionOp->getOperand(0)); 3025 if (!GlobalLoad) 3026 return false; 3027 3028 auto *Store = findSingleUserInBlock<StoreInst>(ReductionOp, BB); 3029 if (!Store) 3030 return false; 3031 3032 return Store->getPointerOperand() == GlobalLoad->getPointerOperand() && 3033 isa<Argument>(GlobalLoad->getPointerOperand()); 3034 } 3035 3036 /// Finds among users of Ptr a pair of GEP instructions with indices [0, 0] and 3037 /// [0, 1], respectively, and assigns results of these instructions to Zero and 3038 /// One. Returns true on success, false on failure or if such instructions are 3039 /// not unique among the users of Ptr. 3040 static bool findGEPZeroOne(Value *Ptr, Value *&Zero, Value *&One) { 3041 Zero = nullptr; 3042 One = nullptr; 3043 for (User *U : Ptr->users()) { 3044 if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) { 3045 if (GEP->getNumIndices() != 2) 3046 continue; 3047 auto *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1)); 3048 auto *SecondIdx = dyn_cast<ConstantInt>(GEP->getOperand(2)); 3049 EXPECT_NE(FirstIdx, nullptr); 3050 EXPECT_NE(SecondIdx, nullptr); 3051 3052 EXPECT_TRUE(FirstIdx->isZero()); 3053 if (SecondIdx->isZero()) { 3054 if (Zero) 3055 return false; 3056 Zero = GEP; 3057 } else if (SecondIdx->isOne()) { 3058 if (One) 3059 return false; 3060 One = GEP; 3061 } else { 3062 return false; 3063 } 3064 } 3065 } 3066 return Zero != nullptr && One != nullptr; 3067 } 3068 3069 static OpenMPIRBuilder::InsertPointTy 3070 sumReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS, 3071 Value *&Result) { 3072 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 3073 Result = Builder.CreateFAdd(LHS, RHS, "red.add"); 3074 return Builder.saveIP(); 3075 } 3076 3077 static OpenMPIRBuilder::InsertPointTy 3078 sumAtomicReduction(OpenMPIRBuilder::InsertPointTy IP, Type *Ty, Value *LHS, 3079 Value *RHS) { 3080 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 3081 Value *Partial = Builder.CreateLoad(Ty, RHS, "red.partial"); 3082 Builder.CreateAtomicRMW(AtomicRMWInst::FAdd, LHS, Partial, None, 3083 AtomicOrdering::Monotonic); 3084 return Builder.saveIP(); 3085 } 3086 3087 static OpenMPIRBuilder::InsertPointTy 3088 xorReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS, 3089 Value *&Result) { 3090 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 3091 Result = Builder.CreateXor(LHS, RHS, "red.xor"); 3092 return Builder.saveIP(); 3093 } 3094 3095 static OpenMPIRBuilder::InsertPointTy 3096 xorAtomicReduction(OpenMPIRBuilder::InsertPointTy IP, Type *Ty, Value *LHS, 3097 Value *RHS) { 3098 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 3099 Value *Partial = Builder.CreateLoad(Ty, RHS, "red.partial"); 3100 Builder.CreateAtomicRMW(AtomicRMWInst::Xor, LHS, Partial, None, 3101 AtomicOrdering::Monotonic); 3102 return Builder.saveIP(); 3103 } 3104 3105 /// Populate Calls with call instructions calling the function with the given 3106 /// FnID from the given function F. 3107 static void findCalls(Function *F, omp::RuntimeFunction FnID, 3108 OpenMPIRBuilder &OMPBuilder, 3109 SmallVectorImpl<CallInst *> &Calls) { 3110 Function *Fn = OMPBuilder.getOrCreateRuntimeFunctionPtr(FnID); 3111 for (BasicBlock &BB : *F) { 3112 for (Instruction &I : BB) { 3113 auto *Call = dyn_cast<CallInst>(&I); 3114 if (Call && Call->getCalledFunction() == Fn) 3115 Calls.push_back(Call); 3116 } 3117 } 3118 } 3119 3120 TEST_F(OpenMPIRBuilderTest, CreateReductions) { 3121 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 3122 OpenMPIRBuilder OMPBuilder(*M); 3123 OMPBuilder.initialize(); 3124 F->setName("func"); 3125 IRBuilder<> Builder(BB); 3126 3127 BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F); 3128 Builder.CreateBr(EnterBB); 3129 Builder.SetInsertPoint(EnterBB); 3130 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3131 3132 // Create variables to be reduced. 3133 InsertPointTy OuterAllocaIP(&F->getEntryBlock(), 3134 F->getEntryBlock().getFirstInsertionPt()); 3135 Type *SumType = Builder.getFloatTy(); 3136 Type *XorType = Builder.getInt32Ty(); 3137 Value *SumReduced; 3138 Value *XorReduced; 3139 { 3140 IRBuilderBase::InsertPointGuard Guard(Builder); 3141 Builder.restoreIP(OuterAllocaIP); 3142 SumReduced = Builder.CreateAlloca(SumType); 3143 XorReduced = Builder.CreateAlloca(XorType); 3144 } 3145 3146 // Store initial values of reductions into global variables. 3147 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), SumReduced); 3148 Builder.CreateStore(Builder.getInt32(1), XorReduced); 3149 3150 // The loop body computes two reductions: 3151 // sum of (float) thread-id; 3152 // xor of thread-id; 3153 // and store the result in global variables. 3154 InsertPointTy BodyIP, BodyAllocaIP; 3155 auto BodyGenCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP, 3156 BasicBlock &ContinuationBB) { 3157 IRBuilderBase::InsertPointGuard Guard(Builder); 3158 Builder.restoreIP(CodeGenIP); 3159 3160 uint32_t StrSize; 3161 Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc, StrSize); 3162 Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr, StrSize); 3163 Value *TID = OMPBuilder.getOrCreateThreadID(Ident); 3164 Value *SumLocal = 3165 Builder.CreateUIToFP(TID, Builder.getFloatTy(), "sum.local"); 3166 Value *SumPartial = Builder.CreateLoad(SumType, SumReduced, "sum.partial"); 3167 Value *XorPartial = Builder.CreateLoad(XorType, XorReduced, "xor.partial"); 3168 Value *Sum = Builder.CreateFAdd(SumPartial, SumLocal, "sum"); 3169 Value *Xor = Builder.CreateXor(XorPartial, TID, "xor"); 3170 Builder.CreateStore(Sum, SumReduced); 3171 Builder.CreateStore(Xor, XorReduced); 3172 3173 BodyIP = Builder.saveIP(); 3174 BodyAllocaIP = InnerAllocaIP; 3175 }; 3176 3177 // Privatization for reduction creates local copies of reduction variables and 3178 // initializes them to reduction-neutral values. 3179 Value *SumPrivatized; 3180 Value *XorPrivatized; 3181 auto PrivCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP, 3182 Value &Original, Value &Inner, Value *&ReplVal) { 3183 IRBuilderBase::InsertPointGuard Guard(Builder); 3184 Builder.restoreIP(InnerAllocaIP); 3185 if (&Original == SumReduced) { 3186 SumPrivatized = Builder.CreateAlloca(Builder.getFloatTy()); 3187 ReplVal = SumPrivatized; 3188 } else if (&Original == XorReduced) { 3189 XorPrivatized = Builder.CreateAlloca(Builder.getInt32Ty()); 3190 ReplVal = XorPrivatized; 3191 } else { 3192 ReplVal = &Inner; 3193 return CodeGenIP; 3194 } 3195 3196 Builder.restoreIP(CodeGenIP); 3197 if (&Original == SumReduced) 3198 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), 3199 SumPrivatized); 3200 else if (&Original == XorReduced) 3201 Builder.CreateStore(Builder.getInt32(0), XorPrivatized); 3202 3203 return Builder.saveIP(); 3204 }; 3205 3206 // Do nothing in finalization. 3207 auto FiniCB = [&](InsertPointTy CodeGenIP) { return CodeGenIP; }; 3208 3209 InsertPointTy AfterIP = 3210 OMPBuilder.createParallel(Loc, OuterAllocaIP, BodyGenCB, PrivCB, FiniCB, 3211 /* IfCondition */ nullptr, 3212 /* NumThreads */ nullptr, OMP_PROC_BIND_default, 3213 /* IsCancellable */ false); 3214 Builder.restoreIP(AfterIP); 3215 3216 OpenMPIRBuilder::ReductionInfo ReductionInfos[] = { 3217 {SumType, SumReduced, SumPrivatized, sumReduction, sumAtomicReduction}, 3218 {XorType, XorReduced, XorPrivatized, xorReduction, xorAtomicReduction}}; 3219 3220 OMPBuilder.createReductions(BodyIP, BodyAllocaIP, ReductionInfos); 3221 3222 Builder.restoreIP(AfterIP); 3223 Builder.CreateRetVoid(); 3224 3225 OMPBuilder.finalize(F); 3226 3227 // The IR must be valid. 3228 EXPECT_FALSE(verifyModule(*M)); 3229 3230 // Outlining must have happened. 3231 SmallVector<CallInst *> ForkCalls; 3232 findCalls(F, omp::RuntimeFunction::OMPRTL___kmpc_fork_call, OMPBuilder, 3233 ForkCalls); 3234 ASSERT_EQ(ForkCalls.size(), 1u); 3235 Value *CalleeVal = cast<Constant>(ForkCalls[0]->getOperand(2))->getOperand(0); 3236 Function *Outlined = dyn_cast<Function>(CalleeVal); 3237 EXPECT_NE(Outlined, nullptr); 3238 3239 // Check that the lock variable was created with the expected name. 3240 GlobalVariable *LockVar = 3241 M->getGlobalVariable(".gomp_critical_user_.reduction.var"); 3242 EXPECT_NE(LockVar, nullptr); 3243 3244 // Find the allocation of a local array that will be used to call the runtime 3245 // reduciton function. 3246 BasicBlock &AllocBlock = Outlined->getEntryBlock(); 3247 Value *LocalArray = nullptr; 3248 for (Instruction &I : AllocBlock) { 3249 if (AllocaInst *Alloc = dyn_cast<AllocaInst>(&I)) { 3250 if (!Alloc->getAllocatedType()->isArrayTy() || 3251 !Alloc->getAllocatedType()->getArrayElementType()->isPointerTy()) 3252 continue; 3253 LocalArray = Alloc; 3254 break; 3255 } 3256 } 3257 ASSERT_NE(LocalArray, nullptr); 3258 3259 // Find the call to the runtime reduction function. 3260 BasicBlock *BB = AllocBlock.getUniqueSuccessor(); 3261 Value *LocalArrayPtr = nullptr; 3262 Value *ReductionFnVal = nullptr; 3263 Value *SwitchArg = nullptr; 3264 for (Instruction &I : *BB) { 3265 if (CallInst *Call = dyn_cast<CallInst>(&I)) { 3266 if (Call->getCalledFunction() != 3267 OMPBuilder.getOrCreateRuntimeFunctionPtr( 3268 RuntimeFunction::OMPRTL___kmpc_reduce)) 3269 continue; 3270 LocalArrayPtr = Call->getOperand(4); 3271 ReductionFnVal = Call->getOperand(5); 3272 SwitchArg = Call; 3273 break; 3274 } 3275 } 3276 3277 // Check that the local array is passed to the function. 3278 ASSERT_NE(LocalArrayPtr, nullptr); 3279 BitCastInst *BitCast = dyn_cast<BitCastInst>(LocalArrayPtr); 3280 ASSERT_NE(BitCast, nullptr); 3281 EXPECT_EQ(BitCast->getOperand(0), LocalArray); 3282 3283 // Find the GEP instructions preceding stores to the local array. 3284 Value *FirstArrayElemPtr = nullptr; 3285 Value *SecondArrayElemPtr = nullptr; 3286 EXPECT_EQ(LocalArray->getNumUses(), 3u); 3287 ASSERT_TRUE( 3288 findGEPZeroOne(LocalArray, FirstArrayElemPtr, SecondArrayElemPtr)); 3289 3290 // Check that the values stored into the local array are privatized reduction 3291 // variables. 3292 auto *FirstStored = dyn_cast_or_null<BitCastInst>( 3293 findStoredValue<GetElementPtrInst>(FirstArrayElemPtr)); 3294 auto *SecondStored = dyn_cast_or_null<BitCastInst>( 3295 findStoredValue<GetElementPtrInst>(SecondArrayElemPtr)); 3296 ASSERT_NE(FirstStored, nullptr); 3297 ASSERT_NE(SecondStored, nullptr); 3298 Value *FirstPrivatized = FirstStored->getOperand(0); 3299 Value *SecondPrivatized = SecondStored->getOperand(0); 3300 EXPECT_TRUE( 3301 isSimpleBinaryReduction(FirstPrivatized, FirstStored->getParent())); 3302 EXPECT_TRUE( 3303 isSimpleBinaryReduction(SecondPrivatized, SecondStored->getParent())); 3304 3305 // Check that the result of the runtime reduction call is used for further 3306 // dispatch. 3307 ASSERT_EQ(SwitchArg->getNumUses(), 1u); 3308 SwitchInst *Switch = dyn_cast<SwitchInst>(*SwitchArg->user_begin()); 3309 ASSERT_NE(Switch, nullptr); 3310 EXPECT_EQ(Switch->getNumSuccessors(), 3u); 3311 BasicBlock *NonAtomicBB = Switch->case_begin()->getCaseSuccessor(); 3312 BasicBlock *AtomicBB = std::next(Switch->case_begin())->getCaseSuccessor(); 3313 3314 // Non-atomic block contains reductions to the global reduction variable, 3315 // which is passed into the outlined function as an argument. 3316 Value *FirstLoad = 3317 findSingleUserInBlock<LoadInst>(FirstPrivatized, NonAtomicBB); 3318 Value *SecondLoad = 3319 findSingleUserInBlock<LoadInst>(SecondPrivatized, NonAtomicBB); 3320 EXPECT_TRUE(isValueReducedToFuncArg(FirstLoad, NonAtomicBB)); 3321 EXPECT_TRUE(isValueReducedToFuncArg(SecondLoad, NonAtomicBB)); 3322 3323 // Atomic block also constains reductions to the global reduction variable. 3324 FirstLoad = findSingleUserInBlock<LoadInst>(FirstPrivatized, AtomicBB); 3325 SecondLoad = findSingleUserInBlock<LoadInst>(SecondPrivatized, AtomicBB); 3326 auto *FirstAtomic = findSingleUserInBlock<AtomicRMWInst>(FirstLoad, AtomicBB); 3327 auto *SecondAtomic = 3328 findSingleUserInBlock<AtomicRMWInst>(SecondLoad, AtomicBB); 3329 ASSERT_NE(FirstAtomic, nullptr); 3330 EXPECT_TRUE(isa<Argument>(FirstAtomic->getPointerOperand())); 3331 ASSERT_NE(SecondAtomic, nullptr); 3332 EXPECT_TRUE(isa<Argument>(SecondAtomic->getPointerOperand())); 3333 3334 // Check that the separate reduction function also performs (non-atomic) 3335 // reductions after extracting reduction variables from its arguments. 3336 Function *ReductionFn = cast<Function>(ReductionFnVal); 3337 BasicBlock *FnReductionBB = &ReductionFn->getEntryBlock(); 3338 auto *Bitcast = 3339 findSingleUserInBlock<BitCastInst>(ReductionFn->getArg(0), FnReductionBB); 3340 Value *FirstLHSPtr; 3341 Value *SecondLHSPtr; 3342 ASSERT_TRUE(findGEPZeroOne(Bitcast, FirstLHSPtr, SecondLHSPtr)); 3343 Value *Opaque = findSingleUserInBlock<LoadInst>(FirstLHSPtr, FnReductionBB); 3344 ASSERT_NE(Opaque, nullptr); 3345 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3346 ASSERT_NE(Bitcast, nullptr); 3347 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB)); 3348 Opaque = findSingleUserInBlock<LoadInst>(SecondLHSPtr, FnReductionBB); 3349 ASSERT_NE(Opaque, nullptr); 3350 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3351 ASSERT_NE(Bitcast, nullptr); 3352 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB)); 3353 3354 Bitcast = 3355 findSingleUserInBlock<BitCastInst>(ReductionFn->getArg(1), FnReductionBB); 3356 Value *FirstRHS; 3357 Value *SecondRHS; 3358 EXPECT_TRUE(findGEPZeroOne(Bitcast, FirstRHS, SecondRHS)); 3359 } 3360 3361 TEST_F(OpenMPIRBuilderTest, CreateTwoReductions) { 3362 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 3363 OpenMPIRBuilder OMPBuilder(*M); 3364 OMPBuilder.initialize(); 3365 F->setName("func"); 3366 IRBuilder<> Builder(BB); 3367 3368 BasicBlock *EnterBB = BasicBlock::Create(Ctx, "parallel.enter", F); 3369 Builder.CreateBr(EnterBB); 3370 Builder.SetInsertPoint(EnterBB); 3371 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3372 3373 // Create variables to be reduced. 3374 InsertPointTy OuterAllocaIP(&F->getEntryBlock(), 3375 F->getEntryBlock().getFirstInsertionPt()); 3376 Type *SumType = Builder.getFloatTy(); 3377 Type *XorType = Builder.getInt32Ty(); 3378 Value *SumReduced; 3379 Value *XorReduced; 3380 { 3381 IRBuilderBase::InsertPointGuard Guard(Builder); 3382 Builder.restoreIP(OuterAllocaIP); 3383 SumReduced = Builder.CreateAlloca(SumType); 3384 XorReduced = Builder.CreateAlloca(XorType); 3385 } 3386 3387 // Store initial values of reductions into global variables. 3388 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), SumReduced); 3389 Builder.CreateStore(Builder.getInt32(1), XorReduced); 3390 3391 InsertPointTy FirstBodyIP, FirstBodyAllocaIP; 3392 auto FirstBodyGenCB = [&](InsertPointTy InnerAllocaIP, 3393 InsertPointTy CodeGenIP, 3394 BasicBlock &ContinuationBB) { 3395 IRBuilderBase::InsertPointGuard Guard(Builder); 3396 Builder.restoreIP(CodeGenIP); 3397 3398 uint32_t StrSize; 3399 Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc, StrSize); 3400 Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr, StrSize); 3401 Value *TID = OMPBuilder.getOrCreateThreadID(Ident); 3402 Value *SumLocal = 3403 Builder.CreateUIToFP(TID, Builder.getFloatTy(), "sum.local"); 3404 Value *SumPartial = Builder.CreateLoad(SumType, SumReduced, "sum.partial"); 3405 Value *Sum = Builder.CreateFAdd(SumPartial, SumLocal, "sum"); 3406 Builder.CreateStore(Sum, SumReduced); 3407 3408 FirstBodyIP = Builder.saveIP(); 3409 FirstBodyAllocaIP = InnerAllocaIP; 3410 }; 3411 3412 InsertPointTy SecondBodyIP, SecondBodyAllocaIP; 3413 auto SecondBodyGenCB = [&](InsertPointTy InnerAllocaIP, 3414 InsertPointTy CodeGenIP, 3415 BasicBlock &ContinuationBB) { 3416 IRBuilderBase::InsertPointGuard Guard(Builder); 3417 Builder.restoreIP(CodeGenIP); 3418 3419 uint32_t StrSize; 3420 Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc, StrSize); 3421 Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr, StrSize); 3422 Value *TID = OMPBuilder.getOrCreateThreadID(Ident); 3423 Value *XorPartial = Builder.CreateLoad(XorType, XorReduced, "xor.partial"); 3424 Value *Xor = Builder.CreateXor(XorPartial, TID, "xor"); 3425 Builder.CreateStore(Xor, XorReduced); 3426 3427 SecondBodyIP = Builder.saveIP(); 3428 SecondBodyAllocaIP = InnerAllocaIP; 3429 }; 3430 3431 // Privatization for reduction creates local copies of reduction variables and 3432 // initializes them to reduction-neutral values. The same privatization 3433 // callback is used for both loops, with dispatch based on the value being 3434 // privatized. 3435 Value *SumPrivatized; 3436 Value *XorPrivatized; 3437 auto PrivCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP, 3438 Value &Original, Value &Inner, Value *&ReplVal) { 3439 IRBuilderBase::InsertPointGuard Guard(Builder); 3440 Builder.restoreIP(InnerAllocaIP); 3441 if (&Original == SumReduced) { 3442 SumPrivatized = Builder.CreateAlloca(Builder.getFloatTy()); 3443 ReplVal = SumPrivatized; 3444 } else if (&Original == XorReduced) { 3445 XorPrivatized = Builder.CreateAlloca(Builder.getInt32Ty()); 3446 ReplVal = XorPrivatized; 3447 } else { 3448 ReplVal = &Inner; 3449 return CodeGenIP; 3450 } 3451 3452 Builder.restoreIP(CodeGenIP); 3453 if (&Original == SumReduced) 3454 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), 3455 SumPrivatized); 3456 else if (&Original == XorReduced) 3457 Builder.CreateStore(Builder.getInt32(0), XorPrivatized); 3458 3459 return Builder.saveIP(); 3460 }; 3461 3462 // Do nothing in finalization. 3463 auto FiniCB = [&](InsertPointTy CodeGenIP) { return CodeGenIP; }; 3464 3465 Builder.restoreIP( 3466 OMPBuilder.createParallel(Loc, OuterAllocaIP, FirstBodyGenCB, PrivCB, 3467 FiniCB, /* IfCondition */ nullptr, 3468 /* NumThreads */ nullptr, OMP_PROC_BIND_default, 3469 /* IsCancellable */ false)); 3470 InsertPointTy AfterIP = OMPBuilder.createParallel( 3471 {Builder.saveIP(), DL}, OuterAllocaIP, SecondBodyGenCB, PrivCB, FiniCB, 3472 /* IfCondition */ nullptr, 3473 /* NumThreads */ nullptr, OMP_PROC_BIND_default, 3474 /* IsCancellable */ false); 3475 3476 OMPBuilder.createReductions( 3477 FirstBodyIP, FirstBodyAllocaIP, 3478 {{SumType, SumReduced, SumPrivatized, sumReduction, sumAtomicReduction}}); 3479 OMPBuilder.createReductions( 3480 SecondBodyIP, SecondBodyAllocaIP, 3481 {{XorType, XorReduced, XorPrivatized, xorReduction, xorAtomicReduction}}); 3482 3483 Builder.restoreIP(AfterIP); 3484 Builder.CreateRetVoid(); 3485 3486 OMPBuilder.finalize(F); 3487 3488 // The IR must be valid. 3489 EXPECT_FALSE(verifyModule(*M)); 3490 3491 // Two different outlined functions must have been created. 3492 SmallVector<CallInst *> ForkCalls; 3493 findCalls(F, omp::RuntimeFunction::OMPRTL___kmpc_fork_call, OMPBuilder, 3494 ForkCalls); 3495 ASSERT_EQ(ForkCalls.size(), 2u); 3496 Value *CalleeVal = cast<Constant>(ForkCalls[0]->getOperand(2))->getOperand(0); 3497 Function *FirstCallee = cast<Function>(CalleeVal); 3498 CalleeVal = cast<Constant>(ForkCalls[1]->getOperand(2))->getOperand(0); 3499 Function *SecondCallee = cast<Function>(CalleeVal); 3500 EXPECT_NE(FirstCallee, SecondCallee); 3501 3502 // Two different reduction functions must have been created. 3503 SmallVector<CallInst *> ReduceCalls; 3504 findCalls(FirstCallee, omp::RuntimeFunction::OMPRTL___kmpc_reduce, OMPBuilder, 3505 ReduceCalls); 3506 ASSERT_EQ(ReduceCalls.size(), 1u); 3507 auto *AddReduction = cast<Function>(ReduceCalls[0]->getOperand(5)); 3508 ReduceCalls.clear(); 3509 findCalls(SecondCallee, omp::RuntimeFunction::OMPRTL___kmpc_reduce, 3510 OMPBuilder, ReduceCalls); 3511 auto *XorReduction = cast<Function>(ReduceCalls[0]->getOperand(5)); 3512 EXPECT_NE(AddReduction, XorReduction); 3513 3514 // Each reduction function does its own kind of reduction. 3515 BasicBlock *FnReductionBB = &AddReduction->getEntryBlock(); 3516 auto *Bitcast = findSingleUserInBlock<BitCastInst>(AddReduction->getArg(0), 3517 FnReductionBB); 3518 ASSERT_NE(Bitcast, nullptr); 3519 Value *FirstLHSPtr = 3520 findSingleUserInBlock<GetElementPtrInst>(Bitcast, FnReductionBB); 3521 ASSERT_NE(FirstLHSPtr, nullptr); 3522 Value *Opaque = findSingleUserInBlock<LoadInst>(FirstLHSPtr, FnReductionBB); 3523 ASSERT_NE(Opaque, nullptr); 3524 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3525 ASSERT_NE(Bitcast, nullptr); 3526 Instruction::BinaryOps Opcode = Instruction::FAdd; 3527 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB, &Opcode)); 3528 3529 FnReductionBB = &XorReduction->getEntryBlock(); 3530 Bitcast = findSingleUserInBlock<BitCastInst>(XorReduction->getArg(0), 3531 FnReductionBB); 3532 ASSERT_NE(Bitcast, nullptr); 3533 Value *SecondLHSPtr = 3534 findSingleUserInBlock<GetElementPtrInst>(Bitcast, FnReductionBB); 3535 ASSERT_NE(FirstLHSPtr, nullptr); 3536 Opaque = findSingleUserInBlock<LoadInst>(SecondLHSPtr, FnReductionBB); 3537 ASSERT_NE(Opaque, nullptr); 3538 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3539 ASSERT_NE(Bitcast, nullptr); 3540 Opcode = Instruction::Xor; 3541 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB, &Opcode)); 3542 } 3543 3544 TEST_F(OpenMPIRBuilderTest, CreateSectionsSimple) { 3545 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 3546 using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy; 3547 OpenMPIRBuilder OMPBuilder(*M); 3548 OMPBuilder.initialize(); 3549 F->setName("func"); 3550 IRBuilder<> Builder(BB); 3551 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3552 llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector; 3553 llvm::SmallVector<BasicBlock *, 4> CaseBBs; 3554 3555 auto FiniCB = [&](InsertPointTy IP) {}; 3556 auto SectionCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 3557 BasicBlock &FiniBB) { 3558 Builder.restoreIP(CodeGenIP); 3559 Builder.CreateBr(&FiniBB); 3560 }; 3561 SectionCBVector.push_back(SectionCB); 3562 3563 auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 3564 llvm::Value &, llvm::Value &Val, 3565 llvm::Value *&ReplVal) { return CodeGenIP; }; 3566 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3567 F->getEntryBlock().getFirstInsertionPt()); 3568 Builder.restoreIP(OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector, 3569 PrivCB, FiniCB, false, false)); 3570 Builder.CreateRetVoid(); // Required at the end of the function 3571 EXPECT_NE(F->getEntryBlock().getTerminator(), nullptr); 3572 EXPECT_FALSE(verifyModule(*M, &errs())); 3573 } 3574 3575 TEST_F(OpenMPIRBuilderTest, CreateSections) { 3576 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 3577 using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy; 3578 OpenMPIRBuilder OMPBuilder(*M); 3579 OMPBuilder.initialize(); 3580 F->setName("func"); 3581 IRBuilder<> Builder(BB); 3582 3583 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3584 llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector; 3585 llvm::SmallVector<BasicBlock *, 4> CaseBBs; 3586 3587 BasicBlock *SwitchBB = nullptr; 3588 BasicBlock *ForExitBB = nullptr; 3589 BasicBlock *ForIncBB = nullptr; 3590 AllocaInst *PrivAI = nullptr; 3591 SwitchInst *Switch = nullptr; 3592 3593 unsigned NumBodiesGenerated = 0; 3594 unsigned NumFiniCBCalls = 0; 3595 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 3596 3597 auto FiniCB = [&](InsertPointTy IP) { 3598 ++NumFiniCBCalls; 3599 BasicBlock *IPBB = IP.getBlock(); 3600 EXPECT_NE(IPBB->end(), IP.getPoint()); 3601 }; 3602 3603 auto SectionCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 3604 BasicBlock &FiniBB) { 3605 ++NumBodiesGenerated; 3606 CaseBBs.push_back(CodeGenIP.getBlock()); 3607 SwitchBB = CodeGenIP.getBlock()->getSinglePredecessor(); 3608 Builder.restoreIP(CodeGenIP); 3609 Builder.CreateStore(F->arg_begin(), PrivAI); 3610 Value *PrivLoad = 3611 Builder.CreateLoad(F->arg_begin()->getType(), PrivAI, "local.alloca"); 3612 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 3613 Builder.CreateBr(&FiniBB); 3614 ForIncBB = 3615 CodeGenIP.getBlock()->getSinglePredecessor()->getSingleSuccessor(); 3616 }; 3617 auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 3618 llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) { 3619 // TODO: Privatization not implemented yet 3620 return CodeGenIP; 3621 }; 3622 3623 SectionCBVector.push_back(SectionCB); 3624 SectionCBVector.push_back(SectionCB); 3625 3626 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3627 F->getEntryBlock().getFirstInsertionPt()); 3628 Builder.restoreIP(OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector, 3629 PrivCB, FiniCB, false, false)); 3630 Builder.CreateRetVoid(); // Required at the end of the function 3631 3632 // Switch BB's predecessor is loop condition BB, whose successor at index 1 is 3633 // loop's exit BB 3634 ForExitBB = 3635 SwitchBB->getSinglePredecessor()->getTerminator()->getSuccessor(1); 3636 EXPECT_NE(ForExitBB, nullptr); 3637 3638 EXPECT_NE(PrivAI, nullptr); 3639 Function *OutlinedFn = PrivAI->getFunction(); 3640 EXPECT_EQ(F, OutlinedFn); 3641 EXPECT_FALSE(verifyModule(*M, &errs())); 3642 EXPECT_EQ(OutlinedFn->arg_size(), 1U); 3643 EXPECT_EQ(OutlinedFn->getBasicBlockList().size(), size_t(11)); 3644 3645 BasicBlock *LoopPreheaderBB = 3646 OutlinedFn->getEntryBlock().getSingleSuccessor(); 3647 // loop variables are 5 - lower bound, upper bound, stride, islastiter, and 3648 // iterator/counter 3649 bool FoundForInit = false; 3650 for (Instruction &Inst : *LoopPreheaderBB) { 3651 if (isa<CallInst>(Inst)) { 3652 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 3653 "__kmpc_for_static_init_4u") { 3654 FoundForInit = true; 3655 } 3656 } 3657 } 3658 EXPECT_EQ(FoundForInit, true); 3659 3660 bool FoundForExit = false; 3661 bool FoundBarrier = false; 3662 for (Instruction &Inst : *ForExitBB) { 3663 if (isa<CallInst>(Inst)) { 3664 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 3665 "__kmpc_for_static_fini") { 3666 FoundForExit = true; 3667 } 3668 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 3669 "__kmpc_barrier") { 3670 FoundBarrier = true; 3671 } 3672 if (FoundForExit && FoundBarrier) 3673 break; 3674 } 3675 } 3676 EXPECT_EQ(FoundForExit, true); 3677 EXPECT_EQ(FoundBarrier, true); 3678 3679 EXPECT_NE(SwitchBB, nullptr); 3680 EXPECT_NE(SwitchBB->getTerminator(), nullptr); 3681 EXPECT_EQ(isa<SwitchInst>(SwitchBB->getTerminator()), true); 3682 Switch = cast<SwitchInst>(SwitchBB->getTerminator()); 3683 EXPECT_EQ(Switch->getNumCases(), 2U); 3684 EXPECT_NE(ForIncBB, nullptr); 3685 EXPECT_EQ(Switch->getSuccessor(0), ForIncBB); 3686 3687 EXPECT_EQ(CaseBBs.size(), 2U); 3688 for (auto *&CaseBB : CaseBBs) { 3689 EXPECT_EQ(CaseBB->getParent(), OutlinedFn); 3690 EXPECT_EQ(CaseBB->getSingleSuccessor(), ForExitBB); 3691 } 3692 3693 ASSERT_EQ(NumBodiesGenerated, 2U); 3694 ASSERT_EQ(NumFiniCBCalls, 1U); 3695 EXPECT_FALSE(verifyModule(*M, &errs())); 3696 } 3697 3698 TEST_F(OpenMPIRBuilderTest, CreateSectionsNoWait) { 3699 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 3700 using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy; 3701 OpenMPIRBuilder OMPBuilder(*M); 3702 OMPBuilder.initialize(); 3703 F->setName("func"); 3704 IRBuilder<> Builder(BB); 3705 3706 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3707 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3708 F->getEntryBlock().getFirstInsertionPt()); 3709 llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector; 3710 auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 3711 llvm::Value &, llvm::Value &Val, 3712 llvm::Value *&ReplVal) { return CodeGenIP; }; 3713 auto FiniCB = [&](InsertPointTy IP) {}; 3714 3715 Builder.restoreIP(OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector, 3716 PrivCB, FiniCB, false, true)); 3717 Builder.CreateRetVoid(); // Required at the end of the function 3718 for (auto &Inst : instructions(*F)) { 3719 EXPECT_FALSE(isa<CallInst>(Inst) && 3720 cast<CallInst>(&Inst)->getCalledFunction()->getName() == 3721 "__kmpc_barrier" && 3722 "call to function __kmpc_barrier found with nowait"); 3723 } 3724 } 3725 3726 TEST_F(OpenMPIRBuilderTest, CreateOffloadMaptypes) { 3727 OpenMPIRBuilder OMPBuilder(*M); 3728 OMPBuilder.initialize(); 3729 3730 IRBuilder<> Builder(BB); 3731 3732 SmallVector<uint64_t> Mappings = {0, 1}; 3733 GlobalVariable *OffloadMaptypesGlobal = 3734 OMPBuilder.createOffloadMaptypes(Mappings, "offload_maptypes"); 3735 EXPECT_FALSE(M->global_empty()); 3736 EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_maptypes"); 3737 EXPECT_TRUE(OffloadMaptypesGlobal->isConstant()); 3738 EXPECT_TRUE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr()); 3739 EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage()); 3740 EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer()); 3741 Constant *Initializer = OffloadMaptypesGlobal->getInitializer(); 3742 EXPECT_TRUE(isa<ConstantDataArray>(Initializer)); 3743 ConstantDataArray *MappingInit = dyn_cast<ConstantDataArray>(Initializer); 3744 EXPECT_EQ(MappingInit->getNumElements(), Mappings.size()); 3745 EXPECT_TRUE(MappingInit->getType()->getElementType()->isIntegerTy(64)); 3746 Constant *CA = ConstantDataArray::get(Builder.getContext(), Mappings); 3747 EXPECT_EQ(MappingInit, CA); 3748 } 3749 3750 TEST_F(OpenMPIRBuilderTest, CreateOffloadMapnames) { 3751 OpenMPIRBuilder OMPBuilder(*M); 3752 OMPBuilder.initialize(); 3753 3754 IRBuilder<> Builder(BB); 3755 3756 uint32_t StrSize; 3757 Constant *Cst1 = 3758 OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5, StrSize); 3759 Constant *Cst2 = 3760 OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5, StrSize); 3761 SmallVector<llvm::Constant *> Names = {Cst1, Cst2}; 3762 3763 GlobalVariable *OffloadMaptypesGlobal = 3764 OMPBuilder.createOffloadMapnames(Names, "offload_mapnames"); 3765 EXPECT_FALSE(M->global_empty()); 3766 EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_mapnames"); 3767 EXPECT_TRUE(OffloadMaptypesGlobal->isConstant()); 3768 EXPECT_FALSE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr()); 3769 EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage()); 3770 EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer()); 3771 Constant *Initializer = OffloadMaptypesGlobal->getInitializer(); 3772 EXPECT_TRUE(isa<Constant>(Initializer->getOperand(0)->stripPointerCasts())); 3773 EXPECT_TRUE(isa<Constant>(Initializer->getOperand(1)->stripPointerCasts())); 3774 3775 GlobalVariable *Name1Gbl = 3776 cast<GlobalVariable>(Initializer->getOperand(0)->stripPointerCasts()); 3777 EXPECT_TRUE(isa<ConstantDataArray>(Name1Gbl->getInitializer())); 3778 ConstantDataArray *Name1GblCA = 3779 dyn_cast<ConstantDataArray>(Name1Gbl->getInitializer()); 3780 EXPECT_EQ(Name1GblCA->getAsCString(), ";file1;array1;2;5;;"); 3781 3782 GlobalVariable *Name2Gbl = 3783 cast<GlobalVariable>(Initializer->getOperand(1)->stripPointerCasts()); 3784 EXPECT_TRUE(isa<ConstantDataArray>(Name2Gbl->getInitializer())); 3785 ConstantDataArray *Name2GblCA = 3786 dyn_cast<ConstantDataArray>(Name2Gbl->getInitializer()); 3787 EXPECT_EQ(Name2GblCA->getAsCString(), ";file1;array2;3;5;;"); 3788 3789 EXPECT_TRUE(Initializer->getType()->getArrayElementType()->isPointerTy()); 3790 EXPECT_EQ(Initializer->getType()->getArrayNumElements(), Names.size()); 3791 } 3792 3793 TEST_F(OpenMPIRBuilderTest, CreateMapperAllocas) { 3794 OpenMPIRBuilder OMPBuilder(*M); 3795 OMPBuilder.initialize(); 3796 F->setName("func"); 3797 IRBuilder<> Builder(BB); 3798 3799 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3800 3801 unsigned TotalNbOperand = 2; 3802 3803 OpenMPIRBuilder::MapperAllocas MapperAllocas; 3804 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3805 F->getEntryBlock().getFirstInsertionPt()); 3806 OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas); 3807 EXPECT_NE(MapperAllocas.ArgsBase, nullptr); 3808 EXPECT_NE(MapperAllocas.Args, nullptr); 3809 EXPECT_NE(MapperAllocas.ArgSizes, nullptr); 3810 EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType()->isArrayTy()); 3811 ArrayType *ArrType = 3812 dyn_cast<ArrayType>(MapperAllocas.ArgsBase->getAllocatedType()); 3813 EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand); 3814 EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType() 3815 ->getArrayElementType() 3816 ->isPointerTy()); 3817 EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType() 3818 ->getArrayElementType() 3819 ->getPointerElementType() 3820 ->isIntegerTy(8)); 3821 3822 EXPECT_TRUE(MapperAllocas.Args->getAllocatedType()->isArrayTy()); 3823 ArrType = dyn_cast<ArrayType>(MapperAllocas.Args->getAllocatedType()); 3824 EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand); 3825 EXPECT_TRUE(MapperAllocas.Args->getAllocatedType() 3826 ->getArrayElementType() 3827 ->isPointerTy()); 3828 EXPECT_TRUE(MapperAllocas.Args->getAllocatedType() 3829 ->getArrayElementType() 3830 ->getPointerElementType() 3831 ->isIntegerTy(8)); 3832 3833 EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType()->isArrayTy()); 3834 ArrType = dyn_cast<ArrayType>(MapperAllocas.ArgSizes->getAllocatedType()); 3835 EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand); 3836 EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType() 3837 ->getArrayElementType() 3838 ->isIntegerTy(64)); 3839 } 3840 3841 TEST_F(OpenMPIRBuilderTest, EmitMapperCall) { 3842 OpenMPIRBuilder OMPBuilder(*M); 3843 OMPBuilder.initialize(); 3844 F->setName("func"); 3845 IRBuilder<> Builder(BB); 3846 LLVMContext &Ctx = M->getContext(); 3847 3848 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3849 3850 unsigned TotalNbOperand = 2; 3851 3852 OpenMPIRBuilder::MapperAllocas MapperAllocas; 3853 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3854 F->getEntryBlock().getFirstInsertionPt()); 3855 OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas); 3856 3857 auto *BeginMapperFunc = OMPBuilder.getOrCreateRuntimeFunctionPtr( 3858 omp::OMPRTL___tgt_target_data_begin_mapper); 3859 3860 SmallVector<uint64_t> Flags = {0, 2}; 3861 3862 uint32_t StrSize; 3863 Constant *SrcLocCst = 3864 OMPBuilder.getOrCreateSrcLocStr("", "file1", 2, 5, StrSize); 3865 Value *SrcLocInfo = OMPBuilder.getOrCreateIdent(SrcLocCst, StrSize); 3866 3867 Constant *Cst1 = 3868 OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5, StrSize); 3869 Constant *Cst2 = 3870 OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5, StrSize); 3871 SmallVector<llvm::Constant *> Names = {Cst1, Cst2}; 3872 3873 GlobalVariable *Maptypes = 3874 OMPBuilder.createOffloadMaptypes(Flags, ".offload_maptypes"); 3875 Value *MaptypesArg = Builder.CreateConstInBoundsGEP2_32( 3876 ArrayType::get(Type::getInt64Ty(Ctx), TotalNbOperand), Maptypes, 3877 /*Idx0=*/0, /*Idx1=*/0); 3878 3879 GlobalVariable *Mapnames = 3880 OMPBuilder.createOffloadMapnames(Names, ".offload_mapnames"); 3881 Value *MapnamesArg = Builder.CreateConstInBoundsGEP2_32( 3882 ArrayType::get(Type::getInt8PtrTy(Ctx), TotalNbOperand), Mapnames, 3883 /*Idx0=*/0, /*Idx1=*/0); 3884 3885 OMPBuilder.emitMapperCall(Builder.saveIP(), BeginMapperFunc, SrcLocInfo, 3886 MaptypesArg, MapnamesArg, MapperAllocas, -1, 3887 TotalNbOperand); 3888 3889 CallInst *MapperCall = dyn_cast<CallInst>(&BB->back()); 3890 EXPECT_NE(MapperCall, nullptr); 3891 EXPECT_EQ(MapperCall->arg_size(), 9U); 3892 EXPECT_EQ(MapperCall->getCalledFunction()->getName(), 3893 "__tgt_target_data_begin_mapper"); 3894 EXPECT_EQ(MapperCall->getOperand(0), SrcLocInfo); 3895 EXPECT_TRUE(MapperCall->getOperand(1)->getType()->isIntegerTy(64)); 3896 EXPECT_TRUE(MapperCall->getOperand(2)->getType()->isIntegerTy(32)); 3897 3898 EXPECT_EQ(MapperCall->getOperand(6), MaptypesArg); 3899 EXPECT_EQ(MapperCall->getOperand(7), MapnamesArg); 3900 EXPECT_TRUE(MapperCall->getOperand(8)->getType()->isPointerTy()); 3901 } 3902 3903 } // namespace 3904