From c6ad97a3e7bf1d38e1f73f8351695aa833f10c69 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Fri, 1 Apr 2016 09:23:34 +0000 Subject: [PATCH] [OPENMP 4.5] Allow data members as loop counters in loop-based directives. OpenMP 4.5 allows privatization of non-static data members in non-static member functions. Patch allows to use and implicit privatization of data members used as counters in loop-based directives. llvm-svn: 265121 --- clang/lib/Sema/SemaOpenMP.cpp | 393 ++++++++++-------- clang/test/OpenMP/for_lastprivate_codegen.cpp | 60 +++ 2 files changed, 288 insertions(+), 165 deletions(-) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 3c50eec3a671..bb0a9caa7ac9 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -90,7 +90,8 @@ private: }; typedef llvm::DenseMap DeclSAMapTy; typedef llvm::DenseMap AlignedMapTy; - typedef llvm::DenseMap LoopControlVariablesMapTy; + typedef std::pair LCDeclInfo; + typedef llvm::DenseMap LoopControlVariablesMapTy; typedef llvm::DenseMap MappedDeclsTy; typedef llvm::StringMap> CriticalsWithHintsTy; @@ -183,17 +184,17 @@ public: Expr *addUniqueAligned(ValueDecl *D, Expr *NewDE); /// \brief Register specified variable as loop control variable. - void addLoopControlVariable(ValueDecl *D); + void addLoopControlVariable(ValueDecl *D, VarDecl *Capture); /// \brief Check if the specified variable is a loop control variable for /// current region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). - unsigned isLoopControlVariable(ValueDecl *D); + LCDeclInfo isLoopControlVariable(ValueDecl *D); /// \brief Check if the specified variable is a loop control variable for /// parent region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). - unsigned isParentLoopControlVariable(ValueDecl *D); + LCDeclInfo isParentLoopControlVariable(ValueDecl *D); /// \brief Get the loop control variable for the I-th loop (or nullptr) in /// parent directive. ValueDecl *getParentLoopControlVariable(unsigned I); @@ -522,24 +523,26 @@ Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) { return nullptr; } -void DSAStackTy::addLoopControlVariable(ValueDecl *D) { +void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - Stack.back().LCVMap.insert(std::make_pair(D, Stack.back().LCVMap.size() + 1)); + Stack.back().LCVMap.insert( + std::make_pair(D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture))); } -unsigned DSAStackTy::isLoopControlVariable(ValueDecl *D) { +DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); - return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] : 0; + return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] + : LCDeclInfo(0, nullptr); } -unsigned DSAStackTy::isParentLoopControlVariable(ValueDecl *D) { +DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) { assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); D = getCanonicalDecl(D); return Stack[Stack.size() - 2].LCVMap.count(D) > 0 ? Stack[Stack.size() - 2].LCVMap[D] - : 0; + : LCDeclInfo(0, nullptr); } ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { @@ -547,7 +550,7 @@ ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { if (Stack[Stack.size() - 2].LCVMap.size() < I) return nullptr; for (auto &Pair : Stack[Stack.size() - 2].LCVMap) { - if (Pair.second == I) + if (Pair.second.first == I) return Pair.first; } return nullptr; @@ -928,11 +931,12 @@ VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { if (DSAStack->getCurrentDirective() != OMPD_unknown && (!DSAStack->isClauseParsingMode() || DSAStack->getParentDirective() != OMPD_unknown)) { - if (DSAStack->isLoopControlVariable(D) || + auto &&Info = DSAStack->isLoopControlVariable(D); + if (Info.first || (VD && VD->hasLocalStorage() && isParallelOrTaskRegion(DSAStack->getCurrentDirective())) || (VD && DSAStack->isForceVarCapturing())) - return VD; + return VD ? VD : Info.second; auto DVarPrivate = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return VD ? VD : cast(DVarPrivate.PrivateCopy->getDecl()); @@ -3242,33 +3246,29 @@ class OpenMPIterationSpaceChecker { /// \brief A source location for referring to increment later. SourceRange IncrementSrcRange; /// \brief Loop variable. - VarDecl *Var; + ValueDecl *LCDecl = nullptr; /// \brief Reference to loop variable. - DeclRefExpr *VarRef; + Expr *LCRef = nullptr; /// \brief Lower bound (initializer for the var). - Expr *LB; + Expr *LB = nullptr; /// \brief Upper bound. - Expr *UB; + Expr *UB = nullptr; /// \brief Loop step (increment). - Expr *Step; + Expr *Step = nullptr; /// \brief This flag is true when condition is one of: /// Var < UB /// Var <= UB /// UB > Var /// UB >= Var - bool TestIsLessOp; + bool TestIsLessOp = false; /// \brief This flag is true when condition is strict ( < or > ). - bool TestIsStrictOp; + bool TestIsStrictOp = false; /// \brief This flag is true when step is subtracted on each iteration. - bool SubtractStep; + bool SubtractStep = false; public: OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) - : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), - InitSrcRange(SourceRange()), ConditionSrcRange(SourceRange()), - IncrementSrcRange(SourceRange()), Var(nullptr), VarRef(nullptr), - LB(nullptr), UB(nullptr), Step(nullptr), TestIsLessOp(false), - TestIsStrictOp(false), SubtractStep(false) {} + : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {} /// \brief Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool CheckInit(Stmt *S, bool EmitDiags = true); @@ -3279,9 +3279,9 @@ public: /// does not conform, otherwise save loop step (#Step). bool CheckInc(Expr *S); /// \brief Return the loop counter variable. - VarDecl *GetLoopVar() const { return Var; } + ValueDecl *GetLoopDecl() const { return LCDecl; } /// \brief Return the reference expression to loop counter variable. - DeclRefExpr *GetLoopVarRefExpr() const { return VarRef; } + Expr *GetLoopDeclRefExpr() const { return LCRef; } /// \brief Source range of the loop init. SourceRange GetInitSrcRange() const { return InitSrcRange; } /// \brief Source range of the loop condition. @@ -3298,7 +3298,8 @@ public: Expr *BuildPreCond(Scope *S, Expr *Cond, llvm::MapVector &Captures) const; /// \brief Build reference expression to the counter be used for codegen. - Expr *BuildCounterVar() const; + DeclRefExpr * + BuildCounterVar(llvm::MapVector &Captures) const; /// \brief Build reference expression to the private counter be used for /// codegen. Expr *BuildPrivateCounterVar() const; @@ -3314,7 +3315,7 @@ private: /// expression. bool CheckIncRHS(Expr *RHS); /// \brief Helper to set loop counter variable and its initializer. - bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB); + bool SetLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB); /// \brief Helper to set upper bound. bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); @@ -3323,16 +3324,16 @@ private: }; bool OpenMPIterationSpaceChecker::Dependent() const { - if (!Var) { + if (!LCDecl) { assert(!LB && !UB && !Step); return false; } - return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) || - (UB && UB->isValueDependent()) || (Step && Step->isValueDependent()); + return LCDecl->getType()->isDependentType() || + (LB && LB->isValueDependent()) || (UB && UB->isValueDependent()) || + (Step && Step->isValueDependent()); } -template -static T *getExprAsWritten(T *E) { +static Expr *getExprAsWritten(Expr *E) { if (auto *ExprTemp = dyn_cast(E)) E = ExprTemp->getSubExpr(); @@ -3347,16 +3348,16 @@ static T *getExprAsWritten(T *E) { return E->IgnoreParens(); } -bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, - DeclRefExpr *NewVarRefExpr, - Expr *NewLB) { +bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl, + Expr *NewLCRefExpr, + Expr *NewLB) { // State consistency checking to ensure correct usage. - assert(Var == nullptr && LB == nullptr && VarRef == nullptr && + assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); - if (!NewVar || !NewLB) + if (!NewLCDecl || !NewLB) return true; - Var = NewVar; - VarRef = NewVarRefExpr; + LCDecl = getCanonicalDecl(NewLCDecl); + LCRef = NewLCRefExpr; if (auto *CE = dyn_cast_or_null(NewLB)) if (const CXXConstructorDecl *Ctor = CE->getConstructor()) if ((Ctor->isCopyOrMoveConstructor() || @@ -3370,8 +3371,8 @@ bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. - assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && - !TestIsLessOp && !TestIsStrictOp); + assert(LCDecl != nullptr && LB != nullptr && UB == nullptr && + Step == nullptr && !TestIsLessOp && !TestIsStrictOp); if (!NewUB) return true; UB = NewUB; @@ -3384,7 +3385,7 @@ bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { // State consistency checking to ensure correct usage. - assert(Var != nullptr && LB != nullptr && Step == nullptr); + assert(LCDecl != nullptr && LB != nullptr && Step == nullptr); if (!NewStep) return true; if (!NewStep->isValueDependent()) { @@ -3420,7 +3421,7 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { : (IsConstPos || (IsUnsigned && !Subtract))))) { SemaRef.Diag(NewStep->getExprLoc(), diag::err_omp_loop_incr_not_compatible) - << Var << TestIsLessOp << NewStep->getSourceRange(); + << LCDecl << TestIsLessOp << NewStep->getSourceRange(); SemaRef.Diag(ConditionLoc, diag::note_omp_loop_cond_requres_compatible_incr) << TestIsLessOp << ConditionSrcRange; @@ -3457,10 +3458,20 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { if (Expr *E = dyn_cast(S)) S = E->IgnoreParens(); if (auto BO = dyn_cast(S)) { - if (BO->getOpcode() == BO_Assign) - if (auto DRE = dyn_cast(BO->getLHS()->IgnoreParens())) - return SetVarAndLB(dyn_cast(DRE->getDecl()), DRE, - BO->getRHS()); + if (BO->getOpcode() == BO_Assign) { + auto *LHS = BO->getLHS()->IgnoreParens(); + if (auto *DRE = dyn_cast(LHS)) { + if (auto *CED = dyn_cast(DRE->getDecl())) + if (auto *ME = dyn_cast(getExprAsWritten(CED->getInit()))) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return SetLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS()); + } + if (auto *ME = dyn_cast(LHS)) { + if (ME->isArrow() && + isa(ME->getBase()->IgnoreParenImpCasts())) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + } + } } else if (auto DS = dyn_cast(S)) { if (DS->isSingleDecl()) { if (auto Var = dyn_cast_or_null(DS->getSingleDecl())) { @@ -3470,16 +3481,29 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::ext_omp_loop_not_canonical_init) << S->getSourceRange(); - return SetVarAndLB(Var, nullptr, Var->getInit()); + return SetLCDeclAndLB(Var, nullptr, Var->getInit()); } } } - } else if (auto CE = dyn_cast(S)) - if (CE->getOperator() == OO_Equal) - if (auto DRE = dyn_cast(CE->getArg(0))) - return SetVarAndLB(dyn_cast(DRE->getDecl()), DRE, - CE->getArg(1)); + } else if (auto CE = dyn_cast(S)) { + if (CE->getOperator() == OO_Equal) { + auto *LHS = CE->getArg(0); + if (auto DRE = dyn_cast(LHS)) { + if (auto *CED = dyn_cast(DRE->getDecl())) + if (auto *ME = dyn_cast(getExprAsWritten(CED->getInit()))) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return SetLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1)); + } + if (auto *ME = dyn_cast(LHS)) { + if (ME->isArrow() && + isa(ME->getBase()->IgnoreParenImpCasts())) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + } + } + } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; if (EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) << S->getSourceRange(); @@ -3489,7 +3513,7 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { /// \brief Ignore parenthesizes, implicit casts, copy constructor and return the /// variable (which may be the loop variable) if possible. -static const VarDecl *GetInitVarDecl(const Expr *E) { +static const ValueDecl *GetInitLCDecl(Expr *E) { if (!E) return nullptr; E = getExprAsWritten(E); @@ -3499,10 +3523,18 @@ static const VarDecl *GetInitVarDecl(const Expr *E) { Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) && CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) E = CE->getArg(0)->IgnoreParenImpCasts(); - auto DRE = dyn_cast_or_null(E); - if (!DRE) - return nullptr; - return dyn_cast(DRE->getDecl()); + if (auto *DRE = dyn_cast_or_null(E)) { + if (auto *VD = dyn_cast(DRE->getDecl())) { + if (auto *CED = dyn_cast(VD)) + if (auto *ME = dyn_cast(getExprAsWritten(CED->getInit()))) + return getCanonicalDecl(ME->getMemberDecl()); + return getCanonicalDecl(VD); + } + } + if (auto *ME = dyn_cast_or_null(E)) + if (ME->isArrow() && isa(ME->getBase()->IgnoreParenImpCasts())) + return getCanonicalDecl(ME->getMemberDecl()); + return nullptr; } bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { @@ -3513,19 +3545,19 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { // b relational-op var // if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl; return true; } S = getExprAsWritten(S); SourceLocation CondLoc = S->getLocStart(); if (auto BO = dyn_cast(S)) { if (BO->isRelationalOp()) { - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetUB(BO->getRHS(), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); - if (GetInitVarDecl(BO->getRHS()) == Var) + if (GetInitLCDecl(BO->getRHS()) == LCDecl) return SetUB(BO->getLHS(), (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), @@ -3539,11 +3571,11 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { case OO_GreaterEqual: case OO_Less: case OO_LessEqual: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); - if (GetInitVarDecl(CE->getArg(1)) == Var) + if (GetInitLCDecl(CE->getArg(1)) == LCDecl) return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); @@ -3553,8 +3585,10 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { } } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) - << S->getSourceRange() << Var; + << S->getSourceRange() << LCDecl; return true; } @@ -3568,22 +3602,24 @@ bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { if (auto BO = dyn_cast(RHS)) { if (BO->isAdditiveOp()) { bool IsAdd = BO->getOpcode() == BO_Add; - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetStep(BO->getRHS(), !IsAdd); - if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var) + if (IsAdd && GetInitLCDecl(BO->getRHS()) == LCDecl) return SetStep(BO->getLHS(), false); } } else if (auto CE = dyn_cast(RHS)) { bool IsAdd = CE->getOperator() == OO_Plus; if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep(CE->getArg(1), !IsAdd); - if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var) + if (IsAdd && GetInitLCDecl(CE->getArg(1)) == LCDecl) return SetStep(CE->getArg(0), false); } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) - << RHS->getSourceRange() << Var; + << RHS->getSourceRange() << LCDecl; return true; } @@ -3602,13 +3638,14 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { // var = var - incr // if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << LCDecl; return true; } IncrementSrcRange = S->getSourceRange(); S = S->IgnoreParens(); if (auto UO = dyn_cast(S)) { - if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var) + if (UO->isIncrementDecrementOp() && + GetInitLCDecl(UO->getSubExpr()) == LCDecl) return SetStep( SemaRef.ActOnIntegerConstant(UO->getLocStart(), (UO->isDecrementOp() ? -1 : 1)).get(), @@ -3617,11 +3654,11 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { switch (BO->getOpcode()) { case BO_AddAssign: case BO_SubAssign: - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); break; case BO_Assign: - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return CheckIncRHS(BO->getRHS()); break; default: @@ -3631,7 +3668,7 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { switch (CE->getOperator()) { case OO_PlusPlus: case OO_MinusMinus: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep( SemaRef.ActOnIntegerConstant( CE->getLocStart(), @@ -3640,19 +3677,21 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { break; case OO_PlusEqual: case OO_MinusEqual: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); break; case OO_Equal: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return CheckIncRHS(CE->getArg(1)); break; default: break; } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) - << S->getSourceRange() << Var; + << S->getSourceRange() << LCDecl; return true; } @@ -3677,7 +3716,7 @@ Expr *OpenMPIterationSpaceChecker::BuildNumIterations( Scope *S, const bool LimitedType, llvm::MapVector &Captures) const { ExprResult Diff; - auto VarType = Var->getType().getNonReferenceType(); + auto VarType = LCDecl->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { // Upper - Lower @@ -3798,17 +3837,26 @@ Expr *OpenMPIterationSpaceChecker::BuildPreCond( } /// \brief Build reference expression to the counter be used for codegen. -Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const { - return buildDeclRefExpr(SemaRef, Var, Var->getType().getNonReferenceType(), +DeclRefExpr *OpenMPIterationSpaceChecker::BuildCounterVar( + llvm::MapVector &Captures) const { + auto *VD = dyn_cast(LCDecl); + if (!VD) { + VD = SemaRef.IsOpenMPCapturedDecl(LCDecl); + auto *Ref = buildDeclRefExpr( + SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); + Captures.insert(std::make_pair(LCRef, Ref)); + return Ref; + } + return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); } Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { - if (Var && !Var->isInvalidDecl()) { - auto Type = Var->getType().getNonReferenceType(); + if (LCDecl && !LCDecl->isInvalidDecl()) { + auto Type = LCDecl->getType().getNonReferenceType(); auto *PrivateVar = - buildVarDecl(SemaRef, DefaultLoc, Type, Var->getName(), - Var->hasAttrs() ? &Var->getAttrs() : nullptr); + buildVarDecl(SemaRef, DefaultLoc, Type, LCDecl->getName(), + LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr); if (PrivateVar->isInvalidDecl()) return nullptr; return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc); @@ -3857,8 +3905,21 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { OpenMPIterationSpaceChecker ISC(*this, ForLoc); - if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) - DSAStack->addLoopControlVariable(ISC.GetLoopVar()); + if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) { + if (auto *D = ISC.GetLoopDecl()) { + auto *VD = dyn_cast(D); + if (!VD) { + if (auto *Private = IsOpenMPCapturedDecl(D)) + VD = Private; + else { + auto *Ref = buildCapture(*this, D, ISC.GetLoopDeclRefExpr(), + /*WithInit=*/false); + VD = cast(Ref->getDecl()); + } + } + DSAStack->addLoopControlVariable(D, VD); + } + } DSAStack->setAssociatedLoops(AssociatedLoops - 1); } } @@ -3903,88 +3964,89 @@ static bool CheckOpenMPIterationSpace( // Check init. auto Init = For->getInit(); - if (ISC.CheckInit(Init)) { + if (ISC.CheckInit(Init)) return true; - } bool HasErrors = false; // Check loop variable's type. - auto Var = ISC.GetLoopVar(); + if (auto *LCDecl = ISC.GetLoopDecl()) { + auto *LoopDeclRefExpr = ISC.GetLoopDeclRefExpr(); - // OpenMP [2.6, Canonical Loop Form] - // Var is one of the following: - // A variable of signed or unsigned integer type. - // For C++, a variable of a random access iterator type. - // For C, a variable of a pointer type. - auto VarType = Var->getType().getNonReferenceType(); - if (!VarType->isDependentType() && !VarType->isIntegerType() && - !VarType->isPointerType() && - !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { - SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) - << SemaRef.getLangOpts().CPlusPlus; - HasErrors = true; + // OpenMP [2.6, Canonical Loop Form] + // Var is one of the following: + // A variable of signed or unsigned integer type. + // For C++, a variable of a random access iterator type. + // For C, a variable of a pointer type. + auto VarType = LCDecl->getType().getNonReferenceType(); + if (!VarType->isDependentType() && !VarType->isIntegerType() && + !VarType->isPointerType() && + !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { + SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) + << SemaRef.getLangOpts().CPlusPlus; + HasErrors = true; + } + + // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in + // a Construct + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct is (are) private. + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop is linear with a + // constant-linear-step that is the increment of the associated for-loop. + // Exclude loop var from the list of variables with implicitly defined data + // sharing attributes. + VarsWithImplicitDSA.erase(LCDecl); + + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++]. + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop may be listed in a linear + // clause with a constant-linear-step that is the increment of the + // associated for-loop. + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct may be listed in a private or lastprivate clause. + DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false); + // If LoopVarRefExpr is nullptr it means the corresponding loop variable is + // declared in the loop and it is predetermined as a private. + auto PredeterminedCKind = + isOpenMPSimdDirective(DKind) + ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) + : OMPC_private; + if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != PredeterminedCKind) || + ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || + isOpenMPDistributeDirective(DKind)) && + !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && + (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { + SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) + << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(PredeterminedCKind); + if (DVar.RefExpr == nullptr) + DVar.CKind = PredeterminedCKind; + ReportOriginalDSA(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); + HasErrors = true; + } else if (LoopDeclRefExpr != nullptr) { + // Make the loop iteration variable private (for worksharing constructs), + // linear (for simd directives with the only one associated loop) or + // lastprivate (for simd directives with several collapsed or ordered + // loops). + if (DVar.CKind == OMPC_unknown) + DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate, MatchesAlways(), + /*FromParent=*/false); + DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); + } + + assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); + + // Check test-expr. + HasErrors |= ISC.CheckCond(For->getCond()); + + // Check incr-expr. + HasErrors |= ISC.CheckInc(For->getInc()); } - // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in a - // Construct - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct is (are) private. - // The loop iteration variable in the associated for-loop of a simd construct - // with just one associated for-loop is linear with a constant-linear-step - // that is the increment of the associated for-loop. - // Exclude loop var from the list of variables with implicitly defined data - // sharing attributes. - VarsWithImplicitDSA.erase(Var); - - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in - // a Construct, C/C++]. - // The loop iteration variable in the associated for-loop of a simd construct - // with just one associated for-loop may be listed in a linear clause with a - // constant-linear-step that is the increment of the associated for-loop. - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct may be listed in a private or lastprivate clause. - DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false); - auto LoopVarRefExpr = ISC.GetLoopVarRefExpr(); - // If LoopVarRefExpr is nullptr it means the corresponding loop variable is - // declared in the loop and it is predetermined as a private. - auto PredeterminedCKind = - isOpenMPSimdDirective(DKind) - ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) - : OMPC_private; - if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != PredeterminedCKind) || - ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || - isOpenMPDistributeDirective(DKind)) && - !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && - (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { - SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) - << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) - << getOpenMPClauseName(PredeterminedCKind); - if (DVar.RefExpr == nullptr) - DVar.CKind = PredeterminedCKind; - ReportOriginalDSA(SemaRef, &DSA, Var, DVar, /*IsLoopIterVar=*/true); - HasErrors = true; - } else if (LoopVarRefExpr != nullptr) { - // Make the loop iteration variable private (for worksharing constructs), - // linear (for simd directives with the only one associated loop) or - // lastprivate (for simd directives with several collapsed or ordered - // loops). - if (DVar.CKind == OMPC_unknown) - DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(), - /*FromParent=*/false); - DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind); - } - - assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); - - // Check test-expr. - HasErrors |= ISC.CheckCond(For->getCond()); - - // Check incr-expr. - HasErrors |= ISC.CheckInc(For->getInc()); - if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; @@ -3996,7 +4058,7 @@ static bool CheckOpenMPIterationSpace( (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), Captures); - ResultIterSpace.CounterVar = ISC.BuildCounterVar(); + ResultIterSpace.CounterVar = ISC.BuildCounterVar(Captures); ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar(); ResultIterSpace.CounterInit = ISC.BuildCounterInit(); ResultIterSpace.CounterStep = ISC.BuildCounterStep(); @@ -9112,7 +9174,8 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, auto *VD = dyn_cast(DE->getDecl()); if (!CurContext->isDependentContext() && DSAStack->getParentOrderedRegionParam() && - (!VD || DepCounter != DSAStack->isParentLoopControlVariable(VD))) { + (!VD || + DepCounter != DSAStack->isParentLoopControlVariable(VD).first)) { Diag(DE->getExprLoc(), diag::err_omp_depend_sink_expected_loop_iteration) << DSAStack->getParentLoopControlVariable( diff --git a/clang/test/OpenMP/for_lastprivate_codegen.cpp b/clang/test/OpenMP/for_lastprivate_codegen.cpp index 2ddd06aaeff5..f9a2bccdca85 100644 --- a/clang/test/OpenMP/for_lastprivate_codegen.cpp +++ b/clang/test/OpenMP/for_lastprivate_codegen.cpp @@ -36,6 +36,29 @@ struct SS { }(); #else ++this->a, --b, c /= 1; +#endif +#pragma omp for + for (a = 0; a < 2; ++a) +#ifdef LAMBDA + [&]() { + ++this->a, --b, (this)->c /= 1; +#pragma omp parallel +#pragma omp for lastprivate(b) + for (b = 0; b < 2; ++b) + ++(this)->a, --b, this->c /= 1; + }(); +#elif defined(BLOCKS) + ^{ + ++a; + --this->b; + (this)->c /= 1; +#pragma omp parallel +#pragma omp for + for (c = 0; c < 2; ++c) + ++(this)->a, --b, this->c /= 1; + }(); +#else + ++this->a, --b, c /= 1; #endif } }; @@ -69,6 +92,27 @@ struct SST { }(); #else ++(this)->a; +#endif +#pragma omp for + for (a = 0; a < 2; ++a) +#ifdef LAMBDA + [&]() { + ++this->a; +#pragma omp parallel +#pragma omp for + for (a = 0; a < 2; ++(this)->a) + ++(this)->a; + }(); +#elif defined(BLOCKS) + ^{ + ++a; +#pragma omp parallel +#pragma omp for + for (this->a = 0; a < 2; ++a) + ++(this)->a; + }(); +#else + ++(this)->a; #endif } }; @@ -144,6 +188,11 @@ int main() { // LAMBDA: store i8 // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 // LAMBDA: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void + // LAMBDA: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 + // LAMBDA: call void @__kmpc_for_static_init_4( + // LAMBDA-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 + // LAMBDA: call void {{.+}} [[SS_LAMBDA:@[^ ]+]] + // LAMBDA: call void @__kmpc_for_static_fini(% // LAMBDA: ret // LAMBDA: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}) @@ -322,6 +371,11 @@ int main() { // BLOCKS: store i8 // BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 // BLOCKS: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void +// BLOCKS: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// BLOCKS: call void @__kmpc_for_static_init_4( +// BLOCKS-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// BLOCKS: call void +// BLOCKS: call void @__kmpc_for_static_fini(% // BLOCKS: ret // BLOCKS: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}}) @@ -596,6 +650,12 @@ int main() { // CHECK: store i8 // CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 // CHECK: call void (%{{.+}}*, i{{[0-9]+}}, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)*, ...) @__kmpc_fork_call(%{{.+}}* @{{.+}}, i{{[0-9]+}} 1, void (i{{[0-9]+}}*, i{{[0-9]+}}*, ...)* bitcast (void (i{{[0-9]+}}*, i{{[0-9]+}}*, [[SS_TY]]*)* [[SS_MICROTASK:@.+]] to void +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// CHECK: call void @__kmpc_for_static_init_4( +// CHECK-NOT: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 0 +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 1 +// CHECK: getelementptr inbounds [[SS_TY]], [[SS_TY]]* %{{.+}}, i32 0, i32 2 +// CHECK: call void @__kmpc_for_static_fini(% // CHECK: ret // CHECK: define internal void [[SS_MICROTASK]](i{{[0-9]+}}* noalias [[GTID_ADDR:%.+]], i{{[0-9]+}}* noalias %{{.+}}, [[SS_TY]]* %{{.+}})