diff options
Diffstat (limited to 'clang/lib')
24 files changed, 732 insertions, 19 deletions
diff --git a/clang/lib/AST/CXXInheritance.cpp b/clang/lib/AST/CXXInheritance.cpp index 6785a0c2935..6a6ca76a016 100644 --- a/clang/lib/AST/CXXInheritance.cpp +++ b/clang/lib/AST/CXXInheritance.cpp @@ -405,6 +405,21 @@ bool CXXRecordDecl::FindOrdinaryMember(const CXXBaseSpecifier *Specifier, return false; } +bool CXXRecordDecl::FindOMPReductionMember(const CXXBaseSpecifier *Specifier, + CXXBasePath &Path, + DeclarationName Name) { + RecordDecl *BaseRecord = + Specifier->getType()->castAs<RecordType>()->getDecl(); + + for (Path.Decls = BaseRecord->lookup(Name); !Path.Decls.empty(); + Path.Decls = Path.Decls.slice(1)) { + if (Path.Decls.front()->isInIdentifierNamespace(IDNS_OMPReduction)) + return true; + } + + return false; +} + bool CXXRecordDecl:: FindNestedNameSpecifierMember(const CXXBaseSpecifier *Specifier, CXXBasePath &Path, diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 6451a5c4b17..041b530bf07 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -18,6 +18,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" diff --git a/clang/lib/AST/DeclBase.cpp b/clang/lib/AST/DeclBase.cpp index a572687afe6..27ccb7d5d76 100644 --- a/clang/lib/AST/DeclBase.cpp +++ b/clang/lib/AST/DeclBase.cpp @@ -633,6 +633,9 @@ unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { case TemplateTemplateParm: return IDNS_Ordinary | IDNS_Tag | IDNS_Type; + case OMPDeclareReduction: + return IDNS_OMPReduction; + // Never have names. case Friend: case FriendTemplate: @@ -963,6 +966,7 @@ DeclContext *DeclContext::getPrimaryContext() { case Decl::LinkageSpec: case Decl::Block: case Decl::Captured: + case Decl::OMPDeclareReduction: // There is only one DeclContext for these entities. return this; diff --git a/clang/lib/AST/DeclOpenMP.cpp b/clang/lib/AST/DeclOpenMP.cpp index 2c474106e89..5b06ce0778a 100644 --- a/clang/lib/AST/DeclOpenMP.cpp +++ b/clang/lib/AST/DeclOpenMP.cpp @@ -54,6 +54,36 @@ void OMPThreadPrivateDecl::setVars(ArrayRef<Expr *> VL) { } //===----------------------------------------------------------------------===// +// OMPDeclareReductionDecl Implementation. +//===----------------------------------------------------------------------===// + +void OMPDeclareReductionDecl::anchor() {} + +OMPDeclareReductionDecl *OMPDeclareReductionDecl::Create( + ASTContext &C, DeclContext *DC, SourceLocation L, DeclarationName Name, + QualType T, OMPDeclareReductionDecl *PrevDeclInScope) { + return new (C, DC) OMPDeclareReductionDecl(OMPDeclareReduction, DC, L, Name, + T, PrevDeclInScope); +} + +OMPDeclareReductionDecl * +OMPDeclareReductionDecl::CreateDeserialized(ASTContext &C, unsigned ID) { + return new (C, ID) OMPDeclareReductionDecl( + OMPDeclareReduction, /*DC=*/nullptr, SourceLocation(), DeclarationName(), + QualType(), /*PrevDeclInScope=*/nullptr); +} + +OMPDeclareReductionDecl *OMPDeclareReductionDecl::getPrevDeclInScope() { + return cast_or_null<OMPDeclareReductionDecl>( + PrevDeclInScope.get(getASTContext().getExternalSource())); +} +const OMPDeclareReductionDecl * +OMPDeclareReductionDecl::getPrevDeclInScope() const { + return cast_or_null<OMPDeclareReductionDecl>( + PrevDeclInScope.get(getASTContext().getExternalSource())); +} + +//===----------------------------------------------------------------------===// // OMPCapturedExprDecl Implementation. //===----------------------------------------------------------------------===// diff --git a/clang/lib/AST/DeclPrinter.cpp b/clang/lib/AST/DeclPrinter.cpp index 76940840f42..dd3f3b4a0d9 100644 --- a/clang/lib/AST/DeclPrinter.cpp +++ b/clang/lib/AST/DeclPrinter.cpp @@ -92,6 +92,7 @@ namespace { void VisitUsingDecl(UsingDecl *D); void VisitUsingShadowDecl(UsingShadowDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); void PrintTemplateParameters(const TemplateParameterList *Params, @@ -334,7 +335,7 @@ void DeclPrinter::VisitDeclContext(DeclContext *DC, bool Indent) { // FIXME: Need to be able to tell the DeclPrinter when const char *Terminator = nullptr; - if (isa<OMPThreadPrivateDecl>(*D)) + if (isa<OMPThreadPrivateDecl>(*D) || isa<OMPDeclareReductionDecl>(*D)) Terminator = nullptr; else if (isa<FunctionDecl>(*D) && cast<FunctionDecl>(*D)->isThisDeclarationADefinition()) @@ -1367,6 +1368,37 @@ void DeclPrinter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { } } +void DeclPrinter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + if (!D->isInvalidDecl()) { + Out << "#pragma omp declare reduction ("; + if (D->getDeclName().getNameKind() == DeclarationName::CXXOperatorName) { + static const char *const OperatorNames[NUM_OVERLOADED_OPERATORS] = { + nullptr, +#define OVERLOADED_OPERATOR(Name, Spelling, Token, Unary, Binary, MemberOnly) \ + Spelling, +#include "clang/Basic/OperatorKinds.def" + }; + const char *OpName = + OperatorNames[D->getDeclName().getCXXOverloadedOperator()]; + assert(OpName && "not an overloaded operator"); + Out << OpName; + } else { + assert(D->getDeclName().isIdentifier()); + D->printName(Out); + } + Out << " : "; + D->getType().print(Out, Policy); + Out << " : "; + D->getCombiner()->printPretty(Out, nullptr, Policy, 0); + Out << ")"; + if (auto *Init = D->getInitializer()) { + Out << " initializer("; + Init->printPretty(Out, nullptr, Policy, 0); + Out << ")"; + } + } +} + void DeclPrinter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { D->getInit()->printPretty(Out, nullptr, Policy, Indentation); } diff --git a/clang/lib/AST/ItaniumMangle.cpp b/clang/lib/AST/ItaniumMangle.cpp index 68f76f54eda..71c94104ccc 100644 --- a/clang/lib/AST/ItaniumMangle.cpp +++ b/clang/lib/AST/ItaniumMangle.cpp @@ -20,6 +20,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -66,8 +67,9 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) { } const DeclContext *DC = D->getDeclContext(); - if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC)) - return getEffectiveDeclContext(CD); + if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) { + return getEffectiveDeclContext(cast<Decl>(DC)); + } if (const auto *VD = dyn_cast<VarDecl>(D)) if (VD->isExternC()) diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp index 930cf00d9e3..65b7905f962 100644 --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -58,8 +59,9 @@ static const DeclContext *getEffectiveDeclContext(const Decl *D) { } const DeclContext *DC = D->getDeclContext(); - if (const CapturedDecl *CD = dyn_cast<CapturedDecl>(DC)) - return getEffectiveDeclContext(CD); + if (isa<CapturedDecl>(DC) || isa<OMPDeclareReductionDecl>(DC)) { + return getEffectiveDeclContext(cast<Decl>(DC)); + } return DC; } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index ae509772f35..3b5bc56036b 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -554,6 +554,7 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind, case OMPD_taskwait: case OMPD_taskgroup: case OMPD_cancellation_point: + case OMPD_declare_reduction: break; } return false; diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp index c218ca41a1d..36d20cca380 100644 --- a/clang/lib/CodeGen/CGDecl.cpp +++ b/clang/lib/CodeGen/CGDecl.cpp @@ -21,6 +21,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/CodeGen/CGFunctionInfo.h" @@ -118,6 +119,9 @@ void CodeGenFunction::EmitDecl(const Decl &D) { return EmitVarDecl(VD); } + case Decl::OMPDeclareReduction: + return CGM.EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(&D)); + case Decl::Typedef: // typedef int X; case Decl::TypeAlias: { // using X = int; [C++0x] const TypedefNameDecl &TD = cast<TypedefNameDecl>(D); @@ -1862,3 +1866,7 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg, if (D.hasAttr<AnnotateAttr>()) EmitVarAnnotations(&D, DeclPtr.getPointer()); } + +void CodeGenModule::EmitOMPDeclareReduction( + const OMPDeclareReductionDecl * /*D*/) {} + diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 7df90346571..e171abeacee 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -3796,6 +3796,10 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) { break; } + case Decl::OMPDeclareReduction: + EmitOMPDeclareReduction(cast<OMPDeclareReductionDecl>(D)); + break; + default: // Make sure we handled everything we should, every other kind is a // non-top-level decl. FIXME: Would be nice to have an isTopLevelDeclKind diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index db2df793dbc..87183582e7d 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -21,6 +21,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclOpenMP.h" #include "clang/AST/GlobalDecl.h" #include "clang/AST/Mangle.h" #include "clang/Basic/ABI.h" @@ -1110,6 +1111,9 @@ public: /// \param D Threadprivate declaration. void EmitOMPThreadPrivateDecl(const OMPThreadPrivateDecl *D); + /// \brief Emit a code for declare reduction construct. + void EmitOMPDeclareReduction(const OMPDeclareReductionDecl *D); + /// Returns whether we need bit sets attached to vtables. bool NeedVTableBitSets(); diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index ab6f3ccc2db..8e6f1ab652b 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -3644,13 +3644,11 @@ void Parser::ParseStructUnionBody(SourceLocation RecordLoc, } if (Tok.is(tok::annot_pragma_openmp)) { - // Result can be ignored, because it must be always empty. - auto Res = ParseOpenMPDeclarativeDirective(); - assert(!Res); - // Silence possible warnings. - (void)Res; + // There may be declared reduction operator inside structure/union. + (void)ParseOpenMPDeclarativeDirective(AS_public); continue; } + if (!Tok.is(tok::at)) { auto CFieldCallback = [&](ParsingFieldDeclarator &FD) { // Install the declarator into the current TagDecl. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 814234d96da..798284b3d39 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -2910,7 +2910,7 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclarationWithPragmas( } if (Tok.is(tok::annot_pragma_openmp)) - return ParseOpenMPDeclarativeDirective(); + return ParseOpenMPDeclarativeDirective(AS); // Parse all the comma separated declarators. return ParseCXXClassMemberDeclaration(AS, AccessAttrs.getList()); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index d87abb60204..2d5afd6042d 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -30,9 +30,11 @@ namespace { enum OpenMPDirectiveKindEx { OMPD_cancellation = OMPD_unknown + 1, OMPD_data, + OMPD_declare, OMPD_enter, OMPD_exit, OMPD_point, + OMPD_reduction, OMPD_target_enter, OMPD_target_exit }; @@ -48,9 +50,11 @@ static unsigned getOpenMPDirectiveKindEx(StringRef S) { return llvm::StringSwitch<unsigned>(S) .Case("cancellation", OMPD_cancellation) .Case("data", OMPD_data) + .Case("declare", OMPD_declare) .Case("enter", OMPD_enter) .Case("exit", OMPD_exit) .Case("point", OMPD_point) + .Case("reduction", OMPD_reduction) .Default(OMPD_unknown); } @@ -60,6 +64,7 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { // TODO: add other combined directives in topological order. static const unsigned F[][3] = { { OMPD_cancellation, OMPD_point, OMPD_cancellation_point }, + { OMPD_declare, OMPD_reduction, OMPD_declare_reduction }, { OMPD_target, OMPD_data, OMPD_target_data }, { OMPD_target, OMPD_enter, OMPD_target_enter }, { OMPD_target, OMPD_exit, OMPD_target_exit }, @@ -73,6 +78,7 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { { OMPD_target, OMPD_parallel, OMPD_target_parallel }, { OMPD_target_parallel, OMPD_for, OMPD_target_parallel_for } }; + enum { CancellationPoint = 0, DeclareReduction = 1, TargetData = 2 }; auto Tok = P.getCurToken(); unsigned DKind = Tok.isAnnotation() @@ -98,16 +104,226 @@ static OpenMPDirectiveKind ParseOpenMPDirectiveKind(Parser &P) { DKind = F[i][2]; } } - return DKind <= OMPD_unknown ? static_cast<OpenMPDirectiveKind>(DKind) - : OMPD_unknown; + return DKind < OMPD_unknown ? static_cast<OpenMPDirectiveKind>(DKind) + : OMPD_unknown; +} + +static DeclarationName parseOpenMPReductionId(Parser &P) { + const Token Tok = P.getCurToken(); + Sema &Actions = P.getActions(); + OverloadedOperatorKind OOK = OO_None; + switch (Tok.getKind()) { + case tok::plus: // '+' + OOK = OO_Plus; + break; + case tok::minus: // '-' + OOK = OO_Minus; + break; + case tok::star: // '*' + OOK = OO_Star; + break; + case tok::amp: // '&' + OOK = OO_Amp; + break; + case tok::pipe: // '|' + OOK = OO_Pipe; + break; + case tok::caret: // '^' + OOK = OO_Caret; + break; + case tok::ampamp: // '&&' + OOK = OO_AmpAmp; + break; + case tok::pipepipe: // '||' + OOK = OO_PipePipe; + break; + case tok::identifier: // identifier + break; + default: + P.Diag(Tok.getLocation(), diag::err_omp_expected_reduction_identifier); + P.SkipUntil(tok::colon, tok::r_paren, tok::annot_pragma_openmp_end, + Parser::StopBeforeMatch); + return DeclarationName(); + } + P.ConsumeToken(); + auto &DeclNames = Actions.getASTContext().DeclarationNames; + return OOK == OO_None ? DeclNames.getIdentifier(Tok.getIdentifierInfo()) + : DeclNames.getCXXOperatorName(OOK); +} + +/// \brief Parse 'omp declare reduction' construct. +/// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' +/// '(' <reduction_id> ':' <type> {',' <type>} ':' <expression> ')' +/// ['initializer' '(' ('omp_priv' '=' <expression>)|<function_call> ')'] +/// annot_pragma_openmp_end +/// <reduction_id> is either a base language identifier or one of the following +/// operators: '+', '-', '*', '&', '|', '^', '&&' and '||'. +/// +Parser::DeclGroupPtrTy +Parser::ParseOpenMPDeclareReductionDirective(AccessSpecifier AS) { + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, tok::annot_pragma_openmp_end); + if (T.expectAndConsume(diag::err_expected_lparen_after, + getOpenMPDirectiveName(OMPD_declare_reduction))) { + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + return DeclGroupPtrTy(); + } + + DeclarationName Name = parseOpenMPReductionId(*this); + if (Name.isEmpty() && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + // Consume ':'. + bool IsCorrect = !ExpectAndConsume(tok::colon); + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_type); + IsCorrect = false; + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + SmallVector<std::pair<QualType, SourceLocation>, 8> ReductionTypes; + // Parse list of types until ':' token. + do { + ColonProtectionRAIIObject ColonRAII(*this); + SourceRange Range; + TypeResult TR = ParseTypeName(&Range, Declarator::PrototypeContext, AS); + if (TR.isUsable()) { + auto ReductionType = + Actions.ActOnOpenMPDeclareReductionType(Range.getBegin(), TR); + if (!ReductionType.isNull()) { + ReductionTypes.push_back( + std::make_pair(ReductionType, Range.getBegin())); + } + } else { + SkipUntil(tok::comma, tok::colon, tok::annot_pragma_openmp_end, + StopBeforeMatch); + } + + if (Tok.is(tok::colon) || Tok.is(tok::annot_pragma_openmp_end)) + break; + + // Consume ','. + if (ExpectAndConsume(tok::comma)) { + IsCorrect = false; + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_type); + return DeclGroupPtrTy(); + } + } + } while (Tok.isNot(tok::annot_pragma_openmp_end)); + + if (ReductionTypes.empty()) { + SkipUntil(tok::annot_pragma_openmp_end, StopBeforeMatch); + return DeclGroupPtrTy(); + } + + if (!IsCorrect && Tok.is(tok::annot_pragma_openmp_end)) + return DeclGroupPtrTy(); + + // Consume ':'. + if (ExpectAndConsume(tok::colon)) + IsCorrect = false; + + if (Tok.is(tok::annot_pragma_openmp_end)) { + Diag(Tok.getLocation(), diag::err_expected_expression); + return DeclGroupPtrTy(); + } + + DeclGroupPtrTy DRD = Actions.ActOnOpenMPDeclareReductionDirectiveStart( + getCurScope(), Actions.getCurLexicalContext(), Name, ReductionTypes, AS); + + // Parse <combiner> expression and then parse initializer if any for each + // correct type. + unsigned I = 0, E = ReductionTypes.size(); + for (auto *D : DRD.get()) { + TentativeParsingAction TPA(*this); + ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::OpenMPDirectiveScope); + // Parse <combiner> expression. + Actions.ActOnOpenMPDeclareReductionCombinerStart(getCurScope(), D); + ExprResult CombinerResult = + Actions.ActOnFinishFullExpr(ParseAssignmentExpression().get(), + D->getLocation(), /*DiscardedValue=*/true); + Actions.ActOnOpenMPDeclareReductionCombinerEnd(D, CombinerResult.get()); + + if (CombinerResult.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = !T.consumeClose() && IsCorrect && CombinerResult.isUsable(); + ExprResult InitializerResult; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + // Parse <initializer> expression. + if (Tok.is(tok::identifier) && + Tok.getIdentifierInfo()->isStr("initializer")) + ConsumeToken(); + else { + Diag(Tok.getLocation(), diag::err_expected) << "'initializer'"; + TPA.Commit(); + IsCorrect = false; + break; + } + // Parse '('. + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + IsCorrect = + !T.expectAndConsume(diag::err_expected_lparen_after, "initializer") && + IsCorrect; + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + ParseScope OMPDRScope(this, Scope::FnScope | Scope::DeclScope | + Scope::OpenMPDirectiveScope); + // Parse expression. + Actions.ActOnOpenMPDeclareReductionInitializerStart(getCurScope(), D); + InitializerResult = Actions.ActOnFinishFullExpr( + ParseAssignmentExpression().get(), D->getLocation(), + /*DiscardedValue=*/true); + Actions.ActOnOpenMPDeclareReductionInitializerEnd( + D, InitializerResult.get()); + if (InitializerResult.isInvalid() && Tok.isNot(tok::r_paren) && + Tok.isNot(tok::annot_pragma_openmp_end)) { + TPA.Commit(); + IsCorrect = false; + break; + } + IsCorrect = + !T.consumeClose() && IsCorrect && !InitializerResult.isInvalid(); + } + } + + ++I; + // Revert parsing if not the last type, otherwise accept it, we're done with + // parsing. + if (I != E) + TPA.Revert(); + else + TPA.Commit(); + } + return Actions.ActOnOpenMPDeclareReductionDirectiveEnd(getCurScope(), DRD, + IsCorrect); } /// \brief Parsing of declarative OpenMP directives. /// /// threadprivate-directive: /// annot_pragma_openmp 'threadprivate' simple-variable-list +/// annot_pragma_openmp_end +/// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' [...] +/// annot_pragma_openmp_end /// -Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { +Parser::DeclGroupPtrTy +Parser::ParseOpenMPDeclarativeDirective(AccessSpecifier AS) { assert(Tok.is(tok::annot_pragma_openmp) && "Not an OpenMP directive!"); ParenBraceBracketBalancer BalancerRAIIObj(*this); @@ -131,6 +347,22 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { return Actions.ActOnOpenMPThreadprivateDirective(Loc, Identifiers); } break; + case OMPD_declare_reduction: + ConsumeToken(); + if (auto Res = ParseOpenMPDeclareReductionDirective(AS)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + // Skip the last annot_pragma_openmp_end. + ConsumeToken(); + return Res; + } + break; case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; @@ -170,7 +402,9 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { << getOpenMPDirectiveName(DKind); break; } - SkipUntil(tok::annot_pragma_openmp_end); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + ConsumeAnyToken(); return nullptr; } @@ -180,6 +414,12 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirective() { /// annot_pragma_openmp 'threadprivate' simple-variable-list /// annot_pragma_openmp_end /// +/// declare-reduction-directive: +/// annot_pragma_openmp 'declare' 'reduction' '(' <reduction_id> ':' +/// <type> {',' <type>} ':' <expression> ')' ['initializer' '(' +/// ('omp_priv' '=' <expression>|<function_call>) ')'] +/// annot_pragma_openmp_end +/// /// executable-directive: /// annot_pragma_openmp 'parallel' | 'simd' | 'for' | 'sections' | /// 'section' | 'single' | 'master' | 'critical' [ '(' <name> ')' ] | @@ -231,6 +471,22 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( } SkipUntil(tok::annot_pragma_openmp_end); break; + case OMPD_declare_reduction: + ConsumeToken(); + if (auto Res = ParseOpenMPDeclareReductionDirective(/*AS=*/AS_none)) { + // The last seen token is annot_pragma_openmp_end - need to check for + // extra tokens. + if (Tok.isNot(tok::annot_pragma_openmp_end)) { + Diag(Tok, diag::warn_omp_extra_tokens_at_eol) + << getOpenMPDirectiveName(OMPD_declare_reduction); + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + } + ConsumeAnyToken(); + Directive = Actions.ActOnDeclStmt(Res, Loc, Tok.getLocation()); + } else + SkipUntil(tok::annot_pragma_openmp_end); + break; case OMPD_flush: if (PP.LookAhead(0).is(tok::l_paren)) { FlushHasClause = true; diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 149765ca813..9ef57cb5384 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -659,7 +659,7 @@ Parser::ParseExternalDeclaration(ParsedAttributesWithRange &attrs, HandlePragmaOpenCLExtension(); return nullptr; case tok::annot_pragma_openmp: - return ParseOpenMPDeclarativeDirective(); + return ParseOpenMPDeclarativeDirective(/*AS=*/AS_none); case tok::annot_pragma_ms_pointers_to_members: HandlePragmaMSPointersToMembers(); return nullptr; diff --git a/clang/lib/Sema/ScopeInfo.cpp b/clang/lib/Sema/ScopeInfo.cpp index cbd7ef7abb4..ef9eed65ebc 100644 --- a/clang/lib/Sema/ScopeInfo.cpp +++ b/clang/lib/Sema/ScopeInfo.cpp @@ -28,6 +28,7 @@ void FunctionScopeInfo::Clear() { HasBranchIntoScope = false; HasIndirectGoto = false; HasDroppedStmt = false; + HasOMPDeclareReductionCombiner = false; ObjCShouldCallSuper = false; ObjCIsDesignatedInit = false; ObjCWarnForNoDesignatedInitChain = false; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index f7fe506f4ae..f20b4d06287 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5640,7 +5640,7 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) { static bool shouldConsiderLinkage(const VarDecl *VD) { const DeclContext *DC = VD->getDeclContext()->getRedeclContext(); - if (DC->isFunctionOrMethod()) + if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC)) return VD->hasExternalStorage(); if (DC->isFileContext()) return true; @@ -5651,7 +5651,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { static bool shouldConsiderLinkage(const FunctionDecl *FD) { const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); - if (DC->isFileContext() || DC->isFunctionOrMethod()) + if (DC->isFileContext() || DC->isFunctionOrMethod() || + isa<OMPDeclareReductionDecl>(DC)) return true; if (DC->isRecord()) return false; diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 0ca5555e1da..b644ff215cd 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -376,6 +376,19 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, DeduceReturnType(FD, Loc)) return true; } + + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions + // Only the variables omp_in and omp_out are allowed in the combiner. + // Only the variables omp_priv and omp_orig are allowed in the + // initializer-clause. + auto *DRD = dyn_cast<OMPDeclareReductionDecl>(CurContext); + if (LangOpts.OpenMP && DRD && !CurContext->containsDecl(D) && + isa<VarDecl>(D)) { + Diag(Loc, diag::err_omp_wrong_var_in_declare_reduction) + << getCurFunction()->HasOMPDeclareReductionCombiner; + Diag(D->getLocation(), diag::note_entity_declared_at) << D; + return true; + } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, ObjCPropertyAccess); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 4baf6053359..00379336251 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -280,6 +280,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_ObjCProtocol; break; + case Sema::LookupOMPReductionName: + IDNS = Decl::IDNS_OMPReduction; + break; + case Sema::LookupAnyName: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol @@ -2015,6 +2019,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, BaseCallback = &LookupAnyMember; break; + case LookupOMPReductionName: + BaseCallback = &CXXRecordDecl::FindOMPReductionMember; + break; + case LookupUsingDeclName: // This lookup is for redeclarations only. diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 50148b5187c..ffac56b1ddd 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -21,6 +21,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeOrdering.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -1698,6 +1699,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_flush: case OMPD_target_enter_data: case OMPD_target_exit_data: + case OMPD_declare_reduction: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -3139,6 +3141,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc, VarsWithInheritedDSA); break; case OMPD_threadprivate: + case OMPD_declare_reduction: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -9584,6 +9587,235 @@ Sema::ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier, MapLoc); } +QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, + TypeResult ParsedType) { + assert(ParsedType.isUsable()); + + QualType ReductionType = GetTypeFromParser(ParsedType.get()); + if (ReductionType.isNull()) + return QualType(); + + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions, C\C++ + // A type name in a declare reduction directive cannot be a function type, an + // array type, a reference type, or a type qualified with const, volatile or + // restrict. + if (ReductionType.hasQualifiers()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 0; + return QualType(); + } + + if (ReductionType->isFunctionType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 1; + return QualType(); + } + if (ReductionType->isReferenceType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 2; + return QualType(); + } + if (ReductionType->isArrayType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 3; + return QualType(); + } + return ReductionType; +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( + Scope *S, DeclContext *DC, DeclarationName Name, + ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes, + AccessSpecifier AS, Decl *PrevDeclInScope) { + SmallVector<Decl *, 8> Decls; + Decls.reserve(ReductionTypes.size()); + + LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName, + ForRedeclaration); + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions + // A reduction-identifier may not be re-declared in the current scope for the + // same type or for a type that is compatible according to the base language + // rules. + llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes; + OMPDeclareReductionDecl *PrevDRD = nullptr; + bool InCompoundScope = true; + if (S != nullptr) { + // Find previous declaration with the same name not referenced in other + // declarations. + FunctionScopeInfo *ParentFn = getEnclosingFunction(); + InCompoundScope = + (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty(); + LookupName(Lookup, S); + FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious; + auto Filter = Lookup.makeFilter(); + while (Filter.hasNext()) { + auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next()); + if (InCompoundScope) { + auto I = UsedAsPrevious.find(PrevDecl); + if (I == UsedAsPrevious.end()) + UsedAsPrevious[PrevDecl] = false; + if (auto *D = PrevDecl->getPrevDeclInScope()) + UsedAsPrevious[D] = true; + } + PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] = + PrevDecl->getLocation(); + } + Filter.done(); + if (InCompoundScope) { + for (auto &PrevData : UsedAsPrevious) { + if (!PrevData.second) { + PrevDRD = PrevData.first; + break; + } + } + } + } else if (PrevDeclInScope != nullptr) { + auto *PrevDRDInScope = PrevDRD = + cast<OMPDeclareReductionDecl>(PrevDeclInScope); + do { + PreviousRedeclTypes[PrevDRDInScope->getType().getCanonicalType()] = + PrevDRDInScope->getLocation(); + PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope(); + } while (PrevDRDInScope != nullptr); + } + for (auto &TyData : ReductionTypes) { + auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType()); + bool Invalid = false; + if (I != PreviousRedeclTypes.end()) { + Diag(TyData.second, diag::err_omp_declare_reduction_redefinition) + << TyData.first; + Diag(I->second, diag::note_previous_definition); + Invalid = true; + } + PreviousRedeclTypes[TyData.first.getCanonicalType()] = TyData.second; + auto *DRD = OMPDeclareReductionDecl::Create(Context, DC, TyData.second, + Name, TyData.first, PrevDRD); + DC->addDecl(DRD); + DRD->setAccess(AS); + Decls.push_back(DRD); + if (Invalid) + DRD->setInvalidDecl(); + else + PrevDRD = DRD; + } + + return DeclGroupPtrTy::make( + DeclGroupRef::Create(Context, Decls.begin(), Decls.size())); +} + +void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + + // Enter new function scope. + PushFunctionScope(); + getCurFunction()->setHasBranchProtectedScope(); + getCurFunction()->setHasOMPDeclareReductionCombiner(); + + if (S != nullptr) + PushDeclContext(S, DRD); + else + CurContext = DRD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); + + QualType ReductionType = DRD->getType(); + // Create 'T omp_in;' implicit param. + auto *OmpInParm = + ImplicitParamDecl::Create(Context, DRD, D->getLocation(), + &Context.Idents.get("omp_in"), ReductionType); + // Create 'T* omp_parm;T omp_out;'. All references to 'omp_out' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_out' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_out;' variable. + auto *OmpOutParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_out"); + if (S != nullptr) { + PushOnScopeChains(OmpInParm, S); + PushOnScopeChains(OmpOutParm, S); + } else { + DRD->addDecl(OmpInParm); + DRD->addDecl(OmpOutParm); + } +} + +void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + PopDeclContext(); + PopFunctionScopeInfo(); + + if (Combiner != nullptr) + DRD->setCombiner(Combiner); + else + DRD->setInvalidDecl(); +} + +void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + + // Enter new function scope. + PushFunctionScope(); + getCurFunction()->setHasBranchProtectedScope(); + + if (S != nullptr) + PushDeclContext(S, DRD); + else + CurContext = DRD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); + + QualType ReductionType = DRD->getType(); + // Create 'T omp_orig;' implicit param. + auto *OmpOrigParm = + ImplicitParamDecl::Create(Context, DRD, D->getLocation(), + &Context.Idents.get("omp_orig"), ReductionType); + // Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_priv' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_priv;' variable. + auto *OmpPrivParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv"); + if (S != nullptr) { + PushOnScopeChains(OmpPrivParm, S); + PushOnScopeChains(OmpOrigParm, S); + } else { + DRD->addDecl(OmpPrivParm); + DRD->addDecl(OmpOrigParm); + } +} + +void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, + Expr *Initializer) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + PopDeclContext(); + PopFunctionScopeInfo(); + + if (Initializer != nullptr) + DRD->setInitializer(Initializer); + else + DRD->setInvalidDecl(); +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( + Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) { + for (auto *D : DeclReductions.get()) { + if (IsValid) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + if (S != nullptr) + PushOnScopeChains(DRD, S, /*AddToContext=*/false); + } else + D->setInvalidDecl(); + } + return DeclReductions; +} + OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index af93cde68c1..c021b34a4e5 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -2503,6 +2503,81 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( return TD; } +Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( + OMPDeclareReductionDecl *D) { + // Instantiate type and check if it is allowed. + QualType SubstReductionType = SemaRef.ActOnOpenMPDeclareReductionType( + D->getLocation(), + ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs, + D->getLocation(), DeclarationName()))); + if (SubstReductionType.isNull()) + return nullptr; + bool IsCorrect = !SubstReductionType.isNull(); + // Create instantiated copy. + std::pair<QualType, SourceLocation> ReductionTypes[] = { + std::make_pair(SubstReductionType, D->getLocation())}; + auto *PrevDeclInScope = D->getPrevDeclInScope(); + if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) { + PrevDeclInScope = cast<OMPDeclareReductionDecl>( + SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope) + ->get<Decl *>()); + } + auto DRD = SemaRef.ActOnOpenMPDeclareReductionDirectiveStart( + /*S=*/nullptr, Owner, D->getDeclName(), ReductionTypes, D->getAccess(), + PrevDeclInScope); + auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl()); + if (isDeclWithinFunction(NewDRD)) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD); + Expr *SubstCombiner = nullptr; + Expr *SubstInitializer = nullptr; + // Combiners instantiation sequence. + if (D->getCombiner()) { + SemaRef.ActOnOpenMPDeclareReductionCombinerStart( + /*S=*/nullptr, NewDRD); + const char *Names[] = {"omp_in", "omp_out"}; + for (auto &Name : Names) { + DeclarationName DN(&SemaRef.Context.Idents.get(Name)); + auto OldLookup = D->lookup(DN); + auto Lookup = NewDRD->lookup(DN); + if (!OldLookup.empty() && !Lookup.empty()) { + assert(Lookup.size() == 1 && OldLookup.size() == 1); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldLookup.front(), + Lookup.front()); + } + } + SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get(); + SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner); + // Initializers instantiation sequence. + if (D->getInitializer()) { + SemaRef.ActOnOpenMPDeclareReductionInitializerStart( + /*S=*/nullptr, NewDRD); + const char *Names[] = {"omp_orig", "omp_priv"}; + for (auto &Name : Names) { + DeclarationName DN(&SemaRef.Context.Idents.get(Name)); + auto OldLookup = D->lookup(DN); + auto Lookup = NewDRD->lookup(DN); + if (!OldLookup.empty() && !Lookup.empty()) { + assert(Lookup.size() == 1 && OldLookup.size() == 1); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + OldLookup.front(), Lookup.front()); + } + } + SubstInitializer = + SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get(); + SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD, + SubstInitializer); + } + IsCorrect = IsCorrect && SubstCombiner && + (!D->getInitializer() || SubstInitializer); + } else + IsCorrect = false; + + (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD, + IsCorrect); + + return NewDRD; +} + Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl( OMPCapturedExprDecl * /*D*/) { llvm_unreachable("Should not be met in templates"); diff --git a/clang/lib/Serialization/ASTCommon.cpp b/clang/lib/Serialization/ASTCommon.cpp index aba39231327..c83c664d2a9 100644 --- a/clang/lib/Serialization/ASTCommon.cpp +++ b/clang/lib/Serialization/ASTCommon.cpp @@ -332,6 +332,7 @@ bool serialization::isRedeclarableDeclKind(unsigned Kind) { case Decl::Import: case Decl::OMPThreadPrivate: case Decl::OMPCapturedExpr: + case Decl::OMPDeclareReduction: case Decl::BuiltinTemplate: return false; diff --git a/clang/lib/Serialization/ASTReaderDecl.cpp b/clang/lib/Serialization/ASTReaderDecl.cpp index 213f2aa0ecf..2389d671d42 100644 --- a/clang/lib/Serialization/ASTReaderDecl.cpp +++ b/clang/lib/Serialization/ASTReaderDecl.cpp @@ -356,6 +356,7 @@ namespace clang { void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); /// We've merged the definition \p MergedDef into the existing definition @@ -2394,6 +2395,15 @@ void ASTDeclReader::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { D->setVars(Vars); } +void ASTDeclReader::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + VisitNamedDecl(D); + D->setLocation(Reader.ReadSourceLocation(F, Record, Idx)); + D->setCombiner(Reader.ReadExpr(F)); + D->setInitializer(Reader.ReadExpr(F)); + D->PrevDeclInScope = Reader.ReadDeclID(F, Record, Idx); + D->setType(Reader.readType(F, Record, Idx)); +} + void ASTDeclReader::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { VisitVarDecl(D); } @@ -2449,7 +2459,8 @@ static bool isConsumerInterestedIn(Decl *D, bool HasBody) { isa<ImportDecl>(D) || isa<PragmaCommentDecl>(D) || isa<PragmaDetectMismatchDecl>(D) || - isa<OMPThreadPrivateDecl>(D)) + isa<OMPThreadPrivateDecl>(D) || + isa<OMPDeclareReductionDecl>(D)) return true; if (VarDecl *Var = dyn_cast<VarDecl>(D)) return Var->isFileVarDecl() && @@ -3363,6 +3374,9 @@ Decl *ASTReader::ReadDeclRecord(DeclID ID) { case DECL_OMP_THREADPRIVATE: D = OMPThreadPrivateDecl::CreateDeserialized(Context, ID, Record[Idx++]); break; + case DECL_OMP_DECLARE_REDUCTION: + D = OMPDeclareReductionDecl::CreateDeserialized(Context, ID); + break; case DECL_OMP_CAPTUREDEXPR: D = OMPCapturedExprDecl::CreateDeserialized(Context, ID); break; diff --git a/clang/lib/Serialization/ASTWriterDecl.cpp b/clang/lib/Serialization/ASTWriterDecl.cpp index ee693bf2fc7..88b74a4b4c5 100644 --- a/clang/lib/Serialization/ASTWriterDecl.cpp +++ b/clang/lib/Serialization/ASTWriterDecl.cpp @@ -133,6 +133,7 @@ namespace clang { void VisitObjCPropertyDecl(ObjCPropertyDecl *D); void VisitObjCPropertyImplDecl(ObjCPropertyImplDecl *D); void VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D); + void VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D); void VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D); /// Add an Objective-C type parameter list to the given record. @@ -1653,6 +1654,16 @@ void ASTDeclWriter::VisitOMPThreadPrivateDecl(OMPThreadPrivateDecl *D) { Code = serialization::DECL_OMP_THREADPRIVATE; } +void ASTDeclWriter::VisitOMPDeclareReductionDecl(OMPDeclareReductionDecl *D) { + VisitNamedDecl(D); + Writer.AddSourceLocation(D->getLocStart(), Record); + Writer.AddStmt(D->getCombiner()); + Writer.AddStmt(D->getInitializer()); + Writer.AddDeclRef(D->getPrevDeclInScope(), Record); + Writer.AddTypeRef(D->getType(), Record); + Code = serialization::DECL_OMP_DECLARE_REDUCTION; +} + void ASTDeclWriter::VisitOMPCapturedExprDecl(OMPCapturedExprDecl *D) { VisitVarDecl(D); Code = serialization::DECL_OMP_CAPTUREDEXPR; |