diff options
author | dim <dim@FreeBSD.org> | 2015-05-27 20:44:45 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2015-05-27 20:44:45 +0000 |
commit | fae9061769fe2114f1a7875c781cc369ff303a11 (patch) | |
tree | 50a603f7e1932cd42f58e26687ce907933014db0 /contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp | |
parent | 5ef8fd3549d38e883a31881636be3dc2a275de20 (diff) | |
parent | 3191b2b32a96e1a6ee833fcca73e5c8e0c67ba65 (diff) | |
download | FreeBSD-src-fae9061769fe2114f1a7875c781cc369ff303a11.zip FreeBSD-src-fae9061769fe2114f1a7875c781cc369ff303a11.tar.gz |
Merge clang trunk r238337 from ^/vendor/clang/dist, resolve conflicts,
and preserve our customizations, where necessary.
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp | 1666 |
1 files changed, 1272 insertions, 394 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index d72942a..cfe8db3 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -82,10 +82,12 @@ private: }; typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy; typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy; + typedef llvm::DenseSet<VarDecl *> LoopControlVariablesSetTy; struct SharingMapTy { DeclSAMapTy SharingMap; AlignedMapTy AlignedMap; + LoopControlVariablesSetTy LCVSet; DefaultDataSharingAttributes DefaultAttr; SourceLocation DefaultAttrLoc; OpenMPDirectiveKind Directive; @@ -93,22 +95,28 @@ private: Scope *CurScope; SourceLocation ConstructLoc; bool OrderedRegion; + unsigned CollapseNumber; SourceLocation InnerTeamsRegionLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) - : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), + : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified), Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), - ConstructLoc(Loc), OrderedRegion(false), InnerTeamsRegionLoc() {} + ConstructLoc(Loc), OrderedRegion(false), CollapseNumber(1), + InnerTeamsRegionLoc() {} SharingMapTy() - : SharingMap(), AlignedMap(), DefaultAttr(DSA_unspecified), + : SharingMap(), AlignedMap(), LCVSet(), DefaultAttr(DSA_unspecified), Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), - ConstructLoc(), OrderedRegion(false), InnerTeamsRegionLoc() {} + ConstructLoc(), OrderedRegion(false), CollapseNumber(1), + InnerTeamsRegionLoc() {} }; typedef SmallVector<SharingMapTy, 64> StackTy; /// \brief Stack of used declaration and their data-sharing attributes. StackTy Stack; + /// \brief true, if check for DSA must be from parent directive, false, if + /// from current directive. + bool FromParent; Sema &SemaRef; typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator; @@ -119,7 +127,10 @@ private: bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); public: - explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {} + explicit DSAStackTy(Sema &S) : Stack(1), FromParent(false), SemaRef(S) {} + + bool isFromParent() const { return FromParent; } + void setFromParent(bool Flag) { FromParent = Flag; } void push(OpenMPDirectiveKind DKind, const DeclarationNameInfo &DirName, Scope *CurScope, SourceLocation Loc) { @@ -137,6 +148,12 @@ public: /// for diagnostics. DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE); + /// \brief Register specified variable as loop control variable. + void addLoopControlVariable(VarDecl *D); + /// \brief Check if the specified variable is a loop control variable for + /// current region. + bool isLoopControlVariable(VarDecl *D); + /// \brief Adds explicit data sharing attribute to the specified declaration. void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); @@ -209,6 +226,13 @@ public: return false; } + /// \brief Set collapse value for the region. + void setCollapseNumber(unsigned Val) { Stack.back().CollapseNumber = Val; } + /// \brief Return collapse value for region. + unsigned getCollapseNumber() const { + return Stack.back().CollapseNumber; + } + /// \brief Marks current target region as one with closely nested teams /// region. void setParentTeamsRegionLoc(SourceLocation TeamsRegionLoc) { @@ -238,6 +262,7 @@ bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, VarDecl *D) { + D = D->getCanonicalDecl(); DSAVarData DVar; if (Iter == std::prev(Stack.rend())) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -308,8 +333,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // bound to the current team is shared. if (DVar.DKind == OMPD_task) { DSAVarData DVarTemp; - for (StackTy::reverse_iterator I = std::next(Iter), - EE = std::prev(Stack.rend()); + for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend(); I != EE; ++I) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables // Referenced @@ -343,6 +367,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); + D = D->getCanonicalDecl(); auto It = Stack.back().AlignedMap.find(D); if (It == Stack.back().AlignedMap.end()) { assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); @@ -355,7 +380,20 @@ DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { return nullptr; } +void DSAStackTy::addLoopControlVariable(VarDecl *D) { + assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); + D = D->getCanonicalDecl(); + Stack.back().LCVSet.insert(D); +} + +bool DSAStackTy::isLoopControlVariable(VarDecl *D) { + assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); + D = D->getCanonicalDecl(); + return Stack.back().LCVSet.count(D) > 0; +} + void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { + D = D->getCanonicalDecl(); if (A == OMPC_threadprivate) { Stack[0].SharingMap[D].Attributes = A; Stack[0].SharingMap[D].RefExpr = E; @@ -367,6 +405,7 @@ void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { } bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { + D = D->getCanonicalDecl(); if (Stack.size() > 2) { reverse_iterator I = Iter, E = std::prev(Stack.rend()); Scope *TopScope = nullptr; @@ -385,16 +424,41 @@ bool DSAStackTy::isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter) { return false; } +/// \brief Build a variable declaration for OpenMP loop iteration variable. +static VarDecl *buildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, + StringRef Name) { + DeclContext *DC = SemaRef.CurContext; + IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); + TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); + VarDecl *Decl = + VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); + Decl->setImplicit(); + return Decl; +} + +static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty, + SourceLocation Loc, + bool RefersToCapture = false) { + D->setReferenced(); + D->markUsed(S.Context); + return DeclRefExpr::Create(S.getASTContext(), NestedNameSpecifierLoc(), + SourceLocation(), D, RefersToCapture, Loc, Ty, + VK_LValue); +} + DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { + D = D->getCanonicalDecl(); DSAVarData DVar; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. if (D->getTLSKind() != VarDecl::TLS_None || - D->getStorageClass() == SC_Register) { - DVar.CKind = OMPC_threadprivate; - return DVar; + (D->getStorageClass() == SC_Register && D->hasAttr<AsmLabelAttr>() && + !D->isLocalVarDecl())) { + addDSA(D, buildDeclRefExpr(SemaRef, D, D->getType().getNonReferenceType(), + D->getLocation()), + OMPC_threadprivate); } if (Stack[0].SharingMap.count(D)) { DVar.RefExpr = Stack[0].SharingMap[D].RefExpr; @@ -421,29 +485,28 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { DVar.CKind = OMPC_private; return DVar; } - } - // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++, predetermined, p.4] - // Static data members are shared. - if (D->isStaticDataMember()) { - // Variables with const-qualified type having no mutable member may be - // listed in a firstprivate clause, even if they are static data members. - DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate), - MatchesAlways(), FromParent); - if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) - return DVar; + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++, predetermined, p.4] + // Static data members are shared. + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++, predetermined, p.7] + // Variables with static storage duration that are declared in a scope + // inside the construct are shared. + if (D->isStaticDataMember() || D->isStaticLocal()) { + DSAVarData DVarTemp = + hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent); + if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) + return DVar; - DVar.CKind = OMPC_shared; - return DVar; + DVar.CKind = OMPC_shared; + return DVar; + } } QualType Type = D->getType().getNonReferenceType().getCanonicalType(); bool IsConstant = Type.isConstant(SemaRef.getASTContext()); - while (Type->isArrayType()) { - QualType ElemType = cast<ArrayType>(Type.getTypePtr())->getElementType(); - Type = ElemType.getNonReferenceType().getCanonicalType(); - } + Type = SemaRef.getASTContext().getBaseElementType(Type); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.6] // Variables with const qualified type having no mutable member are @@ -463,15 +526,6 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { return DVar; } - // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced - // in a Construct, C/C++, predetermined, p.7] - // Variables with static storage duration that are declared in a scope - // inside the construct are shared. - if (D->isStaticLocal()) { - DVar.CKind = OMPC_shared; - return DVar; - } - // Explicitly specified attributes and local variables with predetermined // attributes. auto I = std::prev(StartI); @@ -485,6 +539,7 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { } DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) { + D = D->getCanonicalDecl(); auto StartI = Stack.rbegin(); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { @@ -497,6 +552,7 @@ template <class ClausesPredicate, class DirectivesPredicate> DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred, DirectivesPredicate DPred, bool FromParent) { + D = D->getCanonicalDecl(); auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { @@ -516,6 +572,7 @@ template <class ClausesPredicate, class DirectivesPredicate> DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, DirectivesPredicate DPred, bool FromParent) { + D = D->getCanonicalDecl(); auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { @@ -554,12 +611,17 @@ void Sema::InitDataSharingAttributesStack() { bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); + VD = VD->getCanonicalDecl(); if (DSAStack->getCurrentDirective() != OMPD_unknown) { - auto DVarPrivate = DSAStack->getTopDSA(VD, /*FromParent=*/false); + if (DSAStack->isLoopControlVariable(VD) || + (VD->hasLocalStorage() && + isParallelOrTaskRegion(DSAStack->getCurrentDirective()))) + return true; + auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isFromParent()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) return true; DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), - /*FromParent=*/false); + DSAStack->isFromParent()); return DVarPrivate.CKind != OMPC_unknown; } return false; @@ -574,6 +636,14 @@ void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, PushExpressionEvaluationContext(PotentiallyEvaluated); } +void Sema::StartOpenMPClauses() { + DSAStack->setFromParent(/*Flag=*/true); +} + +void Sema::EndOpenMPClauses() { + DSAStack->setFromParent(/*Flag=*/false); +} + void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a lastprivate @@ -581,46 +651,41 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // class type, unless the list item is also specified in a firstprivate // clause. if (auto D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) { - for (auto C : D->clauses()) { - if (auto Clause = dyn_cast<OMPLastprivateClause>(C)) { - for (auto VarRef : Clause->varlists()) { - if (VarRef->isValueDependent() || VarRef->isTypeDependent()) + for (auto *C : D->clauses()) { + if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) { + SmallVector<Expr *, 8> PrivateCopies; + for (auto *DE : Clause->varlists()) { + if (DE->isValueDependent() || DE->isTypeDependent()) { + PrivateCopies.push_back(nullptr); continue; - auto VD = cast<VarDecl>(cast<DeclRefExpr>(VarRef)->getDecl()); + } + auto *VD = cast<VarDecl>(cast<DeclRefExpr>(DE)->getDecl()); + QualType Type = VD->getType(); auto DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_lastprivate) { - SourceLocation ELoc = VarRef->getExprLoc(); - auto Type = VarRef->getType(); - if (Type->isArrayType()) - Type = QualType(Type->getArrayElementTypeNoTypeQual(), 0); - CXXRecordDecl *RD = - getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; - // FIXME This code must be replaced by actual constructing of the - // lastprivate variable. - if (RD) { - CXXConstructorDecl *CD = LookupDefaultConstructor(RD); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess( - ELoc, CD, InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_lastprivate) << 0; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), IsDecl ? diag::note_previous_decl - : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, CD); - DiagnoseUseOfDecl(CD, ELoc); - } + // Generate helper private variable and initialize it with the + // default value. The address of the original variable is replaced + // by the address of the new private variable in CodeGen. This new + // variable is not added to IdResolver, so the code in the OpenMP + // region uses original variable for proper diagnostics. + auto *VDPrivate = + buildVarDecl(*this, DE->getExprLoc(), Type.getUnqualifiedType(), + VD->getName()); + ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); + if (VDPrivate->isInvalidDecl()) + continue; + PrivateCopies.push_back(buildDeclRefExpr( + *this, VDPrivate, DE->getType(), DE->getExprLoc())); + } else { + // The variable is also a firstprivate, so initialization sequence + // for private copy is generated already. + PrivateCopies.push_back(nullptr); } } + // Set initializers to private copies if no errors were found. + if (PrivateCopies.size() == Clause->varlist_size()) { + Clause->setPrivateCopies(PrivateCopies); + } } } } @@ -630,6 +695,10 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { PopExpressionEvaluationContext(); } +static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, + Expr *NumIterations, Sema &SemaRef, + Scope *S); + namespace { class VarDeclFilterCCC : public CorrectionCandidateCallback { @@ -763,14 +832,14 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, // OpenMP [2.9.2, Restrictions, C/C++, p.2-6] // A threadprivate directive must lexically precede all references to any // of the variables in its list. - if (VD->isUsed()) { + if (VD->isUsed() && !DSAStack->isThreadPrivate(VD)) { Diag(Id.getLoc(), diag::err_omp_var_used) << getOpenMPDirectiveName(OMPD_threadprivate) << VD; return ExprError(); } QualType ExprType = VD->getType().getNonReferenceType(); - ExprResult DE = BuildDeclRefExpr(VD, ExprType, VK_LValue, Id.getLoc()); + ExprResult DE = buildDeclRefExpr(*this, VD, ExprType, Id.getLoc()); return DE; } @@ -821,6 +890,13 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { VarDecl *VD = cast<VarDecl>(DE->getDecl()); SourceLocation ILoc = DE->getExprLoc(); + QualType QType = VD->getType(); + if (QType->isDependentType() || QType->isInstantiationDependentType()) { + // It will be analyzed later. + Vars.push_back(DE); + continue; + } + // OpenMP [2.9.2, Restrictions, C/C++, p.10] // A threadprivate variable must not have an incomplete type. if (RequireCompleteType(ILoc, VD->getType(), @@ -843,7 +919,8 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { // Check if this is a TLS variable. if (VD->getTLSKind() != VarDecl::TLS_None || - VD->getStorageClass() == SC_Register) { + (VD->getStorageClass() == SC_Register && VD->hasAttr<AsmLabelAttr>() && + !VD->isLocalVarDecl())) { Diag(ILoc, diag::err_omp_var_thread_local) << VD << ((VD->getTLSKind() != VarDecl::TLS_None) ? 0 : 1); bool IsDecl = @@ -1121,7 +1198,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_parallel_sections: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty); Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32PtrTy), + std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -1129,11 +1210,28 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { break; } case OMPD_task: { + QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", KmpInt32Ty), + std::make_pair(".privates.", + Context.VoidPtrTy.withConst().withRestrict()), + std::make_pair( + ".copy_fn.", + Context.getPointerType(CopyFnType).withConst().withRestrict()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); break; } case OMPD_ordered: { @@ -1183,6 +1281,36 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } } +StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, + ArrayRef<OMPClause *> Clauses) { + if (!S.isUsable()) { + ActOnCapturedRegionError(); + return StmtError(); + } + // This is required for proper codegen. + for (auto *Clause : Clauses) { + if (isOpenMPPrivate(Clause->getClauseKind()) || + Clause->getClauseKind() == OMPC_copyprivate) { + // Mark all variables in private list clauses as used in inner region. + for (auto *VarRef : Clause->children()) { + if (auto *E = cast_or_null<Expr>(VarRef)) { + MarkDeclarationsReferencedInExpr(E); + } + } + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && + Clause->getClauseKind() == OMPC_schedule) { + // Mark all variables in private list clauses as used in inner region. + // Required for proper codegen of combined directives. + // TODO: add processing for other clauses. + if (auto *E = cast_or_null<Expr>( + cast<OMPScheduleClause>(Clause)->getHelperChunkSize())) { + MarkDeclarationsReferencedInExpr(E); + } + } + } + return ActOnCapturedRegionEnd(S.get()); +} + static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, OpenMPDirectiveKind CurrentRegion, const DeclarationNameInfo &CurrentName, @@ -1914,7 +2042,7 @@ public: TestIsStrictOp(false), SubtractStep(false) {} /// \brief Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. - bool CheckInit(Stmt *S); + bool CheckInit(Stmt *S, bool EmitDiags = true); /// \brief Check test-expr for canonical form, save upper-bound (#UB), flags /// for less/greater and for strict/non-strict comparison. bool CheckCond(Expr *S); @@ -1935,6 +2063,8 @@ public: bool ShouldSubtractStep() const { return SubtractStep; } /// \brief Build the expression to calculate the number of iterations. Expr *BuildNumIterations(Scope *S, const bool LimitedType) const; + /// \brief Build the precondition expression for the loops. + Expr *BuildPreCond(Scope *S, Expr *Cond) const; /// \brief Build reference expression to the counter be used for codegen. Expr *BuildCounterVar() const; /// \brief Build initization of the counter be used for codegen. @@ -2052,7 +2182,7 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { return false; } -bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { +bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { // Check init-expr for canonical loop form and save loop counter // variable - #Var and its initialization value - #LB. // OpenMP [2.6] Canonical loop form. init-expr may be one of the following: @@ -2062,7 +2192,9 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { // pointer-type var = lb // if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init); + if (EmitDiags) { + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_init); + } return true; } InitSrcRange = S->getSourceRange(); @@ -2078,7 +2210,7 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { if (Var->hasInit()) { // Accept non-canonical init form here but emit ext. warning. - if (Var->getInitStyle() != VarDecl::CInit) + if (Var->getInitStyle() != VarDecl::CInit && EmitDiags) SemaRef.Diag(S->getLocStart(), diag::ext_omp_loop_not_canonical_init) << S->getSourceRange(); @@ -2092,8 +2224,10 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S) { return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE, CE->getArg(1)); - SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) - << S->getSourceRange(); + if (EmitDiags) { + SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) + << S->getSourceRange(); + } return true; } @@ -2338,11 +2472,22 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, return Diff.get(); } +Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const { + // Try to build LB <op> UB, where <op> is <, >, <=, or >=. + bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); + SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + auto CondExpr = SemaRef.BuildBinOp( + S, DefaultLoc, TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE) + : (TestIsStrictOp ? BO_GT : BO_GE), + LB, UB); + SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); + // Otherwise use original loop conditon and evaluate it in runtime. + return CondExpr.isUsable() ? CondExpr.get() : Cond; +} + /// \brief Build reference expression to the counter be used for codegen. Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const { - return DeclRefExpr::Create(SemaRef.Context, NestedNameSpecifierLoc(), - GetIncrementSrcRange().getBegin(), Var, false, - DefaultLoc, Var->getType(), VK_LValue); + return buildDeclRefExpr(SemaRef, Var, Var->getType(), DefaultLoc); } /// \brief Build initization of the counter be used for codegen. @@ -2353,6 +2498,8 @@ Expr *OpenMPIterationSpaceChecker::BuildCounterStep() const { return Step; } /// \brief Iteration space of a single for loop. struct LoopIterationSpace { + /// \brief Condition of the loop. + Expr *PreCond; /// \brief This expression calculates the number of iterations in the loop. /// It is always possible to calculate it before starting the loop. Expr *NumIterations; @@ -2375,6 +2522,20 @@ struct LoopIterationSpace { } // namespace +void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { + assert(getLangOpts().OpenMP && "OpenMP is not active."); + assert(Init && "Expected loop in canonical form."); + unsigned CollapseIteration = DSAStack->getCollapseNumber(); + if (CollapseIteration > 0 && + isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { + OpenMPIterationSpaceChecker ISC(*this, ForLoc); + if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) { + DSAStack->addLoopControlVariable(ISC.GetLoopVar()); + } + DSAStack->setCollapseNumber(CollapseIteration - 1); + } +} + /// \brief Called on a for stmt to check and extract its iteration space /// for further processing (such as collapsing). static bool CheckOpenMPIterationSpace( @@ -2453,32 +2614,27 @@ static bool CheckOpenMPIterationSpace( ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) : OMPC_private; if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != PredeterminedCKind) || + DVar.CKind != OMPC_threadprivate && DVar.CKind != PredeterminedCKind) || (isOpenMPWorksharingDirective(DKind) && !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private && - DVar.CKind != OMPC_lastprivate)) && - (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { + DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_threadprivate)) && + ((DVar.CKind != OMPC_private && DVar.CKind != OMPC_threadprivate) || + DVar.RefExpr != nullptr)) { SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) << getOpenMPClauseName(PredeterminedCKind); - ReportOriginalDSA(SemaRef, &DSA, Var, DVar, true); + 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 loops). - // FIXME: the next check and error message must be removed once the - // capturing of global variables in loops is fixed. if (DVar.CKind == OMPC_unknown) DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(), /*FromParent=*/false); - if (!Var->hasLocalStorage() && DVar.CKind == OMPC_unknown) { - SemaRef.Diag(Init->getLocStart(), diag::err_omp_global_loop_var_dsa) - << getOpenMPClauseName(PredeterminedCKind) - << getOpenMPDirectiveName(DKind); - HasErrors = true; - } else - DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind); + DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind); } assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); @@ -2493,6 +2649,7 @@ static bool CheckOpenMPIterationSpace( return HasErrors; // Build the loop's iteration space representation. + ResultIterSpace.PreCond = ISC.BuildPreCond(DSA.getCurScope(), For->getCond()); ResultIterSpace.NumIterations = ISC.BuildNumIterations( DSA.getCurScope(), /* LimitedType */ isOpenMPWorksharingDirective(DKind)); ResultIterSpace.CounterVar = ISC.BuildCounterVar(); @@ -2503,7 +2660,8 @@ static bool CheckOpenMPIterationSpace( ResultIterSpace.IncSrcRange = ISC.GetIncrementSrcRange(); ResultIterSpace.Subtract = ISC.ShouldSubtractStep(); - HasErrors |= (ResultIterSpace.NumIterations == nullptr || + HasErrors |= (ResultIterSpace.PreCond == nullptr || + ResultIterSpace.NumIterations == nullptr || ResultIterSpace.CounterVar == nullptr || ResultIterSpace.CounterInit == nullptr || ResultIterSpace.CounterStep == nullptr); @@ -2511,18 +2669,6 @@ static bool CheckOpenMPIterationSpace( return HasErrors; } -/// \brief Build a variable declaration for OpenMP loop iteration variable. -static VarDecl *BuildVarDecl(Sema &SemaRef, SourceLocation Loc, QualType Type, - StringRef Name) { - DeclContext *DC = SemaRef.CurContext; - IdentifierInfo *II = &SemaRef.PP.getIdentifierTable().get(Name); - TypeSourceInfo *TInfo = SemaRef.Context.getTrivialTypeSourceInfo(Type, Loc); - VarDecl *Decl = - VarDecl::Create(SemaRef.Context, DC, Loc, Loc, II, Type, TInfo, SC_None); - Decl->setImplicit(); - return Decl; -} - /// \brief Build 'VarRef = Start + Iter * Step'. static ExprResult BuildCounterUpdate(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, @@ -2648,6 +2794,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, // Last iteration number is (I1 * I2 * ... In) - 1, where I1, I2 ... In are // the iteration counts of the collapsed for loops. + // Precondition tests if there is at least one iteration (all conditions are + // true). + auto PreCond = ExprResult(IterSpaces[0].PreCond); auto N0 = IterSpaces[0].NumIterations; ExprResult LastIteration32 = WidenIterationCount(32 /* Bits */, N0, SemaRef); ExprResult LastIteration64 = WidenIterationCount(64 /* Bits */, N0, SemaRef); @@ -2660,6 +2809,10 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, Scope *CurScope = DSA.getCurScope(); for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) { + if (PreCond.isUsable()) { + PreCond = SemaRef.BuildBinOp(CurScope, SourceLocation(), BO_LAnd, + PreCond.get(), IterSpaces[Cnt].PreCond); + } auto N = IterSpaces[Cnt].NumIterations; AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32; if (LastIteration32.isUsable()) @@ -2703,10 +2856,10 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, if (!IsConstant) { SourceLocation SaveLoc; VarDecl *SaveVar = - BuildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(), + buildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(), ".omp.last.iteration"); - ExprResult SaveRef = SemaRef.BuildDeclRefExpr( - SaveVar, LastIteration.get()->getType(), VK_LValue, SaveLoc); + ExprResult SaveRef = buildDeclRefExpr( + SemaRef, SaveVar, LastIteration.get()->getType(), SaveLoc); CalcLastIteration = SemaRef.BuildBinOp(CurScope, SaveLoc, BO_Assign, SaveRef.get(), LastIteration.get()); LastIteration = SaveRef; @@ -2721,25 +2874,20 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); - // Precondition tests if there is at least one iteration (LastIteration > 0). - ExprResult PreCond = SemaRef.BuildBinOp( - CurScope, InitLoc, BO_GT, LastIteration.get(), - SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get()); - QualType VType = LastIteration.get()->getType(); // Build variables passed into runtime, nesessary for worksharing directives. ExprResult LB, UB, IL, ST, EUB; if (isOpenMPWorksharingDirective(DKind)) { // Lower bound variable, initialized with zero. - VarDecl *LBDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); - LB = SemaRef.BuildDeclRefExpr(LBDecl, VType, VK_LValue, InitLoc); + VarDecl *LBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.lb"); + LB = buildDeclRefExpr(SemaRef, LBDecl, VType, InitLoc); SemaRef.AddInitializerToDecl( LBDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Upper bound variable, initialized with last iteration number. - VarDecl *UBDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.ub"); - UB = SemaRef.BuildDeclRefExpr(UBDecl, VType, VK_LValue, InitLoc); + VarDecl *UBDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.ub"); + UB = buildDeclRefExpr(SemaRef, UBDecl, VType, InitLoc); SemaRef.AddInitializerToDecl(UBDecl, LastIteration.get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); @@ -2747,15 +2895,15 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, // A 32-bit variable-flag where runtime returns 1 for the last iteration. // This will be used to implement clause 'lastprivate'. QualType Int32Ty = SemaRef.Context.getIntTypeForBitwidth(32, true); - VarDecl *ILDecl = BuildVarDecl(SemaRef, InitLoc, Int32Ty, ".omp.is_last"); - IL = SemaRef.BuildDeclRefExpr(ILDecl, Int32Ty, VK_LValue, InitLoc); + VarDecl *ILDecl = buildVarDecl(SemaRef, InitLoc, Int32Ty, ".omp.is_last"); + IL = buildDeclRefExpr(SemaRef, ILDecl, Int32Ty, InitLoc); SemaRef.AddInitializerToDecl( ILDecl, SemaRef.ActOnIntegerConstant(InitLoc, 0).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Stride variable returned by runtime (we initialize it to 1 by default). - VarDecl *STDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.stride"); - ST = SemaRef.BuildDeclRefExpr(STDecl, VType, VK_LValue, InitLoc); + VarDecl *STDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.stride"); + ST = buildDeclRefExpr(SemaRef, STDecl, VType, InitLoc); SemaRef.AddInitializerToDecl( STDecl, SemaRef.ActOnIntegerConstant(InitLoc, 1).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); @@ -2775,8 +2923,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, ExprResult IV; ExprResult Init; { - VarDecl *IVDecl = BuildVarDecl(SemaRef, InitLoc, VType, ".omp.iv"); - IV = SemaRef.BuildDeclRefExpr(IVDecl, VType, VK_LValue, InitLoc); + VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.iv"); + IV = buildDeclRefExpr(SemaRef, IVDecl, VType, InitLoc); Expr *RHS = isOpenMPWorksharingDirective(DKind) ? LB.get() : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); @@ -2864,9 +3012,13 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, break; } - // Build update: IS.CounterVar = IS.Start + Iter * IS.Step + // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step + auto *CounterVar = buildDeclRefExpr( + SemaRef, cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()), + IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), + /*RefersToCapture=*/true); ExprResult Update = - BuildCounterUpdate(SemaRef, CurScope, UpdLoc, IS.CounterVar, + BuildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, IS.CounterStep, IS.Subtract); if (!Update.isUsable()) { HasErrors = true; @@ -2875,7 +3027,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step ExprResult Final = BuildCounterUpdate( - SemaRef, CurScope, UpdLoc, IS.CounterVar, IS.CounterInit, + SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, IS.NumIterations, IS.CounterStep, IS.Subtract); if (!Final.isUsable()) { HasErrors = true; @@ -2915,6 +3067,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, // Save results Built.IterationVarRef = IV.get(); Built.LastIteration = LastIteration.get(); + Built.NumIterations = NumIterations.get(); Built.CalcLastIteration = CalcLastIteration.get(); Built.PreCond = PreCond.get(); Built.Cond = Cond.get(); @@ -2933,11 +3086,11 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *NestedLoopCountExpr, } static Expr *GetCollapseNumberExpr(ArrayRef<OMPClause *> Clauses) { - auto CollapseFilter = [](const OMPClause *C) -> bool { + auto &&CollapseFilter = [](const OMPClause *C) -> bool { return C->getClauseKind() == OMPC_collapse; }; OMPExecutableDirective::filtered_clause_iterator<decltype(CollapseFilter)> I( - Clauses, CollapseFilter); + Clauses, std::move(CollapseFilter)); if (I) return cast<OMPCollapseClause>(*I)->getNumForLoops(); return nullptr; @@ -2958,6 +3111,16 @@ StmtResult Sema::ActOnOpenMPSimdDirective( assert((CurContext->isDependentContext() || B.builtAll()) && "omp simd loop exprs were not built"); + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope)) + return StmtError(); + } + } + getCurFunction()->setHasBranchProtectedScope(); return OMPSimdDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); @@ -3055,6 +3218,23 @@ StmtResult Sema::ActOnOpenMPSingleDirective(ArrayRef<OMPClause *> Clauses, getCurFunction()->setHasBranchProtectedScope(); + // OpenMP [2.7.3, single Construct, Restrictions] + // The copyprivate clause must not be used with the nowait clause. + OMPClause *Nowait = nullptr; + OMPClause *Copyprivate = nullptr; + for (auto *Clause : Clauses) { + if (Clause->getClauseKind() == OMPC_nowait) + Nowait = Clause; + else if (Clause->getClauseKind() == OMPC_copyprivate) + Copyprivate = Clause; + if (Copyprivate && Nowait) { + Diag(Copyprivate->getLocStart(), + diag::err_omp_single_copyprivate_with_nowait); + Diag(Nowait->getLocStart(), diag::note_omp_nowait_clause_here); + return StmtError(); + } + } + return OMPSingleDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } @@ -3219,6 +3399,246 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(Stmt *AStmt, return OMPOrderedDirective::Create(Context, StartLoc, EndLoc, AStmt); } +namespace { +/// \brief Helper class for checking expression in 'omp atomic [update]' +/// construct. +class OpenMPAtomicUpdateChecker { + /// \brief Error results for atomic update expressions. + enum ExprAnalysisErrorCode { + /// \brief A statement is not an expression statement. + NotAnExpression, + /// \brief Expression is not builtin binary or unary operation. + NotABinaryOrUnaryExpression, + /// \brief Unary operation is not post-/pre- increment/decrement operation. + NotAnUnaryIncDecExpression, + /// \brief An expression is not of scalar type. + NotAScalarType, + /// \brief A binary operation is not an assignment operation. + NotAnAssignmentOp, + /// \brief RHS part of the binary operation is not a binary expression. + NotABinaryExpression, + /// \brief RHS part is not additive/multiplicative/shift/biwise binary + /// expression. + NotABinaryOperator, + /// \brief RHS binary operation does not have reference to the updated LHS + /// part. + NotAnUpdateExpression, + /// \brief No errors is found. + NoError + }; + /// \brief Reference to Sema. + Sema &SemaRef; + /// \brief A location for note diagnostics (when error is found). + SourceLocation NoteLoc; + /// \brief 'x' lvalue part of the source atomic expression. + Expr *X; + /// \brief 'expr' rvalue part of the source atomic expression. + Expr *E; + /// \brief Helper expression of the form + /// 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or + /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. + Expr *UpdateExpr; + /// \brief Is 'x' a LHS in a RHS part of full update expression. It is + /// important for non-associative operations. + bool IsXLHSInRHSPart; + BinaryOperatorKind Op; + SourceLocation OpLoc; + /// \brief true if the source expression is a postfix unary operation, false + /// if it is a prefix unary operation. + bool IsPostfixUpdate; + +public: + OpenMPAtomicUpdateChecker(Sema &SemaRef) + : SemaRef(SemaRef), X(nullptr), E(nullptr), UpdateExpr(nullptr), + IsXLHSInRHSPart(false), Op(BO_PtrMemD), IsPostfixUpdate(false) {} + /// \brief Check specified statement that it is suitable for 'atomic update' + /// constructs and extract 'x', 'expr' and Operation from the original + /// expression. If DiagId and NoteId == 0, then only check is performed + /// without error notification. + /// \param DiagId Diagnostic which should be emitted if error is found. + /// \param NoteId Diagnostic note for the main error message. + /// \return true if statement is not an update expression, false otherwise. + bool checkStatement(Stmt *S, unsigned DiagId = 0, unsigned NoteId = 0); + /// \brief Return the 'x' lvalue part of the source atomic expression. + Expr *getX() const { return X; } + /// \brief Return the 'expr' rvalue part of the source atomic expression. + Expr *getExpr() const { return E; } + /// \brief Return the update expression used in calculation of the updated + /// value. Always has form 'OpaqueValueExpr(x) binop OpaqueValueExpr(expr)' or + /// 'OpaqueValueExpr(expr) binop OpaqueValueExpr(x)'. + Expr *getUpdateExpr() const { return UpdateExpr; } + /// \brief Return true if 'x' is LHS in RHS part of full update expression, + /// false otherwise. + bool isXLHSInRHSPart() const { return IsXLHSInRHSPart; } + + /// \brief true if the source expression is a postfix unary operation, false + /// if it is a prefix unary operation. + bool isPostfixUpdate() const { return IsPostfixUpdate; } + +private: + bool checkBinaryOperation(BinaryOperator *AtomicBinOp, unsigned DiagId = 0, + unsigned NoteId = 0); +}; +} // namespace + +bool OpenMPAtomicUpdateChecker::checkBinaryOperation( + BinaryOperator *AtomicBinOp, unsigned DiagId, unsigned NoteId) { + ExprAnalysisErrorCode ErrorFound = NoError; + SourceLocation ErrorLoc, NoteLoc; + SourceRange ErrorRange, NoteRange; + // Allowed constructs are: + // x = x binop expr; + // x = expr binop x; + if (AtomicBinOp->getOpcode() == BO_Assign) { + X = AtomicBinOp->getLHS(); + if (auto *AtomicInnerBinOp = dyn_cast<BinaryOperator>( + AtomicBinOp->getRHS()->IgnoreParenImpCasts())) { + if (AtomicInnerBinOp->isMultiplicativeOp() || + AtomicInnerBinOp->isAdditiveOp() || AtomicInnerBinOp->isShiftOp() || + AtomicInnerBinOp->isBitwiseOp()) { + Op = AtomicInnerBinOp->getOpcode(); + OpLoc = AtomicInnerBinOp->getOperatorLoc(); + auto *LHS = AtomicInnerBinOp->getLHS(); + auto *RHS = AtomicInnerBinOp->getRHS(); + llvm::FoldingSetNodeID XId, LHSId, RHSId; + X->IgnoreParenImpCasts()->Profile(XId, SemaRef.getASTContext(), + /*Canonical=*/true); + LHS->IgnoreParenImpCasts()->Profile(LHSId, SemaRef.getASTContext(), + /*Canonical=*/true); + RHS->IgnoreParenImpCasts()->Profile(RHSId, SemaRef.getASTContext(), + /*Canonical=*/true); + if (XId == LHSId) { + E = RHS; + IsXLHSInRHSPart = true; + } else if (XId == RHSId) { + E = LHS; + IsXLHSInRHSPart = false; + } else { + ErrorLoc = AtomicInnerBinOp->getExprLoc(); + ErrorRange = AtomicInnerBinOp->getSourceRange(); + NoteLoc = X->getExprLoc(); + NoteRange = X->getSourceRange(); + ErrorFound = NotAnUpdateExpression; + } + } else { + ErrorLoc = AtomicInnerBinOp->getExprLoc(); + ErrorRange = AtomicInnerBinOp->getSourceRange(); + NoteLoc = AtomicInnerBinOp->getOperatorLoc(); + NoteRange = SourceRange(NoteLoc, NoteLoc); + ErrorFound = NotABinaryOperator; + } + } else { + NoteLoc = ErrorLoc = AtomicBinOp->getRHS()->getExprLoc(); + NoteRange = ErrorRange = AtomicBinOp->getRHS()->getSourceRange(); + ErrorFound = NotABinaryExpression; + } + } else { + ErrorLoc = AtomicBinOp->getExprLoc(); + ErrorRange = AtomicBinOp->getSourceRange(); + NoteLoc = AtomicBinOp->getOperatorLoc(); + NoteRange = SourceRange(NoteLoc, NoteLoc); + ErrorFound = NotAnAssignmentOp; + } + if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) { + SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange; + SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange; + return true; + } else if (SemaRef.CurContext->isDependentContext()) + E = X = UpdateExpr = nullptr; + return ErrorFound != NoError; +} + +bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, + unsigned NoteId) { + ExprAnalysisErrorCode ErrorFound = NoError; + SourceLocation ErrorLoc, NoteLoc; + SourceRange ErrorRange, NoteRange; + // Allowed constructs are: + // x++; + // x--; + // ++x; + // --x; + // x binop= expr; + // x = x binop expr; + // x = expr binop x; + if (auto *AtomicBody = dyn_cast<Expr>(S)) { + AtomicBody = AtomicBody->IgnoreParenImpCasts(); + if (AtomicBody->getType()->isScalarType() || + AtomicBody->isInstantiationDependent()) { + if (auto *AtomicCompAssignOp = dyn_cast<CompoundAssignOperator>( + AtomicBody->IgnoreParenImpCasts())) { + // Check for Compound Assignment Operation + Op = BinaryOperator::getOpForCompoundAssignment( + AtomicCompAssignOp->getOpcode()); + OpLoc = AtomicCompAssignOp->getOperatorLoc(); + E = AtomicCompAssignOp->getRHS(); + X = AtomicCompAssignOp->getLHS(); + IsXLHSInRHSPart = true; + } else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>( + AtomicBody->IgnoreParenImpCasts())) { + // Check for Binary Operation + if(checkBinaryOperation(AtomicBinOp, DiagId, NoteId)) + return true; + } else if (auto *AtomicUnaryOp = + dyn_cast<UnaryOperator>(AtomicBody->IgnoreParenImpCasts())) { + // Check for Unary Operation + if (AtomicUnaryOp->isIncrementDecrementOp()) { + IsPostfixUpdate = AtomicUnaryOp->isPostfix(); + Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub; + OpLoc = AtomicUnaryOp->getOperatorLoc(); + X = AtomicUnaryOp->getSubExpr(); + E = SemaRef.ActOnIntegerConstant(OpLoc, /*uint64_t Val=*/1).get(); + IsXLHSInRHSPart = true; + } else { + ErrorFound = NotAnUnaryIncDecExpression; + ErrorLoc = AtomicUnaryOp->getExprLoc(); + ErrorRange = AtomicUnaryOp->getSourceRange(); + NoteLoc = AtomicUnaryOp->getOperatorLoc(); + NoteRange = SourceRange(NoteLoc, NoteLoc); + } + } else { + ErrorFound = NotABinaryOrUnaryExpression; + NoteLoc = ErrorLoc = AtomicBody->getExprLoc(); + NoteRange = ErrorRange = AtomicBody->getSourceRange(); + } + } else { + ErrorFound = NotAScalarType; + NoteLoc = ErrorLoc = AtomicBody->getLocStart(); + NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); + } + } else { + ErrorFound = NotAnExpression; + NoteLoc = ErrorLoc = S->getLocStart(); + NoteRange = ErrorRange = SourceRange(NoteLoc, NoteLoc); + } + if (ErrorFound != NoError && DiagId != 0 && NoteId != 0) { + SemaRef.Diag(ErrorLoc, DiagId) << ErrorRange; + SemaRef.Diag(NoteLoc, NoteId) << ErrorFound << NoteRange; + return true; + } else if (SemaRef.CurContext->isDependentContext()) + E = X = UpdateExpr = nullptr; + if (ErrorFound == NoError && E && X) { + // Build an update expression of form 'OpaqueValueExpr(x) binop + // OpaqueValueExpr(expr)' or 'OpaqueValueExpr(expr) binop + // OpaqueValueExpr(x)' and then cast it to the type of the 'x' expression. + auto *OVEX = new (SemaRef.getASTContext()) + OpaqueValueExpr(X->getExprLoc(), X->getType(), VK_RValue); + auto *OVEExpr = new (SemaRef.getASTContext()) + OpaqueValueExpr(E->getExprLoc(), E->getType(), VK_RValue); + auto Update = + SemaRef.CreateBuiltinBinOp(OpLoc, Op, IsXLHSInRHSPart ? OVEX : OVEExpr, + IsXLHSInRHSPart ? OVEExpr : OVEX); + if (Update.isInvalid()) + return true; + Update = SemaRef.PerformImplicitConversion(Update.get(), X->getType(), + Sema::AA_Casting); + if (Update.isInvalid()) + return true; + UpdateExpr = Update.get(); + } + return ErrorFound != NoError; +} + StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -3230,7 +3650,6 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // top and a single exit at the bottom. // The point of exit cannot be a branch out of the structured block. // longjmp() and throw() must not violate the entry/exit criteria. - // TODO further analysis of associated statements and clauses. OpenMPClauseKind AtomicKind = OMPC_unknown; SourceLocation AtomicKindLoc; for (auto *C : Clauses) { @@ -3250,9 +3669,15 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } auto Body = CS->getCapturedStmt(); + if (auto *EWC = dyn_cast<ExprWithCleanups>(Body)) + Body = EWC->getSubExpr(); + Expr *X = nullptr; Expr *V = nullptr; Expr *E = nullptr; + Expr *UE = nullptr; + bool IsXLHSInRHSPart = false; + bool IsPostfixUpdate = false; // OpenMP [2.12.6, atomic Construct] // In the next expressions: // * x and v (as applicable) are both l-value expressions with scalar type. @@ -3275,14 +3700,14 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // expr or subexpressions of expr. // * For forms that allow multiple occurrences of x, the number of times // that x is evaluated is unspecified. - enum { - NotAnExpression, - NotAnAssignmentOp, - NotAScalarType, - NotAnLValue, - NoError - } ErrorFound = NoError; if (AtomicKind == OMPC_read) { + enum { + NotAnExpression, + NotAnAssignmentOp, + NotAScalarType, + NotAnLValue, + NoError + } ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; // If clause is read: @@ -3338,6 +3763,13 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } else if (CurContext->isDependentContext()) V = X = nullptr; } else if (AtomicKind == OMPC_write) { + enum { + NotAnExpression, + NotAnAssignmentOp, + NotAScalarType, + NotAnLValue, + NoError + } ErrorFound = NoError; SourceLocation ErrorLoc, NoteLoc; SourceRange ErrorRange, NoteRange; // If clause is write: @@ -3346,8 +3778,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, auto AtomicBinOp = dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { - X = AtomicBinOp->getLHS()->IgnoreParenImpCasts(); - E = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); + X = AtomicBinOp->getLHS(); + E = AtomicBinOp->getRHS(); if ((X->isInstantiationDependent() || X->getType()->isScalarType()) && (E->isInstantiationDependent() || E->getType()->isScalarType())) { if (!X->isLValue()) { @@ -3392,28 +3824,240 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, } else if (CurContext->isDependentContext()) E = X = nullptr; } else if (AtomicKind == OMPC_update || AtomicKind == OMPC_unknown) { - if (!isa<Expr>(Body)) { - Diag(Body->getLocStart(), - diag::err_omp_atomic_update_not_expression_statement) - << (AtomicKind == OMPC_update); + // If clause is update: + // x++; + // x--; + // ++x; + // --x; + // x binop= expr; + // x = x binop expr; + // x = expr binop x; + OpenMPAtomicUpdateChecker Checker(*this); + if (Checker.checkStatement( + Body, (AtomicKind == OMPC_update) + ? diag::err_omp_atomic_update_not_expression_statement + : diag::err_omp_atomic_not_expression_statement, + diag::note_omp_atomic_update)) return StmtError(); + if (!CurContext->isDependentContext()) { + E = Checker.getExpr(); + X = Checker.getX(); + UE = Checker.getUpdateExpr(); + IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); } } else if (AtomicKind == OMPC_capture) { - if (isa<Expr>(Body) && !isa<BinaryOperator>(Body)) { - Diag(Body->getLocStart(), - diag::err_omp_atomic_capture_not_expression_statement); - return StmtError(); - } else if (!isa<Expr>(Body) && !isa<CompoundStmt>(Body)) { - Diag(Body->getLocStart(), - diag::err_omp_atomic_capture_not_compound_statement); - return StmtError(); + enum { + NotAnAssignmentOp, + NotACompoundStatement, + NotTwoSubstatements, + NotASpecificExpression, + NoError + } ErrorFound = NoError; + SourceLocation ErrorLoc, NoteLoc; + SourceRange ErrorRange, NoteRange; + if (auto *AtomicBody = dyn_cast<Expr>(Body)) { + // If clause is a capture: + // v = x++; + // v = x--; + // v = ++x; + // v = --x; + // v = x binop= expr; + // v = x = x binop expr; + // v = x = expr binop x; + auto *AtomicBinOp = + dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); + if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { + V = AtomicBinOp->getLHS(); + Body = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); + OpenMPAtomicUpdateChecker Checker(*this); + if (Checker.checkStatement( + Body, diag::err_omp_atomic_capture_not_expression_statement, + diag::note_omp_atomic_update)) + return StmtError(); + E = Checker.getExpr(); + X = Checker.getX(); + UE = Checker.getUpdateExpr(); + IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); + IsPostfixUpdate = Checker.isPostfixUpdate(); + } else { + ErrorLoc = AtomicBody->getExprLoc(); + ErrorRange = AtomicBody->getSourceRange(); + NoteLoc = AtomicBinOp ? AtomicBinOp->getOperatorLoc() + : AtomicBody->getExprLoc(); + NoteRange = AtomicBinOp ? AtomicBinOp->getSourceRange() + : AtomicBody->getSourceRange(); + ErrorFound = NotAnAssignmentOp; + } + if (ErrorFound != NoError) { + Diag(ErrorLoc, diag::err_omp_atomic_capture_not_expression_statement) + << ErrorRange; + Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; + return StmtError(); + } else if (CurContext->isDependentContext()) { + UE = V = E = X = nullptr; + } + } else { + // If clause is a capture: + // { v = x; x = expr; } + // { v = x; x++; } + // { v = x; x--; } + // { v = x; ++x; } + // { v = x; --x; } + // { v = x; x binop= expr; } + // { v = x; x = x binop expr; } + // { v = x; x = expr binop x; } + // { x++; v = x; } + // { x--; v = x; } + // { ++x; v = x; } + // { --x; v = x; } + // { x binop= expr; v = x; } + // { x = x binop expr; v = x; } + // { x = expr binop x; v = x; } + if (auto *CS = dyn_cast<CompoundStmt>(Body)) { + // Check that this is { expr1; expr2; } + if (CS->size() == 2) { + auto *First = CS->body_front(); + auto *Second = CS->body_back(); + if (auto *EWC = dyn_cast<ExprWithCleanups>(First)) + First = EWC->getSubExpr()->IgnoreParenImpCasts(); + if (auto *EWC = dyn_cast<ExprWithCleanups>(Second)) + Second = EWC->getSubExpr()->IgnoreParenImpCasts(); + // Need to find what subexpression is 'v' and what is 'x'. + OpenMPAtomicUpdateChecker Checker(*this); + bool IsUpdateExprFound = !Checker.checkStatement(Second); + BinaryOperator *BinOp = nullptr; + if (IsUpdateExprFound) { + BinOp = dyn_cast<BinaryOperator>(First); + IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign; + } + if (IsUpdateExprFound && !CurContext->isDependentContext()) { + // { v = x; x++; } + // { v = x; x--; } + // { v = x; ++x; } + // { v = x; --x; } + // { v = x; x binop= expr; } + // { v = x; x = x binop expr; } + // { v = x; x = expr binop x; } + // Check that the first expression has form v = x. + auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); + llvm::FoldingSetNodeID XId, PossibleXId; + Checker.getX()->Profile(XId, Context, /*Canonical=*/true); + PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true); + IsUpdateExprFound = XId == PossibleXId; + if (IsUpdateExprFound) { + V = BinOp->getLHS(); + X = Checker.getX(); + E = Checker.getExpr(); + UE = Checker.getUpdateExpr(); + IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); + IsPostfixUpdate = true; + } + } + if (!IsUpdateExprFound) { + IsUpdateExprFound = !Checker.checkStatement(First); + BinOp = nullptr; + if (IsUpdateExprFound) { + BinOp = dyn_cast<BinaryOperator>(Second); + IsUpdateExprFound = BinOp && BinOp->getOpcode() == BO_Assign; + } + if (IsUpdateExprFound && !CurContext->isDependentContext()) { + // { x++; v = x; } + // { x--; v = x; } + // { ++x; v = x; } + // { --x; v = x; } + // { x binop= expr; v = x; } + // { x = x binop expr; v = x; } + // { x = expr binop x; v = x; } + // Check that the second expression has form v = x. + auto *PossibleX = BinOp->getRHS()->IgnoreParenImpCasts(); + llvm::FoldingSetNodeID XId, PossibleXId; + Checker.getX()->Profile(XId, Context, /*Canonical=*/true); + PossibleX->Profile(PossibleXId, Context, /*Canonical=*/true); + IsUpdateExprFound = XId == PossibleXId; + if (IsUpdateExprFound) { + V = BinOp->getLHS(); + X = Checker.getX(); + E = Checker.getExpr(); + UE = Checker.getUpdateExpr(); + IsXLHSInRHSPart = Checker.isXLHSInRHSPart(); + IsPostfixUpdate = false; + } + } + } + if (!IsUpdateExprFound) { + // { v = x; x = expr; } + auto *FirstBinOp = dyn_cast<BinaryOperator>(First); + if (!FirstBinOp || FirstBinOp->getOpcode() != BO_Assign) { + ErrorFound = NotAnAssignmentOp; + NoteLoc = ErrorLoc = FirstBinOp ? FirstBinOp->getOperatorLoc() + : First->getLocStart(); + NoteRange = ErrorRange = FirstBinOp + ? FirstBinOp->getSourceRange() + : SourceRange(ErrorLoc, ErrorLoc); + } else { + auto *SecondBinOp = dyn_cast<BinaryOperator>(Second); + if (!SecondBinOp || SecondBinOp->getOpcode() != BO_Assign) { + ErrorFound = NotAnAssignmentOp; + NoteLoc = ErrorLoc = SecondBinOp ? SecondBinOp->getOperatorLoc() + : Second->getLocStart(); + NoteRange = ErrorRange = SecondBinOp + ? SecondBinOp->getSourceRange() + : SourceRange(ErrorLoc, ErrorLoc); + } else { + auto *PossibleXRHSInFirst = + FirstBinOp->getRHS()->IgnoreParenImpCasts(); + auto *PossibleXLHSInSecond = + SecondBinOp->getLHS()->IgnoreParenImpCasts(); + llvm::FoldingSetNodeID X1Id, X2Id; + PossibleXRHSInFirst->Profile(X1Id, Context, /*Canonical=*/true); + PossibleXLHSInSecond->Profile(X2Id, Context, + /*Canonical=*/true); + IsUpdateExprFound = X1Id == X2Id; + if (IsUpdateExprFound) { + V = FirstBinOp->getLHS(); + X = SecondBinOp->getLHS(); + E = SecondBinOp->getRHS(); + UE = nullptr; + IsXLHSInRHSPart = false; + IsPostfixUpdate = true; + } else { + ErrorFound = NotASpecificExpression; + ErrorLoc = FirstBinOp->getExprLoc(); + ErrorRange = FirstBinOp->getSourceRange(); + NoteLoc = SecondBinOp->getLHS()->getExprLoc(); + NoteRange = SecondBinOp->getRHS()->getSourceRange(); + } + } + } + } + } else { + NoteLoc = ErrorLoc = Body->getLocStart(); + NoteRange = ErrorRange = + SourceRange(Body->getLocStart(), Body->getLocStart()); + ErrorFound = NotTwoSubstatements; + } + } else { + NoteLoc = ErrorLoc = Body->getLocStart(); + NoteRange = ErrorRange = + SourceRange(Body->getLocStart(), Body->getLocStart()); + ErrorFound = NotACompoundStatement; + } + if (ErrorFound != NoError) { + Diag(ErrorLoc, diag::err_omp_atomic_capture_not_compound_statement) + << ErrorRange; + Diag(NoteLoc, diag::note_omp_atomic_capture) << ErrorFound << NoteRange; + return StmtError(); + } else if (CurContext->isDependentContext()) { + UE = V = E = X = nullptr; + } } } getCurFunction()->setHasBranchProtectedScope(); return OMPAtomicDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, - X, V, E); + X, V, E, UE, IsXLHSInRHSPart, + IsPostfixUpdate); } StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, @@ -3655,6 +4299,9 @@ ExprResult Sema::VerifyPositiveIntegerConstantInClause(Expr *E, << E->getSourceRange(); return ExprError(); } + if (CKind == OMPC_collapse) { + DSAStack->setCollapseNumber(Result.getExtValue()); + } return ICE; } @@ -3882,6 +4529,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( return nullptr; } Expr *ValExpr = ChunkSize; + Expr *HelperValExpr = nullptr; if (ChunkSize) { if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() && !ChunkSize->isInstantiationDependent() && @@ -3898,17 +4546,25 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( // chunk_size must be a loop invariant integer expression with a positive // value. llvm::APSInt Result; - if (ValExpr->isIntegerConstantExpr(Result, Context) && - Result.isSigned() && !Result.isStrictlyPositive()) { - Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) - << "schedule" << ChunkSize->getSourceRange(); - return nullptr; + if (ValExpr->isIntegerConstantExpr(Result, Context)) { + if (Result.isSigned() && !Result.isStrictlyPositive()) { + Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) + << "schedule" << ChunkSize->getSourceRange(); + return nullptr; + } + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { + auto *ImpVar = buildVarDecl(*this, ChunkSize->getExprLoc(), + ChunkSize->getType(), ".chunk."); + auto *ImpVarRef = buildDeclRefExpr(*this, ImpVar, ChunkSize->getType(), + ChunkSize->getExprLoc(), + /*RefersToCapture=*/true); + HelperValExpr = ImpVarRef; } } } return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, - EndLoc, Kind, ValExpr); + EndLoc, Kind, ValExpr, HelperValExpr); } OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, @@ -4133,14 +4789,6 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, continue; } - // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] - // A variable of class type (or array thereof) that appears in a private - // clause requires an accessible, unambiguous default constructor for the - // class type. - while (Type->isArrayType()) { - Type = cast<ArrayType>(Type.getTypePtr())->getElementType(); - } - // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be @@ -4156,25 +4804,36 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, continue; } + // Variably modified types are not supported for tasks. + if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && + DSAStack->getCurrentDirective() == OMPD_task) { + Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) + << getOpenMPClauseName(OMPC_private) << Type + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + + // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] + // A variable of class type (or array thereof) that appears in a private + // clause requires an accessible, unambiguous default constructor for the + // class type. // Generate helper private variable and initialize it with the default // value. The address of the original variable is replaced by the address of // the new private variable in CodeGen. This new variable is not added to // IdResolver, so the code in the OpenMP region uses original variable for // proper diagnostics. - auto VDPrivate = - VarDecl::Create(Context, CurContext, DE->getLocStart(), - DE->getExprLoc(), VD->getIdentifier(), VD->getType(), - VD->getTypeSourceInfo(), /*S*/ SC_Auto); - ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto*/ false); + Type = Type.getUnqualifiedType(); + auto VDPrivate = buildVarDecl(*this, DE->getExprLoc(), Type, VD->getName()); + ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); if (VDPrivate->isInvalidDecl()) continue; - CurContext->addDecl(VDPrivate); - auto VDPrivateRefExpr = - DeclRefExpr::Create(Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), - /*TemplateKWLoc*/ SourceLocation(), VDPrivate, - /*RefersToEnclosingVariableOrCapture*/ false, - /*NameLoc*/ SourceLocation(), DE->getType(), - /*VK*/ VK_LValue); + auto VDPrivateRefExpr = buildDeclRefExpr( + *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); DSAStack->addDSA(VD, DE, OMPC_private); Vars.push_back(DE); @@ -4285,14 +4944,12 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous copy constructor for the // class type. - Type = Context.getBaseElementType(Type); + auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); // If an implicit firstprivate variable found it was checked already. if (!IsImplicitClause) { DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); - Type = Type.getNonReferenceType().getCanonicalType(); - bool IsConstant = Type.isConstant(Context); - Type = Context.getBaseElementType(Type); + bool IsConstant = ElemType.isConstant(Context); // OpenMP [2.4.13, Data-sharing Attribute Clauses] // A list item that specifies a given variable may not appear in more // than one clause on the same directive, except that a variable may be @@ -4375,10 +5032,22 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, } } + // Variably modified types are not supported for tasks. + if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && + DSAStack->getCurrentDirective() == OMPD_task) { + Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) + << getOpenMPClauseName(OMPC_firstprivate) << Type + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + Type = Type.getUnqualifiedType(); - auto VDPrivate = VarDecl::Create(Context, CurContext, DE->getLocStart(), - ELoc, VD->getIdentifier(), VD->getType(), - VD->getTypeSourceInfo(), /*S*/ SC_Auto); + auto VDPrivate = buildVarDecl(*this, ELoc, Type, VD->getName()); // Generate helper private variable and initialize it with the value of the // original variable. The address of the original variable is replaced by // the address of the new private variable in the CodeGen. This new variable @@ -4387,19 +5056,16 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, Expr *VDInitRefExpr = nullptr; // For arrays generate initializer for single element and replace it by the // original array element in CodeGen. - if (DE->getType()->isArrayType()) { - auto VDInit = VarDecl::Create(Context, CurContext, DE->getLocStart(), - ELoc, VD->getIdentifier(), Type, - VD->getTypeSourceInfo(), /*S*/ SC_Auto); - CurContext->addHiddenDecl(VDInit); - VDInitRefExpr = DeclRefExpr::Create( - Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), - /*TemplateKWLoc*/ SourceLocation(), VDInit, - /*RefersToEnclosingVariableOrCapture*/ true, ELoc, Type, - /*VK*/ VK_LValue); - VDInit->setIsUsed(); + if (Type->isArrayType()) { + auto VDInit = + buildVarDecl(*this, DE->getExprLoc(), ElemType, VD->getName()); + VDInitRefExpr = buildDeclRefExpr(*this, VDInit, ElemType, ELoc); auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); - InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInit); + ElemType = ElemType.getUnqualifiedType(); + auto *VDInitTemp = buildVarDecl(*this, DE->getLocStart(), ElemType, + ".firstprivate.temp"); + InitializedEntity Entity = + InitializedEntity::InitializeVariable(VDInitTemp); InitializationKind Kind = InitializationKind::CreateCopy(ELoc, ELoc); InitializationSequence InitSeq(*this, Entity, Kind, Init); @@ -4409,15 +5075,13 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, else VDPrivate->setInit(Result.getAs<Expr>()); } else { - AddInitializerToDecl( - VDPrivate, - DefaultLvalueConversion( - DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), - SourceLocation(), DE->getDecl(), - /*RefersToEnclosingVariableOrCapture=*/true, - DE->getExprLoc(), DE->getType(), - /*VK=*/VK_LValue)).get(), - /*DirectInit=*/false, /*TypeMayContainAuto=*/false); + auto *VDInit = + buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp"); + VDInitRefExpr = + buildDeclRefExpr(*this, VDInit, DE->getType(), DE->getExprLoc()); + AddInitializerToDecl(VDPrivate, + DefaultLvalueConversion(VDInitRefExpr).get(), + /*DirectInit=*/false, /*TypeMayContainAuto=*/false); } if (VDPrivate->isInvalidDecl()) { if (IsImplicitClause) { @@ -4427,12 +5091,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, continue; } CurContext->addDecl(VDPrivate); - auto VDPrivateRefExpr = - DeclRefExpr::Create(Context, /*QualifierLoc*/ NestedNameSpecifierLoc(), - /*TemplateKWLoc*/ SourceLocation(), VDPrivate, - /*RefersToEnclosingVariableOrCapture*/ false, - DE->getLocStart(), DE->getType(), - /*VK*/ VK_LValue); + auto VDPrivateRefExpr = buildDeclRefExpr( + *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); DSAStack->addDSA(VD, DE, OMPC_firstprivate); Vars.push_back(DE); PrivateCopies.push_back(VDPrivateRefExpr); @@ -4451,11 +5111,17 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> SrcExprs; + SmallVector<Expr *, 8> DstExprs; + SmallVector<Expr *, 8> AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + SrcExprs.push_back(nullptr); + DstExprs.push_back(nullptr); + AssignmentOps.push_back(nullptr); continue; } @@ -4477,6 +5143,9 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, 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; } @@ -4521,6 +5190,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // lastprivate clause on a worksharing construct if any of the corresponding // worksharing regions ever binds to any of the corresponding parallel // regions. + DSAStackTy::DSAVarData TopDVar = DVar; if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(VD, true); @@ -4540,65 +5210,39 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a // lastprivate clause requires an accessible, unambiguous copy assignment // operator for the class type. - while (Type.getNonReferenceType()->isArrayType()) - Type = cast<ArrayType>(Type.getNonReferenceType().getTypePtr()) - ->getElementType(); - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual copying and destructing of the - // lastprivate variable. - if (RD) { - CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); - DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); - if (MD) { - if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || - MD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_lastprivate) << 2; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, MD); - DiagnoseUseOfDecl(MD, ELoc); - } - - CXXDestructorDecl *DD = RD->getDestructor(); - if (DD) { - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || - DD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_lastprivate) << 4; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, DD); - DiagnoseUseOfDecl(DD, ELoc); - } - } + Type = Context.getBaseElementType(Type).getNonReferenceType(); + auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), + Type.getUnqualifiedType(), ".lastprivate.src"); + auto *PseudoSrcExpr = buildDeclRefExpr( + *this, SrcVD, Type.getUnqualifiedType(), DE->getExprLoc()); + auto *DstVD = + buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst"); + auto *PseudoDstExpr = + buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); + // 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, + PseudoDstExpr, PseudoSrcExpr); + if (AssignmentOp.isInvalid()) + continue; + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + /*DiscardedValue=*/true); + if (AssignmentOp.isInvalid()) + continue; - if (DVar.CKind != OMPC_firstprivate) + if (TopDVar.CKind != OMPC_firstprivate) DSAStack->addDSA(VD, DE, OMPC_lastprivate); Vars.push_back(DE); + SrcExprs.push_back(PseudoSrcExpr); + DstExprs.push_back(PseudoDstExpr); + AssignmentOps.push_back(AssignmentOp.get()); } if (Vars.empty()) return nullptr; return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars); + Vars, SrcExprs, DstExprs, AssignmentOps); } OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, @@ -4718,19 +5362,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause( switch (OOK) { case OO_Plus: case OO_Minus: - BOK = BO_AddAssign; + BOK = BO_Add; break; case OO_Star: - BOK = BO_MulAssign; + BOK = BO_Mul; break; case OO_Amp: - BOK = BO_AndAssign; + BOK = BO_And; break; case OO_Pipe: - BOK = BO_OrAssign; + BOK = BO_Or; break; case OO_Caret: - BOK = BO_XorAssign; + BOK = BO_Xor; break; case OO_AmpAmp: BOK = BO_LAnd; @@ -4738,7 +5382,44 @@ OMPClause *Sema::ActOnOpenMPReductionClause( case OO_PipePipe: BOK = BO_LOr; break; - default: + case OO_New: + case OO_Delete: + case OO_Array_New: + case OO_Array_Delete: + case OO_Slash: + case OO_Percent: + case OO_Tilde: + case OO_Exclaim: + case OO_Equal: + case OO_Less: + case OO_Greater: + case OO_LessEqual: + case OO_GreaterEqual: + case OO_PlusEqual: + case OO_MinusEqual: + case OO_StarEqual: + case OO_SlashEqual: + case OO_PercentEqual: + case OO_CaretEqual: + case OO_AmpEqual: + case OO_PipeEqual: + case OO_LessLess: + case OO_GreaterGreater: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + case OO_EqualEqual: + case OO_ExclaimEqual: + case OO_PlusPlus: + case OO_MinusMinus: + case OO_Comma: + case OO_ArrowStar: + case OO_Arrow: + case OO_Call: + case OO_Subscript: + case OO_Conditional: + case NUM_OVERLOADED_OPERATORS: + llvm_unreachable("Unexpected reduction identifier"); + case OO_None: if (auto II = DN.getAsIdentifierInfo()) { if (II->isStr("max")) BOK = BO_GT; @@ -4760,11 +5441,17 @@ OMPClause *Sema::ActOnOpenMPReductionClause( } SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> LHSs; + SmallVector<Expr *, 8> RHSs; + SmallVector<Expr *, 8> ReductionOps; for (auto RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + ReductionOps.push_back(nullptr); continue; } @@ -4773,6 +5460,9 @@ OMPClause *Sema::ActOnOpenMPReductionClause( RefExpr->containsUnexpandedParameterPack()) { // It will be analyzed later. Vars.push_back(RefExpr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + ReductionOps.push_back(nullptr); continue; } @@ -4865,23 +5555,6 @@ OMPClause *Sema::ActOnOpenMPReductionClause( << VD; continue; } - bool Suppress = getDiagnostics().getSuppressAllDiagnostics(); - getDiagnostics().setSuppressAllDiagnostics(true); - ExprResult ReductionOp = - BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, - RefExpr, RefExpr); - getDiagnostics().setSuppressAllDiagnostics(Suppress); - if (ReductionOp.isInvalid()) { - Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type - << ReductionIdRange; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be @@ -4924,55 +5597,160 @@ OMPClause *Sema::ActOnOpenMPReductionClause( continue; } } - - CXXRecordDecl *RD = getLangOpts().CPlusPlus - ? Type.getNonReferenceType()->getAsCXXRecordDecl() - : nullptr; - // FIXME This code must be replaced by actual constructing/destructing of - // the reduction variable. - if (RD) { - CXXConstructorDecl *CD = LookupDefaultConstructor(RD); - PartialDiagnostic PD = - PartialDiagnostic(PartialDiagnostic::NullDiagnostic()); - if (!CD || - CheckConstructorAccess(ELoc, CD, - InitializedEntity::InitializeTemporary(Type), - CD->getAccess(), PD) == AR_inaccessible || - CD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_reduction) << 0; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; + Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); + auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs"); + auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName()); + // Add initializer for private variable. + Expr *Init = nullptr; + switch (BOK) { + case BO_Add: + case BO_Xor: + case BO_Or: + case BO_LOr: + // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. + if (Type->isScalarType() || Type->isAnyComplexType()) { + Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); } - MarkFunctionReferenced(ELoc, CD); - DiagnoseUseOfDecl(CD, ELoc); - - CXXDestructorDecl *DD = RD->getDestructor(); - if (DD) { - if (CheckDestructorAccess(ELoc, DD, PD) == AR_inaccessible || - DD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_reduction) << 4; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; + break; + case BO_Mul: + case BO_LAnd: + if (Type->isScalarType() || Type->isAnyComplexType()) { + // '*' and '&&' reduction ops - initializer is '1'. + Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get(); + } + break; + case BO_And: { + // '&' reduction op - initializer is '~0'. + QualType OrigType = Type; + if (auto *ComplexTy = OrigType->getAs<ComplexType>()) { + Type = ComplexTy->getElementType(); + } + if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = + llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), + /*isIEEE=*/true); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); + } else if (Type->isScalarType()) { + auto Size = Context.getTypeSize(Type); + QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); + llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + } + if (Init && OrigType->isAnyComplexType()) { + // Init = 0xFFFF + 0xFFFFi; + auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); + Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); + } + Type = OrigType; + break; + } + case BO_LT: + case BO_GT: { + // 'min' reduction op - initializer is 'Largest representable number in + // the reduction list item type'. + // 'max' reduction op - initializer is 'Least representable number in + // the reduction list item type'. + if (Type->isIntegerType() || Type->isPointerType()) { + bool IsSigned = Type->hasSignedIntegerRepresentation(); + auto Size = Context.getTypeSize(Type); + QualType IntTy = + Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); + llvm::APInt InitValue = + (BOK != BO_LT) + ? IsSigned ? llvm::APInt::getSignedMinValue(Size) + : llvm::APInt::getMinValue(Size) + : IsSigned ? llvm::APInt::getSignedMaxValue(Size) + : llvm::APInt::getMaxValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + if (Type->isPointerType()) { + // Cast to pointer type. + auto CastExpr = BuildCStyleCastExpr( + SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), + SourceLocation(), Init); + if (CastExpr.isInvalid()) + continue; + Init = CastExpr.get(); } - MarkFunctionReferenced(ELoc, DD); - DiagnoseUseOfDecl(DD, ELoc); + } else if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = llvm::APFloat::getLargest( + Context.getFloatTypeSemantics(Type), BOK != BO_LT); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); + } + break; + } + case BO_PtrMemD: + case BO_PtrMemI: + case BO_MulAssign: + case BO_Div: + case BO_Rem: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: + case BO_Assign: + case BO_AddAssign: + case BO_SubAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_Comma: + llvm_unreachable("Unexpected reduction operation"); + } + if (Init) { + AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false, + /*TypeMayContainAuto=*/false); + } else { + ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false); + } + if (!RHSVD->hasInit()) { + Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type + << ReductionIdRange; + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc); + auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc); + ExprResult ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, + LHSDRE, RHSDRE); + if (ReductionOp.isUsable()) { + if (BOK != BO_LT && BOK != BO_GT) { + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ReductionOp.get()); + } else { + auto *ConditionalOp = new (Context) ConditionalOperator( + ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), + RHSDRE, Type, VK_LValue, OK_Ordinary); + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ConditionalOp); + } + if (ReductionOp.isUsable()) { + ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); } } + if (ReductionOp.isInvalid()) + continue; DSAStack->addDSA(VD, DE, OMPC_reduction); Vars.push_back(DE); + LHSs.push_back(LHSDRE); + RHSs.push_back(RHSDRE); + ReductionOps.push_back(ReductionOp.get()); } if (Vars.empty()) @@ -4980,7 +5758,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return OMPReductionClause::Create( Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId); + ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, LHSs, + RHSs, ReductionOps); } OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, @@ -4989,11 +5768,13 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, SourceLocation ColonLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> Inits; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + Inits.push_back(nullptr); continue; } @@ -5035,6 +5816,7 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, if (QType->isDependentType() || QType->isInstantiationDependentType()) { // It will be analyzed later. Vars.push_back(DE); + Inits.push_back(nullptr); continue; } @@ -5080,14 +5862,22 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, continue; } + // Build var to save initial value. + VarDecl *Init = buildVarDecl(*this, ELoc, QType, ".linear.start"); + AddInitializerToDecl(Init, DefaultLvalueConversion(DE).get(), + /*DirectInit*/ false, /*TypeMayContainAuto*/ false); + auto InitRef = buildDeclRefExpr( + *this, Init, DE->getType().getUnqualifiedType(), DE->getExprLoc()); DSAStack->addDSA(VD, DE, OMPC_linear); Vars.push_back(DE); + Inits.push_back(InitRef); } if (Vars.empty()) return nullptr; Expr *StepExpr = Step; + Expr *CalcStepExpr = nullptr; if (Step && !Step->isValueDependent() && !Step->isTypeDependent() && !Step->isInstantiationDependent() && !Step->containsUnexpandedParameterPack()) { @@ -5097,17 +5887,82 @@ OMPClause *Sema::ActOnOpenMPLinearClause(ArrayRef<Expr *> VarList, Expr *Step, return nullptr; StepExpr = Val.get(); + // Build var to save the step value. + VarDecl *SaveVar = + buildVarDecl(*this, StepLoc, StepExpr->getType(), ".linear.step"); + ExprResult SaveRef = + buildDeclRefExpr(*this, SaveVar, StepExpr->getType(), StepLoc); + ExprResult CalcStep = + BuildBinOp(CurScope, StepLoc, BO_Assign, SaveRef.get(), StepExpr); + // Warn about zero linear step (it would be probably better specified as // making corresponding variables 'const'). llvm::APSInt Result; - if (StepExpr->isIntegerConstantExpr(Result, Context) && - !Result.isNegative() && !Result.isStrictlyPositive()) + bool IsConstant = StepExpr->isIntegerConstantExpr(Result, Context); + if (IsConstant && !Result.isNegative() && !Result.isStrictlyPositive()) Diag(StepLoc, diag::warn_omp_linear_step_zero) << Vars[0] << (Vars.size() > 1); + if (!IsConstant && CalcStep.isUsable()) { + // Calculate the step beforehand instead of doing this on each iteration. + // (This is not used if the number of iterations may be kfold-ed). + CalcStepExpr = CalcStep.get(); + } } return OMPLinearClause::Create(Context, StartLoc, LParenLoc, ColonLoc, EndLoc, - Vars, StepExpr); + Vars, Inits, StepExpr, CalcStepExpr); +} + +static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, + Expr *NumIterations, Sema &SemaRef, + Scope *S) { + // Walk the vars and build update/final expressions for the CodeGen. + SmallVector<Expr *, 8> Updates; + SmallVector<Expr *, 8> Finals; + Expr *Step = Clause.getStep(); + Expr *CalcStep = Clause.getCalcStep(); + // OpenMP [2.14.3.7, linear clause] + // If linear-step is not specified it is assumed to be 1. + if (Step == nullptr) + Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(); + else if (CalcStep) + Step = cast<BinaryOperator>(CalcStep)->getLHS(); + bool HasErrors = false; + auto CurInit = Clause.inits().begin(); + for (auto &RefExpr : Clause.varlists()) { + Expr *InitExpr = *CurInit; + + // Build privatized reference to the current linear var. + auto DE = cast<DeclRefExpr>(RefExpr); + auto PrivateRef = + buildDeclRefExpr(SemaRef, cast<VarDecl>(DE->getDecl()), + DE->getType().getUnqualifiedType(), DE->getExprLoc(), + /*RefersToCapture=*/true); + + // Build update: Var = InitExpr + IV * Step + ExprResult Update = + BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), PrivateRef, + InitExpr, IV, Step, /* Subtract */ false); + Update = SemaRef.ActOnFinishFullExpr(Update.get()); + + // Build final: Var = InitExpr + NumIterations * Step + ExprResult Final = + BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), PrivateRef, + InitExpr, NumIterations, Step, /* Subtract */ false); + Final = SemaRef.ActOnFinishFullExpr(Final.get()); + if (!Update.isUsable() || !Final.isUsable()) { + Updates.push_back(nullptr); + Finals.push_back(nullptr); + HasErrors = true; + } else { + Updates.push_back(Update.get()); + Finals.push_back(Final.get()); + } + ++CurInit; + } + Clause.setUpdates(Updates); + Clause.setFinals(Finals); + return HasErrors; } OMPClause *Sema::ActOnOpenMPAlignedClause( @@ -5137,10 +5992,8 @@ OMPClause *Sema::ActOnOpenMPAlignedClause( // OpenMP [2.8.1, simd construct, Restrictions] // The type of list items appearing in the aligned clause must be // array, pointer, reference to array, or reference to pointer. - QualType QType = DE->getType() - .getNonReferenceType() - .getUnqualifiedType() - .getCanonicalType(); + QualType QType = VD->getType(); + QType = QType.getNonReferenceType().getUnqualifiedType().getCanonicalType(); const Type *Ty = QType.getTypePtrOrNull(); if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() && !Ty->isPointerType())) { @@ -5190,11 +6043,17 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> SrcExprs; + SmallVector<Expr *, 8> DstExprs; + SmallVector<Expr *, 8> AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP copyin clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + SrcExprs.push_back(nullptr); + DstExprs.push_back(nullptr); + AssignmentOps.push_back(nullptr); continue; } @@ -5216,6 +6075,9 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, 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; } @@ -5232,40 +6094,38 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, // A variable of class type (or array thereof) that appears in a // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. - Type = Context.getBaseElementType(Type); - CXXRecordDecl *RD = - getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; - // FIXME This code must be replaced by actual assignment of the - // threadprivate variable. - if (RD) { - CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); - DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); - if (MD) { - if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || - MD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_copyin) << 2; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, MD); - DiagnoseUseOfDecl(MD, ELoc); - } - } + auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); + auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), + ElemType.getUnqualifiedType(), ".copyin.src"); + auto *PseudoSrcExpr = buildDeclRefExpr( + *this, SrcVD, ElemType.getUnqualifiedType(), DE->getExprLoc()); + auto *DstVD = + buildVarDecl(*this, DE->getLocStart(), ElemType, ".copyin.dst"); + auto *PseudoDstExpr = + buildDeclRefExpr(*this, DstVD, ElemType, DE->getExprLoc()); + // 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, + PseudoDstExpr, PseudoSrcExpr); + if (AssignmentOp.isInvalid()) + continue; + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + /*DiscardedValue=*/true); + if (AssignmentOp.isInvalid()) + continue; DSAStack->addDSA(VD, DE, OMPC_copyin); Vars.push_back(DE); + SrcExprs.push_back(PseudoSrcExpr); + DstExprs.push_back(PseudoDstExpr); + AssignmentOps.push_back(AssignmentOp.get()); } if (Vars.empty()) return nullptr; - return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); + return OMPCopyinClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, + SrcExprs, DstExprs, AssignmentOps); } OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, @@ -5273,11 +6133,17 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, SourceLocation LParenLoc, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; + SmallVector<Expr *, 8> SrcExprs; + SmallVector<Expr *, 8> DstExprs; + SmallVector<Expr *, 8> AssignmentOps; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); + SrcExprs.push_back(nullptr); + DstExprs.push_back(nullptr); + AssignmentOps.push_back(nullptr); continue; } @@ -5299,6 +6165,9 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, 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; } @@ -5307,8 +6176,8 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // private or firstprivate clause on the single construct. if (!DSAStack->isThreadPrivate(VD)) { auto DVar = DSAStack->getTopDSA(VD, false); - if (DVar.CKind != OMPC_copyprivate && DVar.CKind != OMPC_unknown && - !(DVar.CKind == OMPC_private && !DVar.RefExpr)) { + if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate && + DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_copyprivate); @@ -5331,45 +6200,54 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, } } + // Variably modified types are not supported. + if (!Type->isAnyPointerType() && Type->isVariablyModifiedType()) { + Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) + << getOpenMPClauseName(OMPC_copyprivate) << Type + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + bool IsDecl = + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(VD->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << VD; + continue; + } + // OpenMP [2.14.4.1, Restrictions, C/C++, p.2] // A variable of class type (or array thereof) that appears in a // copyin clause requires an accessible, unambiguous copy assignment // operator for the class type. - Type = Context.getBaseElementType(Type); - CXXRecordDecl *RD = - getLangOpts().CPlusPlus ? Type->getAsCXXRecordDecl() : nullptr; - // FIXME This code must be replaced by actual assignment of the - // threadprivate variable. - if (RD) { - CXXMethodDecl *MD = LookupCopyingAssignment(RD, 0, false, 0); - DeclAccessPair FoundDecl = DeclAccessPair::make(MD, MD->getAccess()); - if (MD) { - if (CheckMemberAccess(ELoc, RD, FoundDecl) == AR_inaccessible || - MD->isDeleted()) { - Diag(ELoc, diag::err_omp_required_method) - << getOpenMPClauseName(OMPC_copyprivate) << 2; - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - Diag(RD->getLocation(), diag::note_previous_decl) << RD; - continue; - } - MarkFunctionReferenced(ELoc, MD); - DiagnoseUseOfDecl(MD, ELoc); - } - } + Type = Context.getBaseElementType(Type).getUnqualifiedType(); + auto *SrcVD = + buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src"); + auto *PseudoSrcExpr = + buildDeclRefExpr(*this, SrcVD, Type, DE->getExprLoc()); + auto *DstVD = + buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst"); + auto *PseudoDstExpr = + buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); + auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, + PseudoDstExpr, PseudoSrcExpr); + if (AssignmentOp.isInvalid()) + continue; + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + /*DiscardedValue=*/true); + if (AssignmentOp.isInvalid()) + continue; // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. Vars.push_back(DE); + SrcExprs.push_back(PseudoSrcExpr); + DstExprs.push_back(PseudoDstExpr); + AssignmentOps.push_back(AssignmentOp.get()); } if (Vars.empty()) return nullptr; - return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); + return OMPCopyprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, + Vars, SrcExprs, DstExprs, AssignmentOps); } OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, |