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