diff --git a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h --- a/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h +++ b/llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h @@ -315,7 +315,7 @@ BodyGenCallbackTy BodyGenCB, FinalizeCallbackTy FiniCB); - /// Generator for '#omp master' + /// Generator for '#omp critical' /// /// \param Loc The insert and source location description. /// \param BodyGenCB Callback that will generate the region body code. @@ -329,6 +329,58 @@ FinalizeCallbackTy FiniCB, StringRef CriticalName, Value *HintInst); + /// Generate conditional branch and relevant BasicBlocks through which private + /// threads copy the 'copyin' variables from Master copy to threadprivate + /// copies. + /// + /// \param IP insertion block for copyin conditional + /// \param MasterVarPtr a pointer to the master variable + /// \param PrivateVarPtr a pointer to the threadprivate variable + /// \param IntPtrTy Pointer size type + /// \param BranchtoEnd Create a branch between the copyin.not.master blocks + // and copy.in.end block + /// + /// \returns The insertion point where copying operation to be emitted. + InsertPointTy CreateCopyinClauseBlocks(InsertPointTy IP, Value *MasterAddr, + Value *PrivateAddr, + llvm::IntegerType *IntPtrTy, + bool BranchtoEnd = true); + + /// Create a runtime call for kmpc_Alloc + /// + /// \param Loc The insert and source location description. + /// \param Size Size of allocated memory space + /// \param Allocator Allocator information instruction + /// \param Name Name of call Instruction for OMP_alloc + /// + /// \returns CallInst to the OMP_Alloc call + CallInst *CreateOMPAlloc(const LocationDescription &Loc, Value *Size, + Value *Allocator, std::string Name = ""); + + /// Create a runtime call for kmpc_free + /// + /// \param Loc The insert and source location description. + /// \param Addr Address of memory space to be freed + /// \param Allocator Allocator information instruction + /// \param Name Name of call Instruction for OMP_Free + /// + /// \returns CallInst to the OMP_Free call + CallInst *CreateOMPFree(const LocationDescription &Loc, Value *Addr, + Value *Allocator, std::string Name = ""); + + /// Create a runtime call for kmpc_threadprivate_cached + /// + /// \param Loc The insert and source location description. + /// \param Pointer pointer to data to be cached + /// \param Size size of data to be cached + /// \param Name Name of call Instruction for callinst + /// + /// \returns CallInst to the thread private cache call. + CallInst *CreateCachedThreadPrivate(const LocationDescription &Loc, + llvm::Value *Pointer, + llvm::ConstantInt *Size, + const llvm::Twine &Name = Twine("")); + private: /// Common interface for generating entry calls for OMP Directives. /// if the directive has a region/body, It will set the insertion @@ -387,7 +439,7 @@ /// \param Parts different parts of the final name that needs separation /// \param FirstSeparator First separator used between the initial two /// parts of the name. - /// \param Separator separator used between all of the rest consecutinve + /// \param Separator separator used between all of the rest consecutive /// parts of the name static std::string getNameWithSeparators(ArrayRef Parts, StringRef FirstSeparator, diff --git a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp --- a/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp +++ b/llvm/lib/Frontend/OpenMP/OMPIRBuilder.cpp @@ -611,9 +611,6 @@ "Unexpected finalization stack state!"); Instruction *PRegPreFiniTI = PRegPreFiniBB->getTerminator(); - assert(PRegPreFiniTI->getNumSuccessors() == 1 && - PRegPreFiniTI->getSuccessor(0) == PRegExitBB && - "Unexpected CFG structure!"); InsertPointTy PreFiniIP(PRegPreFiniBB, PRegPreFiniTI->getIterator()); FiniCB(PreFiniIP); @@ -948,6 +945,105 @@ ExitCall->getIterator()); } +OpenMPIRBuilder::InsertPointTy OpenMPIRBuilder::CreateCopyinClauseBlocks( + InsertPointTy IP, Value *MasterAddr, Value *PrivateAddr, + llvm::IntegerType *IntPtrTy, bool BranchtoEnd) { + if (!IP.isSet()) + return IP; + + IRBuilder<>::InsertPointGuard IPG(Builder); + + // creates the following CFG structure + // OMP_Entry : (MasterAddr != PrivateAddr)? + // F T + // | \ + // | copin.not.master + // | / + // v / + // copyin.not.master.end + // | + // v + // OMP.Entry.Next + + BasicBlock *OMP_Entry = IP.getBlock(); + Function *CurFn = OMP_Entry->getParent(); + BasicBlock *CopyBegin = + BasicBlock::Create(M.getContext(), "copyin.not.master", CurFn); + BasicBlock *CopyEnd = nullptr; + + // If entry block is terminated, split to preserve the branch to following + // basic block (i.e. OMP.Entry.Next), otherwise, leave everything as is. + if (isa_and_nonnull(OMP_Entry->getTerminator())) { + CopyEnd = OMP_Entry->splitBasicBlock(OMP_Entry->getTerminator(), + "copyin.not.master.end"); + OMP_Entry->getTerminator()->eraseFromParent(); + } else { + CopyEnd = + BasicBlock::Create(M.getContext(), "copyin.not.master.end", CurFn); + } + + Builder.SetInsertPoint(OMP_Entry); + Value *MasterPtr = Builder.CreatePtrToInt(MasterAddr, IntPtrTy); + Value *PrivatePtr = Builder.CreatePtrToInt(PrivateAddr, IntPtrTy); + Value *cmp = Builder.CreateICmpNE(MasterPtr, PrivatePtr); + Builder.CreateCondBr(cmp, CopyBegin, CopyEnd); + + Builder.SetInsertPoint(CopyBegin); + if (BranchtoEnd) + Builder.SetInsertPoint(Builder.CreateBr(CopyEnd)); + + return Builder.saveIP(); +} + +CallInst *OpenMPIRBuilder::CreateOMPAlloc(const LocationDescription &Loc, + Value *Size, Value *Allocator, + std::string Name) { + IRBuilder<>::InsertPointGuard IPG(Builder); + Builder.restoreIP(Loc.IP); + + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc); + Value *Ident = getOrCreateIdent(SrcLocStr); + Value *ThreadId = getOrCreateThreadID(Ident); + Value *Args[] = {ThreadId, Size, Allocator}; + + Function *Fn = getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_alloc); + + return Builder.CreateCall(Fn, Args, Name); +} + +CallInst *OpenMPIRBuilder::CreateOMPFree(const LocationDescription &Loc, + Value *Addr, Value *Allocator, + std::string Name) { + IRBuilder<>::InsertPointGuard IPG(Builder); + Builder.restoreIP(Loc.IP); + + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc); + Value *Ident = getOrCreateIdent(SrcLocStr); + Value *ThreadId = getOrCreateThreadID(Ident); + Value *Args[] = {ThreadId, Addr, Allocator}; + Function *Fn = getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_free); + return Builder.CreateCall(Fn, Args, Name); +} + +CallInst *OpenMPIRBuilder::CreateCachedThreadPrivate( + const LocationDescription &Loc, llvm::Value *Pointer, + llvm::ConstantInt *Size, const llvm::Twine &Name) { + IRBuilder<>::InsertPointGuard IPG(Builder); + Builder.restoreIP(Loc.IP); + + Constant *SrcLocStr = getOrCreateSrcLocStr(Loc); + Value *Ident = getOrCreateIdent(SrcLocStr); + Value *ThreadId = getOrCreateThreadID(Ident); + Constant *ThreadPrivateCache = + getOrCreateOMPInternalVariable(Int8PtrPtr, Name); + llvm::Value *Args[] = {Ident, ThreadId, Pointer, Size, ThreadPrivateCache}; + + Function *Fn = + getOrCreateRuntimeFunctionPtr(OMPRTL___kmpc_threadprivate_cached); + + return Builder.CreateCall(Fn, Args); +} + std::string OpenMPIRBuilder::getNameWithSeparators(ArrayRef Parts, StringRef FirstSeparator, StringRef Separator) { diff --git a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp --- a/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp +++ b/llvm/unittests/Frontend/OpenMPIRBuilderTest.cpp @@ -779,4 +779,41 @@ EXPECT_EQ(CriticalEndCI->getArgOperand(2)->getType(), CriticalNamePtrTy); } +TEST_F(OpenMPIRBuilderTest, CopyinBlocks) { + 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()); + IntegerType* Int32 = Type::getInt32Ty(M->getContext()); + AllocaInst* MasterAddress = Builder.CreateAlloca(Int32->getPointerTo()); + AllocaInst* PrivAddress = Builder.CreateAlloca(Int32->getPointerTo()); + + BasicBlock *EntryBB = BB; + + OMPBuilder.CreateCopyinClauseBlocks(Builder.saveIP(), MasterAddress, PrivAddress, Int32, /*BranchtoEnd*/true); + + BranchInst* EntryBr = dyn_cast_or_null(EntryBB->getTerminator()); + + EXPECT_NE(EntryBr, nullptr); + EXPECT_TRUE(EntryBr->isConditional()); + + BasicBlock* NotMasterBB = EntryBr->getSuccessor(0); + BasicBlock* CopyinEnd = EntryBr->getSuccessor(1); + CmpInst* CMP = dyn_cast_or_null(EntryBr->getCondition()); + + EXPECT_NE(CMP, nullptr); + EXPECT_NE(NotMasterBB, nullptr); + EXPECT_NE(CopyinEnd, nullptr); + + BranchInst* NotMasterBr = dyn_cast_or_null(NotMasterBB->getTerminator()); + EXPECT_NE(NotMasterBr, nullptr); + EXPECT_FALSE(NotMasterBr->isConditional()); + EXPECT_EQ(CopyinEnd,NotMasterBr->getSuccessor(0)); +} + } // namespace