Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7700,13 +7700,15 @@ public: /// \brief Check if the specified variable is used in one of the private /// clauses (private, firstprivate, lastprivate, reduction etc.) in OpenMP - /// constructs. - bool IsOpenMPCapturedVar(VarDecl *VD); + /// constructs. \a PropagateCapture is set to false if the capture should not + /// be propagated into innermost scopes. + bool IsOpenMPCapturedVar(VarDecl *VD, bool &PropagateCapture); - /// \brief Check if the specified variable is used in 'private' clause. + /// \brief Check if the specified variable is used in 'private' or 'copyin' + /// clause. /// \param Level Relative level of nested OpenMP construct for that the check /// is performed. - bool isOpenMPPrivateVar(VarDecl *VD, unsigned Level); + bool isOpenMPPrivateOrCopyinVar(VarDecl *VD, unsigned Level); ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op); @@ -7743,7 +7745,10 @@ ArrayRef VarList); /// \brief Initialization of captured region for OpenMP region. - void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope); + /// + /// \param Clauses List of clauses for the current OpenMP region. + void ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope, + ArrayRef Clauses); /// \brief End of OpenMP region. /// /// \param S Statement associated with the current OpenMP region. Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -227,10 +227,22 @@ auto *VD = cast(cast(*IRef)->getDecl()); QualType Type = VD->getType(); if (CopiedVars.insert(VD->getCanonicalDecl()).second) { - // Get the address of the master variable. - auto *MasterAddr = VD->isStaticLocal() - ? CGM.getStaticLocalDeclAddress(VD) - : CGM.GetAddrOfGlobal(VD); + + // Get the address of the master variable. If we are emitting code with + // TLS support, the address is passed from the master as field in the + // captured declaration. + llvm::Value *MasterAddr; + if (getLangOpts().OpenMPUseTLS && + getContext().getTargetInfo().isTLSSupported()) { + assert(CapturedStmtInfo->lookup(VD) && + "Copyin threadprivates should have been captured!"); + DeclRefExpr DRE(const_cast(VD), true, (*IRef)->getType(), + VK_LValue, (*IRef)->getExprLoc()); + MasterAddr = EmitLValue(&DRE).getAddress(); + } else { + MasterAddr = VD->isStaticLocal() ? CGM.getStaticLocalDeclAddress(VD) + : CGM.GetAddrOfGlobal(VD); + } // Get the address of the threadprivate variable. auto *PrivateAddr = EmitLValue(*IRef).getAddress(); if (CopiedVars.size() == 1) { Index: lib/Parse/ParseOpenMP.cpp =================================================================== --- lib/Parse/ParseOpenMP.cpp +++ lib/Parse/ParseOpenMP.cpp @@ -292,7 +292,7 @@ if (HasAssociatedStatement) { // The body is a block scope like in Lambdas and Blocks. Sema::CompoundScopeRAII CompoundScope(Actions); - Actions.ActOnOpenMPRegionStart(DKind, getCurScope()); + Actions.ActOnOpenMPRegionStart(DKind, getCurScope(), Clauses); Actions.ActOnStartOfCompoundStmt(); // Parse statement AssociatedStmt = ParseStatement(); Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -12533,7 +12533,8 @@ // By default, capture variables by reference. bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). - if (S.getLangOpts().OpenMP && S.IsOpenMPCapturedVar(Var)) + bool PropagateCapture = true; + if (S.getLangOpts().OpenMP && S.IsOpenMPCapturedVar(Var, PropagateCapture)) DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = S.Context.getLValueReferenceType(DeclRefType); Expr *CopyExpr = nullptr; @@ -12698,8 +12699,9 @@ VarDC = VarDC->getParent(); DeclContext *DC = CurContext; - const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt - ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; + unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt + ? *FunctionScopeIndexToStopAt + : FunctionScopes.size() - 1; // We need to sync up the Declaration Context with the // FunctionScopeIndexToStopAt if (FunctionScopeIndexToStopAt) { @@ -12718,7 +12720,9 @@ // Capture global variables if it is required to use private copy of this // variable. bool IsGlobal = !Var->hasLocalStorage(); - if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var))) + bool PropagateCapture = true; + if (IsGlobal && + !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var, PropagateCapture))) return true; // Walk up the stack to determine whether we can capture the variable, @@ -12758,18 +12762,33 @@ // Check whether we've already captured it. - if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, - DeclRefType)) + if (isVariableAlreadyCapturedInScopeInfo(CSI, Var, Nested, CaptureType, + DeclRefType)) { + // If this capture should not be propagated and was already captured, we + // don't need to do anything. + if (!PropagateCapture) + return true; break; + } if (getLangOpts().OpenMP) { if (auto *RSI = dyn_cast(CSI)) { - // OpenMP private variables should not be captured in outer scope, so - // just break here. + if (RSI->CapRegionKind == CR_OpenMP) { - if (isOpenMPPrivateVar(Var, OpenMPLevel)) { - Nested = true; + // OpenMP private variables should not be captured in outer scope, so + // just break here. + // If an OpenMP copyin variable is being captured, PropagateCapture + // will be set to false and the capture should happen only in the + // scope of the copyin clause. + if (isOpenMPPrivateOrCopyinVar(Var, OpenMPLevel)) { + Nested = PropagateCapture; DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); + + if (!PropagateCapture) { + --FunctionScopesIndex; + MaxFunctionScopesIndex = + std::min(MaxFunctionScopesIndex, FunctionScopesIndex + 1); + } break; } ++OpenMPLevel; @@ -12981,7 +13000,9 @@ Nested = true; } } - return false; + // If PropagateCapture is false, we are not interested in communicating that + // a capture was done. + return !PropagateCapture; } bool Sema::tryCaptureVariable(VarDecl *Var, SourceLocation Loc, Index: lib/Sema/SemaOpenMP.cpp =================================================================== --- lib/Sema/SemaOpenMP.cpp +++ lib/Sema/SemaOpenMP.cpp @@ -80,6 +80,7 @@ struct DSAInfo { OpenMPClauseKind Attributes; DeclRefExpr *RefExpr; + DSAInfo() : Attributes(OMPC_unknown), RefExpr(nullptr) {} }; typedef llvm::SmallDenseMap DeclSAMapTy; typedef llvm::SmallDenseMap AlignedMapTy; @@ -156,6 +157,9 @@ /// \brief Check if the specified variable is a loop control variable for /// current region. bool isLoopControlVariable(VarDecl *D); + /// \brief Check if the specified variable is a 'copyin' variable for the + /// current region. + bool isCopyinVariable(VarDecl *D); /// \brief Adds explicit data sharing attribute to the specified declaration. void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); @@ -412,6 +416,13 @@ return Stack.back().LCVSet.count(D) > 0; } +bool DSAStackTy::isCopyinVariable(VarDecl *D) { + assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); + D = D->getCanonicalDecl(); + auto L = Stack.back().SharingMap.lookup(D); + return L.Attributes == OMPC_copyin; +} + void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { D = D->getCanonicalDecl(); if (A == OMPC_threadprivate) { @@ -649,7 +660,7 @@ #define DSAStack static_cast(VarDataSharingAttributesStack) -bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { +bool Sema::IsOpenMPCapturedVar(VarDecl *VD, bool &PropagateCapture) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); VD = VD->getCanonicalDecl(); if (DSAStack->getCurrentDirective() != OMPD_unknown) { @@ -660,6 +671,14 @@ auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return true; + + if (getLangOpts().OpenMPUseTLS && + getASTContext().getTargetInfo().isTLSSupported() && + !DSAStack->isClauseParsingMode() && + DSAStack->isCopyinVariable(VD)) { + PropagateCapture = false; + return true; + } DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), DSAStack->isClauseParsingMode()); return DVarPrivate.CKind != OMPC_unknown; @@ -667,10 +686,11 @@ return false; } -bool Sema::isOpenMPPrivateVar(VarDecl *VD, unsigned Level) { +bool Sema::isOpenMPPrivateOrCopyinVar(VarDecl *VD, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); - return DSAStack->hasExplicitDSA( - VD, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); + return DSAStack->hasExplicitDSA(VD, [](OpenMPClauseKind K) -> bool { + return K == OMPC_private || K == OMPC_copyin; + }, Level); } void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } @@ -1145,7 +1165,8 @@ }; } // namespace -void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { +void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope, + ArrayRef Clauses) { switch (DKind) { case OMPD_parallel: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); @@ -1340,6 +1361,19 @@ case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } + + // Make sure we capture the declarations used in 'copyin' clause. We can only + // do this after the captured region is created. We need to try to captured + // those declaration even if they do not have any use in the captured region. + if (isOpenMPParallelDirective(DKind)) { + for (auto *C : Clauses) + if (OMPCopyinClause *CI = dyn_cast(C)) + for (auto *Expr : CI->varlists()) { + DeclRefExpr *DE = cast(Expr); + tryCaptureVariable(cast(DE->getDecl()), DE->getLocation(), + TryCapture_Implicit); + } + } } StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, Index: lib/Sema/TreeTransform.h =================================================================== --- lib/Sema/TreeTransform.h +++ lib/Sema/TreeTransform.h @@ -6849,7 +6849,8 @@ return StmtError(); } getDerived().getSema().ActOnOpenMPRegionStart(D->getDirectiveKind(), - /*CurScope=*/nullptr); + /*CurScope=*/nullptr, + Clauses); StmtResult Body; { Sema::CompoundScopeRAII CompoundScope(getSema());