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