diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -196,6 +196,17 @@ llvm::DenseSet> UsedInScanDirective; llvm::DenseMap, UsesAllocatorsDeclKind> UsesAllocatorsDecls; + struct ImplicitDefaultFDInfoTy { + const FieldDecl *FD = nullptr; + size_t StackLevel = 0; + VarDecl *VD = nullptr; + ImplicitDefaultFDInfoTy(const FieldDecl *FD, size_t StackLevel, + VarDecl *VD) + : FD(FD), StackLevel(StackLevel), VD(VD) {} + }; + /// List of captuer fields + llvm::SmallVector + ImplicitDefaultFirstprivateFDs; Expr *DeclareMapperVar = nullptr; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) @@ -577,7 +588,9 @@ /// predicate. const DSAVarData hasDSA(ValueDecl *D, - const llvm::function_ref CPred, + const llvm::function_ref + CPred, const llvm::function_ref DPred, bool FromParent) const; /// Checks if the specified variables has data-sharing attributes which @@ -1120,6 +1133,52 @@ const SharingMapTy *Top = getTopOfStackOrNull(); return Top ? Top->DeclareMapperVar : nullptr; } + /// get captured field from ImplicitDefaultFirstprivateFDs + VarDecl *getImplicitFDCapExprDecl(const FieldDecl *FD) const { + const_iterator I = begin(); + const_iterator EndI = end(); + size_t StackLevel = getStackSize(); + for (; I != EndI; ++I) { + if (I->DefaultAttr == DSA_firstprivate || I->DefaultAttr == DSA_private) + break; + StackLevel--; + } + assert((StackLevel > 0 && I != EndI) || (StackLevel == 0 && I == EndI)); + if (I == EndI) + return nullptr; + for (const auto &IFD : I->ImplicitDefaultFirstprivateFDs) + if (IFD.FD == FD && IFD.StackLevel == StackLevel) + return IFD.VD; + return nullptr; + } + /// Check if capture decl is field captured in ImplicitDefaultFirstprivateFDs + bool isImplicitDefaultFirstprivateFD(VarDecl *VD) const { + const_iterator I = begin(); + const_iterator EndI = end(); + for (; I != EndI; ++I) + if (I->DefaultAttr == DSA_firstprivate || I->DefaultAttr == DSA_private) + break; + if (I == EndI) + return false; + for (const auto &IFD : I->ImplicitDefaultFirstprivateFDs) + if (IFD.VD == VD) + return true; + return false; + } + /// Store capture FD info in ImplicitDefaultFirstprivateFDs + void addImplicitDefaultFirstprivateFD(const FieldDecl *FD, VarDecl *VD) { + iterator I = begin(); + const_iterator EndI = end(); + size_t StackLevel = getStackSize(); + for (; I != EndI; ++I) { + if (I->DefaultAttr == DSA_private || I->DefaultAttr == DSA_firstprivate) { + I->ImplicitDefaultFirstprivateFDs.emplace_back(FD, StackLevel, VD); + break; + } + StackLevel--; + } + assert((StackLevel > 0 && I != EndI) || (StackLevel == 0 && I == EndI)); + } }; bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) { @@ -1815,7 +1874,9 @@ const DSAStackTy::DSAVarData DSAStackTy::hasDSA(ValueDecl *D, - const llvm::function_ref CPred, + const llvm::function_ref + CPred, const llvm::function_ref DPred, bool FromParent) const { if (isStackEmpty()) @@ -1831,7 +1892,7 @@ continue; const_iterator NewI = I; DSAVarData DVar = getDSA(NewI, D); - if (I == NewI && CPred(DVar.CKind, DVar.AppliedToPointee)) + if (I == NewI && CPred(DVar.CKind, DVar.AppliedToPointee, I->DefaultAttr)) return DVar; } return {}; @@ -2203,6 +2264,11 @@ false); } +static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, + Expr *CaptureExpr, bool WithInit, + DeclContext *CurContext, + bool AsExpression); + VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, unsigned StopAt) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); @@ -2301,7 +2367,7 @@ // default(none) clause and not used in any clause. DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA( D, - [](OpenMPClauseKind C, bool AppliedToPointee) { + [](OpenMPClauseKind C, bool AppliedToPointee, bool) { return isOpenMPPrivate(C) && !AppliedToPointee; }, [](OpenMPDirectiveKind) { return true; }, @@ -2313,6 +2379,43 @@ DSAStack->getDefaultDSA() != DSA_firstprivate) || DVarTop.CKind == OMPC_shared)) return nullptr; + auto *FD = dyn_cast(D); + if (DVarPrivate.CKind != OMPC_unknown && !VD && FD && + !DVarPrivate.PrivateCopy) { + DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA( + D, + [](OpenMPClauseKind C, bool AppliedToPointee, + DefaultDataSharingAttributes DefaultAttr) { + return isOpenMPPrivate(C) && !AppliedToPointee && + (DefaultAttr == DSA_firstprivate || + DefaultAttr == DSA_private); + }, + [](OpenMPDirectiveKind) { return true; }, + DSAStack->isClauseParsingMode()); + if (DVarPrivate.CKind == OMPC_unknown) + return nullptr; + + VarDecl *VD = DSAStack->getImplicitFDCapExprDecl(FD); + if (VD) + return VD; + Expr *ThisExpr = BuildCXXThisExpr(SourceLocation(), getCurrentThisType(), + /*IsImplicit=*/true); + const CXXScopeSpec CS = CXXScopeSpec(); + Expr *ME = BuildMemberExpr(ThisExpr, /*IsArrow=*/true, SourceLocation(), + NestedNameSpecifierLoc(), SourceLocation(), FD, + DeclAccessPair::make(FD, FD->getAccess()), + /*HadMultipleCandidates=*/false, + DeclarationNameInfo(), FD->getType(), + VK_LValue, OK_Ordinary); + OMPCapturedExprDecl *CD = buildCaptureDecl( + *this, FD->getIdentifier(), ME, DVarPrivate.CKind != OMPC_private, + CurContext->getParent(), /*AsExpression=*/false); + DeclRefExpr *VDPrivateRefExpr = buildDeclRefExpr( + *this, CD, CD->getType().getNonReferenceType(), SourceLocation()); + VD = cast(VDPrivateRefExpr->getDecl()); + DSAStack->addImplicitDefaultFirstprivateFD(FD, VD); + return VD; + } if (DVarPrivate.CKind != OMPC_unknown || (VD && (DSAStack->getDefaultDSA() == DSA_none || DSAStack->getDefaultDSA() == DSA_private || @@ -2344,6 +2447,23 @@ OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level, unsigned CapLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); + if (DSAStack->getCurrentDirective() != OMPD_unknown && + (!DSAStack->isClauseParsingMode() || + DSAStack->getParentDirective() != OMPD_unknown)) { + DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA( + D, + [](OpenMPClauseKind C, bool AppliedToPointee, + DefaultDataSharingAttributes DefaultAttr) { + return isOpenMPPrivate(C) && !AppliedToPointee && + DefaultAttr == DSA_private; + }, + [](OpenMPDirectiveKind) { return true; }, + DSAStack->isClauseParsingMode()); + if (DVarPrivate.CKind == OMPC_private && isa(D) && + DSAStack->isImplicitDefaultFirstprivateFD(cast(D)) && + !DSAStack->isLoopControlVariable(D).first) + return OMPC_private; + } if (DSAStack->hasExplicitDirective(isOpenMPTaskingDirective, Level)) { bool IsTriviallyCopyable = D->getType().getNonReferenceType().isTriviallyCopyableType(Context) && @@ -3524,7 +3644,8 @@ if (auto *VD = dyn_cast(E->getDecl())) { // Check the datasharing rules for the expressions in the clauses. if (!CS || (isa(VD) && !CS->capturesVariable(VD) && - !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr)) { + !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr && + !Stack->isImplicitDefaultFirstprivateFD(VD))) { if (auto *CED = dyn_cast(VD)) if (!CED->hasAttr()) { Visit(CED->getInit()); @@ -3533,10 +3654,12 @@ } else if (VD->isImplicit() || isa(VD)) // Do not analyze internal variables and do not enclose them into // implicit clauses. - return; + if (!Stack->isImplicitDefaultFirstprivateFD(VD)) + return; VD = VD->getCanonicalDecl(); // Skip internally declared variables. if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) && + !Stack->isImplicitDefaultFirstprivateFD(VD) && !Stack->isImplicitTaskFirstprivate(VD)) return; // Skip allocators in uses_allocators clauses. @@ -4419,6 +4542,7 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, Expr *CaptureExpr, bool WithInit, + DeclContext *CurContext, bool AsExpression) { assert(CaptureExpr); ASTContext &C = S.getASTContext(); @@ -4437,11 +4561,11 @@ } WithInit = true; } - auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty, + auto *CED = OMPCapturedExprDecl::Create(C, CurContext, Id, Ty, CaptureExpr->getBeginLoc()); if (!WithInit) CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C)); - S.CurContext->addHiddenDecl(CED); + CurContext->addHiddenDecl(CED); Sema::TentativeAnalysisScope Trap(S); S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false); return CED; @@ -4454,6 +4578,7 @@ CD = cast(VD); else CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit, + S.CurContext, /*AsExpression=*/false); return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), CaptureExpr->getExprLoc()); @@ -4464,7 +4589,7 @@ if (!Ref) { OMPCapturedExprDecl *CD = buildCaptureDecl( S, &S.getASTContext().Idents.get(".capture_expr."), CaptureExpr, - /*WithInit=*/true, /*AsExpression=*/true); + /*WithInit=*/true, S.CurContext, /*AsExpression=*/true); Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), CaptureExpr->getExprLoc()); } @@ -17361,6 +17486,8 @@ SourceLocation EndLoc) { SmallVector Vars; SmallVector PrivateCopies; + bool IsImplicitClause = + StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid(); for (Expr *RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); SourceLocation ELoc; @@ -17475,9 +17602,17 @@ *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc); DeclRefExpr *Ref = nullptr; - if (!VD && !CurContext->isDependentContext()) - Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); - DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); + if (!VD && !CurContext->isDependentContext()) { + auto *FD = dyn_cast(D); + VarDecl *VD = FD ? DSAStack->getImplicitFDCapExprDecl(FD) : nullptr; + if (VD) + Ref = buildDeclRefExpr(*this, VD, VD->getType().getNonReferenceType(), + RefExpr->getExprLoc()); + else + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + } + if (!IsImplicitClause) + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); Vars.push_back((VD || CurContext->isDependentContext()) ? RefExpr->IgnoreParens() : Ref); @@ -17750,8 +17885,14 @@ if (TopDVar.CKind == OMPC_lastprivate) { Ref = TopDVar.PrivateCopy; } else { - Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); - if (!isOpenMPCapturedDecl(D)) + auto *FD = dyn_cast(D); + VarDecl *VD = FD ? DSAStack->getImplicitFDCapExprDecl(FD) : nullptr; + if (VD) + Ref = buildDeclRefExpr(*this, VD, VD->getType().getNonReferenceType(), + RefExpr->getExprLoc()); + else + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + if (VD || !isOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } } @@ -18021,7 +18162,7 @@ return true; DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA( VD, - [](OpenMPClauseKind C, bool AppliedToPointee) { + [](OpenMPClauseKind C, bool AppliedToPointee, bool) { return isOpenMPPrivate(C) && !AppliedToPointee; }, [](OpenMPDirectiveKind) { return true; }, diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -11097,11 +11097,14 @@ FoundDecl == E->getFoundDecl() && !E->hasExplicitTemplateArgs()) { - // Mark it referenced in the new context regardless. - // FIXME: this is a bit instantiation-specific. - SemaRef.MarkMemberReferenced(E); - - return E; + // Skip for member expression of (this->f), rebuilt thisi->f is needed + // for Openmp where the field need to be privatizized in the case. + if (!(getSema().getLangOpts().OpenMP && isa(E->getBase()))) { + // Mark it referenced in the new context regardless. + // FIXME: this is a bit instantiation-specific. + SemaRef.MarkMemberReferenced(E); + return E; + } } TemplateArgumentListInfo TransArgs; diff --git a/clang/test/OpenMP/default_firstprivate_ast_print.cpp b/clang/test/OpenMP/default_firstprivate_ast_print.cpp --- a/clang/test/OpenMP/default_firstprivate_ast_print.cpp +++ b/clang/test/OpenMP/default_firstprivate_ast_print.cpp @@ -45,7 +45,8 @@ // PRINT-NEXT: this->targetDev++; // CHECK-NEXT: } // DUMP: -OMPParallelDirective - // DUMP->NEXT: -OMPDefaultClause + // DUMP-NEXT: -OMPDefaultClause + // DUMP-NOT: -OMPFirstprivateClause } // PRINT: template<> void apply<32U>() // PRINT: #pragma omp parallel default(firstprivate) @@ -54,6 +55,8 @@ // CHECK-NEXT: } // DUMP: -OMPParallelDirective // DUMP-NEXT: -OMPDefaultClause + // DUMP-NEXT: -OMPFirstprivateClause + // DUMP-NEXT: -DeclRefExpr {{.*}} 'targetDev' }; void use_template() { @@ -99,4 +102,60 @@ // DUMP-NEXT: -DeclRefExpr {{.*}} 'yy' // DUMP-NEXT: -DeclRefExpr {{.*}} 'y' } +void zoo(int); +struct A { + int z; + int f; + A(); + ~A(); + void foo() { +#pragma omp parallel firstprivate(z) default(firstprivate) + { + z++; + f++; + zoo(z + f); + f++; + } + } + // PRINT: #pragma omp parallel firstprivate(this->z) default(firstprivate) + // DUMP: -OMPParallelDirective + // DUMP-NEXT: -OMPFirstprivateClause + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' + // DUMP-NEXT: -OMPDefaultClause + // DUMP-NEXT: -OMPFirstprivateClause {{.*}} + // DUMP-NEXT: -DeclRefExpr {{.*}} 'f' + // DUMP: -CXXThisExpr {{.*}} 'A *' implicit this + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' + // DUMP-NEXT: -DeclRefExpr {{.*}} 'f' + void bar() { +#pragma omp parallel firstprivate(z) default(firstprivate) + { +#pragma omp parallel private(z) default(firstprivate) + { + z++; + f++; + zoo(z + f); + f++; + } + } + } + // PRINT: #pragma omp parallel firstprivate(this->z) default(firstprivate) + // PRINT: #pragma omp parallel private(this->z) default(firstprivate) + // DUMP: -OMPParallelDirective + // DUMP-NEXT: -OMPFirstprivateClause + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' + // DUMP-NEXT: -OMPDefaultClause + // DUMP: -OMPParallelDirective + // DUMP-NEXT: -OMPPrivateClaus + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' + // DUMP-NEXT: -OMPDefaultClause + // DUMP-NEXT: -OMPFirstprivateClause {{.*}} + // DUMP-NEXT: -DeclRefExpr {{.*}} 'f' + // DUMP: -CXXThisExpr {{.*}} 'A *' implicit this + // DUMP-NEXT: -DeclRefExpr {{.*}} 'f' + // DUMP: -MemberExpr {{.*}} + // DUMP-NEXT: -CXXThisExpr + // DUMP: -CXXThisExpr {{.*}} 'A *' implicit this + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' +}; #endif // HEADER diff --git a/clang/test/OpenMP/default_private_ast_print.cpp b/clang/test/OpenMP/default_private_ast_print.cpp --- a/clang/test/OpenMP/default_private_ast_print.cpp +++ b/clang/test/OpenMP/default_private_ast_print.cpp @@ -96,4 +96,57 @@ // DUMP-NEXT: -DeclRefExpr {{.*}} 'a' // DUMP-NEXT: -DeclRefExpr {{.*}} 'yy' } + +void zoo(int); +struct A { + int z; + int f; + A(); + ~A(); + void foo() { +#pragma omp parallel private(z) default(private) + { + z++; + f++; + zoo(z + f); + f++; + } + } + // PRINT: #pragma omp parallel private(this->z) default(private) + // DUMP: -OMPParallelDirective + // DUMP-NEXT: -OMPPrivateClause + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' + // DUMP-NEXT: -OMPDefaultClause + // DUMP-NEXT: -OMPPrivateClause + // DUMP-NEXT: -DeclRefExpr {{.*}} 'f' + // DUMP: -CXXThisExpr {{.*}} 'A *' implicit this + void bar() { +#pragma omp parallel private(z) default(private) + { +#pragma omp parallel private(z) default(private) + { + z++; + f++; + zoo(z + f); + f++; + } + } + } + // PRINT: #pragma omp parallel private(this->z) default(private) + // PRINT: #pragma omp parallel private(this->z) default(private) + // DUMP: -OMPParallelDirective + // DUMP-NEXT: -OMPPrivateClause + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' + // DUMP-NEXT: -OMPDefaultClause + // DUMP: -OMPParallelDirective + // DUMP-NEXT: -OMPPrivateClause + // DUMP-NEXT: -DeclRefExpr {{.*}} 'z' + // DUMP-NEXT: -OMPDefaultClause + // DUMP-NEXT: -OMPPrivateClause {{.*}} + // DUMP-NEXT: -DeclRefExpr {{.*}} 'f' + // DUMP: -CXXThisExpr + // DUMP: -MemberExpr + // DUMP-NEXT: -CXXThisExpr + // DUMP: -CXXThisExpr +}; #endif // HEADER