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