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