diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -10614,6 +10614,16 @@ /// constructs. VarDecl *isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo = false, unsigned StopAt = 0); + + VarDecl *isOpenMPFDCaptureDecl(ValueDecl *D, Expr *Base, bool IsArrow, + SourceLocation OpLoc, const CXXScopeSpec *SS, + SourceLocation TemplateKWLoc, + ValueDecl *Member, DeclAccessPair FoundDecl, + bool HadMultipleCandidates, + const DeclarationNameInfo &MemberNameInfo, + QualType Ty, ExprValueKind VK, + ExprObjectKind OK); + ExprResult getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, ExprObjectKind OK, SourceLocation Loc); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1866,10 +1866,13 @@ if (getLangOpts().OpenMP && IsArrow && !CurContext->isDependentContext() && isa(Base.get()->IgnoreParenImpCasts())) { - if (auto *PrivateCopy = isOpenMPCapturedDecl(Field)) { + if (auto *PrivateCopy = + isOpenMPFDCaptureDecl(Field, Base.get(), IsArrow, OpLoc, &SS, + /*TemplateKWLoc=*/SourceLocation(), Field, + FoundDecl, /*HadMultipleCandidates=*/false, + MemberNameInfo, MemberType, VK, OK)) return getOpenMPCapturedExpr(PrivateCopy, VK, OK, MemberNameInfo.getLoc()); - } } return BuildMemberExpr(Base.get(), IsArrow, OpLoc, &SS, 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 @@ -75,14 +75,15 @@ DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; bool AppliedToPointee = false; + bool ImplicitFD = false; DSAVarData() = default; DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, const Expr *RefExpr, DeclRefExpr *PrivateCopy, SourceLocation ImplicitDSALoc, unsigned Modifier, - bool AppliedToPointee) + bool AppliedToPointee, bool ImplicitFD) : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr), PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc), - AppliedToPointee(AppliedToPointee) {} + AppliedToPointee(AppliedToPointee), ImplicitFD(ImplicitFD) {} }; using OperatorOffsetTy = llvm::SmallVector, 4>; @@ -109,6 +110,7 @@ /// true if the attribute is applied to the pointee, not the variable /// itself. bool AppliedToPointee = false; + bool ImplicitFD = false; }; using DeclSAMapTy = llvm::SmallDenseMap; using UsedRefMapTy = llvm::SmallDenseMap; @@ -526,6 +528,14 @@ DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0, bool AppliedToPointee = false); + void insertDSA(ValueDecl *D, Expr *E, DeclRefExpr *PrivateCopy, + OpenMPClauseKind A, + const llvm::function_ref + CPred, + const llvm::function_ref DPred, + bool FromParent); + /// Adds additional information for the reduction items with the reduction id /// represented as an operator. void addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, @@ -577,7 +587,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 @@ -1224,6 +1236,7 @@ DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; DVar.Modifier = Data.Modifier; DVar.AppliedToPointee = Data.AppliedToPointee; + DVar.ImplicitFD = Data.ImplicitFD; return DVar; } @@ -1418,6 +1431,7 @@ Data.RefExpr.setPointerAndInt(E, IsLastprivate); Data.PrivateCopy = PrivateCopy; Data.AppliedToPointee = AppliedToPointee; + Data.ImplicitFD = false; if (PrivateCopy) { DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()]; Data.Modifier = Modifier; @@ -1425,6 +1439,7 @@ Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); Data.PrivateCopy = nullptr; Data.AppliedToPointee = AppliedToPointee; + Data.ImplicitFD = false; } } } @@ -1533,7 +1548,7 @@ TaskgroupDescriptor = I->TaskgroupReductionRef; return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(), Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task, - /*AppliedToPointee=*/false); + /*AppliedToPointee=*/false, /*ImplicitFD=*/false); } return DSAVarData(); } @@ -1560,7 +1575,7 @@ TaskgroupDescriptor = I->TaskgroupReductionRef; return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(), Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task, - /*AppliedToPointee=*/false); + /*AppliedToPointee=*/false, /*ImplicitFD*/false); } return DSAVarData(); } @@ -1734,6 +1749,7 @@ DVar.DKind = I->Directive; DVar.Modifier = Data.Modifier; DVar.AppliedToPointee = Data.AppliedToPointee; + DVar.ImplicitFD = Data.ImplicitFD; return DVar; } } @@ -1785,6 +1801,7 @@ DVar.DKind = I->Directive; DVar.Modifier = Data.Modifier; DVar.AppliedToPointee = Data.AppliedToPointee; + DVar.ImplicitFD = Data.ImplicitFD; } return DVar; @@ -1813,11 +1830,13 @@ return getDSA(StartI, D); } -const DSAStackTy::DSAVarData -DSAStackTy::hasDSA(ValueDecl *D, - const llvm::function_ref CPred, - const llvm::function_ref DPred, - bool FromParent) const { +const DSAStackTy::DSAVarData DSAStackTy::hasDSA( + ValueDecl *D, + const llvm::function_ref + CPred, + const llvm::function_ref DPred, + bool FromParent) const { if (isStackEmpty()) return {}; D = getCanonicalDecl(D); @@ -1831,12 +1850,57 @@ 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 {}; } +void DSAStackTy::insertDSA( + ValueDecl *D, Expr *E, DeclRefExpr *PrivateCopy, OpenMPClauseKind A, + const llvm::function_ref + CPred, + const llvm::function_ref DPred, + bool FromParent) { + if (isStackEmpty()) + return; + D = getCanonicalDecl(D); + iterator I = begin(); + iterator EndI = end(); + if (FromParent && I != EndI) + ++I; + for (; I != EndI; ++I) { + if (!DPred(I->Directive) && + !isImplicitOrExplicitTaskingRegion(I->Directive)) + continue; + const_iterator NewI = I; + DSAVarData DVar = getDSA(NewI, D); + if (I == NewI && CPred(DVar.CKind, DVar.AppliedToPointee, I->DefaultAttr)) { + if (!I->SharingMap.count(D)) { + DSAInfo &Data = (*I).SharingMap[D]; + Data.Attributes = A; + Data.Modifier = 0; + Data.AppliedToPointee = false; + Data.RefExpr.setPointerAndInt(E, /*IsLastprivate*/false); + Data.PrivateCopy = PrivateCopy; + Data.ImplicitFD = true; + if (PrivateCopy) { + DSAInfo &Data = (*I).SharingMap[PrivateCopy->getDecl()]; + Data.Modifier = 0; + Data.Attributes = A; + Data.AppliedToPointee = false; + Data.RefExpr.setPointerAndInt(PrivateCopy, /*IsLastprivate*/false); + Data.PrivateCopy = nullptr; + Data.ImplicitFD = true; + } + } + return; + } + } + return; +} + const DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( ValueDecl *D, const llvm::function_ref CPred, const llvm::function_ref DPred, @@ -2203,6 +2267,68 @@ false); } +static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, + Expr *CaptureExpr, bool WithInit, + DeclContext *CurContext, + bool AsExpression); + +VarDecl *Sema::isOpenMPFDCaptureDecl( + ValueDecl *D, Expr *Base, bool IsArrow, SourceLocation OpLoc, + const CXXScopeSpec *SS, SourceLocation TemplateKWLoc, ValueDecl *Member, + DeclAccessPair FoundDecl, bool HadMultipleCandidates, + const DeclarationNameInfo &MemberNameInfo, QualType Ty, ExprValueKind VK, + ExprObjectKind OK) { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + D = getCanonicalDecl(D); + + auto *FD = dyn_cast(D); + 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_firstprivate || + DefaultAttr == DSA_private); + }, + [](OpenMPDirectiveKind) { return true; }, + DSAStack->isClauseParsingMode()); + if (DVarPrivate.CKind == OMPC_unknown) + return isOpenMPCapturedDecl(FD); + + DeclRefExpr *VDPrivateRefExpr = DVarPrivate.PrivateCopy; + if (!VDPrivateRefExpr) { + ExprResult ME = BuildMemberExpr(Base, IsArrow, OpLoc, SS, TemplateKWLoc, + Member, FoundDecl, HadMultipleCandidates, + MemberNameInfo, Ty, VK, OK); + OMPCapturedExprDecl *CD = + buildCaptureDecl(*this, FD->getIdentifier(), ME.get(), + DVarPrivate.CKind == OMPC_private ? false : true, + CurContext->getParent(), + /*AsExpression=*/false); + VDPrivateRefExpr = + buildDeclRefExpr(*this, CD, CD->getType().getNonReferenceType(), + ME.get()->getExprLoc()); + // save captured expression in DSA. + DSAStack->insertDSA( + D, nullptr, VDPrivateRefExpr, DVarPrivate.CKind, + [](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 isOpenMPCapturedDecl(FD); + } + return nullptr; +} + VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, unsigned StopAt) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); @@ -2301,7 +2427,7 @@ // default(none) clause and not used in any clause. DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA( D, - [](OpenMPClauseKind C, bool AppliedToPointee) { + [](OpenMPClauseKind C, bool AppliedToPointee, ...) { return isOpenMPPrivate(C) && !AppliedToPointee; }, [](OpenMPDirectiveKind) { return true; }, @@ -2344,6 +2470,14 @@ 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 DVar = DSAStack->getImplicitDSA(D, Level); + if (DVar.ImplicitFD && DVar.CKind == OMPC_private && + !DSAStack->isLoopControlVariable(D).first) + return OMPC_private; + } if (DSAStack->hasExplicitDirective(isOpenMPTaskingDirective, Level)) { bool IsTriviallyCopyable = D->getType().getNonReferenceType().isTriviallyCopyableType(Context) && @@ -3522,6 +3656,8 @@ E->isInstantiationDependent()) return; if (auto *VD = dyn_cast(E->getDecl())) { + DSAStackTy::DSAVarData DVarImplicit = + Stack->getImplicitDSA(VD, /*FromParent=*/false); // Check the datasharing rules for the expressions in the clauses. if (!CS || (isa(VD) && !CS->capturesVariable(VD) && !Stack->getTopDSA(VD, /*FromParent=*/false).RefExpr)) { @@ -3533,7 +3669,8 @@ } else if (VD->isImplicit() || isa(VD)) // Do not analyze internal variables and do not enclose them into // implicit clauses. - return; + if (!DVarImplicit.ImplicitFD) + return; VD = VD->getCanonicalDecl(); // Skip internally declared variables. if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) && @@ -3802,6 +3939,12 @@ if (DVar.CKind != OMPC_unknown) ImplicitFirstprivate.push_back(E); } + if (DVar.ImplicitFD && Stack->getDefaultDSA() == DSA_firstprivate && + !DVar.RefExpr && !Stack->isLoopControlVariable(FD).first) + ImplicitFirstprivate.push_back(E); + if (DVar.ImplicitFD && Stack->getDefaultDSA() == DSA_private && + !DVar.RefExpr && !Stack->isLoopControlVariable(FD).first) + ImplicitPrivate.push_back(E); return; } if (isOpenMPTargetExecutionDirective(DKind)) { @@ -4416,6 +4559,7 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, Expr *CaptureExpr, bool WithInit, + DeclContext *CurContext, bool AsExpression) { assert(CaptureExpr); ASTContext &C = S.getASTContext(); @@ -4434,11 +4578,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; @@ -4451,6 +4595,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()); @@ -4461,7 +4606,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()); } @@ -17201,6 +17346,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; @@ -17317,7 +17464,8 @@ DeclRefExpr *Ref = nullptr; if (!VD && !CurContext->isDependentContext()) Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); - DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); + if (!IsImplicitClause) + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); Vars.push_back((VD || CurContext->isDependentContext()) ? RefExpr->IgnoreParens() : Ref); @@ -17586,12 +17734,13 @@ *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), RefExpr->getExprLoc()); DeclRefExpr *Ref = nullptr; + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, /*FromParent=*/false); if (!VD && !CurContext->isDependentContext()) { if (TopDVar.CKind == OMPC_lastprivate) { Ref = TopDVar.PrivateCopy; } else { Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); - if (!isOpenMPCapturedDecl(D)) + if (DVar.ImplicitFD || !isOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } } @@ -17861,7 +18010,7 @@ return true; DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA( VD, - [](OpenMPClauseKind C, bool AppliedToPointee) { + [](OpenMPClauseKind C, bool AppliedToPointee, ...) { 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 @@ -11057,7 +11057,7 @@ return ExprError(); } - if (!getDerived().AlwaysRebuild() && + if (!getDerived().AlwaysRebuild() && !getSema().getLangOpts().OpenMP && Base.get() == E->getBase() && QualifierLoc == E->getQualifierLoc() && Member == E->getMemberDecl() && 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 @@ -99,4 +99,53 @@ // 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,50 @@ // 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