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, OrderedDirectiveDependSource) { 2124 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2125 OpenMPIRBuilder OMPBuilder(*M); 2126 OMPBuilder.initialize(); 2127 F->setName("func"); 2128 IRBuilder<> Builder(BB); 2129 LLVMContext &Ctx = M->getContext(); 2130 2131 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2132 2133 InsertPointTy AllocaIP(&F->getEntryBlock(), 2134 F->getEntryBlock().getFirstInsertionPt()); 2135 2136 unsigned NumLoops = 2; 2137 SmallVector<Value *, 2> StoreValues; 2138 Type *LCTy = Type::getInt64Ty(Ctx); 2139 StoreValues.emplace_back(ConstantInt::get(LCTy, 1)); 2140 StoreValues.emplace_back(ConstantInt::get(LCTy, 2)); 2141 2142 // Test for "#omp ordered depend(source)" 2143 Builder.restoreIP(OMPBuilder.createOrderedDepend(Builder, AllocaIP, NumLoops, 2144 StoreValues, ".cnt.addr", 2145 /*IsDependSource=*/true)); 2146 2147 Builder.CreateRetVoid(); 2148 OMPBuilder.finalize(); 2149 EXPECT_FALSE(verifyModule(*M, &errs())); 2150 2151 AllocaInst *AllocInst = dyn_cast<AllocaInst>(&BB->front()); 2152 ASSERT_NE(AllocInst, nullptr); 2153 ArrayType *ArrType = dyn_cast<ArrayType>(AllocInst->getAllocatedType()); 2154 EXPECT_EQ(ArrType->getNumElements(), NumLoops); 2155 EXPECT_TRUE( 2156 AllocInst->getAllocatedType()->getArrayElementType()->isIntegerTy(64)); 2157 2158 Instruction *IterInst = dyn_cast<Instruction>(AllocInst); 2159 for (unsigned Iter = 0; Iter < NumLoops; Iter++) { 2160 GetElementPtrInst *DependAddrGEPIter = 2161 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2162 ASSERT_NE(DependAddrGEPIter, nullptr); 2163 EXPECT_EQ(DependAddrGEPIter->getPointerOperand(), AllocInst); 2164 EXPECT_EQ(DependAddrGEPIter->getNumIndices(), (unsigned)2); 2165 auto *FirstIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(1)); 2166 auto *SecondIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(2)); 2167 ASSERT_NE(FirstIdx, nullptr); 2168 ASSERT_NE(SecondIdx, nullptr); 2169 EXPECT_EQ(FirstIdx->getValue(), 0); 2170 EXPECT_EQ(SecondIdx->getValue(), Iter); 2171 StoreInst *StoreValue = 2172 dyn_cast<StoreInst>(DependAddrGEPIter->getNextNode()); 2173 ASSERT_NE(StoreValue, nullptr); 2174 EXPECT_EQ(StoreValue->getValueOperand(), StoreValues[Iter]); 2175 EXPECT_EQ(StoreValue->getPointerOperand(), DependAddrGEPIter); 2176 IterInst = dyn_cast<Instruction>(StoreValue); 2177 } 2178 2179 GetElementPtrInst *DependBaseAddrGEP = 2180 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2181 ASSERT_NE(DependBaseAddrGEP, nullptr); 2182 EXPECT_EQ(DependBaseAddrGEP->getPointerOperand(), AllocInst); 2183 EXPECT_EQ(DependBaseAddrGEP->getNumIndices(), (unsigned)2); 2184 auto *FirstIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(1)); 2185 auto *SecondIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(2)); 2186 ASSERT_NE(FirstIdx, nullptr); 2187 ASSERT_NE(SecondIdx, nullptr); 2188 EXPECT_EQ(FirstIdx->getValue(), 0); 2189 EXPECT_EQ(SecondIdx->getValue(), 0); 2190 2191 CallInst *GTID = dyn_cast<CallInst>(DependBaseAddrGEP->getNextNode()); 2192 ASSERT_NE(GTID, nullptr); 2193 EXPECT_EQ(GTID->getNumArgOperands(), 1U); 2194 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 2195 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 2196 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 2197 2198 CallInst *Depend = dyn_cast<CallInst>(GTID->getNextNode()); 2199 ASSERT_NE(Depend, nullptr); 2200 EXPECT_EQ(Depend->getNumArgOperands(), 3U); 2201 EXPECT_EQ(Depend->getCalledFunction()->getName(), "__kmpc_doacross_post"); 2202 EXPECT_TRUE(isa<GlobalVariable>(Depend->getArgOperand(0))); 2203 EXPECT_EQ(Depend->getArgOperand(1), GTID); 2204 EXPECT_EQ(Depend->getArgOperand(2), DependBaseAddrGEP); 2205 } 2206 2207 TEST_F(OpenMPIRBuilderTest, OrderedDirectiveDependSink) { 2208 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2209 OpenMPIRBuilder OMPBuilder(*M); 2210 OMPBuilder.initialize(); 2211 F->setName("func"); 2212 IRBuilder<> Builder(BB); 2213 LLVMContext &Ctx = M->getContext(); 2214 2215 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2216 2217 InsertPointTy AllocaIP(&F->getEntryBlock(), 2218 F->getEntryBlock().getFirstInsertionPt()); 2219 2220 unsigned NumLoops = 2; 2221 SmallVector<Value *, 2> StoreValues; 2222 Type *LCTy = Type::getInt64Ty(Ctx); 2223 StoreValues.emplace_back(ConstantInt::get(LCTy, 1)); 2224 StoreValues.emplace_back(ConstantInt::get(LCTy, 2)); 2225 2226 // Test for "#omp ordered depend(sink: vec)" 2227 Builder.restoreIP(OMPBuilder.createOrderedDepend(Builder, AllocaIP, NumLoops, 2228 StoreValues, ".cnt.addr", 2229 /*IsDependSource=*/false)); 2230 2231 Builder.CreateRetVoid(); 2232 OMPBuilder.finalize(); 2233 EXPECT_FALSE(verifyModule(*M, &errs())); 2234 2235 AllocaInst *AllocInst = dyn_cast<AllocaInst>(&BB->front()); 2236 ASSERT_NE(AllocInst, nullptr); 2237 ArrayType *ArrType = dyn_cast<ArrayType>(AllocInst->getAllocatedType()); 2238 EXPECT_EQ(ArrType->getNumElements(), NumLoops); 2239 EXPECT_TRUE( 2240 AllocInst->getAllocatedType()->getArrayElementType()->isIntegerTy(64)); 2241 2242 Instruction *IterInst = dyn_cast<Instruction>(AllocInst); 2243 for (unsigned Iter = 0; Iter < NumLoops; Iter++) { 2244 GetElementPtrInst *DependAddrGEPIter = 2245 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2246 ASSERT_NE(DependAddrGEPIter, nullptr); 2247 EXPECT_EQ(DependAddrGEPIter->getPointerOperand(), AllocInst); 2248 EXPECT_EQ(DependAddrGEPIter->getNumIndices(), (unsigned)2); 2249 auto *FirstIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(1)); 2250 auto *SecondIdx = dyn_cast<ConstantInt>(DependAddrGEPIter->getOperand(2)); 2251 ASSERT_NE(FirstIdx, nullptr); 2252 ASSERT_NE(SecondIdx, nullptr); 2253 EXPECT_EQ(FirstIdx->getValue(), 0); 2254 EXPECT_EQ(SecondIdx->getValue(), Iter); 2255 StoreInst *StoreValue = 2256 dyn_cast<StoreInst>(DependAddrGEPIter->getNextNode()); 2257 ASSERT_NE(StoreValue, nullptr); 2258 EXPECT_EQ(StoreValue->getValueOperand(), StoreValues[Iter]); 2259 EXPECT_EQ(StoreValue->getPointerOperand(), DependAddrGEPIter); 2260 IterInst = dyn_cast<Instruction>(StoreValue); 2261 } 2262 2263 GetElementPtrInst *DependBaseAddrGEP = 2264 dyn_cast<GetElementPtrInst>(IterInst->getNextNode()); 2265 ASSERT_NE(DependBaseAddrGEP, nullptr); 2266 EXPECT_EQ(DependBaseAddrGEP->getPointerOperand(), AllocInst); 2267 EXPECT_EQ(DependBaseAddrGEP->getNumIndices(), (unsigned)2); 2268 auto *FirstIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(1)); 2269 auto *SecondIdx = dyn_cast<ConstantInt>(DependBaseAddrGEP->getOperand(2)); 2270 ASSERT_NE(FirstIdx, nullptr); 2271 ASSERT_NE(SecondIdx, nullptr); 2272 EXPECT_EQ(FirstIdx->getValue(), 0); 2273 EXPECT_EQ(SecondIdx->getValue(), 0); 2274 2275 CallInst *GTID = dyn_cast<CallInst>(DependBaseAddrGEP->getNextNode()); 2276 ASSERT_NE(GTID, nullptr); 2277 EXPECT_EQ(GTID->getNumArgOperands(), 1U); 2278 EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); 2279 EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); 2280 EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); 2281 2282 CallInst *Depend = dyn_cast<CallInst>(GTID->getNextNode()); 2283 ASSERT_NE(Depend, nullptr); 2284 EXPECT_EQ(Depend->getNumArgOperands(), 3U); 2285 EXPECT_EQ(Depend->getCalledFunction()->getName(), "__kmpc_doacross_wait"); 2286 EXPECT_TRUE(isa<GlobalVariable>(Depend->getArgOperand(0))); 2287 EXPECT_EQ(Depend->getArgOperand(1), GTID); 2288 EXPECT_EQ(Depend->getArgOperand(2), DependBaseAddrGEP); 2289 } 2290 2291 TEST_F(OpenMPIRBuilderTest, OrderedDirectiveThreads) { 2292 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2293 OpenMPIRBuilder OMPBuilder(*M); 2294 OMPBuilder.initialize(); 2295 F->setName("func"); 2296 IRBuilder<> Builder(BB); 2297 2298 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2299 2300 AllocaInst *PrivAI = 2301 Builder.CreateAlloca(F->arg_begin()->getType(), nullptr, "priv.inst"); 2302 2303 BasicBlock *EntryBB = nullptr; 2304 2305 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2306 BasicBlock &FiniBB) { 2307 EntryBB = FiniBB.getUniquePredecessor(); 2308 2309 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2310 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2311 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2312 EXPECT_EQ(EntryBB, CodeGenIPBB); 2313 2314 Builder.restoreIP(CodeGenIP); 2315 Builder.CreateStore(F->arg_begin(), PrivAI); 2316 Value *PrivLoad = 2317 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2318 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2319 }; 2320 2321 auto FiniCB = [&](InsertPointTy IP) { 2322 BasicBlock *IPBB = IP.getBlock(); 2323 EXPECT_NE(IPBB->end(), IP.getPoint()); 2324 }; 2325 2326 // Test for "#omp ordered [threads]" 2327 Builder.restoreIP( 2328 OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, true)); 2329 2330 Builder.CreateRetVoid(); 2331 OMPBuilder.finalize(); 2332 EXPECT_FALSE(verifyModule(*M, &errs())); 2333 2334 EXPECT_NE(EntryBB->getTerminator(), nullptr); 2335 2336 CallInst *OrderedEntryCI = nullptr; 2337 for (auto &EI : *EntryBB) { 2338 Instruction *Cur = &EI; 2339 if (isa<CallInst>(Cur)) { 2340 OrderedEntryCI = cast<CallInst>(Cur); 2341 if (OrderedEntryCI->getCalledFunction()->getName() == "__kmpc_ordered") 2342 break; 2343 OrderedEntryCI = nullptr; 2344 } 2345 } 2346 EXPECT_NE(OrderedEntryCI, nullptr); 2347 EXPECT_EQ(OrderedEntryCI->getNumArgOperands(), 2U); 2348 EXPECT_EQ(OrderedEntryCI->getCalledFunction()->getName(), "__kmpc_ordered"); 2349 EXPECT_TRUE(isa<GlobalVariable>(OrderedEntryCI->getArgOperand(0))); 2350 2351 CallInst *OrderedEndCI = nullptr; 2352 for (auto &FI : *EntryBB) { 2353 Instruction *Cur = &FI; 2354 if (isa<CallInst>(Cur)) { 2355 OrderedEndCI = cast<CallInst>(Cur); 2356 if (OrderedEndCI->getCalledFunction()->getName() == "__kmpc_end_ordered") 2357 break; 2358 OrderedEndCI = nullptr; 2359 } 2360 } 2361 EXPECT_NE(OrderedEndCI, nullptr); 2362 EXPECT_EQ(OrderedEndCI->getNumArgOperands(), 2U); 2363 EXPECT_TRUE(isa<GlobalVariable>(OrderedEndCI->getArgOperand(0))); 2364 EXPECT_EQ(OrderedEndCI->getArgOperand(1), OrderedEntryCI->getArgOperand(1)); 2365 } 2366 2367 TEST_F(OpenMPIRBuilderTest, OrderedDirectiveSimd) { 2368 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2369 OpenMPIRBuilder OMPBuilder(*M); 2370 OMPBuilder.initialize(); 2371 F->setName("func"); 2372 IRBuilder<> Builder(BB); 2373 2374 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2375 2376 AllocaInst *PrivAI = 2377 Builder.CreateAlloca(F->arg_begin()->getType(), nullptr, "priv.inst"); 2378 2379 BasicBlock *EntryBB = nullptr; 2380 2381 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2382 BasicBlock &FiniBB) { 2383 EntryBB = FiniBB.getUniquePredecessor(); 2384 2385 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2386 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2387 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2388 EXPECT_EQ(EntryBB, CodeGenIPBB); 2389 2390 Builder.restoreIP(CodeGenIP); 2391 Builder.CreateStore(F->arg_begin(), PrivAI); 2392 Value *PrivLoad = 2393 Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, "local.use"); 2394 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2395 }; 2396 2397 auto FiniCB = [&](InsertPointTy IP) { 2398 BasicBlock *IPBB = IP.getBlock(); 2399 EXPECT_NE(IPBB->end(), IP.getPoint()); 2400 }; 2401 2402 // Test for "#omp ordered simd" 2403 Builder.restoreIP( 2404 OMPBuilder.createOrderedThreadsSimd(Builder, BodyGenCB, FiniCB, false)); 2405 2406 Builder.CreateRetVoid(); 2407 OMPBuilder.finalize(); 2408 EXPECT_FALSE(verifyModule(*M, &errs())); 2409 2410 EXPECT_NE(EntryBB->getTerminator(), nullptr); 2411 2412 CallInst *OrderedEntryCI = nullptr; 2413 for (auto &EI : *EntryBB) { 2414 Instruction *Cur = &EI; 2415 if (isa<CallInst>(Cur)) { 2416 OrderedEntryCI = cast<CallInst>(Cur); 2417 if (OrderedEntryCI->getCalledFunction()->getName() == "__kmpc_ordered") 2418 break; 2419 OrderedEntryCI = nullptr; 2420 } 2421 } 2422 EXPECT_EQ(OrderedEntryCI, nullptr); 2423 2424 CallInst *OrderedEndCI = nullptr; 2425 for (auto &FI : *EntryBB) { 2426 Instruction *Cur = &FI; 2427 if (isa<CallInst>(Cur)) { 2428 OrderedEndCI = cast<CallInst>(Cur); 2429 if (OrderedEndCI->getCalledFunction()->getName() == "__kmpc_end_ordered") 2430 break; 2431 OrderedEndCI = nullptr; 2432 } 2433 } 2434 EXPECT_EQ(OrderedEndCI, nullptr); 2435 } 2436 2437 TEST_F(OpenMPIRBuilderTest, CopyinBlocks) { 2438 OpenMPIRBuilder OMPBuilder(*M); 2439 OMPBuilder.initialize(); 2440 F->setName("func"); 2441 IRBuilder<> Builder(BB); 2442 2443 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2444 2445 IntegerType* Int32 = Type::getInt32Ty(M->getContext()); 2446 AllocaInst* MasterAddress = Builder.CreateAlloca(Int32->getPointerTo()); 2447 AllocaInst* PrivAddress = Builder.CreateAlloca(Int32->getPointerTo()); 2448 2449 BasicBlock *EntryBB = BB; 2450 2451 OMPBuilder.createCopyinClauseBlocks(Builder.saveIP(), MasterAddress, 2452 PrivAddress, Int32, /*BranchtoEnd*/ true); 2453 2454 BranchInst* EntryBr = dyn_cast_or_null<BranchInst>(EntryBB->getTerminator()); 2455 2456 EXPECT_NE(EntryBr, nullptr); 2457 EXPECT_TRUE(EntryBr->isConditional()); 2458 2459 BasicBlock* NotMasterBB = EntryBr->getSuccessor(0); 2460 BasicBlock* CopyinEnd = EntryBr->getSuccessor(1); 2461 CmpInst* CMP = dyn_cast_or_null<CmpInst>(EntryBr->getCondition()); 2462 2463 EXPECT_NE(CMP, nullptr); 2464 EXPECT_NE(NotMasterBB, nullptr); 2465 EXPECT_NE(CopyinEnd, nullptr); 2466 2467 BranchInst* NotMasterBr = dyn_cast_or_null<BranchInst>(NotMasterBB->getTerminator()); 2468 EXPECT_NE(NotMasterBr, nullptr); 2469 EXPECT_FALSE(NotMasterBr->isConditional()); 2470 EXPECT_EQ(CopyinEnd,NotMasterBr->getSuccessor(0)); 2471 } 2472 2473 TEST_F(OpenMPIRBuilderTest, SingleDirective) { 2474 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2475 OpenMPIRBuilder OMPBuilder(*M); 2476 OMPBuilder.initialize(); 2477 F->setName("func"); 2478 IRBuilder<> Builder(BB); 2479 2480 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2481 2482 AllocaInst *PrivAI = nullptr; 2483 2484 BasicBlock *EntryBB = nullptr; 2485 BasicBlock *ExitBB = nullptr; 2486 BasicBlock *ThenBB = nullptr; 2487 2488 auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 2489 BasicBlock &FiniBB) { 2490 if (AllocaIP.isSet()) 2491 Builder.restoreIP(AllocaIP); 2492 else 2493 Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); 2494 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 2495 Builder.CreateStore(F->arg_begin(), PrivAI); 2496 2497 llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); 2498 llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); 2499 EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); 2500 2501 Builder.restoreIP(CodeGenIP); 2502 2503 // collect some info for checks later 2504 ExitBB = FiniBB.getUniqueSuccessor(); 2505 ThenBB = Builder.GetInsertBlock(); 2506 EntryBB = ThenBB->getUniquePredecessor(); 2507 2508 // simple instructions for body 2509 Value *PrivLoad = Builder.CreateLoad(PrivAI->getAllocatedType(), PrivAI, 2510 "local.use"); 2511 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 2512 }; 2513 2514 auto FiniCB = [&](InsertPointTy IP) { 2515 BasicBlock *IPBB = IP.getBlock(); 2516 EXPECT_NE(IPBB->end(), IP.getPoint()); 2517 }; 2518 2519 Builder.restoreIP( 2520 OMPBuilder.createSingle(Builder, BodyGenCB, FiniCB, /*DidIt*/ nullptr)); 2521 Value *EntryBBTI = EntryBB->getTerminator(); 2522 EXPECT_NE(EntryBBTI, nullptr); 2523 EXPECT_TRUE(isa<BranchInst>(EntryBBTI)); 2524 BranchInst *EntryBr = cast<BranchInst>(EntryBB->getTerminator()); 2525 EXPECT_TRUE(EntryBr->isConditional()); 2526 EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); 2527 EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); 2528 EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); 2529 2530 CmpInst *CondInst = cast<CmpInst>(EntryBr->getCondition()); 2531 EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0))); 2532 2533 CallInst *SingleEntryCI = cast<CallInst>(CondInst->getOperand(0)); 2534 EXPECT_EQ(SingleEntryCI->getNumArgOperands(), 2U); 2535 EXPECT_EQ(SingleEntryCI->getCalledFunction()->getName(), "__kmpc_single"); 2536 EXPECT_TRUE(isa<GlobalVariable>(SingleEntryCI->getArgOperand(0))); 2537 2538 CallInst *SingleEndCI = nullptr; 2539 for (auto &FI : *ThenBB) { 2540 Instruction *cur = &FI; 2541 if (isa<CallInst>(cur)) { 2542 SingleEndCI = cast<CallInst>(cur); 2543 if (SingleEndCI->getCalledFunction()->getName() == "__kmpc_end_single") 2544 break; 2545 SingleEndCI = nullptr; 2546 } 2547 } 2548 EXPECT_NE(SingleEndCI, nullptr); 2549 EXPECT_EQ(SingleEndCI->getNumArgOperands(), 2U); 2550 EXPECT_TRUE(isa<GlobalVariable>(SingleEndCI->getArgOperand(0))); 2551 EXPECT_EQ(SingleEndCI->getArgOperand(1), SingleEntryCI->getArgOperand(1)); 2552 } 2553 2554 TEST_F(OpenMPIRBuilderTest, OMPAtomicReadFlt) { 2555 OpenMPIRBuilder OMPBuilder(*M); 2556 OMPBuilder.initialize(); 2557 F->setName("func"); 2558 IRBuilder<> Builder(BB); 2559 2560 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2561 2562 Type *Float32 = Type::getFloatTy(M->getContext()); 2563 AllocaInst *XVal = Builder.CreateAlloca(Float32); 2564 XVal->setName("AtomicVar"); 2565 AllocaInst *VVal = Builder.CreateAlloca(Float32); 2566 VVal->setName("AtomicRead"); 2567 AtomicOrdering AO = AtomicOrdering::Monotonic; 2568 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2569 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2570 2571 Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO)); 2572 2573 IntegerType *IntCastTy = 2574 IntegerType::get(M->getContext(), Float32->getScalarSizeInBits()); 2575 2576 BitCastInst *CastFrmFlt = cast<BitCastInst>(VVal->getNextNode()); 2577 EXPECT_EQ(CastFrmFlt->getSrcTy(), Float32->getPointerTo()); 2578 EXPECT_EQ(CastFrmFlt->getDestTy(), IntCastTy->getPointerTo()); 2579 EXPECT_EQ(CastFrmFlt->getOperand(0), XVal); 2580 2581 LoadInst *AtomicLoad = cast<LoadInst>(CastFrmFlt->getNextNode()); 2582 EXPECT_TRUE(AtomicLoad->isAtomic()); 2583 EXPECT_EQ(AtomicLoad->getPointerOperand(), CastFrmFlt); 2584 2585 BitCastInst *CastToFlt = cast<BitCastInst>(AtomicLoad->getNextNode()); 2586 EXPECT_EQ(CastToFlt->getSrcTy(), IntCastTy); 2587 EXPECT_EQ(CastToFlt->getDestTy(), Float32); 2588 EXPECT_EQ(CastToFlt->getOperand(0), AtomicLoad); 2589 2590 StoreInst *StoreofAtomic = cast<StoreInst>(CastToFlt->getNextNode()); 2591 EXPECT_EQ(StoreofAtomic->getValueOperand(), CastToFlt); 2592 EXPECT_EQ(StoreofAtomic->getPointerOperand(), VVal); 2593 2594 Builder.CreateRetVoid(); 2595 OMPBuilder.finalize(); 2596 EXPECT_FALSE(verifyModule(*M, &errs())); 2597 } 2598 2599 TEST_F(OpenMPIRBuilderTest, OMPAtomicReadInt) { 2600 OpenMPIRBuilder OMPBuilder(*M); 2601 OMPBuilder.initialize(); 2602 F->setName("func"); 2603 IRBuilder<> Builder(BB); 2604 2605 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2606 2607 IntegerType *Int32 = Type::getInt32Ty(M->getContext()); 2608 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2609 XVal->setName("AtomicVar"); 2610 AllocaInst *VVal = Builder.CreateAlloca(Int32); 2611 VVal->setName("AtomicRead"); 2612 AtomicOrdering AO = AtomicOrdering::Monotonic; 2613 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2614 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2615 2616 BasicBlock *EntryBB = BB; 2617 2618 Builder.restoreIP(OMPBuilder.createAtomicRead(Loc, X, V, AO)); 2619 LoadInst *AtomicLoad = nullptr; 2620 StoreInst *StoreofAtomic = nullptr; 2621 2622 for (Instruction &Cur : *EntryBB) { 2623 if (isa<LoadInst>(Cur)) { 2624 AtomicLoad = cast<LoadInst>(&Cur); 2625 if (AtomicLoad->getPointerOperand() == XVal) 2626 continue; 2627 AtomicLoad = nullptr; 2628 } else if (isa<StoreInst>(Cur)) { 2629 StoreofAtomic = cast<StoreInst>(&Cur); 2630 if (StoreofAtomic->getPointerOperand() == VVal) 2631 continue; 2632 StoreofAtomic = nullptr; 2633 } 2634 } 2635 2636 EXPECT_NE(AtomicLoad, nullptr); 2637 EXPECT_TRUE(AtomicLoad->isAtomic()); 2638 2639 EXPECT_NE(StoreofAtomic, nullptr); 2640 EXPECT_EQ(StoreofAtomic->getValueOperand(), AtomicLoad); 2641 2642 Builder.CreateRetVoid(); 2643 OMPBuilder.finalize(); 2644 2645 EXPECT_FALSE(verifyModule(*M, &errs())); 2646 } 2647 2648 TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteFlt) { 2649 OpenMPIRBuilder OMPBuilder(*M); 2650 OMPBuilder.initialize(); 2651 F->setName("func"); 2652 IRBuilder<> Builder(BB); 2653 2654 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2655 2656 LLVMContext &Ctx = M->getContext(); 2657 Type *Float32 = Type::getFloatTy(Ctx); 2658 AllocaInst *XVal = Builder.CreateAlloca(Float32); 2659 XVal->setName("AtomicVar"); 2660 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2661 AtomicOrdering AO = AtomicOrdering::Monotonic; 2662 Constant *ValToWrite = ConstantFP::get(Float32, 1.0); 2663 2664 Builder.restoreIP(OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO)); 2665 2666 IntegerType *IntCastTy = 2667 IntegerType::get(M->getContext(), Float32->getScalarSizeInBits()); 2668 2669 BitCastInst *CastFrmFlt = cast<BitCastInst>(XVal->getNextNode()); 2670 EXPECT_EQ(CastFrmFlt->getSrcTy(), Float32->getPointerTo()); 2671 EXPECT_EQ(CastFrmFlt->getDestTy(), IntCastTy->getPointerTo()); 2672 EXPECT_EQ(CastFrmFlt->getOperand(0), XVal); 2673 2674 Value *ExprCast = Builder.CreateBitCast(ValToWrite, IntCastTy); 2675 2676 StoreInst *StoreofAtomic = cast<StoreInst>(CastFrmFlt->getNextNode()); 2677 EXPECT_EQ(StoreofAtomic->getValueOperand(), ExprCast); 2678 EXPECT_EQ(StoreofAtomic->getPointerOperand(), CastFrmFlt); 2679 EXPECT_TRUE(StoreofAtomic->isAtomic()); 2680 2681 Builder.CreateRetVoid(); 2682 OMPBuilder.finalize(); 2683 EXPECT_FALSE(verifyModule(*M, &errs())); 2684 } 2685 2686 TEST_F(OpenMPIRBuilderTest, OMPAtomicWriteInt) { 2687 OpenMPIRBuilder OMPBuilder(*M); 2688 OMPBuilder.initialize(); 2689 F->setName("func"); 2690 IRBuilder<> Builder(BB); 2691 2692 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2693 2694 LLVMContext &Ctx = M->getContext(); 2695 IntegerType *Int32 = Type::getInt32Ty(Ctx); 2696 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2697 XVal->setName("AtomicVar"); 2698 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2699 AtomicOrdering AO = AtomicOrdering::Monotonic; 2700 ConstantInt *ValToWrite = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2701 2702 BasicBlock *EntryBB = BB; 2703 2704 Builder.restoreIP(OMPBuilder.createAtomicWrite(Loc, X, ValToWrite, AO)); 2705 2706 StoreInst *StoreofAtomic = nullptr; 2707 2708 for (Instruction &Cur : *EntryBB) { 2709 if (isa<StoreInst>(Cur)) { 2710 StoreofAtomic = cast<StoreInst>(&Cur); 2711 if (StoreofAtomic->getPointerOperand() == XVal) 2712 continue; 2713 StoreofAtomic = nullptr; 2714 } 2715 } 2716 2717 EXPECT_NE(StoreofAtomic, nullptr); 2718 EXPECT_TRUE(StoreofAtomic->isAtomic()); 2719 EXPECT_EQ(StoreofAtomic->getValueOperand(), ValToWrite); 2720 2721 Builder.CreateRetVoid(); 2722 OMPBuilder.finalize(); 2723 EXPECT_FALSE(verifyModule(*M, &errs())); 2724 } 2725 2726 TEST_F(OpenMPIRBuilderTest, OMPAtomicUpdate) { 2727 OpenMPIRBuilder OMPBuilder(*M); 2728 OMPBuilder.initialize(); 2729 F->setName("func"); 2730 IRBuilder<> Builder(BB); 2731 2732 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2733 2734 IntegerType *Int32 = Type::getInt32Ty(M->getContext()); 2735 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2736 XVal->setName("AtomicVar"); 2737 Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal); 2738 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2739 AtomicOrdering AO = AtomicOrdering::Monotonic; 2740 ConstantInt *ConstVal = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2741 Value *Expr = nullptr; 2742 AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Sub; 2743 bool IsXLHSInRHSPart = false; 2744 2745 BasicBlock *EntryBB = BB; 2746 Instruction *AllocIP = EntryBB->getFirstNonPHI(); 2747 Value *Sub = nullptr; 2748 2749 auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) { 2750 Sub = IRB.CreateSub(ConstVal, Atomic); 2751 return Sub; 2752 }; 2753 Builder.restoreIP(OMPBuilder.createAtomicUpdate( 2754 Builder, AllocIP, X, Expr, AO, RMWOp, UpdateOp, IsXLHSInRHSPart)); 2755 BasicBlock *ContBB = EntryBB->getSingleSuccessor(); 2756 BranchInst *ContTI = dyn_cast<BranchInst>(ContBB->getTerminator()); 2757 EXPECT_NE(ContTI, nullptr); 2758 BasicBlock *EndBB = ContTI->getSuccessor(0); 2759 EXPECT_TRUE(ContTI->isConditional()); 2760 EXPECT_EQ(ContTI->getSuccessor(1), ContBB); 2761 EXPECT_NE(EndBB, nullptr); 2762 2763 PHINode *Phi = dyn_cast<PHINode>(&ContBB->front()); 2764 EXPECT_NE(Phi, nullptr); 2765 EXPECT_EQ(Phi->getNumIncomingValues(), 2U); 2766 EXPECT_EQ(Phi->getIncomingBlock(0), EntryBB); 2767 EXPECT_EQ(Phi->getIncomingBlock(1), ContBB); 2768 2769 EXPECT_EQ(Sub->getNumUses(), 1U); 2770 StoreInst *St = dyn_cast<StoreInst>(Sub->user_back()); 2771 AllocaInst *UpdateTemp = dyn_cast<AllocaInst>(St->getPointerOperand()); 2772 2773 ExtractValueInst *ExVI1 = 2774 dyn_cast<ExtractValueInst>(Phi->getIncomingValueForBlock(ContBB)); 2775 EXPECT_NE(ExVI1, nullptr); 2776 AtomicCmpXchgInst *CmpExchg = 2777 dyn_cast<AtomicCmpXchgInst>(ExVI1->getAggregateOperand()); 2778 EXPECT_NE(CmpExchg, nullptr); 2779 EXPECT_EQ(CmpExchg->getPointerOperand(), XVal); 2780 EXPECT_EQ(CmpExchg->getCompareOperand(), Phi); 2781 EXPECT_EQ(CmpExchg->getSuccessOrdering(), AtomicOrdering::Monotonic); 2782 2783 LoadInst *Ld = dyn_cast<LoadInst>(CmpExchg->getNewValOperand()); 2784 EXPECT_NE(Ld, nullptr); 2785 EXPECT_EQ(UpdateTemp, Ld->getPointerOperand()); 2786 2787 Builder.CreateRetVoid(); 2788 OMPBuilder.finalize(); 2789 EXPECT_FALSE(verifyModule(*M, &errs())); 2790 } 2791 2792 TEST_F(OpenMPIRBuilderTest, OMPAtomicCapture) { 2793 OpenMPIRBuilder OMPBuilder(*M); 2794 OMPBuilder.initialize(); 2795 F->setName("func"); 2796 IRBuilder<> Builder(BB); 2797 2798 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2799 2800 LLVMContext &Ctx = M->getContext(); 2801 IntegerType *Int32 = Type::getInt32Ty(Ctx); 2802 AllocaInst *XVal = Builder.CreateAlloca(Int32); 2803 XVal->setName("AtomicVar"); 2804 AllocaInst *VVal = Builder.CreateAlloca(Int32); 2805 VVal->setName("AtomicCapTar"); 2806 StoreInst *Init = 2807 Builder.CreateStore(ConstantInt::get(Type::getInt32Ty(Ctx), 0U), XVal); 2808 2809 OpenMPIRBuilder::AtomicOpValue X = {XVal, false, false}; 2810 OpenMPIRBuilder::AtomicOpValue V = {VVal, false, false}; 2811 AtomicOrdering AO = AtomicOrdering::Monotonic; 2812 ConstantInt *Expr = ConstantInt::get(Type::getInt32Ty(Ctx), 1U); 2813 AtomicRMWInst::BinOp RMWOp = AtomicRMWInst::Add; 2814 bool IsXLHSInRHSPart = true; 2815 bool IsPostfixUpdate = true; 2816 bool UpdateExpr = true; 2817 2818 BasicBlock *EntryBB = BB; 2819 Instruction *AllocIP = EntryBB->getFirstNonPHI(); 2820 2821 // integer update - not used 2822 auto UpdateOp = [&](Value *Atomic, IRBuilder<> &IRB) { return nullptr; }; 2823 2824 Builder.restoreIP(OMPBuilder.createAtomicCapture( 2825 Builder, AllocIP, X, V, Expr, AO, RMWOp, UpdateOp, UpdateExpr, 2826 IsPostfixUpdate, IsXLHSInRHSPart)); 2827 EXPECT_EQ(EntryBB->getParent()->size(), 1U); 2828 AtomicRMWInst *ARWM = dyn_cast<AtomicRMWInst>(Init->getNextNode()); 2829 EXPECT_NE(ARWM, nullptr); 2830 EXPECT_EQ(ARWM->getPointerOperand(), XVal); 2831 EXPECT_EQ(ARWM->getOperation(), RMWOp); 2832 StoreInst *St = dyn_cast<StoreInst>(ARWM->user_back()); 2833 EXPECT_NE(St, nullptr); 2834 EXPECT_EQ(St->getPointerOperand(), VVal); 2835 2836 Builder.CreateRetVoid(); 2837 OMPBuilder.finalize(); 2838 EXPECT_FALSE(verifyModule(*M, &errs())); 2839 } 2840 2841 /// Returns the single instruction of InstTy type in BB that uses the value V. 2842 /// If there is more than one such instruction, returns null. 2843 template <typename InstTy> 2844 static InstTy *findSingleUserInBlock(Value *V, BasicBlock *BB) { 2845 InstTy *Result = nullptr; 2846 for (User *U : V->users()) { 2847 auto *Inst = dyn_cast<InstTy>(U); 2848 if (!Inst || Inst->getParent() != BB) 2849 continue; 2850 if (Result) 2851 return nullptr; 2852 Result = Inst; 2853 } 2854 return Result; 2855 } 2856 2857 /// Returns true if BB contains a simple binary reduction that loads a value 2858 /// from Accum, performs some binary operation with it, and stores it back to 2859 /// Accum. 2860 static bool isSimpleBinaryReduction(Value *Accum, BasicBlock *BB, 2861 Instruction::BinaryOps *OpCode = nullptr) { 2862 StoreInst *Store = findSingleUserInBlock<StoreInst>(Accum, BB); 2863 if (!Store) 2864 return false; 2865 auto *Stored = dyn_cast<BinaryOperator>(Store->getOperand(0)); 2866 if (!Stored) 2867 return false; 2868 if (OpCode && *OpCode != Stored->getOpcode()) 2869 return false; 2870 auto *Load = dyn_cast<LoadInst>(Stored->getOperand(0)); 2871 return Load && Load->getOperand(0) == Accum; 2872 } 2873 2874 /// Returns true if BB contains a binary reduction that reduces V using a binary 2875 /// operator into an accumulator that is a function argument. 2876 static bool isValueReducedToFuncArg(Value *V, BasicBlock *BB) { 2877 auto *ReductionOp = findSingleUserInBlock<BinaryOperator>(V, BB); 2878 if (!ReductionOp) 2879 return false; 2880 2881 auto *GlobalLoad = dyn_cast<LoadInst>(ReductionOp->getOperand(0)); 2882 if (!GlobalLoad) 2883 return false; 2884 2885 auto *Store = findSingleUserInBlock<StoreInst>(ReductionOp, BB); 2886 if (!Store) 2887 return false; 2888 2889 return Store->getPointerOperand() == GlobalLoad->getPointerOperand() && 2890 isa<Argument>(GlobalLoad->getPointerOperand()); 2891 } 2892 2893 /// Finds among users of Ptr a pair of GEP instructions with indices [0, 0] and 2894 /// [0, 1], respectively, and assigns results of these instructions to Zero and 2895 /// One. Returns true on success, false on failure or if such instructions are 2896 /// not unique among the users of Ptr. 2897 static bool findGEPZeroOne(Value *Ptr, Value *&Zero, Value *&One) { 2898 Zero = nullptr; 2899 One = nullptr; 2900 for (User *U : Ptr->users()) { 2901 if (auto *GEP = dyn_cast<GetElementPtrInst>(U)) { 2902 if (GEP->getNumIndices() != 2) 2903 continue; 2904 auto *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1)); 2905 auto *SecondIdx = dyn_cast<ConstantInt>(GEP->getOperand(2)); 2906 EXPECT_NE(FirstIdx, nullptr); 2907 EXPECT_NE(SecondIdx, nullptr); 2908 2909 EXPECT_TRUE(FirstIdx->isZero()); 2910 if (SecondIdx->isZero()) { 2911 if (Zero) 2912 return false; 2913 Zero = GEP; 2914 } else if (SecondIdx->isOne()) { 2915 if (One) 2916 return false; 2917 One = GEP; 2918 } else { 2919 return false; 2920 } 2921 } 2922 } 2923 return Zero != nullptr && One != nullptr; 2924 } 2925 2926 static OpenMPIRBuilder::InsertPointTy 2927 sumReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS, 2928 Value *&Result) { 2929 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 2930 Result = Builder.CreateFAdd(LHS, RHS, "red.add"); 2931 return Builder.saveIP(); 2932 } 2933 2934 static OpenMPIRBuilder::InsertPointTy 2935 sumAtomicReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS) { 2936 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 2937 Value *Partial = Builder.CreateLoad(RHS->getType()->getPointerElementType(), 2938 RHS, "red.partial"); 2939 Builder.CreateAtomicRMW(AtomicRMWInst::FAdd, LHS, Partial, None, 2940 AtomicOrdering::Monotonic); 2941 return Builder.saveIP(); 2942 } 2943 2944 static OpenMPIRBuilder::InsertPointTy 2945 xorReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS, 2946 Value *&Result) { 2947 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 2948 Result = Builder.CreateXor(LHS, RHS, "red.xor"); 2949 return Builder.saveIP(); 2950 } 2951 2952 static OpenMPIRBuilder::InsertPointTy 2953 xorAtomicReduction(OpenMPIRBuilder::InsertPointTy IP, Value *LHS, Value *RHS) { 2954 IRBuilder<> Builder(IP.getBlock(), IP.getPoint()); 2955 Value *Partial = Builder.CreateLoad(RHS->getType()->getPointerElementType(), 2956 RHS, "red.partial"); 2957 Builder.CreateAtomicRMW(AtomicRMWInst::Xor, LHS, Partial, None, 2958 AtomicOrdering::Monotonic); 2959 return Builder.saveIP(); 2960 } 2961 2962 /// Populate Calls with call instructions calling the function with the given 2963 /// FnID from the given function F. 2964 static void findCalls(Function *F, omp::RuntimeFunction FnID, 2965 OpenMPIRBuilder &OMPBuilder, 2966 SmallVectorImpl<CallInst *> &Calls) { 2967 Function *Fn = OMPBuilder.getOrCreateRuntimeFunctionPtr(FnID); 2968 for (BasicBlock &BB : *F) { 2969 for (Instruction &I : BB) { 2970 auto *Call = dyn_cast<CallInst>(&I); 2971 if (Call && Call->getCalledFunction() == Fn) 2972 Calls.push_back(Call); 2973 } 2974 } 2975 } 2976 2977 TEST_F(OpenMPIRBuilderTest, CreateReductions) { 2978 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 2979 OpenMPIRBuilder OMPBuilder(*M); 2980 OMPBuilder.initialize(); 2981 F->setName("func"); 2982 IRBuilder<> Builder(BB); 2983 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 2984 2985 // Create variables to be reduced. 2986 InsertPointTy OuterAllocaIP(&F->getEntryBlock(), 2987 F->getEntryBlock().getFirstInsertionPt()); 2988 Value *SumReduced; 2989 Value *XorReduced; 2990 { 2991 IRBuilderBase::InsertPointGuard Guard(Builder); 2992 Builder.restoreIP(OuterAllocaIP); 2993 SumReduced = Builder.CreateAlloca(Builder.getFloatTy()); 2994 XorReduced = Builder.CreateAlloca(Builder.getInt32Ty()); 2995 } 2996 2997 // Store initial values of reductions into global variables. 2998 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), SumReduced); 2999 Builder.CreateStore(Builder.getInt32(1), XorReduced); 3000 3001 // The loop body computes two reductions: 3002 // sum of (float) thread-id; 3003 // xor of thread-id; 3004 // and store the result in global variables. 3005 InsertPointTy BodyIP, BodyAllocaIP; 3006 auto BodyGenCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP, 3007 BasicBlock &ContinuationBB) { 3008 IRBuilderBase::InsertPointGuard Guard(Builder); 3009 Builder.restoreIP(CodeGenIP); 3010 3011 Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc); 3012 Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr); 3013 Value *TID = OMPBuilder.getOrCreateThreadID(Ident); 3014 Value *SumLocal = 3015 Builder.CreateUIToFP(TID, Builder.getFloatTy(), "sum.local"); 3016 Value *SumPartial = 3017 Builder.CreateLoad(SumReduced->getType()->getPointerElementType(), 3018 SumReduced, "sum.partial"); 3019 Value *XorPartial = 3020 Builder.CreateLoad(XorReduced->getType()->getPointerElementType(), 3021 XorReduced, "xor.partial"); 3022 Value *Sum = Builder.CreateFAdd(SumPartial, SumLocal, "sum"); 3023 Value *Xor = Builder.CreateXor(XorPartial, TID, "xor"); 3024 Builder.CreateStore(Sum, SumReduced); 3025 Builder.CreateStore(Xor, XorReduced); 3026 3027 BodyIP = Builder.saveIP(); 3028 BodyAllocaIP = InnerAllocaIP; 3029 }; 3030 3031 // Privatization for reduction creates local copies of reduction variables and 3032 // initializes them to reduction-neutral values. 3033 Value *SumPrivatized; 3034 Value *XorPrivatized; 3035 auto PrivCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP, 3036 Value &Original, Value &Inner, Value *&ReplVal) { 3037 IRBuilderBase::InsertPointGuard Guard(Builder); 3038 Builder.restoreIP(InnerAllocaIP); 3039 if (&Original == SumReduced) { 3040 SumPrivatized = Builder.CreateAlloca(Builder.getFloatTy()); 3041 ReplVal = SumPrivatized; 3042 } else if (&Original == XorReduced) { 3043 XorPrivatized = Builder.CreateAlloca(Builder.getInt32Ty()); 3044 ReplVal = XorPrivatized; 3045 } else { 3046 ReplVal = &Inner; 3047 return CodeGenIP; 3048 } 3049 3050 Builder.restoreIP(CodeGenIP); 3051 if (&Original == SumReduced) 3052 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), 3053 SumPrivatized); 3054 else if (&Original == XorReduced) 3055 Builder.CreateStore(Builder.getInt32(0), XorPrivatized); 3056 3057 return Builder.saveIP(); 3058 }; 3059 3060 // Do nothing in finalization. 3061 auto FiniCB = [&](InsertPointTy CodeGenIP) { return CodeGenIP; }; 3062 3063 InsertPointTy AfterIP = 3064 OMPBuilder.createParallel(Loc, OuterAllocaIP, BodyGenCB, PrivCB, FiniCB, 3065 /* IfCondition */ nullptr, 3066 /* NumThreads */ nullptr, OMP_PROC_BIND_default, 3067 /* IsCancellable */ false); 3068 Builder.restoreIP(AfterIP); 3069 3070 OpenMPIRBuilder::ReductionInfo ReductionInfos[] = { 3071 {SumReduced, SumPrivatized, sumReduction, sumAtomicReduction}, 3072 {XorReduced, XorPrivatized, xorReduction, xorAtomicReduction}}; 3073 3074 OMPBuilder.createReductions(BodyIP, BodyAllocaIP, ReductionInfos); 3075 3076 Builder.restoreIP(AfterIP); 3077 Builder.CreateRetVoid(); 3078 3079 OMPBuilder.finalize(F); 3080 3081 // The IR must be valid. 3082 EXPECT_FALSE(verifyModule(*M)); 3083 3084 // Outlining must have happened. 3085 SmallVector<CallInst *> ForkCalls; 3086 findCalls(F, omp::RuntimeFunction::OMPRTL___kmpc_fork_call, OMPBuilder, 3087 ForkCalls); 3088 ASSERT_EQ(ForkCalls.size(), 1u); 3089 Value *CalleeVal = cast<Constant>(ForkCalls[0]->getOperand(2))->getOperand(0); 3090 Function *Outlined = dyn_cast<Function>(CalleeVal); 3091 EXPECT_NE(Outlined, nullptr); 3092 3093 // Check that the lock variable was created with the expected name. 3094 GlobalVariable *LockVar = 3095 M->getGlobalVariable(".gomp_critical_user_.reduction.var"); 3096 EXPECT_NE(LockVar, nullptr); 3097 3098 // Find the allocation of a local array that will be used to call the runtime 3099 // reduciton function. 3100 BasicBlock &AllocBlock = Outlined->getEntryBlock(); 3101 Value *LocalArray = nullptr; 3102 for (Instruction &I : AllocBlock) { 3103 if (AllocaInst *Alloc = dyn_cast<AllocaInst>(&I)) { 3104 if (!Alloc->getAllocatedType()->isArrayTy() || 3105 !Alloc->getAllocatedType()->getArrayElementType()->isPointerTy()) 3106 continue; 3107 LocalArray = Alloc; 3108 break; 3109 } 3110 } 3111 ASSERT_NE(LocalArray, nullptr); 3112 3113 // Find the call to the runtime reduction function. 3114 BasicBlock *BB = AllocBlock.getUniqueSuccessor(); 3115 Value *LocalArrayPtr = nullptr; 3116 Value *ReductionFnVal = nullptr; 3117 Value *SwitchArg = nullptr; 3118 for (Instruction &I : *BB) { 3119 if (CallInst *Call = dyn_cast<CallInst>(&I)) { 3120 if (Call->getCalledFunction() != 3121 OMPBuilder.getOrCreateRuntimeFunctionPtr( 3122 RuntimeFunction::OMPRTL___kmpc_reduce)) 3123 continue; 3124 LocalArrayPtr = Call->getOperand(4); 3125 ReductionFnVal = Call->getOperand(5); 3126 SwitchArg = Call; 3127 break; 3128 } 3129 } 3130 3131 // Check that the local array is passed to the function. 3132 ASSERT_NE(LocalArrayPtr, nullptr); 3133 BitCastInst *BitCast = dyn_cast<BitCastInst>(LocalArrayPtr); 3134 ASSERT_NE(BitCast, nullptr); 3135 EXPECT_EQ(BitCast->getOperand(0), LocalArray); 3136 3137 // Find the GEP instructions preceding stores to the local array. 3138 Value *FirstArrayElemPtr = nullptr; 3139 Value *SecondArrayElemPtr = nullptr; 3140 EXPECT_EQ(LocalArray->getNumUses(), 3u); 3141 ASSERT_TRUE( 3142 findGEPZeroOne(LocalArray, FirstArrayElemPtr, SecondArrayElemPtr)); 3143 3144 // Check that the values stored into the local array are privatized reduction 3145 // variables. 3146 auto *FirstStored = dyn_cast_or_null<BitCastInst>( 3147 findStoredValue<GetElementPtrInst>(FirstArrayElemPtr)); 3148 auto *SecondStored = dyn_cast_or_null<BitCastInst>( 3149 findStoredValue<GetElementPtrInst>(SecondArrayElemPtr)); 3150 ASSERT_NE(FirstStored, nullptr); 3151 ASSERT_NE(SecondStored, nullptr); 3152 Value *FirstPrivatized = FirstStored->getOperand(0); 3153 Value *SecondPrivatized = SecondStored->getOperand(0); 3154 EXPECT_TRUE( 3155 isSimpleBinaryReduction(FirstPrivatized, FirstStored->getParent())); 3156 EXPECT_TRUE( 3157 isSimpleBinaryReduction(SecondPrivatized, SecondStored->getParent())); 3158 3159 // Check that the result of the runtime reduction call is used for further 3160 // dispatch. 3161 ASSERT_EQ(SwitchArg->getNumUses(), 1u); 3162 SwitchInst *Switch = dyn_cast<SwitchInst>(*SwitchArg->user_begin()); 3163 ASSERT_NE(Switch, nullptr); 3164 EXPECT_EQ(Switch->getNumSuccessors(), 3u); 3165 BasicBlock *NonAtomicBB = Switch->case_begin()->getCaseSuccessor(); 3166 BasicBlock *AtomicBB = std::next(Switch->case_begin())->getCaseSuccessor(); 3167 3168 // Non-atomic block contains reductions to the global reduction variable, 3169 // which is passed into the outlined function as an argument. 3170 Value *FirstLoad = 3171 findSingleUserInBlock<LoadInst>(FirstPrivatized, NonAtomicBB); 3172 Value *SecondLoad = 3173 findSingleUserInBlock<LoadInst>(SecondPrivatized, NonAtomicBB); 3174 EXPECT_TRUE(isValueReducedToFuncArg(FirstLoad, NonAtomicBB)); 3175 EXPECT_TRUE(isValueReducedToFuncArg(SecondLoad, NonAtomicBB)); 3176 3177 // Atomic block also constains reductions to the global reduction variable. 3178 FirstLoad = findSingleUserInBlock<LoadInst>(FirstPrivatized, AtomicBB); 3179 SecondLoad = findSingleUserInBlock<LoadInst>(SecondPrivatized, AtomicBB); 3180 auto *FirstAtomic = findSingleUserInBlock<AtomicRMWInst>(FirstLoad, AtomicBB); 3181 auto *SecondAtomic = 3182 findSingleUserInBlock<AtomicRMWInst>(SecondLoad, AtomicBB); 3183 ASSERT_NE(FirstAtomic, nullptr); 3184 EXPECT_TRUE(isa<Argument>(FirstAtomic->getPointerOperand())); 3185 ASSERT_NE(SecondAtomic, nullptr); 3186 EXPECT_TRUE(isa<Argument>(SecondAtomic->getPointerOperand())); 3187 3188 // Check that the separate reduction function also performs (non-atomic) 3189 // reductions after extracting reduction variables from its arguments. 3190 Function *ReductionFn = cast<Function>(ReductionFnVal); 3191 BasicBlock *FnReductionBB = &ReductionFn->getEntryBlock(); 3192 auto *Bitcast = 3193 findSingleUserInBlock<BitCastInst>(ReductionFn->getArg(0), FnReductionBB); 3194 Value *FirstLHSPtr; 3195 Value *SecondLHSPtr; 3196 ASSERT_TRUE(findGEPZeroOne(Bitcast, FirstLHSPtr, SecondLHSPtr)); 3197 Value *Opaque = findSingleUserInBlock<LoadInst>(FirstLHSPtr, FnReductionBB); 3198 ASSERT_NE(Opaque, nullptr); 3199 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3200 ASSERT_NE(Bitcast, nullptr); 3201 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB)); 3202 Opaque = findSingleUserInBlock<LoadInst>(SecondLHSPtr, FnReductionBB); 3203 ASSERT_NE(Opaque, nullptr); 3204 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3205 ASSERT_NE(Bitcast, nullptr); 3206 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB)); 3207 3208 Bitcast = 3209 findSingleUserInBlock<BitCastInst>(ReductionFn->getArg(1), FnReductionBB); 3210 Value *FirstRHS; 3211 Value *SecondRHS; 3212 EXPECT_TRUE(findGEPZeroOne(Bitcast, FirstRHS, SecondRHS)); 3213 } 3214 3215 TEST_F(OpenMPIRBuilderTest, CreateTwoReductions) { 3216 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 3217 OpenMPIRBuilder OMPBuilder(*M); 3218 OMPBuilder.initialize(); 3219 F->setName("func"); 3220 IRBuilder<> Builder(BB); 3221 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3222 3223 // Create variables to be reduced. 3224 InsertPointTy OuterAllocaIP(&F->getEntryBlock(), 3225 F->getEntryBlock().getFirstInsertionPt()); 3226 Value *SumReduced; 3227 Value *XorReduced; 3228 { 3229 IRBuilderBase::InsertPointGuard Guard(Builder); 3230 Builder.restoreIP(OuterAllocaIP); 3231 SumReduced = Builder.CreateAlloca(Builder.getFloatTy()); 3232 XorReduced = Builder.CreateAlloca(Builder.getInt32Ty()); 3233 } 3234 3235 // Store initial values of reductions into global variables. 3236 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), SumReduced); 3237 Builder.CreateStore(Builder.getInt32(1), XorReduced); 3238 3239 InsertPointTy FirstBodyIP, FirstBodyAllocaIP; 3240 auto FirstBodyGenCB = [&](InsertPointTy InnerAllocaIP, 3241 InsertPointTy CodeGenIP, 3242 BasicBlock &ContinuationBB) { 3243 IRBuilderBase::InsertPointGuard Guard(Builder); 3244 Builder.restoreIP(CodeGenIP); 3245 3246 Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc); 3247 Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr); 3248 Value *TID = OMPBuilder.getOrCreateThreadID(Ident); 3249 Value *SumLocal = 3250 Builder.CreateUIToFP(TID, Builder.getFloatTy(), "sum.local"); 3251 Value *SumPartial = 3252 Builder.CreateLoad(SumReduced->getType()->getPointerElementType(), 3253 SumReduced, "sum.partial"); 3254 Value *Sum = Builder.CreateFAdd(SumPartial, SumLocal, "sum"); 3255 Builder.CreateStore(Sum, SumReduced); 3256 3257 FirstBodyIP = Builder.saveIP(); 3258 FirstBodyAllocaIP = InnerAllocaIP; 3259 }; 3260 3261 InsertPointTy SecondBodyIP, SecondBodyAllocaIP; 3262 auto SecondBodyGenCB = [&](InsertPointTy InnerAllocaIP, 3263 InsertPointTy CodeGenIP, 3264 BasicBlock &ContinuationBB) { 3265 IRBuilderBase::InsertPointGuard Guard(Builder); 3266 Builder.restoreIP(CodeGenIP); 3267 3268 Constant *SrcLocStr = OMPBuilder.getOrCreateSrcLocStr(Loc); 3269 Value *Ident = OMPBuilder.getOrCreateIdent(SrcLocStr); 3270 Value *TID = OMPBuilder.getOrCreateThreadID(Ident); 3271 Value *XorPartial = 3272 Builder.CreateLoad(XorReduced->getType()->getPointerElementType(), 3273 XorReduced, "xor.partial"); 3274 Value *Xor = Builder.CreateXor(XorPartial, TID, "xor"); 3275 Builder.CreateStore(Xor, XorReduced); 3276 3277 SecondBodyIP = Builder.saveIP(); 3278 SecondBodyAllocaIP = InnerAllocaIP; 3279 }; 3280 3281 // Privatization for reduction creates local copies of reduction variables and 3282 // initializes them to reduction-neutral values. The same privatization 3283 // callback is used for both loops, with dispatch based on the value being 3284 // privatized. 3285 Value *SumPrivatized; 3286 Value *XorPrivatized; 3287 auto PrivCB = [&](InsertPointTy InnerAllocaIP, InsertPointTy CodeGenIP, 3288 Value &Original, Value &Inner, Value *&ReplVal) { 3289 IRBuilderBase::InsertPointGuard Guard(Builder); 3290 Builder.restoreIP(InnerAllocaIP); 3291 if (&Original == SumReduced) { 3292 SumPrivatized = Builder.CreateAlloca(Builder.getFloatTy()); 3293 ReplVal = SumPrivatized; 3294 } else if (&Original == XorReduced) { 3295 XorPrivatized = Builder.CreateAlloca(Builder.getInt32Ty()); 3296 ReplVal = XorPrivatized; 3297 } else { 3298 ReplVal = &Inner; 3299 return CodeGenIP; 3300 } 3301 3302 Builder.restoreIP(CodeGenIP); 3303 if (&Original == SumReduced) 3304 Builder.CreateStore(ConstantFP::get(Builder.getFloatTy(), 0.0), 3305 SumPrivatized); 3306 else if (&Original == XorReduced) 3307 Builder.CreateStore(Builder.getInt32(0), XorPrivatized); 3308 3309 return Builder.saveIP(); 3310 }; 3311 3312 // Do nothing in finalization. 3313 auto FiniCB = [&](InsertPointTy CodeGenIP) { return CodeGenIP; }; 3314 3315 Builder.restoreIP( 3316 OMPBuilder.createParallel(Loc, OuterAllocaIP, FirstBodyGenCB, PrivCB, 3317 FiniCB, /* IfCondition */ nullptr, 3318 /* NumThreads */ nullptr, OMP_PROC_BIND_default, 3319 /* IsCancellable */ false)); 3320 InsertPointTy AfterIP = OMPBuilder.createParallel( 3321 {Builder.saveIP(), DL}, OuterAllocaIP, SecondBodyGenCB, PrivCB, FiniCB, 3322 /* IfCondition */ nullptr, 3323 /* NumThreads */ nullptr, OMP_PROC_BIND_default, 3324 /* IsCancellable */ false); 3325 3326 OMPBuilder.createReductions( 3327 FirstBodyIP, FirstBodyAllocaIP, 3328 {{SumReduced, SumPrivatized, sumReduction, sumAtomicReduction}}); 3329 OMPBuilder.createReductions( 3330 SecondBodyIP, SecondBodyAllocaIP, 3331 {{XorReduced, XorPrivatized, xorReduction, xorAtomicReduction}}); 3332 3333 Builder.restoreIP(AfterIP); 3334 Builder.CreateRetVoid(); 3335 3336 OMPBuilder.finalize(F); 3337 3338 // The IR must be valid. 3339 EXPECT_FALSE(verifyModule(*M)); 3340 3341 // Two different outlined functions must have been created. 3342 SmallVector<CallInst *> ForkCalls; 3343 findCalls(F, omp::RuntimeFunction::OMPRTL___kmpc_fork_call, OMPBuilder, 3344 ForkCalls); 3345 ASSERT_EQ(ForkCalls.size(), 2u); 3346 Value *CalleeVal = cast<Constant>(ForkCalls[0]->getOperand(2))->getOperand(0); 3347 Function *FirstCallee = cast<Function>(CalleeVal); 3348 CalleeVal = cast<Constant>(ForkCalls[1]->getOperand(2))->getOperand(0); 3349 Function *SecondCallee = cast<Function>(CalleeVal); 3350 EXPECT_NE(FirstCallee, SecondCallee); 3351 3352 // Two different reduction functions must have been created. 3353 SmallVector<CallInst *> ReduceCalls; 3354 findCalls(FirstCallee, omp::RuntimeFunction::OMPRTL___kmpc_reduce, OMPBuilder, 3355 ReduceCalls); 3356 ASSERT_EQ(ReduceCalls.size(), 1u); 3357 auto *AddReduction = cast<Function>(ReduceCalls[0]->getOperand(5)); 3358 ReduceCalls.clear(); 3359 findCalls(SecondCallee, omp::RuntimeFunction::OMPRTL___kmpc_reduce, 3360 OMPBuilder, ReduceCalls); 3361 auto *XorReduction = cast<Function>(ReduceCalls[0]->getOperand(5)); 3362 EXPECT_NE(AddReduction, XorReduction); 3363 3364 // Each reduction function does its own kind of reduction. 3365 BasicBlock *FnReductionBB = &AddReduction->getEntryBlock(); 3366 auto *Bitcast = findSingleUserInBlock<BitCastInst>(AddReduction->getArg(0), 3367 FnReductionBB); 3368 ASSERT_NE(Bitcast, nullptr); 3369 Value *FirstLHSPtr = 3370 findSingleUserInBlock<GetElementPtrInst>(Bitcast, FnReductionBB); 3371 ASSERT_NE(FirstLHSPtr, nullptr); 3372 Value *Opaque = findSingleUserInBlock<LoadInst>(FirstLHSPtr, FnReductionBB); 3373 ASSERT_NE(Opaque, nullptr); 3374 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3375 ASSERT_NE(Bitcast, nullptr); 3376 Instruction::BinaryOps Opcode = Instruction::FAdd; 3377 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB, &Opcode)); 3378 3379 FnReductionBB = &XorReduction->getEntryBlock(); 3380 Bitcast = findSingleUserInBlock<BitCastInst>(XorReduction->getArg(0), 3381 FnReductionBB); 3382 ASSERT_NE(Bitcast, nullptr); 3383 Value *SecondLHSPtr = 3384 findSingleUserInBlock<GetElementPtrInst>(Bitcast, FnReductionBB); 3385 ASSERT_NE(FirstLHSPtr, nullptr); 3386 Opaque = findSingleUserInBlock<LoadInst>(SecondLHSPtr, FnReductionBB); 3387 ASSERT_NE(Opaque, nullptr); 3388 Bitcast = findSingleUserInBlock<BitCastInst>(Opaque, FnReductionBB); 3389 ASSERT_NE(Bitcast, nullptr); 3390 Opcode = Instruction::Xor; 3391 EXPECT_TRUE(isSimpleBinaryReduction(Bitcast, FnReductionBB, &Opcode)); 3392 } 3393 3394 TEST_F(OpenMPIRBuilderTest, CreateSections) { 3395 using InsertPointTy = OpenMPIRBuilder::InsertPointTy; 3396 using BodyGenCallbackTy = llvm::OpenMPIRBuilder::StorableBodyGenCallbackTy; 3397 OpenMPIRBuilder OMPBuilder(*M); 3398 OMPBuilder.initialize(); 3399 F->setName("func"); 3400 IRBuilder<> Builder(BB); 3401 3402 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3403 llvm::SmallVector<BodyGenCallbackTy, 4> SectionCBVector; 3404 llvm::SmallVector<BasicBlock *, 4> CaseBBs; 3405 3406 BasicBlock *SwitchBB = nullptr; 3407 BasicBlock *ForExitBB = nullptr; 3408 BasicBlock *ForIncBB = nullptr; 3409 AllocaInst *PrivAI = nullptr; 3410 SwitchInst *Switch = nullptr; 3411 3412 unsigned NumBodiesGenerated = 0; 3413 unsigned NumFiniCBCalls = 0; 3414 PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); 3415 3416 auto FiniCB = [&](InsertPointTy IP) { 3417 ++NumFiniCBCalls; 3418 BasicBlock *IPBB = IP.getBlock(); 3419 EXPECT_NE(IPBB->end(), IP.getPoint()); 3420 }; 3421 3422 auto SectionCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 3423 BasicBlock &FiniBB) { 3424 ++NumBodiesGenerated; 3425 CaseBBs.push_back(CodeGenIP.getBlock()); 3426 SwitchBB = CodeGenIP.getBlock()->getSinglePredecessor(); 3427 Builder.restoreIP(CodeGenIP); 3428 Builder.CreateStore(F->arg_begin(), PrivAI); 3429 Value *PrivLoad = 3430 Builder.CreateLoad(F->arg_begin()->getType(), PrivAI, "local.alloca"); 3431 Builder.CreateICmpNE(F->arg_begin(), PrivLoad); 3432 Builder.CreateBr(&FiniBB); 3433 ForIncBB = 3434 CodeGenIP.getBlock()->getSinglePredecessor()->getSingleSuccessor(); 3435 }; 3436 auto PrivCB = [](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, 3437 llvm::Value &, llvm::Value &Val, llvm::Value *&ReplVal) { 3438 // TODO: Privatization not implemented yet 3439 return CodeGenIP; 3440 }; 3441 3442 SectionCBVector.push_back(SectionCB); 3443 SectionCBVector.push_back(SectionCB); 3444 3445 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3446 F->getEntryBlock().getFirstInsertionPt()); 3447 Builder.restoreIP(OMPBuilder.createSections(Loc, AllocaIP, SectionCBVector, 3448 PrivCB, FiniCB, false, false)); 3449 Builder.CreateRetVoid(); // Required at the end of the function 3450 3451 // Switch BB's predecessor is loop condition BB, whose successor at index 1 is 3452 // loop's exit BB 3453 ForExitBB = 3454 SwitchBB->getSinglePredecessor()->getTerminator()->getSuccessor(1); 3455 EXPECT_NE(ForExitBB, nullptr); 3456 3457 EXPECT_NE(PrivAI, nullptr); 3458 Function *OutlinedFn = PrivAI->getFunction(); 3459 EXPECT_EQ(F, OutlinedFn); 3460 EXPECT_FALSE(verifyModule(*M, &errs())); 3461 EXPECT_EQ(OutlinedFn->arg_size(), 1U); 3462 EXPECT_EQ(OutlinedFn->getBasicBlockList().size(), size_t(11)); 3463 3464 BasicBlock *LoopPreheaderBB = 3465 OutlinedFn->getEntryBlock().getSingleSuccessor(); 3466 // loop variables are 5 - lower bound, upper bound, stride, islastiter, and 3467 // iterator/counter 3468 bool FoundForInit = false; 3469 for (Instruction &Inst : *LoopPreheaderBB) { 3470 if (isa<CallInst>(Inst)) { 3471 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 3472 "__kmpc_for_static_init_4u") { 3473 FoundForInit = true; 3474 } 3475 } 3476 } 3477 EXPECT_EQ(FoundForInit, true); 3478 3479 bool FoundForExit = false; 3480 bool FoundBarrier = false; 3481 for (Instruction &Inst : *ForExitBB) { 3482 if (isa<CallInst>(Inst)) { 3483 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 3484 "__kmpc_for_static_fini") { 3485 FoundForExit = true; 3486 } 3487 if (cast<CallInst>(&Inst)->getCalledFunction()->getName() == 3488 "__kmpc_barrier") { 3489 FoundBarrier = true; 3490 } 3491 if (FoundForExit && FoundBarrier) 3492 break; 3493 } 3494 } 3495 EXPECT_EQ(FoundForExit, true); 3496 EXPECT_EQ(FoundBarrier, true); 3497 3498 EXPECT_NE(SwitchBB, nullptr); 3499 EXPECT_NE(SwitchBB->getTerminator(), nullptr); 3500 EXPECT_EQ(isa<SwitchInst>(SwitchBB->getTerminator()), true); 3501 Switch = cast<SwitchInst>(SwitchBB->getTerminator()); 3502 EXPECT_EQ(Switch->getNumCases(), 2U); 3503 EXPECT_NE(ForIncBB, nullptr); 3504 EXPECT_EQ(Switch->getSuccessor(0), ForIncBB); 3505 3506 EXPECT_EQ(CaseBBs.size(), 2U); 3507 for (auto *&CaseBB : CaseBBs) { 3508 EXPECT_EQ(CaseBB->getParent(), OutlinedFn); 3509 EXPECT_EQ(CaseBB->getSingleSuccessor(), ForExitBB); 3510 } 3511 3512 ASSERT_EQ(NumBodiesGenerated, 2U); 3513 ASSERT_EQ(NumFiniCBCalls, 1U); 3514 } 3515 3516 TEST_F(OpenMPIRBuilderTest, CreateOffloadMaptypes) { 3517 OpenMPIRBuilder OMPBuilder(*M); 3518 OMPBuilder.initialize(); 3519 3520 IRBuilder<> Builder(BB); 3521 3522 SmallVector<uint64_t> Mappings = {0, 1}; 3523 GlobalVariable *OffloadMaptypesGlobal = 3524 OMPBuilder.createOffloadMaptypes(Mappings, "offload_maptypes"); 3525 EXPECT_FALSE(M->global_empty()); 3526 EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_maptypes"); 3527 EXPECT_TRUE(OffloadMaptypesGlobal->isConstant()); 3528 EXPECT_TRUE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr()); 3529 EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage()); 3530 EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer()); 3531 Constant *Initializer = OffloadMaptypesGlobal->getInitializer(); 3532 EXPECT_TRUE(isa<ConstantDataArray>(Initializer)); 3533 ConstantDataArray *MappingInit = dyn_cast<ConstantDataArray>(Initializer); 3534 EXPECT_EQ(MappingInit->getNumElements(), Mappings.size()); 3535 EXPECT_TRUE(MappingInit->getType()->getElementType()->isIntegerTy(64)); 3536 Constant *CA = ConstantDataArray::get(Builder.getContext(), Mappings); 3537 EXPECT_EQ(MappingInit, CA); 3538 } 3539 3540 TEST_F(OpenMPIRBuilderTest, CreateOffloadMapnames) { 3541 OpenMPIRBuilder OMPBuilder(*M); 3542 OMPBuilder.initialize(); 3543 3544 IRBuilder<> Builder(BB); 3545 3546 Constant *Cst1 = OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5); 3547 Constant *Cst2 = OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5); 3548 SmallVector<llvm::Constant *> Names = {Cst1, Cst2}; 3549 3550 GlobalVariable *OffloadMaptypesGlobal = 3551 OMPBuilder.createOffloadMapnames(Names, "offload_mapnames"); 3552 EXPECT_FALSE(M->global_empty()); 3553 EXPECT_EQ(OffloadMaptypesGlobal->getName(), "offload_mapnames"); 3554 EXPECT_TRUE(OffloadMaptypesGlobal->isConstant()); 3555 EXPECT_FALSE(OffloadMaptypesGlobal->hasGlobalUnnamedAddr()); 3556 EXPECT_TRUE(OffloadMaptypesGlobal->hasPrivateLinkage()); 3557 EXPECT_TRUE(OffloadMaptypesGlobal->hasInitializer()); 3558 Constant *Initializer = OffloadMaptypesGlobal->getInitializer(); 3559 EXPECT_TRUE(isa<Constant>(Initializer->getOperand(0)->stripPointerCasts())); 3560 EXPECT_TRUE(isa<Constant>(Initializer->getOperand(1)->stripPointerCasts())); 3561 3562 GlobalVariable *Name1Gbl = 3563 cast<GlobalVariable>(Initializer->getOperand(0)->stripPointerCasts()); 3564 EXPECT_TRUE(isa<ConstantDataArray>(Name1Gbl->getInitializer())); 3565 ConstantDataArray *Name1GblCA = 3566 dyn_cast<ConstantDataArray>(Name1Gbl->getInitializer()); 3567 EXPECT_EQ(Name1GblCA->getAsCString(), ";file1;array1;2;5;;"); 3568 3569 GlobalVariable *Name2Gbl = 3570 cast<GlobalVariable>(Initializer->getOperand(1)->stripPointerCasts()); 3571 EXPECT_TRUE(isa<ConstantDataArray>(Name2Gbl->getInitializer())); 3572 ConstantDataArray *Name2GblCA = 3573 dyn_cast<ConstantDataArray>(Name2Gbl->getInitializer()); 3574 EXPECT_EQ(Name2GblCA->getAsCString(), ";file1;array2;3;5;;"); 3575 3576 EXPECT_TRUE(Initializer->getType()->getArrayElementType()->isPointerTy()); 3577 EXPECT_EQ(Initializer->getType()->getArrayNumElements(), Names.size()); 3578 } 3579 3580 TEST_F(OpenMPIRBuilderTest, CreateMapperAllocas) { 3581 OpenMPIRBuilder OMPBuilder(*M); 3582 OMPBuilder.initialize(); 3583 F->setName("func"); 3584 IRBuilder<> Builder(BB); 3585 3586 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3587 3588 unsigned TotalNbOperand = 2; 3589 3590 OpenMPIRBuilder::MapperAllocas MapperAllocas; 3591 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3592 F->getEntryBlock().getFirstInsertionPt()); 3593 OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas); 3594 EXPECT_NE(MapperAllocas.ArgsBase, nullptr); 3595 EXPECT_NE(MapperAllocas.Args, nullptr); 3596 EXPECT_NE(MapperAllocas.ArgSizes, nullptr); 3597 EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType()->isArrayTy()); 3598 ArrayType *ArrType = 3599 dyn_cast<ArrayType>(MapperAllocas.ArgsBase->getAllocatedType()); 3600 EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand); 3601 EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType() 3602 ->getArrayElementType() 3603 ->isPointerTy()); 3604 EXPECT_TRUE(MapperAllocas.ArgsBase->getAllocatedType() 3605 ->getArrayElementType() 3606 ->getPointerElementType() 3607 ->isIntegerTy(8)); 3608 3609 EXPECT_TRUE(MapperAllocas.Args->getAllocatedType()->isArrayTy()); 3610 ArrType = dyn_cast<ArrayType>(MapperAllocas.Args->getAllocatedType()); 3611 EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand); 3612 EXPECT_TRUE(MapperAllocas.Args->getAllocatedType() 3613 ->getArrayElementType() 3614 ->isPointerTy()); 3615 EXPECT_TRUE(MapperAllocas.Args->getAllocatedType() 3616 ->getArrayElementType() 3617 ->getPointerElementType() 3618 ->isIntegerTy(8)); 3619 3620 EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType()->isArrayTy()); 3621 ArrType = dyn_cast<ArrayType>(MapperAllocas.ArgSizes->getAllocatedType()); 3622 EXPECT_EQ(ArrType->getNumElements(), TotalNbOperand); 3623 EXPECT_TRUE(MapperAllocas.ArgSizes->getAllocatedType() 3624 ->getArrayElementType() 3625 ->isIntegerTy(64)); 3626 } 3627 3628 TEST_F(OpenMPIRBuilderTest, EmitMapperCall) { 3629 OpenMPIRBuilder OMPBuilder(*M); 3630 OMPBuilder.initialize(); 3631 F->setName("func"); 3632 IRBuilder<> Builder(BB); 3633 LLVMContext &Ctx = M->getContext(); 3634 3635 OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); 3636 3637 unsigned TotalNbOperand = 2; 3638 3639 OpenMPIRBuilder::MapperAllocas MapperAllocas; 3640 IRBuilder<>::InsertPoint AllocaIP(&F->getEntryBlock(), 3641 F->getEntryBlock().getFirstInsertionPt()); 3642 OMPBuilder.createMapperAllocas(Loc, AllocaIP, TotalNbOperand, MapperAllocas); 3643 3644 auto *BeginMapperFunc = OMPBuilder.getOrCreateRuntimeFunctionPtr( 3645 omp::OMPRTL___tgt_target_data_begin_mapper); 3646 3647 SmallVector<uint64_t> Flags = {0, 2}; 3648 3649 Constant *SrcLocCst = OMPBuilder.getOrCreateSrcLocStr("", "file1", 2, 5); 3650 Value *SrcLocInfo = OMPBuilder.getOrCreateIdent(SrcLocCst); 3651 3652 Constant *Cst1 = OMPBuilder.getOrCreateSrcLocStr("array1", "file1", 2, 5); 3653 Constant *Cst2 = OMPBuilder.getOrCreateSrcLocStr("array2", "file1", 3, 5); 3654 SmallVector<llvm::Constant *> Names = {Cst1, Cst2}; 3655 3656 GlobalVariable *Maptypes = 3657 OMPBuilder.createOffloadMaptypes(Flags, ".offload_maptypes"); 3658 Value *MaptypesArg = Builder.CreateConstInBoundsGEP2_32( 3659 ArrayType::get(Type::getInt64Ty(Ctx), TotalNbOperand), Maptypes, 3660 /*Idx0=*/0, /*Idx1=*/0); 3661 3662 GlobalVariable *Mapnames = 3663 OMPBuilder.createOffloadMapnames(Names, ".offload_mapnames"); 3664 Value *MapnamesArg = Builder.CreateConstInBoundsGEP2_32( 3665 ArrayType::get(Type::getInt8PtrTy(Ctx), TotalNbOperand), Mapnames, 3666 /*Idx0=*/0, /*Idx1=*/0); 3667 3668 OMPBuilder.emitMapperCall(Builder.saveIP(), BeginMapperFunc, SrcLocInfo, 3669 MaptypesArg, MapnamesArg, MapperAllocas, -1, 3670 TotalNbOperand); 3671 3672 CallInst *MapperCall = dyn_cast<CallInst>(&BB->back()); 3673 EXPECT_NE(MapperCall, nullptr); 3674 EXPECT_EQ(MapperCall->getNumArgOperands(), 9U); 3675 EXPECT_EQ(MapperCall->getCalledFunction()->getName(), 3676 "__tgt_target_data_begin_mapper"); 3677 EXPECT_EQ(MapperCall->getOperand(0), SrcLocInfo); 3678 EXPECT_TRUE(MapperCall->getOperand(1)->getType()->isIntegerTy(64)); 3679 EXPECT_TRUE(MapperCall->getOperand(2)->getType()->isIntegerTy(32)); 3680 3681 EXPECT_EQ(MapperCall->getOperand(6), MaptypesArg); 3682 EXPECT_EQ(MapperCall->getOperand(7), MapnamesArg); 3683 EXPECT_TRUE(MapperCall->getOperand(8)->getType()->isPointerTy()); 3684 } 3685 3686 } // namespace 3687