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