From 74caaf27d8ea8f82f6020d51a2df7d92a3b558e7 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Sat, 20 Feb 2016 04:09:36 +0000 Subject: [PATCH] [OPENMP 4.5] Initial support for data members in 'lastprivate' clause. OpenMP 4.5 allows to privatize non-static data members of current class in non-static member functions. Patch adds initial support for data members. llvm-svn: 261412 --- clang/lib/Sema/SemaOpenMP.cpp | 107 ++++++++++-------------- clang/test/OpenMP/for_ast_print.cpp | 19 ++++- clang/test/OpenMP/simd_lastprivate_messages.cpp | 2 +- 3 files changed, 65 insertions(+), 63 deletions(-) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 7f000dc..31943fa 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -990,17 +990,18 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { PrivateCopies.push_back(nullptr); continue; } - DE = DE->IgnoreParens(); VarDecl *VD = nullptr; FieldDecl *FD = nullptr; ValueDecl *D; - if (auto *DRE = dyn_cast(DE)) { + auto *DRE = cast(DE->IgnoreParens()); + if (auto *OCE = dyn_cast(DRE->getDecl())) { + FD = cast( + cast(OCE->getInit()->IgnoreImpCasts()) + ->getMemberDecl()); + D = FD; + } else { VD = cast(DRE->getDecl()); D = VD; - } else { - assert(isa(DE)); - FD = cast(cast(DE)->getMemberDecl()); - D = FD; } QualType Type = D->getType().getNonReferenceType(); auto DVar = DSAStack->getTopDSA(D, false); @@ -7514,47 +7515,28 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, SmallVector AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); - if (isa(RefExpr)) { + auto Res = getPrivateItem(*this, RefExpr); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.3.5, Restrictions, p.1] - // A variable that is part of another variable (as an array or structure - // element) cannot appear in a lastprivate clause. - DeclRefExpr *DE = dyn_cast_or_null(RefExpr); - if (!DE || !isa(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name_member_expr) - << 0 << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast(D); - QualType Type = VD->getType(); - 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; - } + SourceLocation ELoc = RefExpr->getExprLoc(); + QualType Type = D->getType(); + auto *VD = dyn_cast(D); // OpenMP [2.14.3.5, Restrictions, C/C++, p.2] // A variable that appears in a lastprivate clause must not have an // incomplete type or a reference type. if (RequireCompleteType(ELoc, Type, - diag::err_omp_lastprivate_incomplete_type)) { + diag::err_omp_lastprivate_incomplete_type)) continue; - } Type = Type.getNonReferenceType(); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -7562,14 +7544,14 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_firstprivate && (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_lastprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -7583,15 +7565,28 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, DSAStackTy::DSAVarData TopDVar = DVar; if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_lastprivate) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + + // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] + // A list item may appear in a firstprivate or lastprivate clause but not + // both. + if (CurrDir == OMPD_distribute) { + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + if (DVar.CKind == OMPC_firstprivate) { + Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } + // OpenMP [2.14.3.5, Restrictions, C++, p.1,2] // A variable of class type (or array thereof) that appears in a // lastprivate clause requires an accessible, unambiguous default @@ -7601,42 +7596,32 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, // lastprivate clause requires an accessible, unambiguous copy assignment // operator for the class type. Type = Context.getBaseElementType(Type).getNonReferenceType(); - auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), + auto *SrcVD = buildVarDecl(*this, RefExpr->getLocStart(), Type.getUnqualifiedType(), ".lastprivate.src", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoSrcExpr = buildDeclRefExpr( - *this, SrcVD, Type.getUnqualifiedType(), DE->getExprLoc()); + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoSrcExpr = + buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoDstExpr = - buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); + buildVarDecl(*this, RefExpr->getLocStart(), Type, ".lastprivate.dst", + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); // 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, + auto AssignmentOp = BuildBinOp(/*S=*/nullptr, ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; - AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; - // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] - // A list item may appear in a firstprivate or lastprivate clause but not - // both. - if (CurrDir == OMPD_distribute) { - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); - if (DVar.CKind == OMPC_firstprivate) { - Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); - ReportOriginalDSA(*this, DSAStack, VD, DVar); - continue; - } - } - + DeclRefExpr *Ref = nullptr; + if (!VD) + Ref = buildCapture(*this, D->getIdentifier(), RefExpr); if (TopDVar.CKind != OMPC_firstprivate) - DSAStack->addDSA(VD, DE, OMPC_lastprivate); - Vars.push_back(DE); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_lastprivate, Ref); + Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); diff --git a/clang/test/OpenMP/for_ast_print.cpp b/clang/test/OpenMP/for_ast_print.cpp index 72dd302..38dafc0 100644 --- a/clang/test/OpenMP/for_ast_print.cpp +++ b/clang/test/OpenMP/for_ast_print.cpp @@ -26,25 +26,37 @@ public: #pragma omp for private(a) private(this->a) private(T::a) for (int k = 0; k < a.a; ++k) ++this->a.a; +#pragma omp for lastprivate(a) lastprivate(this->a) lastprivate(T::a) + for (int k = 0; k < a.a; ++k) + ++this->a.a; } S7 &operator=(S7 &s) { #pragma omp for private(a) private(this->a) for (int k = 0; k < s.a.a; ++k) ++s.a.a; +#pragma omp for lastprivate(a) lastprivate(this->a) + for (int k = 0; k < s.a.a; ++k) + ++s.a.a; return *this; } }; // CHECK: #pragma omp for private(this->a) private(this->a) private(this->S::a) +// CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) lastprivate(this->S::a) // CHECK: #pragma omp for private(this->a) private(this->a) private(T::a) +// CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) lastprivate(T::a) // CHECK: #pragma omp for private(this->a) private(this->a) +// CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) class S8 : public S7 { S8() {} public: S8(int v) : S7(v){ -#pragma omp for private(a) private(this->a) private(S7::a) +#pragma omp for private(a) private(this->a) private(S7::a) + for (int k = 0; k < a.a; ++k) + ++this->a.a; +#pragma omp for lastprivate(a) lastprivate(this->a) lastprivate(S7::a) for (int k = 0; k < a.a; ++k) ++this->a.a; } @@ -52,12 +64,17 @@ public: #pragma omp for private(a) private(this->a) for (int k = 0; k < s.a.a; ++k) ++s.a.a; +#pragma omp for lastprivate(a) lastprivate(this->a) + for (int k = 0; k < s.a.a; ++k) + ++s.a.a; return *this; } }; // CHECK: #pragma omp for private(this->a) private(this->a) private(this->S7::a) +// CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) lastprivate(this->S7::a) // CHECK: #pragma omp for private(this->a) private(this->a) +// CHECK: #pragma omp for lastprivate(this->a) lastprivate(this->a) template T tmain(T argc) { diff --git a/clang/test/OpenMP/simd_lastprivate_messages.cpp b/clang/test/OpenMP/simd_lastprivate_messages.cpp index 7cc5ba8..16223db 100644 --- a/clang/test/OpenMP/simd_lastprivate_messages.cpp +++ b/clang/test/OpenMP/simd_lastprivate_messages.cpp @@ -217,5 +217,5 @@ int main(int argc, char **argv) { #pragma omp simd lastprivate(t) // OK for (i = 0; i < argc; ++i) foo(); - return 0; + return foomain(argc, argv); // expected-note {{in instantiation of function template specialization 'foomain' requested here}} } -- 2.7.4