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