diff options
author | Alexey Bataev <a.bataev@hotmail.com> | 2013-10-01 05:32:34 +0000 |
---|---|---|
committer | Alexey Bataev <a.bataev@hotmail.com> | 2013-10-01 05:32:34 +0000 |
commit | d5af8e472d6016f3dca2a33fa9d92bcf35aad43b (patch) | |
tree | 833c55056134f116b594e8e3db9a3c64d0e7ec03 | |
parent | de111a425c0a8e38e4a60f1c5ca310546717a876 (diff) | |
download | llvm-d5af8e472d6016f3dca2a33fa9d92bcf35aad43b.zip llvm-d5af8e472d6016f3dca2a33fa9d92bcf35aad43b.tar.gz llvm-d5af8e472d6016f3dca2a33fa9d92bcf35aad43b.tar.bz2 |
[OpenMP] Added parsing and semantic analysis for firstprivate clause
llvm-svn: 191730
-rw-r--r-- | clang/include/clang/AST/RecursiveASTVisitor.h | 7 | ||||
-rw-r--r-- | clang/include/clang/AST/StmtOpenMP.h | 61 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | clang/include/clang/Basic/OpenMPKinds.def | 2 | ||||
-rw-r--r-- | clang/include/clang/Sema/Sema.h | 5 | ||||
-rw-r--r-- | clang/lib/AST/Stmt.cpp | 23 | ||||
-rw-r--r-- | clang/lib/AST/StmtPrinter.cpp | 8 | ||||
-rw-r--r-- | clang/lib/AST/StmtProfile.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Basic/OpenMPKinds.cpp | 2 | ||||
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 5 | ||||
-rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 254 | ||||
-rw-r--r-- | clang/lib/Sema/TreeTransform.h | 32 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTReaderStmt.cpp | 13 | ||||
-rw-r--r-- | clang/lib/Serialization/ASTWriterStmt.cpp | 9 | ||||
-rw-r--r-- | clang/test/OpenMP/parallel_ast_print.cpp | 40 | ||||
-rw-r--r-- | clang/test/OpenMP/parallel_firstprivate_messages.cpp | 82 | ||||
-rw-r--r-- | clang/test/OpenMP/parallel_private_messages.cpp | 8 | ||||
-rw-r--r-- | clang/test/OpenMP/parallel_shared_messages.cpp | 6 | ||||
-rw-r--r-- | clang/tools/libclang/CIndex.cpp | 4 | ||||
-rw-r--r-- | clang/tools/libclang/RecursiveASTVisitor.h | 7 |
20 files changed, 554 insertions, 20 deletions
diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 3400e1f..d09550f 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -2367,6 +2367,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) { } template<typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause( + OMPFirstprivateClause *C) { + VisitOMPClauseList(C); + return true; +} + +template<typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) { VisitOMPClauseList(C); return true; diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index 57097e9..8570d88 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -249,6 +249,67 @@ public: } }; +/// \brief This represents clause 'firstprivate' in the '#pragma omp ...' +/// directives. +/// +/// \code +/// #pragma omp parallel firstprivate(a,b) +/// \endcode +/// In this example directive '#pragma omp parallel' has clause 'firstprivate' +/// with the variables 'a' and 'b'. +/// +class OMPFirstprivateClause : public OMPClause, + public OMPVarList<OMPFirstprivateClause> { + /// \brief Build clause with number of variables \a N. + /// + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param N Number of the variables in the clause. + /// + OMPFirstprivateClause(SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation EndLoc, unsigned N) + : OMPClause(OMPC_firstprivate, StartLoc, EndLoc), + OMPVarList<OMPFirstprivateClause>(LParenLoc, N) { } + + /// \brief Build an empty clause. + /// + /// \param N Number of variables. + /// + explicit OMPFirstprivateClause(unsigned N) + : OMPClause(OMPC_firstprivate, SourceLocation(), SourceLocation()), + OMPVarList<OMPFirstprivateClause>(SourceLocation(), N) { } +public: + /// \brief Creates clause with a list of variables \a VL. + /// + /// \param C AST context. + /// \param StartLoc Starting location of the clause. + /// \param LParenLoc Location of '('. + /// \param EndLoc Ending location of the clause. + /// \param VL List of references to the variables. + /// + static OMPFirstprivateClause *Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef<Expr *> VL); + /// \brief Creates an empty clause with the place for \a N variables. + /// + /// \param C AST context. + /// \param N The number of variables. + /// + static OMPFirstprivateClause *CreateEmpty(const ASTContext &C, unsigned N); + + StmtRange children() { + return StmtRange(reinterpret_cast<Stmt **>(varlist_begin()), + reinterpret_cast<Stmt **>(varlist_end())); + } + + static bool classof(const OMPClause *T) { + return T->getClauseKind() == OMPC_firstprivate; + } +}; + /// \brief This represents clause 'shared' in the '#pragma omp ...' directives. /// /// \code diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 014cce3..87ce732 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6627,6 +6627,8 @@ def err_omp_var_thread_local : Error< "variable %0 cannot be threadprivate because it is thread-local">; def err_omp_private_incomplete_type : Error< "a private variable with incomplete type %0">; +def err_omp_firstprivate_incomplete_type : Error< + "a firstprivate variable with incomplete type %0">; def err_omp_unexpected_clause_value : Error < "expected %0 in OpenMP clause '%1'">; def err_omp_expected_var_name : Error < diff --git a/clang/include/clang/Basic/OpenMPKinds.def b/clang/include/clang/Basic/OpenMPKinds.def index e7e58c2..6d1a7b2 100644 --- a/clang/include/clang/Basic/OpenMPKinds.def +++ b/clang/include/clang/Basic/OpenMPKinds.def @@ -33,11 +33,13 @@ OPENMP_DIRECTIVE(task) // OpenMP clauses. OPENMP_CLAUSE(default, OMPDefaultClause) OPENMP_CLAUSE(private, OMPPrivateClause) +OPENMP_CLAUSE(firstprivate, OMPFirstprivateClause) OPENMP_CLAUSE(shared, OMPSharedClause) // Clauses allowed for OpenMP directives. OPENMP_PARALLEL_CLAUSE(default) OPENMP_PARALLEL_CLAUSE(private) +OPENMP_PARALLEL_CLAUSE(firstprivate) OPENMP_PARALLEL_CLAUSE(shared) // Static attributes for 'default' clause. diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 3782455..d9af5b6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7027,6 +7027,11 @@ public: SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc); + /// \brief Called on well-formed 'firstprivate' clause. + OMPClause *ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc); /// \brief Called on well-formed 'shared' clause. OMPClause *ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 03215927..de85161 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -1145,6 +1145,29 @@ OMPPrivateClause *OMPPrivateClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPPrivateClause(N); } +OMPFirstprivateClause *OMPFirstprivateClause::Create(const ASTContext &C, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc, + ArrayRef<Expr *> VL) { + void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + + sizeof(Expr *) * VL.size(), + llvm::alignOf<OMPFirstprivateClause>()); + OMPFirstprivateClause *Clause = new (Mem) OMPFirstprivateClause(StartLoc, + LParenLoc, + EndLoc, + VL.size()); + Clause->setVarRefs(VL); + return Clause; +} + +OMPFirstprivateClause *OMPFirstprivateClause::CreateEmpty(const ASTContext &C, + unsigned N) { + void *Mem = C.Allocate(sizeof(OMPFirstprivateClause) + sizeof(Expr *) * N, + llvm::alignOf<OMPFirstprivateClause>()); + return new (Mem) OMPFirstprivateClause(N); +} + OMPSharedClause *OMPSharedClause::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 1bbd466..55cfd3f 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -619,6 +619,14 @@ void OMPClausePrinter::VisitOMPPrivateClause(OMPPrivateClause *Node) { } } +void OMPClausePrinter::VisitOMPFirstprivateClause(OMPFirstprivateClause *Node) { + if (!Node->varlist_empty()) { + OS << "firstprivate"; + VisitOMPClauseList(Node, '('); + OS << ")"; + } +} + void OMPClausePrinter::VisitOMPSharedClause(OMPSharedClause *Node) { if (!Node->varlist_empty()) { OS << "shared"; diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 35f37dd..6805e62 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -278,6 +278,10 @@ void OMPClauseProfiler::VisitOMPClauseList(T *Node) { void OMPClauseProfiler::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); } +void OMPClauseProfiler::VisitOMPFirstprivateClause( + const OMPFirstprivateClause *C) { + VisitOMPClauseList(C); +} void OMPClauseProfiler::VisitOMPSharedClause(const OMPSharedClause *C) { VisitOMPClauseList(C); } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 89a4faa..1350934 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -78,6 +78,7 @@ unsigned clang::getOpenMPSimpleClauseType(OpenMPClauseKind Kind, case OMPC_unknown: case OMPC_threadprivate: case OMPC_private: + case OMPC_firstprivate: case OMPC_shared: case NUM_OPENMP_CLAUSES: break; @@ -100,6 +101,7 @@ const char *clang::getOpenMPSimpleClauseTypeName(OpenMPClauseKind Kind, case OMPC_unknown: case OMPC_threadprivate: case OMPC_private: + case OMPC_firstprivate: case OMPC_shared: case NUM_OPENMP_CLAUSES: break; diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index de76b17..992a443 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -252,7 +252,7 @@ bool Parser::ParseOpenMPSimpleVarList(OpenMPDirectiveKind Kind, /// \brief Parsing of OpenMP clauses. /// /// clause: -/// default-clause|private-clause|shared-clause +/// default-clause|private-clause|firstprivate-clause|shared-clause /// OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, bool FirstClause) { @@ -278,6 +278,7 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind, Clause = ParseOpenMPSimpleClause(CKind); break; case OMPC_private: + case OMPC_firstprivate: case OMPC_shared: Clause = ParseOpenMPVarListClause(CKind); break; @@ -330,6 +331,8 @@ OMPClause *Parser::ParseOpenMPSimpleClause(OpenMPClauseKind Kind) { /// /// private-clause: /// 'private' '(' list ')' +/// firstprivate-clause: +/// 'firstprivate' '(' list ')' /// shared-clause: /// 'shared' '(' list ')' /// diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index dadfa41..d5778bc 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -106,6 +106,11 @@ public: DSAVarData getTopDSA(VarDecl *D); /// \brief Returns data-sharing attributes for the specified declaration. DSAVarData getImplicitDSA(VarDecl *D); + /// \brief Checks if the specified variables has \a CKind data-sharing + /// attribute in \a DKind directive. + DSAVarData hasDSA(VarDecl *D, OpenMPClauseKind CKind, + OpenMPDirectiveKind DKind = OMPD_unknown); + /// \brief Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { @@ -138,6 +143,13 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, if (!D->isFunctionOrMethodVarDecl()) DVar.CKind = OMPC_shared; + // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced + // in a region but not in construct] + // Variables with static storage duration that are declared in called + // routines in the region are shared. + if (D->hasGlobalStorage()) + DVar.CKind = OMPC_shared; + return DVar; } DVar.DKind = Iter->Directive; @@ -189,16 +201,14 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, if (DVarTemp.CKind != OMPC_shared) { DVar.RefExpr = 0; DVar.DKind = OMPD_task; - DVar.CKind = OMPC_unknown; - // TODO: should return OMPC_firstprivate + DVar.CKind = OMPC_firstprivate; return DVar; } if (I->Directive == OMPD_parallel) break; } DVar.DKind = OMPD_task; - // TODO: Should return OMPC_firstprivate instead of OMPC_unknown. DVar.CKind = - (DVarTemp.CKind == OMPC_unknown) ? OMPC_unknown : OMPC_shared; + (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; return DVar; } } @@ -272,9 +282,12 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) { // in a Construct, C/C++, predetermined, p.4] // Static data memebers are shared. if (D->isStaticDataMember()) { - // Variables with const-qualified type having no mutable member may be - // listed in a firstprivate clause, even if they are static data members. - // TODO: + // Variables with const-qualified type having no mutable member may be listed + // in a firstprivate clause, even if they are static data members. + DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate); + if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) + return DVar; + DVar.CKind = OMPC_shared; return DVar; } @@ -295,7 +308,10 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D) { !(Actions.getLangOpts().CPlusPlus && RD && RD->hasMutableFields())) { // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. - // TODO + DSAVarData DVarTemp = hasDSA(D, OMPC_firstprivate); + if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) + return DVar; + DVar.CKind = OMPC_shared; return DVar; } @@ -323,6 +339,19 @@ DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D) { return getDSA(Stack.rbegin() + 1, D); } +DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, OpenMPClauseKind CKind, + OpenMPDirectiveKind DKind) { + for (StackTy::reverse_iterator I = Stack.rbegin() + 1, + E = Stack.rend() - 1; + I != E; ++I) { + if (DKind != OMPD_unknown && DKind != I->Directive) continue; + DSAVarData DVar = getDSA(I, D); + if (DVar.CKind == CKind) + return DVar; + } + return DSAVarData(); +} + void Sema::InitDataSharingAttributesStack() { VarDataSharingAttributesStack = new DSAStackTy(*this); } @@ -551,10 +580,10 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> { Sema &Actions; bool ErrorFound; CapturedStmt *CS; + llvm::SmallVector<Expr *, 8> ImplicitFirstprivate; public: void VisitDeclRefExpr(DeclRefExpr *E) { if(VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) { - if (VD->isImplicit() && VD->hasAttr<UnusedAttr>()) return; // Skip internally declared variables. if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) return; @@ -564,9 +593,8 @@ public: DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD); if (DVar.CKind != OMPC_unknown) { if (DKind == OMPD_task && DVar.CKind != OMPC_shared && - DVar.CKind != OMPC_threadprivate && !DVar.RefExpr) { - // TODO: should be marked as firstprivate. - } + DVar.CKind != OMPC_threadprivate && !DVar.RefExpr) + ImplicitFirstprivate.push_back(DVar.RefExpr); return; } // The default(none) clause requires that each variable that is referenced @@ -588,9 +616,8 @@ public: // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD); - if (DKind == OMPD_task && DVar.CKind != OMPC_shared) { - // TODO: should be marked as firstprivate. - } + if (DKind == OMPD_task && DVar.CKind != OMPC_shared) + ImplicitFirstprivate.push_back(DVar.RefExpr); } } void VisitOMPExecutableDirective(OMPExecutableDirective *S) { @@ -611,6 +638,7 @@ public: } bool isErrorFound() { return ErrorFound; } + ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; } DSAAttrChecker(DSAStackTy *S, Sema &Actions, CapturedStmt *CS) : Stack(S), Actions(Actions), ErrorFound(false), CS(CS) { } @@ -631,10 +659,27 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, DSAChecker.Visit(cast<CapturedStmt>(AStmt)->getCapturedStmt()); if (DSAChecker.isErrorFound()) return StmtError(); + // Generate list of implicitly defined firstprivate variables. + llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; + ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); + + bool ErrorFound = false; + if (!DSAChecker.getImplicitFirstprivate().empty()) { + if (OMPClause *Implicit = + ActOnOpenMPFirstprivateClause(DSAChecker.getImplicitFirstprivate(), + SourceLocation(), SourceLocation(), + SourceLocation())) { + ClausesWithImplicit.push_back(Implicit); + ErrorFound = cast<OMPFirstprivateClause>(Implicit)->varlist_size() != + DSAChecker.getImplicitFirstprivate().size(); + } else + ErrorFound = true; + } switch (Kind) { case OMPD_parallel: - Res = ActOnOpenMPParallelDirective(Clauses, AStmt, StartLoc, EndLoc); + Res = ActOnOpenMPParallelDirective(ClausesWithImplicit, AStmt, + StartLoc, EndLoc); break; case OMPD_threadprivate: case OMPD_task: @@ -643,6 +688,8 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(OpenMPDirectiveKind Kind, case NUM_OPENMP_DIRECTIVES: llvm_unreachable("Unknown OpenMP directive"); } + + if (ErrorFound) return StmtError(); return Res; } @@ -670,6 +717,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(OpenMPClauseKind Kind, ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_private: + case OMPC_firstprivate: case OMPC_shared: case OMPC_threadprivate: case OMPC_unknown: @@ -731,6 +779,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(OpenMPClauseKind Kind, case OMPC_private: Res = ActOnOpenMPPrivateClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_firstprivate: + Res = ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, EndLoc); + break; case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; @@ -876,6 +927,177 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, return OMPPrivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } +OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (ArrayRef<Expr *>::iterator I = VarList.begin(), E = VarList.end(); + I != E; ++I) { + assert(*I && "NULL expr in OpenMP firstprivate clause."); + if (isa<DependentScopeDeclRefExpr>(*I)) { + // It will be analyzed later. + Vars.push_back(*I); + continue; + } + + SourceLocation ELoc = (*I)->getExprLoc(); + // OpenMP [2.1, C/C++] + // A list item is a variable name. + // OpenMP [2.9.3.3, Restrictions, p.1] + // A variable that is part of another variable (as an array or + // structure element) cannot appear in a private clause. + DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(*I); + if (!DE || !isa<VarDecl>(DE->getDecl())) { + Diag(ELoc, diag::err_omp_expected_var_name) + << (*I)->getSourceRange(); + continue; + } + Decl *D = DE->getDecl(); + VarDecl *VD = cast<VarDecl>(D); + + QualType Type = VD->getType(); + if (Type->isDependentType() || Type->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(DE); + continue; + } + + // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] + // A variable that appears in a private clause must not have an incomplete + // type or a reference type. + if (RequireCompleteType(ELoc, Type, + diag::err_omp_firstprivate_incomplete_type)) { + continue; + } + if (Type->isReferenceType()) { + Diag(ELoc, diag::err_omp_clause_ref_type_arg) + << getOpenMPClauseName(OMPC_firstprivate) << Type; + bool IsDecl = VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl : + diag::note_defined_here) << VD; + continue; + } + + // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] + // A variable of class type (or array thereof) that appears in a private + // clause requires an accesible, unambiguous copy constructor for the + // class type. + Type = Context.getBaseElementType(Type); + CXXRecordDecl *RD = getLangOpts().CPlusPlus ? + Type.getNonReferenceType()->getAsCXXRecordDecl() : 0; + if (RD) { + CXXConstructorDecl *CD = LookupCopyingConstructor(RD, 0); + PartialDiagnostic PD = + PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); + if (!CD || + CheckConstructorAccess(ELoc, CD, + InitializedEntity::InitializeTemporary(Type), + CD->getAccess(), PD) == AR_inaccessible || + CD->isDeleted()) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_firstprivate) << 1; + 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, CD); + DiagnoseUseOfDecl(CD, ELoc); + + CXXDestructorDecl *DD = RD->getDestructor(); + if (DD) { + if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || + DD->isDeleted()) { + Diag(ELoc, diag::err_omp_required_method) + << getOpenMPClauseName(OMPC_firstprivate) << 4; + 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, DD); + DiagnoseUseOfDecl(DD, ELoc); + } + } + + // If StartLoc and EndLoc are invalid - this is an implicit firstprivate + // variable and it was checked already. + if (StartLoc.isValid() && EndLoc.isValid()) { + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD); + Type = Type.getNonReferenceType().getCanonicalType(); + bool IsConstant = Type.isConstant(Context); + Type = Context.getBaseElementType(Type); + // OpenMP [2.4.13, Data-sharing Attribute Clauses] + // A list item that specifies a given variable may not appear in more + // than one clause on the same directive, except that a variable may be + // specified in both firstprivate and lastprivate clauses. + // TODO: add processing for lastprivate. + if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && + DVar.RefExpr) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPClauseName(OMPC_firstprivate); + Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(DVar.CKind); + continue; + } + + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct] + // Variables with the predetermined data-sharing attributes may not be + // listed in data-sharing attributes clauses, except for the cases + // listed below. For these exceptions only, listing a predetermined + // variable in a data-sharing attribute clause is allowed and overrides + // the variable's predetermined data-sharing attributes. + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++, p.2] + // Variables with const-qualified type having no mutable member may be + // listed in a firstprivate clause, even if they are static data members. + if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr && + DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) { + Diag(ELoc, diag::err_omp_wrong_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPClauseName(OMPC_firstprivate); + Diag(VD->getLocation(), diag::note_omp_predetermined_dsa) + << getOpenMPClauseName(DVar.CKind); + continue; + } + + // OpenMP [2.9.3.4, Restrictions, p.2] + // A list item that is private within a parallel region must not appear + // in a firstprivate clause on a worksharing construct if any of the + // worksharing regions arising from the worksharing construct ever bind + // to any of the parallel regions arising from the parallel construct. + // OpenMP [2.9.3.4, Restrictions, p.3] + // A list item that appears in a reduction clause of a parallel construct + // must not appear in a firstprivate clause on a worksharing or task + // construct if any of the worksharing or task regions arising from the + // worksharing or task construct ever bind to any of the parallel regions + // arising from the parallel construct. + // OpenMP [2.9.3.4, Restrictions, p.4] + // A list item that appears in a reduction clause in worksharing + // construct must not appear in a firstprivate clause in a task construct + // encountered during execution of any of the worksharing regions arising + // from the worksharing construct. + // TODO: + } + + DSAStack->addDSA(VD, DE, OMPC_firstprivate); + Vars.push_back(DE); + } + + if (Vars.empty()) return 0; + + return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, + Vars); +} + OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 5b019a9..977d013 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -1313,6 +1313,18 @@ public: EndLoc); } + /// \brief Build a new OpenMP 'firstprivate' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPFirstprivateClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPFirstprivateClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + OMPClause *RebuildOMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -6343,6 +6355,26 @@ TreeTransform<Derived>::TransformOMPPrivateClause(OMPPrivateClause *C) { template<typename Derived> OMPClause * +TreeTransform<Derived>::TransformOMPFirstprivateClause( + OMPFirstprivateClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(*I)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.take()); + } + return getDerived().RebuildOMPFirstprivateClause(Vars, + C->getLocStart(), + C->getLParenLoc(), + C->getLocEnd()); +} + +template<typename Derived> +OMPClause * TreeTransform<Derived>::TransformOMPSharedClause(OMPSharedClause *C) { llvm::SmallVector<Expr *, 16> Vars; Vars.reserve(C->varlist_size()); diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp index 23cd9cc..1115e8f 100644 --- a/clang/lib/Serialization/ASTReaderStmt.cpp +++ b/clang/lib/Serialization/ASTReaderStmt.cpp @@ -1697,6 +1697,9 @@ OMPClause *OMPClauseReader::readClause() { case OMPC_private: C = OMPPrivateClause::CreateEmpty(Context, Record[Idx++]); break; + case OMPC_firstprivate: + C = OMPFirstprivateClause::CreateEmpty(Context, Record[Idx++]); + break; case OMPC_shared: C = OMPSharedClause::CreateEmpty(Context, Record[Idx++]); break; @@ -1725,6 +1728,16 @@ void OMPClauseReader::VisitOMPPrivateClause(OMPPrivateClause *C) { C->setVarRefs(Vars); } +void OMPClauseReader::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { + C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); + unsigned NumVars = C->varlist_size(); + SmallVector<Expr *, 16> Vars; + Vars.reserve(NumVars); + for (unsigned i = 0; i != NumVars; ++i) + Vars.push_back(Reader->Reader.ReadSubExpr()); + C->setVarRefs(Vars); +} + void OMPClauseReader::VisitOMPSharedClause(OMPSharedClause *C) { C->setLParenLoc(Reader->ReadSourceLocation(Record, Idx)); unsigned NumVars = C->varlist_size(); diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp index e38d8c6..072fc98 100644 --- a/clang/lib/Serialization/ASTWriterStmt.cpp +++ b/clang/lib/Serialization/ASTWriterStmt.cpp @@ -1712,6 +1712,15 @@ void OMPClauseWriter::VisitOMPPrivateClause(OMPPrivateClause *C) { Writer->Writer.AddStmt(*I); } +void OMPClauseWriter::VisitOMPFirstprivateClause(OMPFirstprivateClause *C) { + Record.push_back(C->varlist_size()); + Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); + for (OMPFirstprivateClause::varlist_iterator I = C->varlist_begin(), + E = C->varlist_end(); + I != E; ++I) + Writer->Writer.AddStmt(*I); +} + void OMPClauseWriter::VisitOMPSharedClause(OMPSharedClause *C) { Record.push_back(C->varlist_size()); Writer->Writer.AddSourceLocation(C->getLParenLoc(), Record); diff --git a/clang/test/OpenMP/parallel_ast_print.cpp b/clang/test/OpenMP/parallel_ast_print.cpp index 44108e7..f2fd2f7 100644 --- a/clang/test/OpenMP/parallel_ast_print.cpp +++ b/clang/test/OpenMP/parallel_ast_print.cpp @@ -8,7 +8,41 @@ void foo() {} + +template <typename T> +T tmain(T argc, T *argv) { + T b = argc, c, d, e, f, g; + static T a; +#pragma omp parallel + a=2; +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) shared (d) + foo(); + return 0; +} +// CHECK: template <typename T = int> int tmain(int argc, int *argv) { +// CHECK-NEXT: int b = argc, c, d, e, f, g; +// CHECK-NEXT: static int a; +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: a = 2; +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) +// CHECK-NEXT: foo() +// CHECK: template <typename T = float> float tmain(float argc, float *argv) { +// CHECK-NEXT: float b = argc, c, d, e, f, g; +// CHECK-NEXT: static float a; +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: a = 2; +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) +// CHECK-NEXT: foo() +// CHECK: template <typename T> T tmain(T argc, T *argv) { +// CHECK-NEXT: T b = argc, c, d, e, f, g; +// CHECK-NEXT: static T a; +// CHECK-NEXT: #pragma omp parallel +// CHECK-NEXT: a = 2; +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) shared(d) +// CHECK-NEXT: foo() + int main (int argc, char **argv) { + float x; int b = argc, c, d, e, f, g; static int a; // CHECK: static int a; @@ -16,11 +50,11 @@ int main (int argc, char **argv) { // CHECK-NEXT: #pragma omp parallel a=2; // CHECK-NEXT: a = 2; -#pragma omp parallel default(none), private(argc,b) -// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) +#pragma omp parallel default(none), private(argc,b) firstprivate(argv) +// CHECK-NEXT: #pragma omp parallel default(none) private(argc,b) firstprivate(argv) foo(); // CHECK-NEXT: foo(); - return (0); + return tmain(b, &b) + tmain(x, &x); } #endif diff --git a/clang/test/OpenMP/parallel_firstprivate_messages.cpp b/clang/test/OpenMP/parallel_firstprivate_messages.cpp new file mode 100644 index 0000000..780059e --- /dev/null +++ b/clang/test/OpenMP/parallel_firstprivate_messages.cpp @@ -0,0 +1,82 @@ +// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s + +void foo() { +} + +bool foobool(int argc) { + return argc; +} + +struct S1; // expected-note {{declared here}} expected-note{{forward declaration of 'S1'}} +extern S1 a; +class S2 { + mutable int a; +public: + S2():a(0) { } + S2(S2 &s2):a(s2.a) { } + static float S2s; + static const float S2sc; +}; +const float S2::S2sc = 0; +const S2 b; +const S2 ba[5]; +class S3 { + int a; +public: + S3():a(0) { } + S3(S3 &s3):a(s3.a) { } +}; +const S3 c; +const S3 ca[5]; +extern const int f; +class S4 { // expected-note {{'S4' declared here}} + int a; + S4(); + S4(const S4 &s4); +public: + S4(int v):a(v) { } +}; +class S5 { // expected-note {{'S5' declared here}} + int a; + S5():a(0) {} + S5(const S5 &s5):a(s5.a) { } +public: + S5(int v):a(v) { } +}; + +S3 h; +#pragma omp threadprivate(h) // expected-note {{defined as threadprivate or thread local}} + +int main(int argc, char **argv) { + const int d = 5; + const int da[5] = { 0 }; + S4 e(4); // expected-note {{'e' defined here}} + S5 g(5); // expected-note {{'g' defined here}} + int i; + int &j = i; // expected-note {{'j' defined here}} + #pragma omp parallel firstprivate // expected-error {{expected '(' after 'firstprivate'}} + #pragma omp parallel firstprivate ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel firstprivate () // expected-error {{expected expression}} + #pragma omp parallel firstprivate (argc // expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel firstprivate (argc, // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}} + #pragma omp parallel firstprivate (argc > 0 ? argv[1] : argv[2]) // expected-error {{expected variable name}} + #pragma omp parallel firstprivate (argc) + #pragma omp parallel firstprivate (S1) // expected-error {{'S1' does not refer to a value}} + #pragma omp parallel firstprivate (a, b, c, d, f) // expected-error {{firstprivate variable with incomplete type 'S1'}} + #pragma omp parallel firstprivate (argv[1]) // expected-error {{expected variable name}} + #pragma omp parallel firstprivate(ba) + #pragma omp parallel firstprivate(ca) + #pragma omp parallel firstprivate(da) + #pragma omp parallel firstprivate(S2::S2s) + #pragma omp parallel firstprivate(S2::S2sc) + #pragma omp parallel firstprivate(e, g) // expected-error 2 {{firstprivate variable must have an accessible, unambiguous copy constructor}} + #pragma omp parallel firstprivate(h) // expected-error {{threadprivate or thread local variable cannot be firstprivate}} + #pragma omp parallel private(i), firstprivate(i) // expected-error {{private variable cannot be firstprivate}} expected-note{{defined as private}} + foo(); + #pragma omp parallel shared(i) + #pragma omp parallel firstprivate(i) + #pragma omp parallel firstprivate(j) // expected-error {{arguments of OpenMP clause 'firstprivate' cannot be of reference type}} + foo(); + + return 0; +} diff --git a/clang/test/OpenMP/parallel_private_messages.cpp b/clang/test/OpenMP/parallel_private_messages.cpp index 102bf30..2037d56 100644 --- a/clang/test/OpenMP/parallel_private_messages.cpp +++ b/clang/test/OpenMP/parallel_private_messages.cpp @@ -64,10 +64,18 @@ int main(int argc, char **argv) { #pragma omp parallel private(S2::S2s) // expected-error {{shared variable cannot be private}} #pragma omp parallel private(e, g) // expected-error 2 {{private variable must have an accessible, unambiguous default constructor}} #pragma omp parallel private(threadvar) // expected-error {{threadprivate or thread local variable cannot be private}} + #pragma omp parallel shared(i), private(i) // expected-error {{shared variable cannot be private}} expected-note {{defined as shared}} + foo(); + #pragma omp parallel firstprivate(i) private(i) // expected-error {{firstprivate variable cannot be private}} expected-note {{defined as firstprivate}} foo(); #pragma omp parallel private(i) #pragma omp parallel private(j) // expected-error {{arguments of OpenMP clause 'private' cannot be of reference type 'int &'}} foo(); + #pragma omp parallel firstprivate(i) + for (int k = 0; k < 10; ++k) { + #pragma omp parallel private(i) + foo(); + } return 0; } diff --git a/clang/test/OpenMP/parallel_shared_messages.cpp b/clang/test/OpenMP/parallel_shared_messages.cpp index 0d8894e..211d392f 100644 --- a/clang/test/OpenMP/parallel_shared_messages.cpp +++ b/clang/test/OpenMP/parallel_shared_messages.cpp @@ -68,10 +68,16 @@ int main(int argc, char **argv) { #pragma omp parallel shared(h) // expected-error {{threadprivate or thread local variable cannot be shared}} #pragma omp parallel private(i), shared(i) // expected-error {{private variable cannot be shared}} expected-note {{defined as private}} foo(); + #pragma omp parallel firstprivate(i), shared(i) // expected-error {{firstprivate variable cannot be shared}} expected-note {{defined as firstprivate}} + foo(); #pragma omp parallel private(i) #pragma omp parallel shared(i) #pragma omp parallel shared(j) foo(); + #pragma omp parallel firstprivate(i) + #pragma omp parallel shared(i) + #pragma omp parallel shared(j) + foo(); return 0; } diff --git a/clang/tools/libclang/CIndex.cpp b/clang/tools/libclang/CIndex.cpp index b40a913..967750f 100644 --- a/clang/tools/libclang/CIndex.cpp +++ b/clang/tools/libclang/CIndex.cpp @@ -1934,6 +1934,10 @@ void OMPClauseEnqueue::VisitOMPClauseList(T *Node) { void OMPClauseEnqueue::VisitOMPPrivateClause(const OMPPrivateClause *C) { VisitOMPClauseList(C); } +void OMPClauseEnqueue::VisitOMPFirstprivateClause( + const OMPFirstprivateClause *C) { + VisitOMPClauseList(C); +} void OMPClauseEnqueue::VisitOMPSharedClause(const OMPSharedClause *C) { VisitOMPClauseList(C); } diff --git a/clang/tools/libclang/RecursiveASTVisitor.h b/clang/tools/libclang/RecursiveASTVisitor.h index fe936f9..3ad5acb 100644 --- a/clang/tools/libclang/RecursiveASTVisitor.h +++ b/clang/tools/libclang/RecursiveASTVisitor.h @@ -2345,6 +2345,13 @@ bool RecursiveASTVisitor<Derived>::VisitOMPPrivateClause(OMPPrivateClause *C) { } template<typename Derived> +bool RecursiveASTVisitor<Derived>::VisitOMPFirstprivateClause( + OMPFirstprivateClause *C) { + VisitOMPClauseList(C); + return true; +} + +template<typename Derived> bool RecursiveASTVisitor<Derived>::VisitOMPSharedClause(OMPSharedClause *C) { VisitOMPClauseList(C); return true; |