diff options
| author | Alexey Bataev <a.bataev@hotmail.com> | 2015-04-16 05:39:01 +0000 |
|---|---|---|
| committer | Alexey Bataev <a.bataev@hotmail.com> | 2015-04-16 05:39:01 +0000 |
| commit | f56f98c925521f4ed0f3b5adeb27e78477d96407 (patch) | |
| tree | 899c8a4ae57add5b0398fae1484cb7b24760a7b3 /clang/lib | |
| parent | 38e8953352c60f0052efa090ee2b18940e3f6ad3 (diff) | |
| download | bcm5719-llvm-f56f98c925521f4ed0f3b5adeb27e78477d96407.tar.gz bcm5719-llvm-f56f98c925521f4ed0f3b5adeb27e78477d96407.zip | |
[OPENMP] Codegen for 'copyin' clause in 'parallel' directive.
Emits the following code for the clause at the beginning of the outlined function for implicit threads:
if (<not a master thread>) {
...
<thread local copy of var> = <master thread local copy of var>;
...
}
<sync point>;
Checking for a non-master thread is performed by comparing of the address of the thread local variable with the address of the master's variable. Master thread always uses original variables, so you always know the address of the variable in the master thread.
Differential Revision: http://reviews.llvm.org/D9026
llvm-svn: 235075
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/Stmt.cpp | 38 | ||||
| -rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 9 | ||||
| -rw-r--r-- | clang/lib/Basic/OpenMPKinds.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGStmtOpenMP.cpp | 64 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.h | 12 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 66 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTReaderStmt.cpp | 20 | ||||
| -rw-r--r-- | clang/lib/Serialization/ASTWriterStmt.cpp | 6 |
8 files changed, 177 insertions, 41 deletions
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 205a3229ee1..0e8652f82a5 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -1395,17 +1395,41 @@ OMPAlignedClause *OMPAlignedClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPAlignedClause(NumVars); } -OMPCopyinClause *OMPCopyinClause::Create(const ASTContext &C, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation EndLoc, - ArrayRef<Expr *> VL) { +void OMPCopyinClause::setSourceExprs(ArrayRef<Expr *> SrcExprs) { + assert(SrcExprs.size() == varlist_size() && "Number of source expressions is " + "not the same as the " + "preallocated buffer"); + std::copy(SrcExprs.begin(), SrcExprs.end(), varlist_end()); +} + +void OMPCopyinClause::setDestinationExprs(ArrayRef<Expr *> DstExprs) { + assert(DstExprs.size() == varlist_size() && "Number of destination " + "expressions is not the same as " + "the preallocated buffer"); + std::copy(DstExprs.begin(), DstExprs.end(), getSourceExprs().end()); +} + +void OMPCopyinClause::setAssignmentOps(ArrayRef<Expr *> AssignmentOps) { + assert(AssignmentOps.size() == varlist_size() && + "Number of assignment expressions is not the same as the preallocated " + "buffer"); + std::copy(AssignmentOps.begin(), AssignmentOps.end(), + getDestinationExprs().end()); +} + +OMPCopyinClause *OMPCopyinClause::Create( + const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, ArrayRef<Expr *> VL, ArrayRef<Expr *> SrcExprs, + ArrayRef<Expr *> DstExprs, ArrayRef<Expr *> AssignmentOps) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * VL.size()); + 4 * sizeof(Expr *) * VL.size()); OMPCopyinClause *Clause = new (Mem) OMPCopyinClause(StartLoc, LParenLoc, EndLoc, VL.size()); Clause->setVarRefs(VL); + Clause->setSourceExprs(SrcExprs); + Clause->setDestinationExprs(DstExprs); + Clause->setAssignmentOps(AssignmentOps); return Clause; } @@ -1413,7 +1437,7 @@ OMPCopyinClause *OMPCopyinClause::CreateEmpty(const ASTContext &C, unsigned N) { void *Mem = C.Allocate(llvm::RoundUpToAlignment(sizeof(OMPCopyinClause), llvm::alignOf<Expr *>()) + - sizeof(Expr *) * N); + 4 * sizeof(Expr *) * N); return new (Mem) OMPCopyinClause(N); } diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 5012b5a0d6f..f6df1ca446a 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -395,6 +395,15 @@ void OMPClauseProfiler::VisitOMPAlignedClause(const OMPAlignedClause *C) { } void OMPClauseProfiler::VisitOMPCopyinClause(const OMPCopyinClause *C) { VisitOMPClauseList(C); + for (auto *E : C->source_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->destination_exprs()) { + Profiler->VisitStmt(E); + } + for (auto *E : C->assignment_ops()) { + Profiler->VisitStmt(E); + } } void OMPClauseProfiler::VisitOMPCopyprivateClause(const OMPCopyprivateClause *C) { diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 6e98d48c27d..b83a0692c13 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -374,7 +374,6 @@ bool clang::isOpenMPPrivate(OpenMPClauseKind Kind) { } bool clang::isOpenMPThreadPrivate(OpenMPClauseKind Kind) { - return Kind == OMPC_threadprivate || - Kind == OMPC_copyin; // TODO add next clauses like 'copyprivate'. + return Kind == OMPC_threadprivate || Kind == OMPC_copyin; } diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index d98b1cc7d7d..aa537560098 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -263,6 +263,62 @@ void CodeGenFunction::EmitOMPPrivateClause( } } +bool CodeGenFunction::EmitOMPCopyinClause(const OMPExecutableDirective &D) { + // threadprivate_var1 = master_threadprivate_var1; + // operator=(threadprivate_var2, master_threadprivate_var2); + // ... + // __kmpc_barrier(&loc, global_tid); + auto CopyinFilter = [](const OMPClause *C) -> bool { + return C->getClauseKind() == OMPC_copyin; + }; + llvm::DenseSet<const VarDecl *> CopiedVars; + llvm::BasicBlock *CopyBegin = nullptr, *CopyEnd = nullptr; + for (OMPExecutableDirective::filtered_clause_iterator<decltype(CopyinFilter)> + I(D.clauses(), CopyinFilter); + I; ++I) { + auto *C = cast<OMPCopyinClause>(*I); + auto IRef = C->varlist_begin(); + auto ISrcRef = C->source_exprs().begin(); + auto IDestRef = C->destination_exprs().begin(); + for (auto *AssignOp : C->assignment_ops()) { + auto *VD = cast<VarDecl>(cast<DeclRefExpr>(*IRef)->getDecl()); + if (CopiedVars.insert(VD->getCanonicalDecl()).second) { + // Get the address of the master variable. + auto *MasterAddr = VD->isStaticLocal() + ? CGM.getStaticLocalDeclAddress(VD) + : CGM.GetAddrOfGlobal(VD); + // Get the address of the threadprivate variable. + auto *PrivateAddr = EmitLValue(*IRef).getAddress(); + if (CopiedVars.size() == 1) { + // At first check if current thread is a master thread. If it is, no + // need to copy data. + CopyBegin = createBasicBlock("copyin.not.master"); + CopyEnd = createBasicBlock("copyin.not.master.end"); + Builder.CreateCondBr( + Builder.CreateICmpNE( + Builder.CreatePtrToInt(MasterAddr, CGM.IntPtrTy), + Builder.CreatePtrToInt(PrivateAddr, CGM.IntPtrTy)), + CopyBegin, CopyEnd); + EmitBlock(CopyBegin); + } + auto *SrcVD = cast<VarDecl>(cast<DeclRefExpr>(*ISrcRef)->getDecl()); + auto *DestVD = cast<VarDecl>(cast<DeclRefExpr>(*IDestRef)->getDecl()); + EmitOMPCopy(*this, (*IRef)->getType(), PrivateAddr, MasterAddr, DestVD, + SrcVD, AssignOp); + } + ++IRef; + ++ISrcRef; + ++IDestRef; + } + } + if (CopyEnd) { + // Exit out of copying procedure for non-master thread. + EmitBlock(CopyEnd, /*IsFinished=*/true); + return true; + } + return false; +} + bool CodeGenFunction::EmitOMPLastprivateClauseInit( const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope) { auto LastprivateFilter = [](const OMPClause *C) -> bool { @@ -465,9 +521,13 @@ void CodeGenFunction::EmitOMPParallelDirective(const OMPParallelDirective &S) { // Emit parallel region as a standalone region. auto &&CodeGen = [&S](CodeGenFunction &CGF) { OMPPrivateScope PrivateScope(CGF); - if (CGF.EmitOMPFirstprivateClause(S, PrivateScope)) { + bool Copyins = CGF.EmitOMPCopyinClause(S); + bool Firstprivates = CGF.EmitOMPFirstprivateClause(S, PrivateScope); + if (Copyins || Firstprivates) { // Emit implicit barrier to synchronize threads and avoid data races on - // initialization of firstprivate variables. + // initialization of firstprivate variables or propagation master's thread + // values of threadprivate variables to local instances of that variables + // of all other implicit threads. CGF.CGM.getOpenMPRuntime().emitBarrierCall(CGF, S.getLocStart(), OMPD_unknown); } diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index c77075c23af..4e7a7e2f5a6 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -2068,6 +2068,18 @@ public: OMPPrivateScope &PrivateScope); void EmitOMPPrivateClause(const OMPExecutableDirective &D, OMPPrivateScope &PrivateScope); + /// \brief Emit code for copyin clause in \a D directive. The next code is + /// generated at the start of outlined functions for directives: + /// \code + /// threadprivate_var1 = master_threadprivate_var1; + /// operator=(threadprivate_var2, master_threadprivate_var2); + /// ... + /// __kmpc_barrier(&loc, global_tid); + /// \endcode + /// + /// \param D OpenMP directive possibly with 'copyin' clause(s). + /// \returns true if at least one copyin variable is found, false otherwise. + bool EmitOMPCopyinClause(const OMPExecutableDirective &D); /// \brief Emit initial code for lastprivate variables. If some variable is /// not also firstprivate, then the default initialization is used. Otherwise /// initialization of this variable is performed by EmitOMPFirstprivateClause diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index cbe252c7111..6082daffef7 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -815,6 +815,13 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { VarDecl *VD = cast<VarDecl>(DE->getDecl()); SourceLocation ILoc = DE->getExprLoc(); + QualType QType = VD->getType(); + if (QType->isDependentType() || QType->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(DE); + continue; + } + // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have an incomplete type. if (RequireCompleteType(ILoc, VD->getType(), @@ -5910,11 +5917,17 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> SrcExprs; + SmallVector<Expr *, 8> DstExprs; + SmallVector<Expr *, 8> AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP copyin clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + SrcExprs.push_back(nullptr); + DstExprs.push_back(nullptr); + AssignmentOps.push_back(nullptr); continue; } @@ -5936,6 +5949,9 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, if (Type->isDependentType() || Type->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + SrcExprs.push_back(nullptr); + DstExprs.push_back(nullptr); + AssignmentOps.push_back(nullptr); continue; } @@ -5952,40 +5968,38 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. - Type = Context.getBaseElementType(Type); - CXXRecordDecl *RD = - getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; - // FIXME This code must be replaced by actual assignment of the - // threadprivate variable. - if (RD) { - CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); - DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); - if (MD) { - if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || - MD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_copyin) << 2; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, MD); - DiagnoseUseOfDecl(MD, ELoc); - } - } + Type = Context.getBaseElementType(Type).getNonReferenceType(); + auto *SrcVD = BuildVarDecl(*this, DE->getLocStart(), + Type.getUnqualifiedType(), ".copyin.src"); + auto *PseudoSrcExpr = BuildDeclRefExpr(SrcVD, Type.getUnqualifiedType(), + VK_LValue, DE->getExprLoc()) + .get(); + auto *DstVD = BuildVarDecl(*this, DE->getLocStart(), Type, ".copyin.dst"); + auto *PseudoDstExpr = + BuildDeclRefExpr(DstVD, Type, VK_LValue, DE->getExprLoc()).get(); + // For arrays generate assignment operation for single element and replace + // it by the original array element in CodeGen. + auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, + PseudoDstExpr, PseudoSrcExpr); + if (AssignmentOp.isInvalid()) + continue; + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + /*DiscardedValue=*/true); + if (AssignmentOp.isInvalid()) + continue; DSAStack->addDSA(VD, DE, OMPC_copyin); Vars.push_back(DE); + SrcExprs.push_back(PseudoSrcExpr); + DstExprs.push_back(PseudoDstExpr); + AssignmentOps.push_back(AssignmentOp.get()); } if (Vars.empty()) return nullptr; - return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); + return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, + SrcExprs, DstExprs, AssignmentOps); } OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 86887ab84f7..57728c1e18e 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1987,11 +1987,23 @@ void OMPClauseReader::VisitOMPAlignedClause(OMPAlignedClause *C) { void OMPClauseReader::VisitOMPCopyinClause(OMPCopyinClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); - SmallVector<Expr *, 16> Vars; - Vars.reserve(NumVars); + SmallVector<Expr *, 16> Exprs; + Exprs.reserve(NumVars); for (unsigned i = 0; i != NumVars; ++i) - Vars.push_back(Reader->Reader.ReadSubExpr()); - C->setVarRefs(Vars); + Exprs.push_back(Reader->Reader.ReadSubExpr()); + C->setVarRefs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Reader->Reader.ReadSubExpr()); + C->setSourceExprs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Reader->Reader.ReadSubExpr()); + C->setDestinationExprs(Exprs); + Exprs.clear(); + for (unsigned i = 0; i != NumVars; ++i) + Exprs.push_back(Reader->Reader.ReadSubExpr()); + C->setAssignmentOps(Exprs); } void OMPClauseReader::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index 71d3de66b02..f15f76cded6 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1865,6 +1865,12 @@ void OMPClauseWriter::VisitOMPCopyinClause(OMPCopyinClause *C) { Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); for (auto *VE : C->varlists()) Writer->Writer.AddStmt(VE); + for (auto *E : C->source_exprs()) + Writer->Writer.AddStmt(E); + for (auto *E : C->destination_exprs()) + Writer->Writer.AddStmt(E); + for (auto *E : C->assignment_ops()) + Writer->Writer.AddStmt(E); } void OMPClauseWriter::VisitOMPCopyprivateClause(OMPCopyprivateClause *C) { |

