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 /clang/lib | |
parent | de111a425c0a8e38e4a60f1c5ca310546717a876 (diff) | |
download | bcm5719-llvm-d5af8e472d6016f3dca2a33fa9d92bcf35aad43b.tar.gz bcm5719-llvm-d5af8e472d6016f3dca2a33fa9d92bcf35aad43b.zip |
[OpenMP] Added parsing and semantic analysis for firstprivate clause
llvm-svn: 191730
Diffstat (limited to 'clang/lib')
-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 |
9 files changed, 333 insertions, 17 deletions
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index 03215927440..de851615cb7 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 1bbd4667fc5..55cfd3f8134 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 35f37ddaa79..6805e62befb 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 89a4faa7d09..1350934d0e6 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 de76b17dd93..992a4431c7a 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 dadfa4129ea..d5778bc6367 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 5b019a96c06..977d0132b7e 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 23cd9cc726b..1115e8fd4f4 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 e38d8c69a72..072fc98e391 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); |