forked from OSchip/llvm-project
				
			
		
			
				
	
	
		
			783 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			783 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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<Module> 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<CallInst>(&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<CallInst>(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<CallInst>(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<CallInst>(&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<CallInst>(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<CallInst>(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<BranchInst>(BB->getTerminator()));
 | |
|   ASSERT_EQ(BB->getTerminator()->getNumSuccessors(), 2U);
 | |
|   BB = BB->getTerminator()->getSuccessor(0);
 | |
|   EXPECT_EQ(BB->size(), 4U);
 | |
| 
 | |
| 
 | |
|   CallInst *GTID = dyn_cast<CallInst>(&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<CallInst>(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<CallInst>(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<CallInst>(&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<CallInst>(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<CallInst>(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<CallInst>(&BB->front());
 | |
|   CallInst *Barrier = dyn_cast<CallInst>(GTID->getNextNode());
 | |
|   EXPECT_EQ(GTID->getDebugLoc(), DL);
 | |
|   EXPECT_EQ(Barrier->getDebugLoc(), DL);
 | |
|   EXPECT_TRUE(isa<GlobalVariable>(Barrier->getOperand(0)));
 | |
|   if (!isa<GlobalVariable>(Barrier->getOperand(0)))
 | |
|     return;
 | |
|   GlobalVariable *Ident = cast<GlobalVariable>(Barrier->getOperand(0));
 | |
|   EXPECT_TRUE(Ident->hasInitializer());
 | |
|   if (!Ident->hasInitializer())
 | |
|     return;
 | |
|   Constant *Initializer = Ident->getInitializer();
 | |
|   EXPECT_TRUE(
 | |
|       isa<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts()));
 | |
|   GlobalVariable *SrcStrGlob =
 | |
|       cast<GlobalVariable>(Initializer->getOperand(4)->stripPointerCasts());
 | |
|   if (!SrcStrGlob)
 | |
|     return;
 | |
|   EXPECT_TRUE(isa<ConstantDataArray>(SrcStrGlob->getInitializer()));
 | |
|   ConstantDataArray *SrcSrc =
 | |
|       dyn_cast<ConstantDataArray>(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<AllocaInst>(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<ConstantExpr>(Usr));
 | |
|   CallInst *ForkCI = dyn_cast<CallInst>(Usr->user_back());
 | |
|   ASSERT_NE(ForkCI, nullptr);
 | |
| 
 | |
|   EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
 | |
|   EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
 | |
|   EXPECT_TRUE(isa<GlobalVariable>(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<AllocaInst>(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<CallInst>(Usr)) {
 | |
|       ASSERT_EQ(DirectCI, nullptr);
 | |
|       DirectCI = cast<CallInst>(Usr);
 | |
|     } else {
 | |
|       ASSERT_TRUE(isa<ConstantExpr>(Usr));
 | |
|       ASSERT_EQ(Usr->getNumUses(), 1U);
 | |
|       ASSERT_TRUE(isa<CallInst>(Usr->user_back()));
 | |
|       ForkCI = cast<CallInst>(Usr->user_back());
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   EXPECT_EQ(ForkCI->getCalledFunction()->getName(), "__kmpc_fork_call");
 | |
|   EXPECT_EQ(ForkCI->getNumArgOperands(), 4U);
 | |
|   EXPECT_TRUE(isa<GlobalVariable>(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<AllocaInst>(DirectCI->getArgOperand(0)));
 | |
|   EXPECT_TRUE(isa<AllocaInst>(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<CallInst>(CBFn->user_back()));
 | |
|     ASSERT_EQ(CBFn->user_back()->getNumUses(), 1U);
 | |
|     CheckedBarrier = cast<CallInst>(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<CallInst>(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<CallInst>(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<CallInst>(Usr);
 | |
|     ASSERT_EQ(CI->getCalledFunction(), FakeDestructor);
 | |
|     ASSERT_TRUE(isa<BranchInst>(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<ReturnInst>(ExitBB->front())) {
 | |
|       ASSERT_TRUE(isa<BranchInst>(ExitBB->front()));
 | |
|       ASSERT_EQ(cast<BranchInst>(ExitBB->front()).getNumSuccessors(), 1U);
 | |
|       ASSERT_TRUE(isa<ReturnInst>(
 | |
|           cast<BranchInst>(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<BranchInst>(EntryBBTI));
 | |
|   BranchInst *EntryBr = cast<BranchInst>(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<CmpInst>(EntryBr->getCondition());
 | |
|   EXPECT_TRUE(isa<CallInst>(CondInst->getOperand(0)));
 | |
| 
 | |
|   CallInst *MasterEntryCI = cast<CallInst>(CondInst->getOperand(0));
 | |
|   EXPECT_EQ(MasterEntryCI->getNumArgOperands(), 2U);
 | |
|   EXPECT_EQ(MasterEntryCI->getCalledFunction()->getName(), "__kmpc_master");
 | |
|   EXPECT_TRUE(isa<GlobalVariable>(MasterEntryCI->getArgOperand(0)));
 | |
| 
 | |
|   CallInst *MasterEndCI = nullptr;
 | |
|   for (auto &FI : *ThenBB) {
 | |
|     Instruction *cur = &FI;
 | |
|     if (isa<CallInst>(cur)) {
 | |
|       MasterEndCI = cast<CallInst>(cur);
 | |
|       if (MasterEndCI->getCalledFunction()->getName() == "__kmpc_end_master")
 | |
|         break;
 | |
|       MasterEndCI = nullptr;
 | |
|     }
 | |
|   }
 | |
|   EXPECT_NE(MasterEndCI, nullptr);
 | |
|   EXPECT_EQ(MasterEndCI->getNumArgOperands(), 2U);
 | |
|   EXPECT_TRUE(isa<GlobalVariable>(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<CallInst>(cur)) {
 | |
|       CriticalEntryCI = cast<CallInst>(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<GlobalVariable>(CriticalEntryCI->getArgOperand(0)));
 | |
| 
 | |
|   CallInst *CriticalEndCI = nullptr;
 | |
|   for (auto &FI : *EntryBB) {
 | |
|     Instruction *cur = &FI;
 | |
|     if (isa<CallInst>(cur)) {
 | |
|       CriticalEndCI = cast<CallInst>(cur);
 | |
|       if (CriticalEndCI->getCalledFunction()->getName() ==
 | |
|           "__kmpc_end_critical")
 | |
|         break;
 | |
|       CriticalEndCI = nullptr;
 | |
|     }
 | |
|   }
 | |
|   EXPECT_NE(CriticalEndCI, nullptr);
 | |
|   EXPECT_EQ(CriticalEndCI->getNumArgOperands(), 3U);
 | |
|   EXPECT_TRUE(isa<GlobalVariable>(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
 |