From 60da77e4388c09f22e5dd0d56b9049c5ac5d5bf3 Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Mon, 29 Feb 2016 05:54:20 +0000 Subject: [PATCH] [OPENMP 4.5] Initial support for data members in 'reduction' clauses. OpenMP 4.5 allows to privatize non-static data members of current class in non-static member functions. Patch adds initial parsing/semantic analysis for data members support in 'reduction' clauses. llvm-svn: 262199 --- clang/lib/AST/StmtPrinter.cpp | 26 +-- clang/lib/Sema/SemaOpenMP.cpp | 286 +++++++++++++++++-------------- clang/test/OpenMP/parallel_ast_print.cpp | 22 +++ 3 files changed, 191 insertions(+), 143 deletions(-) diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 5013fa6..6938aef 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -666,14 +666,7 @@ void OMPClausePrinter::VisitOMPScheduleClause(OMPScheduleClause *Node) { OS << getOpenMPSimpleClauseTypeName(OMPC_schedule, Node->getScheduleKind()); if (auto *E = Node->getChunkSize()) { OS << ", "; - if (Node->getPreInitStmt()) { - cast( - cast(E->IgnoreImpCasts())->getDecl()) - ->getInit() - ->IgnoreImpCasts() - ->printPretty(OS, nullptr, Policy); - } else - E->printPretty(OS, nullptr, Policy); + E->printPretty(OS, nullptr, Policy); } OS << ")"; } @@ -775,8 +768,8 @@ void OMPClausePrinter::VisitOMPClauseList(T *Node, char StartSym) { assert(*I && "Expected non-null Stmt"); OS << (I == Node->varlist_begin() ? StartSym : ','); if (DeclRefExpr *DRE = dyn_cast(*I)) { - if (auto *CED = dyn_cast(DRE->getDecl())) - CED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy, 0); + if (isa(DRE->getDecl())) + DRE->printPretty(OS, nullptr, Policy, 0); else DRE->getDecl()->printQualifiedName(OS); } else @@ -924,14 +917,7 @@ void OMPClausePrinter::VisitOMPDistScheduleClause(OMPDistScheduleClause *Node) { OMPC_dist_schedule, Node->getDistScheduleKind()); if (auto *E = Node->getChunkSize()) { OS << ", "; - if (Node->getPreInitStmt()) { - cast( - cast(E->IgnoreImpCasts())->getDecl()) - ->getInit() - ->IgnoreImpCasts() - ->printPretty(OS, nullptr, Policy); - } else - E->printPretty(OS, nullptr, Policy); + E->printPretty(OS, nullptr, Policy); } OS << ")"; } @@ -1150,6 +1136,10 @@ void StmtPrinter::VisitOMPDistributeDirective(OMPDistributeDirective *Node) { //===----------------------------------------------------------------------===// void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) { + if (auto *OCED = dyn_cast(Node->getDecl())) { + OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy); + return; + } if (NestedNameSpecifier *Qualifier = Node->getQualifier()) Qualifier->print(OS, Policy); if (Node->hasTemplateKeyword()) diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 2463c37..e115a2f 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -7096,27 +7096,60 @@ ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, return Res; } -static std::pair getPrivateItem(Sema &S, Expr *RefExpr) { +static std::pair +getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, + SourceRange &ERange, bool AllowArraySection = false) { if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || RefExpr->containsUnexpandedParameterPack()) return std::make_pair(nullptr, true); - SourceLocation ELoc = RefExpr->getExprLoc(); - SourceRange SR = RefExpr->getSourceRange(); // OpenMP [3.1, C/C++] // A list item is a variable name. // OpenMP [2.9.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. RefExpr = RefExpr->IgnoreParens(); + enum { + NoArrayExpr = -1, + ArraySubscript = 0, + OMPArraySection = 1 + } IsArrayExpr = NoArrayExpr; + if (AllowArraySection) { + if (auto *ASE = dyn_cast_or_null(RefExpr)) { + auto *Base = ASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + RefExpr = Base; + IsArrayExpr = ArraySubscript; + } else if (auto *OASE = dyn_cast_or_null(RefExpr)) { + auto *Base = OASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempOASE = dyn_cast(Base)) + Base = TempOASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + RefExpr = Base; + IsArrayExpr = OMPArraySection; + } + } + ELoc = RefExpr->getExprLoc(); + ERange = RefExpr->getSourceRange(); + RefExpr = RefExpr->IgnoreParenImpCasts(); auto *DE = dyn_cast_or_null(RefExpr); auto *ME = dyn_cast_or_null(RefExpr); if ((!DE || !isa(DE->getDecl())) && (S.getCurrentThisType().isNull() || !ME || !isa(ME->getBase()->IgnoreParenImpCasts()) || !isa(ME->getMemberDecl()))) { - S.Diag(ELoc, diag::err_omp_expected_var_name_member_expr) - << (S.getCurrentThisType().isNull() ? 0 : 1) << SR; + if (IsArrayExpr != NoArrayExpr) + S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr + << ERange; + else { + S.Diag(ELoc, + AllowArraySection + ? diag::err_omp_expected_var_name_member_expr_or_array_item + : diag::err_omp_expected_var_name_member_expr) + << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange; + } return std::make_pair(nullptr, false); } return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false); @@ -7130,7 +7163,10 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, SmallVector PrivateCopies; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); - auto Res = getPrivateItem(*this, RefExpr); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -7140,7 +7176,6 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, if (!D) continue; - SourceLocation ELoc = RefExpr->getExprLoc(); QualType Type = D->getType(); auto *VD = dyn_cast(D); @@ -7201,7 +7236,7 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef VarList, DeclRefExpr *Ref = nullptr; if (!VD) - Ref = buildCapture(*this, D, RefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr); DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref); PrivateCopies.push_back(VDPrivateRefExpr); @@ -7251,7 +7286,10 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP firstprivate clause."); - auto Res = getPrivateItem(*this, RefExpr); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -7262,8 +7300,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, if (!D) continue; - SourceLocation ELoc = - IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc(); + ELoc = IsImplicitClause ? ImplicitClauseLoc : ELoc; QualType Type = D->getType(); auto *VD = dyn_cast(D); @@ -7483,7 +7520,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef VarList, if (TopDVar.CKind == OMPC_lastprivate) Ref = TopDVar.PrivateCopy; else { - Ref = buildCapture(*this, D, RefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr); if (!IsOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } @@ -7520,7 +7557,10 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, SmallVector ExprPostUpdates; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); - auto Res = getPrivateItem(*this, RefExpr); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -7532,7 +7572,6 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, if (!D) continue; - SourceLocation ELoc = RefExpr->getExprLoc(); QualType Type = D->getType(); auto *VD = dyn_cast(D); @@ -7601,13 +7640,13 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, // lastprivate clause requires an accessible, unambiguous copy assignment // operator for the class type. Type = Context.getBaseElementType(Type).getNonReferenceType(); - auto *SrcVD = buildVarDecl(*this, RefExpr->getLocStart(), + auto *SrcVD = buildVarDecl(*this, ERange.getBegin(), Type.getUnqualifiedType(), ".lastprivate.src", D->hasAttrs() ? &D->getAttrs() : nullptr); auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc); auto *DstVD = - buildVarDecl(*this, RefExpr->getLocStart(), Type, ".lastprivate.dst", + buildVarDecl(*this, ERange.getBegin(), Type, ".lastprivate.dst", D->hasAttrs() ? &D->getAttrs() : nullptr); auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); // For arrays generate assignment operation for single element and replace @@ -7626,7 +7665,7 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, if (TopDVar.CKind == OMPC_firstprivate) Ref = TopDVar.PrivateCopy; else { - Ref = buildCapture(*this, D, RefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr); if (!IsOpenMPCapturedDecl(D)) ExprCaptures.push_back(Ref->getDecl()); } @@ -7637,8 +7676,8 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef VarList, if (!RefRes.isUsable()) continue; ExprResult PostUpdateRes = - BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, - RefExpr->IgnoreParenLValueCasts(), RefRes.get()); + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr, + RefRes.get()); if (!PostUpdateRes.isUsable()) continue; ExprPostUpdates.push_back(PostUpdateRes.get()); @@ -7684,7 +7723,10 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, SmallVector Vars; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); - auto Res = getPrivateItem(*this, RefExpr); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); @@ -7693,7 +7735,6 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, if (!D) continue; - SourceLocation ELoc = RefExpr->getExprLoc(); auto *VD = dyn_cast(D); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] @@ -7713,7 +7754,7 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef VarList, DeclRefExpr *Ref = nullptr; if (!VD) - Ref = buildCapture(*this, D, RefExpr); + Ref = buildCapture(*this, D, SimpleRefExpr); DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref); Vars.push_back(VD ? RefExpr->IgnoreParens() : Ref); } @@ -7755,6 +7796,30 @@ public: }; } // namespace +namespace { +// Transform MemberExpression for specified FieldDecl of current class to +// DeclRefExpr to specified OMPCapturedExprDecl. +class TransformExprToCaptures : public TreeTransform { + typedef TreeTransform BaseTransform; + ValueDecl *Field; + DeclRefExpr *CapturedExpr; + +public: + TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl) + : BaseTransform(SemaRef), Field(FieldDecl), CapturedExpr(nullptr) {} + + ExprResult TransformMemberExpr(MemberExpr *E) { + if (isa(E->getBase()->IgnoreParenImpCasts()) && + E->getMemberDecl() == Field) { + CapturedExpr = buildCapture(SemaRef, Field, E); + return CapturedExpr; + } + return BaseTransform::TransformMemberExpr(E); + } + DeclRefExpr *getCapturedExpr() { return CapturedExpr; } +}; +} // namespace + OMPClause *Sema::ActOnOpenMPReductionClause( ArrayRef VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, @@ -7866,85 +7931,45 @@ OMPClause *Sema::ActOnOpenMPReductionClause( SmallVector ReductionOps; for (auto RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); - if (isa(RefExpr)) { + // OpenMP [2.1, C/C++] + // A list item is a variable or array section, subject to the restrictions + // specified in Section 2.4 on page 42 and in each of the sections + // describing clauses and directives for which a list appears. + // OpenMP [2.14.3.3, Restrictions, p.1] + // A variable that is part of another variable (as an array or + // structure element) cannot appear in a private clause. + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); Privates.push_back(nullptr); LHSs.push_back(nullptr); RHSs.push_back(nullptr); ReductionOps.push_back(nullptr); - continue; } - - if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || - RefExpr->isInstantiationDependent() || - RefExpr->containsUnexpandedParameterPack()) { - // It will be analyzed later. - Vars.push_back(RefExpr); - Privates.push_back(nullptr); - LHSs.push_back(nullptr); - RHSs.push_back(nullptr); - ReductionOps.push_back(nullptr); + ValueDecl *D = Res.first; + if (!D) continue; - } - auto ELoc = RefExpr->getExprLoc(); - auto ERange = RefExpr->getSourceRange(); - // OpenMP [2.1, C/C++] - // A list item is a variable or array section, subject to the restrictions - // specified in Section 2.4 on page 42 and in each of the sections - // describing clauses and directives for which a list appears. - // OpenMP [2.14.3.3, Restrictions, p.1] - // A variable that is part of another variable (as an array or - // structure element) cannot appear in a private clause. - auto *DE = dyn_cast(RefExpr); - auto *ASE = dyn_cast(RefExpr); - auto *OASE = dyn_cast(RefExpr); - if (!ASE && !OASE && (!DE || !isa(DE->getDecl()))) { - Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item) - << 0 << ERange; - continue; - } QualType Type; - VarDecl *VD = nullptr; - if (DE) { - auto D = DE->getDecl(); - VD = cast(D); - Type = Context.getBaseElementType(VD->getType().getNonReferenceType()); - } else if (ASE) { + auto *ASE = dyn_cast(RefExpr->IgnoreParens()); + auto *OASE = dyn_cast(RefExpr->IgnoreParens()); + if (ASE) Type = ASE->getType().getNonReferenceType(); - auto *Base = ASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempASE = dyn_cast(Base)) - Base = TempASE->getBase()->IgnoreParenImpCasts(); - DE = dyn_cast(Base); - if (DE) - VD = dyn_cast(DE->getDecl()); - if (!VD) { - Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) - << 0 << Base->getSourceRange(); - continue; - } - } else if (OASE) { + else if (OASE) { auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); if (auto *ATy = BaseType->getAsArrayTypeUnsafe()) Type = ATy->getElementType(); else Type = BaseType->getPointeeType(); Type = Type.getNonReferenceType(); - auto *Base = OASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempOASE = dyn_cast(Base)) - Base = TempOASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempASE = dyn_cast(Base)) - Base = TempASE->getBase()->IgnoreParenImpCasts(); - DE = dyn_cast(Base); - if (DE) - VD = dyn_cast(DE->getDecl()); - if (!VD) { - Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) - << 1 << Base->getSourceRange(); - continue; - } - } + } else + Type = Context.getBaseElementType(D->getType().getNonReferenceType()); + auto *VD = dyn_cast(D); // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete @@ -7959,18 +7984,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause( Diag(ELoc, diag::err_omp_const_reduction_list_item) << getOpenMPClauseName(OMPC_reduction) << Type << ERange; if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; } continue; } // OpenMP [2.9.3.6, Restrictions, C/C++, p.4] // If a list-item is a reference type then it must bind to the same object // for all threads of the team. - if (!ASE && !OASE) { + if (!ASE && !OASE && VD) { VarDecl *VDDef = VD->getDefinition(); if (VD->getType()->isReferenceType() && VDDef) { DSARefChecker Check(DSAStack); @@ -7995,11 +8021,12 @@ OMPClause *Sema::ActOnOpenMPReductionClause( Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) << getLangOpts().CPlusPlus; if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; } continue; } @@ -8007,11 +8034,12 @@ OMPClause *Sema::ActOnOpenMPReductionClause( !getLangOpts().CPlusPlus && Type->isFloatingType()) { Diag(ELoc, diag::err_omp_clause_floating_type_arg); if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; } continue; } @@ -8027,18 +8055,17 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // but a list item can appear only once in the reduction clauses for that // directive. DSAStackTy::DSAVarData DVar; - DVar = DSAStack->getTopDSA(VD, false); + DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind == OMPC_reduction) { Diag(ELoc, diag::err_omp_once_referenced) << getOpenMPClauseName(OMPC_reduction); - if (DVar.RefExpr) { + if (DVar.RefExpr) Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); - } } else if (DVar.CKind != OMPC_unknown) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_reduction); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -8049,24 +8076,25 @@ OMPClause *Sema::ActOnOpenMPReductionClause( OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_reduction) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; if (OASE || - (DE && VD->getType().getNonReferenceType()->isVariablyModifiedType())) { + (!ASE && + D->getType().getNonReferenceType()->isVariablyModifiedType())) { // For arays/array sections only: // Create pseudo array type for private copy. The size for this array will // be generated during codegen. @@ -8076,12 +8104,12 @@ OMPClause *Sema::ActOnOpenMPReductionClause( Type, new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(), VK_RValue), ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); - } else if (DE && - Context.getAsArrayType(VD->getType().getNonReferenceType())) - PrivateTy = VD->getType().getNonReferenceType(); + } else if (!ASE && !OASE && + Context.getAsArrayType(D->getType().getNonReferenceType())) + PrivateTy = D->getType().getNonReferenceType(); // Private copy. - auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); // Add initializer for private variable. Expr *Init = nullptr; switch (BOK) { @@ -8090,9 +8118,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( case BO_Or: case BO_LOr: // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. - if (Type->isScalarType() || Type->isAnyComplexType()) { + if (Type->isScalarType() || Type->isAnyComplexType()) Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); - } break; case BO_Mul: case BO_LAnd: @@ -8104,9 +8131,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( case BO_And: { // '&' reduction op - initializer is '~0'. QualType OrigType = Type; - if (auto *ComplexTy = OrigType->getAs()) { + if (auto *ComplexTy = OrigType->getAs()) Type = ComplexTy->getElementType(); - } if (Type->isRealFloatingType()) { llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), @@ -8195,13 +8221,12 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (!RHSVD->hasInit()) { Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type << ReductionIdRange; - if (VD) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - } + bool IsDecl = + !VD || + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; continue; } // Store initializer for single element in private copy. Will be used during @@ -8232,8 +8257,19 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (ReductionOp.isInvalid()) continue; - DSAStack->addDSA(VD, DE, OMPC_reduction); - Vars.push_back(RefExpr); + DeclRefExpr *Ref = nullptr; + Expr *VarsExpr = RefExpr->IgnoreParens(); + if (!VD) { + if (ASE || OASE) { + TransformExprToCaptures RebuildToCapture(*this, D); + VarsExpr = + RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get(); + Ref = RebuildToCapture.getCapturedExpr(); + } else + VarsExpr = Ref = buildCapture(*this, D, SimpleRefExpr); + } + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); + Vars.push_back(VarsExpr); Privates.push_back(PrivateDRE); LHSs.push_back(LHSDRE); RHSs.push_back(RHSDRE); diff --git a/clang/test/OpenMP/parallel_ast_print.cpp b/clang/test/OpenMP/parallel_ast_print.cpp index b73ab4e..3391b2c 100644 --- a/clang/test/OpenMP/parallel_ast_print.cpp +++ b/clang/test/OpenMP/parallel_ast_print.cpp @@ -13,12 +13,17 @@ struct S1 { S1(int v) : a(v) {} int a; typedef int type; + S1& operator +(const S1&); + S1& operator *(const S1&); + S1& operator &&(const S1&); + S1& operator ^(const S1&); }; template class S7 : public T { protected: T a; + T b[100]; S7() : a(0) {} public: @@ -32,6 +37,9 @@ public: #pragma omp parallel shared(a) shared(this->a) shared(T::a) for (int k = 0; k < a.a; ++k) ++this->a.a; +#pragma omp parallel reduction(+ : a) reduction(*: b[:]) + for (int k = 0; k < a.a; ++k) + ++this->a.a; } S7 &operator=(S7 &s) { #pragma omp parallel private(a) private(this->a) @@ -43,6 +51,9 @@ public: #pragma omp parallel shared(a) shared(this->a) for (int k = 0; k < s.a.a; ++k) ++s.a.a; +#pragma omp parallel reduction(&& : this->a) reduction(^: b[s.a.a]) + for (int k = 0; k < s.a.a; ++k) + ++s.a.a; return *this; } }; @@ -50,12 +61,15 @@ public: // CHECK: #pragma omp parallel private(this->a) private(this->a) private(this->S1::a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) firstprivate(this->S1::a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) shared(this->S1::a) +// CHECK: #pragma omp parallel reduction(+: this->a) reduction(*: this->b[:]) // CHECK: #pragma omp parallel private(this->a) private(this->a) private(T::a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) firstprivate(T::a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) shared(T::a) +// CHECK: #pragma omp parallel reduction(+: this->a) reduction(*: this->b[:]) // CHECK: #pragma omp parallel private(this->a) private(this->a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) +// CHECK: #pragma omp parallel reduction(&&: this->a) reduction(^: this->b[s.a.a]) class S8 : public S7 { S8() {} @@ -71,6 +85,9 @@ public: #pragma omp parallel shared(a) shared(this->a) shared(S7 < S1 > ::a) for (int k = 0; k < a.a; ++k) ++this->a.a; +#pragma omp parallel reduction(^ : S7 < S1 > ::a) reduction(+ : S7 < S1 > ::b[ : S7 < S1 > ::a.a]) + for (int k = 0; k < a.a; ++k) + ++this->a.a; } S8 &operator=(S8 &s) { #pragma omp parallel private(a) private(this->a) @@ -82,6 +99,9 @@ public: #pragma omp parallel shared(a) shared(this->a) for (int k = 0; k < s.a.a; ++k) ++s.a.a; +#pragma omp parallel reduction(* : this->a) reduction(&&:this->b[a.a:]) + for (int k = 0; k < s.a.a; ++k) + ++s.a.a; return *this; } }; @@ -89,9 +109,11 @@ public: // CHECK: #pragma omp parallel private(this->a) private(this->a) private(this->S7::a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) firstprivate(this->S7::a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) shared(this->S7::a) +// CHECK: #pragma omp parallel reduction(^: this->S7::a) reduction(+: this->S7::b[:this->S7::a.a]) // CHECK: #pragma omp parallel private(this->a) private(this->a) // CHECK: #pragma omp parallel firstprivate(this->a) firstprivate(this->a) // CHECK: #pragma omp parallel shared(this->a) shared(this->a) +// CHECK: #pragma omp parallel reduction(*: this->a) reduction(&&: this->b[this->a.a:]) template struct S { -- 2.7.4