//===- llvm/unittest/IR/OpenMPIRBuilderTest.cpp - OpenMPIRBuilder tests ---===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" #include "llvm/IR/BasicBlock.h" #include "llvm/IR/DIBuilder.h" #include "llvm/IR/Function.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Module.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" #include "llvm/IR/Verifier.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" #include "gtest/gtest.h" using namespace llvm; using namespace omp; using namespace types; namespace { class OpenMPIRBuilderTest : public testing::Test { protected: void SetUp() override { M.reset(new Module("MyModule", Ctx)); FunctionType *FTy = FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, /*isVarArg=*/false); F = Function::Create(FTy, Function::ExternalLinkage, "", M.get()); BB = BasicBlock::Create(Ctx, "", F); DIBuilder DIB(*M); auto File = DIB.createFile("test.dbg", "/"); auto CU = DIB.createCompileUnit(dwarf::DW_LANG_C, File, "llvm-C", true, "", 0); auto Type = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None)); auto SP = DIB.createFunction( CU, "foo", "", File, 1, Type, 1, DINode::FlagZero, DISubprogram::SPFlagDefinition | DISubprogram::SPFlagOptimized); F->setSubprogram(SP); auto Scope = DIB.createLexicalBlockFile(SP, File, 0); DIB.finalize(); DL = DebugLoc::get(3, 7, Scope); } void TearDown() override { BB = nullptr; M.reset(); uninitializeTypes(); } LLVMContext Ctx; std::unique_ptr M; Function *F; BasicBlock *BB; DebugLoc DL; }; TEST_F(OpenMPIRBuilderTest, CreateBarrier) { OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); IRBuilder<> Builder(BB); OMPBuilder.CreateBarrier({IRBuilder<>::InsertPoint()}, OMPD_for); EXPECT_TRUE(M->global_empty()); EXPECT_EQ(M->size(), 1U); EXPECT_EQ(F->size(), 1U); EXPECT_EQ(BB->size(), 0U); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); OMPBuilder.CreateBarrier(Loc, OMPD_for); EXPECT_FALSE(M->global_empty()); EXPECT_EQ(M->size(), 3U); EXPECT_EQ(F->size(), 1U); EXPECT_EQ(BB->size(), 2U); CallInst *GTID = dyn_cast(&BB->front()); EXPECT_NE(GTID, nullptr); EXPECT_EQ(GTID->getNumArgOperands(), 1U); EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); CallInst *Barrier = dyn_cast(GTID->getNextNode()); EXPECT_NE(Barrier, nullptr); EXPECT_EQ(Barrier->getNumArgOperands(), 2U); EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_barrier"); EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); EXPECT_EQ(cast(Barrier)->getArgOperand(1), GTID); Builder.CreateUnreachable(); EXPECT_FALSE(verifyModule(*M, &errs())); } TEST_F(OpenMPIRBuilderTest, CreateCancel) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); new UnreachableInst(Ctx, CBB); auto FiniCB = [&](InsertPointTy IP) { ASSERT_NE(IP.getBlock(), nullptr); ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); BranchInst::Create(CBB, IP.getBlock()); }; OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); auto NewIP = OMPBuilder.CreateCancel(Loc, nullptr, OMPD_parallel); Builder.restoreIP(NewIP); EXPECT_FALSE(M->global_empty()); EXPECT_EQ(M->size(), 3U); EXPECT_EQ(F->size(), 4U); EXPECT_EQ(BB->size(), 4U); CallInst *GTID = dyn_cast(&BB->front()); EXPECT_NE(GTID, nullptr); EXPECT_EQ(GTID->getNumArgOperands(), 1U); EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); CallInst *Cancel = dyn_cast(GTID->getNextNode()); EXPECT_NE(Cancel, nullptr); EXPECT_EQ(Cancel->getNumArgOperands(), 3U); EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel"); EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory()); EXPECT_EQ(Cancel->getNumUses(), 1U); Instruction *CancelBBTI = Cancel->getParent()->getTerminator(); EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U); EXPECT_EQ(CancelBBTI->getSuccessor(0), NewIP.getBlock()); EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U); EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 1U); EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), CBB); EXPECT_EQ(cast(Cancel)->getArgOperand(1), GTID); OMPBuilder.popFinalizationCB(); Builder.CreateUnreachable(); EXPECT_FALSE(verifyModule(*M, &errs())); } TEST_F(OpenMPIRBuilderTest, CreateCancelIfCond) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); new UnreachableInst(Ctx, CBB); auto FiniCB = [&](InsertPointTy IP) { ASSERT_NE(IP.getBlock(), nullptr); ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); BranchInst::Create(CBB, IP.getBlock()); }; OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); auto NewIP = OMPBuilder.CreateCancel(Loc, Builder.getTrue(), OMPD_parallel); Builder.restoreIP(NewIP); EXPECT_FALSE(M->global_empty()); EXPECT_EQ(M->size(), 3U); EXPECT_EQ(F->size(), 7U); EXPECT_EQ(BB->size(), 1U); ASSERT_TRUE(isa(BB->getTerminator())); ASSERT_EQ(BB->getTerminator()->getNumSuccessors(), 2U); BB = BB->getTerminator()->getSuccessor(0); EXPECT_EQ(BB->size(), 4U); CallInst *GTID = dyn_cast(&BB->front()); EXPECT_NE(GTID, nullptr); EXPECT_EQ(GTID->getNumArgOperands(), 1U); EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); CallInst *Cancel = dyn_cast(GTID->getNextNode()); EXPECT_NE(Cancel, nullptr); EXPECT_EQ(Cancel->getNumArgOperands(), 3U); EXPECT_EQ(Cancel->getCalledFunction()->getName(), "__kmpc_cancel"); EXPECT_FALSE(Cancel->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(Cancel->getCalledFunction()->doesNotFreeMemory()); EXPECT_EQ(Cancel->getNumUses(), 1U); Instruction *CancelBBTI = Cancel->getParent()->getTerminator(); EXPECT_EQ(CancelBBTI->getNumSuccessors(), 2U); EXPECT_EQ(CancelBBTI->getSuccessor(0)->size(), 1U); EXPECT_EQ(CancelBBTI->getSuccessor(0)->getUniqueSuccessor(), NewIP.getBlock()); EXPECT_EQ(CancelBBTI->getSuccessor(1)->size(), 1U); EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 1U); EXPECT_EQ(CancelBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), CBB); EXPECT_EQ(cast(Cancel)->getArgOperand(1), GTID); OMPBuilder.popFinalizationCB(); Builder.CreateUnreachable(); EXPECT_FALSE(verifyModule(*M, &errs())); } TEST_F(OpenMPIRBuilderTest, CreateCancelBarrier) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); BasicBlock *CBB = BasicBlock::Create(Ctx, "", F); new UnreachableInst(Ctx, CBB); auto FiniCB = [&](InsertPointTy IP) { ASSERT_NE(IP.getBlock(), nullptr); ASSERT_EQ(IP.getBlock()->end(), IP.getPoint()); BranchInst::Create(CBB, IP.getBlock()); }; OMPBuilder.pushFinalizationCB({FiniCB, OMPD_parallel, true}); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP()}); auto NewIP = OMPBuilder.CreateBarrier(Loc, OMPD_for); Builder.restoreIP(NewIP); EXPECT_FALSE(M->global_empty()); EXPECT_EQ(M->size(), 3U); EXPECT_EQ(F->size(), 4U); EXPECT_EQ(BB->size(), 4U); CallInst *GTID = dyn_cast(&BB->front()); EXPECT_NE(GTID, nullptr); EXPECT_EQ(GTID->getNumArgOperands(), 1U); EXPECT_EQ(GTID->getCalledFunction()->getName(), "__kmpc_global_thread_num"); EXPECT_FALSE(GTID->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(GTID->getCalledFunction()->doesNotFreeMemory()); CallInst *Barrier = dyn_cast(GTID->getNextNode()); EXPECT_NE(Barrier, nullptr); EXPECT_EQ(Barrier->getNumArgOperands(), 2U); EXPECT_EQ(Barrier->getCalledFunction()->getName(), "__kmpc_cancel_barrier"); EXPECT_FALSE(Barrier->getCalledFunction()->doesNotAccessMemory()); EXPECT_FALSE(Barrier->getCalledFunction()->doesNotFreeMemory()); EXPECT_EQ(Barrier->getNumUses(), 1U); Instruction *BarrierBBTI = Barrier->getParent()->getTerminator(); EXPECT_EQ(BarrierBBTI->getNumSuccessors(), 2U); EXPECT_EQ(BarrierBBTI->getSuccessor(0), NewIP.getBlock()); EXPECT_EQ(BarrierBBTI->getSuccessor(1)->size(), 1U); EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getNumSuccessors(), 1U); EXPECT_EQ(BarrierBBTI->getSuccessor(1)->getTerminator()->getSuccessor(0), CBB); EXPECT_EQ(cast(Barrier)->getArgOperand(1), GTID); OMPBuilder.popFinalizationCB(); Builder.CreateUnreachable(); EXPECT_FALSE(verifyModule(*M, &errs())); } TEST_F(OpenMPIRBuilderTest, DbgLoc) { OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); OMPBuilder.CreateBarrier(Loc, OMPD_for); CallInst *GTID = dyn_cast(&BB->front()); CallInst *Barrier = dyn_cast(GTID->getNextNode()); EXPECT_EQ(GTID->getDebugLoc(), DL); EXPECT_EQ(Barrier->getDebugLoc(), DL); EXPECT_TRUE(isa(Barrier->getOperand(0))); if (!isa(Barrier->getOperand(0))) return; GlobalVariable *Ident = cast(Barrier->getOperand(0)); EXPECT_TRUE(Ident->hasInitializer()); if (!Ident->hasInitializer()) return; Constant *Initializer = Ident->getInitializer(); EXPECT_TRUE( isa(Initializer->getOperand(4)->stripPointerCasts())); GlobalVariable *SrcStrGlob = cast(Initializer->getOperand(4)->stripPointerCasts()); if (!SrcStrGlob) return; EXPECT_TRUE(isa(SrcStrGlob->getInitializer())); ConstantDataArray *SrcSrc = dyn_cast(SrcStrGlob->getInitializer()); if (!SrcSrc) return; EXPECT_EQ(SrcSrc->getAsCString(), ";test.dbg;foo;3;7;;"); } TEST_F(OpenMPIRBuilderTest, ParallelSimple) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); AllocaInst *PrivAI = nullptr; unsigned NumBodiesGenerated = 0; unsigned NumPrivatizedVars = 0; unsigned NumFinalizationPoints = 0; auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, BasicBlock &ContinuationIP) { ++NumBodiesGenerated; Builder.restoreIP(AllocaIP); PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); Builder.CreateStore(F->arg_begin(), PrivAI); Builder.restoreIP(CodeGenIP); Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use"); Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad); Instruction *ThenTerm, *ElseTerm; SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), &ThenTerm, &ElseTerm); Builder.SetInsertPoint(ThenTerm); Builder.CreateBr(&ContinuationIP); ThenTerm->eraseFromParent(); }; auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &VPtr, Value *&ReplacementValue) -> InsertPointTy { ++NumPrivatizedVars; if (!isa(VPtr)) { EXPECT_EQ(&VPtr, F->arg_begin()); ReplacementValue = &VPtr; return CodeGenIP; } // Trivial copy (=firstprivate). Builder.restoreIP(AllocaIP); Type *VTy = VPtr.getType()->getPointerElementType(); Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload"); ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy"); Builder.restoreIP(CodeGenIP); Builder.CreateStore(V, ReplacementValue); return CodeGenIP; }; auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; }; IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel(Loc, BodyGenCB, PrivCB, FiniCB, nullptr, nullptr, OMP_PROC_BIND_default, false); EXPECT_EQ(NumBodiesGenerated, 1U); EXPECT_EQ(NumPrivatizedVars, 1U); EXPECT_EQ(NumFinalizationPoints, 1U); Builder.restoreIP(AfterIP); Builder.CreateRetVoid(); OMPBuilder.finalize(); EXPECT_NE(PrivAI, nullptr); Function *OutlinedFn = PrivAI->getFunction(); EXPECT_NE(F, OutlinedFn); EXPECT_FALSE(verifyModule(*M, &errs())); EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoUnwind)); EXPECT_TRUE(OutlinedFn->hasFnAttribute(Attribute::NoRecurse)); EXPECT_TRUE(OutlinedFn->hasParamAttribute(0, Attribute::NoAlias)); EXPECT_TRUE(OutlinedFn->hasParamAttribute(1, Attribute::NoAlias)); EXPECT_TRUE(OutlinedFn->hasInternalLinkage()); EXPECT_EQ(OutlinedFn->arg_size(), 3U); EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent()); EXPECT_EQ(OutlinedFn->getNumUses(), 1U); User *Usr = OutlinedFn->user_back(); ASSERT_TRUE(isa(Usr)); CallInst *ForkCI = dyn_cast(Usr->user_back()); ASSERT_NE(ForkCI, nullptr); EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); EXPECT_EQ(ForkCI->getNumArgOperands(), 4U); EXPECT_TRUE(isa(ForkCI->getArgOperand(0))); EXPECT_EQ(ForkCI->getArgOperand(1), ConstantInt::get(Type::getInt32Ty(Ctx), 1U)); EXPECT_EQ(ForkCI->getArgOperand(2), Usr); EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin()); } TEST_F(OpenMPIRBuilderTest, ParallelIfCond) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); AllocaInst *PrivAI = nullptr; unsigned NumBodiesGenerated = 0; unsigned NumPrivatizedVars = 0; unsigned NumFinalizationPoints = 0; auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, BasicBlock &ContinuationIP) { ++NumBodiesGenerated; Builder.restoreIP(AllocaIP); PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); Builder.CreateStore(F->arg_begin(), PrivAI); Builder.restoreIP(CodeGenIP); Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use"); Value *Cmp = Builder.CreateICmpNE(F->arg_begin(), PrivLoad); Instruction *ThenTerm, *ElseTerm; SplitBlockAndInsertIfThenElse(Cmp, CodeGenIP.getBlock()->getTerminator(), &ThenTerm, &ElseTerm); Builder.SetInsertPoint(ThenTerm); Builder.CreateBr(&ContinuationIP); ThenTerm->eraseFromParent(); }; auto PrivCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, Value &VPtr, Value *&ReplacementValue) -> InsertPointTy { ++NumPrivatizedVars; if (!isa(VPtr)) { EXPECT_EQ(&VPtr, F->arg_begin()); ReplacementValue = &VPtr; return CodeGenIP; } // Trivial copy (=firstprivate). Builder.restoreIP(AllocaIP); Type *VTy = VPtr.getType()->getPointerElementType(); Value *V = Builder.CreateLoad(VTy, &VPtr, VPtr.getName() + ".reload"); ReplacementValue = Builder.CreateAlloca(VTy, 0, VPtr.getName() + ".copy"); Builder.restoreIP(CodeGenIP); Builder.CreateStore(V, ReplacementValue); return CodeGenIP; }; auto FiniCB = [&](InsertPointTy CodeGenIP) { ++NumFinalizationPoints; // No destructors. }; IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel( Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()), nullptr, OMP_PROC_BIND_default, false); EXPECT_EQ(NumBodiesGenerated, 1U); EXPECT_EQ(NumPrivatizedVars, 1U); EXPECT_EQ(NumFinalizationPoints, 1U); Builder.restoreIP(AfterIP); Builder.CreateRetVoid(); OMPBuilder.finalize(); EXPECT_NE(PrivAI, nullptr); Function *OutlinedFn = PrivAI->getFunction(); EXPECT_NE(F, OutlinedFn); EXPECT_FALSE(verifyModule(*M, &errs())); EXPECT_TRUE(OutlinedFn->hasInternalLinkage()); EXPECT_EQ(OutlinedFn->arg_size(), 3U); EXPECT_EQ(&OutlinedFn->getEntryBlock(), PrivAI->getParent()); ASSERT_EQ(OutlinedFn->getNumUses(), 2U); CallInst *DirectCI = nullptr; CallInst *ForkCI = nullptr; for (User *Usr : OutlinedFn->users()) { if (isa(Usr)) { ASSERT_EQ(DirectCI, nullptr); DirectCI = cast(Usr); } else { ASSERT_TRUE(isa(Usr)); ASSERT_EQ(Usr->getNumUses(), 1U); ASSERT_TRUE(isa(Usr->user_back())); ForkCI = cast(Usr->user_back()); } } EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call"); EXPECT_EQ(ForkCI->getNumArgOperands(), 4U); EXPECT_TRUE(isa(ForkCI->getArgOperand(0))); EXPECT_EQ(ForkCI->getArgOperand(1), ConstantInt::get(Type::getInt32Ty(Ctx), 1)); EXPECT_EQ(ForkCI->getArgOperand(3), F->arg_begin()); EXPECT_EQ(DirectCI->getCalledFunction(), OutlinedFn); EXPECT_EQ(DirectCI->getNumArgOperands(), 3U); EXPECT_TRUE(isa(DirectCI->getArgOperand(0))); EXPECT_TRUE(isa(DirectCI->getArgOperand(1))); EXPECT_EQ(DirectCI->getArgOperand(2), F->arg_begin()); } TEST_F(OpenMPIRBuilderTest, ParallelCancelBarrier) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); unsigned NumBodiesGenerated = 0; unsigned NumPrivatizedVars = 0; unsigned NumFinalizationPoints = 0; CallInst *CheckedBarrier = nullptr; auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, BasicBlock &ContinuationIP) { ++NumBodiesGenerated; Builder.restoreIP(CodeGenIP); // Create three barriers, two cancel barriers but only one checked. Function *CBFn, *BFn; Builder.restoreIP( OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel)); CBFn = M->getFunction("__kmpc_cancel_barrier"); BFn = M->getFunction("__kmpc_barrier"); ASSERT_NE(CBFn, nullptr); ASSERT_EQ(BFn, nullptr); ASSERT_EQ(CBFn->getNumUses(), 1U); ASSERT_TRUE(isa(CBFn->user_back())); ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U); CheckedBarrier = cast(CBFn->user_back()); Builder.restoreIP( OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel, true)); CBFn = M->getFunction("__kmpc_cancel_barrier"); BFn = M->getFunction("__kmpc_barrier"); ASSERT_NE(CBFn, nullptr); ASSERT_NE(BFn, nullptr); ASSERT_EQ(CBFn->getNumUses(), 1U); ASSERT_EQ(BFn->getNumUses(), 1U); ASSERT_TRUE(isa(BFn->user_back())); ASSERT_EQ(BFn->user_back()->getNumUses(), 0U); Builder.restoreIP(OMPBuilder.CreateBarrier(Builder.saveIP(), OMPD_parallel, false, false)); ASSERT_EQ(CBFn->getNumUses(), 2U); ASSERT_EQ(BFn->getNumUses(), 1U); ASSERT_TRUE(CBFn->user_back() != CheckedBarrier); ASSERT_TRUE(isa(CBFn->user_back())); ASSERT_EQ(CBFn->user_back()->getNumUses(), 0U); }; auto PrivCB = [&](InsertPointTy, InsertPointTy, Value &V, Value *&) -> InsertPointTy { ++NumPrivatizedVars; llvm_unreachable("No privatization callback call expected!"); }; FunctionType *FakeDestructorTy = FunctionType::get(Type::getVoidTy(Ctx), {Type::getInt32Ty(Ctx)}, /*isVarArg=*/false); auto *FakeDestructor = Function::Create( FakeDestructorTy, Function::ExternalLinkage, "fakeDestructor", M.get()); auto FiniCB = [&](InsertPointTy IP) { ++NumFinalizationPoints; Builder.restoreIP(IP); Builder.CreateCall(FakeDestructor, {Builder.getInt32(NumFinalizationPoints)}); }; IRBuilder<>::InsertPoint AfterIP = OMPBuilder.CreateParallel( Loc, BodyGenCB, PrivCB, FiniCB, Builder.CreateIsNotNull(F->arg_begin()), nullptr, OMP_PROC_BIND_default, true); EXPECT_EQ(NumBodiesGenerated, 1U); EXPECT_EQ(NumPrivatizedVars, 0U); EXPECT_EQ(NumFinalizationPoints, 2U); EXPECT_EQ(FakeDestructor->getNumUses(), 2U); Builder.restoreIP(AfterIP); Builder.CreateRetVoid(); OMPBuilder.finalize(); EXPECT_FALSE(verifyModule(*M, &errs())); BasicBlock *ExitBB = nullptr; for (const User *Usr : FakeDestructor->users()) { const CallInst *CI = dyn_cast(Usr); ASSERT_EQ(CI->getCalledFunction(), FakeDestructor); ASSERT_TRUE(isa(CI->getNextNode())); ASSERT_EQ(CI->getNextNode()->getNumSuccessors(), 1U); if (ExitBB) ASSERT_EQ(CI->getNextNode()->getSuccessor(0), ExitBB); else ExitBB = CI->getNextNode()->getSuccessor(0); ASSERT_EQ(ExitBB->size(), 1U); if (!isa(ExitBB->front())) { ASSERT_TRUE(isa(ExitBB->front())); ASSERT_EQ(cast(ExitBB->front()).getNumSuccessors(), 1U); ASSERT_TRUE(isa( cast(ExitBB->front()).getSuccessor(0)->front())); } } } TEST_F(OpenMPIRBuilderTest, MasterDirective) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); AllocaInst *PrivAI = nullptr; BasicBlock *EntryBB = nullptr; BasicBlock *ExitBB = nullptr; BasicBlock *ThenBB = nullptr; auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, BasicBlock &FiniBB) { if (AllocaIP.isSet()) Builder.restoreIP(AllocaIP); else Builder.SetInsertPoint(&*(F->getEntryBlock().getFirstInsertionPt())); PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); Builder.CreateStore(F->arg_begin(), PrivAI); llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); Builder.restoreIP(CodeGenIP); // collect some info for checks later ExitBB = FiniBB.getUniqueSuccessor(); ThenBB = Builder.GetInsertBlock(); EntryBB = ThenBB->getUniquePredecessor(); // simple instructions for body Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use"); Builder.CreateICmpNE(F->arg_begin(), PrivLoad); }; auto FiniCB = [&](InsertPointTy IP) { BasicBlock *IPBB = IP.getBlock(); EXPECT_NE(IPBB->end(), IP.getPoint()); }; Builder.restoreIP(OMPBuilder.CreateMaster(Builder, BodyGenCB, FiniCB)); Value *EntryBBTI = EntryBB->getTerminator(); EXPECT_NE(EntryBBTI, nullptr); EXPECT_TRUE(isa(EntryBBTI)); BranchInst *EntryBr = cast(EntryBB->getTerminator()); EXPECT_TRUE(EntryBr->isConditional()); EXPECT_EQ(EntryBr->getSuccessor(0), ThenBB); EXPECT_EQ(ThenBB->getUniqueSuccessor(), ExitBB); EXPECT_EQ(EntryBr->getSuccessor(1), ExitBB); CmpInst *CondInst = cast(EntryBr->getCondition()); EXPECT_TRUE(isa(CondInst->getOperand(0))); CallInst *MasterEntryCI = cast(CondInst->getOperand(0)); EXPECT_EQ(MasterEntryCI->getNumArgOperands(), 2U); EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master"); EXPECT_TRUE(isa(MasterEntryCI->getArgOperand(0))); CallInst *MasterEndCI = nullptr; for (auto &FI : *ThenBB) { Instruction *cur = &FI; if (isa(cur)) { MasterEndCI = cast(cur); if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master") break; MasterEndCI = nullptr; } } EXPECT_NE(MasterEndCI, nullptr); EXPECT_EQ(MasterEndCI->getNumArgOperands(), 2U); EXPECT_TRUE(isa(MasterEndCI->getArgOperand(0))); EXPECT_EQ(MasterEndCI->getArgOperand(1), MasterEntryCI->getArgOperand(1)); } TEST_F(OpenMPIRBuilderTest, CriticalDirective) { using InsertPointTy = OpenMPIRBuilder::InsertPointTy; OpenMPIRBuilder OMPBuilder(*M); OMPBuilder.initialize(); F->setName("func"); IRBuilder<> Builder(BB); OpenMPIRBuilder::LocationDescription Loc({Builder.saveIP(), DL}); AllocaInst *PrivAI = Builder.CreateAlloca(F->arg_begin()->getType()); BasicBlock *EntryBB = nullptr; auto BodyGenCB = [&](InsertPointTy AllocaIP, InsertPointTy CodeGenIP, BasicBlock &FiniBB) { // collect some info for checks later EntryBB = FiniBB.getUniquePredecessor(); // actual start for bodyCB llvm::BasicBlock *CodeGenIPBB = CodeGenIP.getBlock(); llvm::Instruction *CodeGenIPInst = &*CodeGenIP.getPoint(); EXPECT_EQ(CodeGenIPBB->getTerminator(), CodeGenIPInst); EXPECT_EQ(EntryBB, CodeGenIPBB); // body begin Builder.restoreIP(CodeGenIP); Builder.CreateStore(F->arg_begin(), PrivAI); Value *PrivLoad = Builder.CreateLoad(PrivAI, "local.use"); Builder.CreateICmpNE(F->arg_begin(), PrivLoad); }; auto FiniCB = [&](InsertPointTy IP) { BasicBlock *IPBB = IP.getBlock(); EXPECT_NE(IPBB->end(), IP.getPoint()); }; Builder.restoreIP(OMPBuilder.CreateCritical(Builder, BodyGenCB, FiniCB, "testCRT", nullptr)); Value *EntryBBTI = EntryBB->getTerminator(); EXPECT_EQ(EntryBBTI, nullptr); CallInst *CriticalEntryCI = nullptr; for (auto &EI : *EntryBB) { Instruction *cur = &EI; if (isa(cur)) { CriticalEntryCI = cast(cur); if (CriticalEntryCI->getCalledFunction()->getName() == "__kmpc_critical") break; CriticalEntryCI = nullptr; } } EXPECT_NE(CriticalEntryCI, nullptr); EXPECT_EQ(CriticalEntryCI->getNumArgOperands(), 3U); EXPECT_EQ(CriticalEntryCI->getCalledFunction()->getName(), "__kmpc_critical"); EXPECT_TRUE(isa(CriticalEntryCI->getArgOperand(0))); CallInst *CriticalEndCI = nullptr; for (auto &FI : *EntryBB) { Instruction *cur = &FI; if (isa(cur)) { CriticalEndCI = cast(cur); if (CriticalEndCI->getCalledFunction()->getName() == "__kmpc_end_critical") break; CriticalEndCI = nullptr; } } EXPECT_NE(CriticalEndCI, nullptr); EXPECT_EQ(CriticalEndCI->getNumArgOperands(), 3U); EXPECT_TRUE(isa(CriticalEndCI->getArgOperand(0))); EXPECT_EQ(CriticalEndCI->getArgOperand(1), CriticalEntryCI->getArgOperand(1)); PointerType *CriticalNamePtrTy = PointerType::getUnqual(ArrayType::get(Type::getInt32Ty(Ctx), 8)); EXPECT_EQ(CriticalEndCI->getArgOperand(2), CriticalEntryCI->getArgOperand(2)); EXPECT_EQ(CriticalEndCI->getArgOperand(2)->getType(), CriticalNamePtrTy); } } // namespace