diff options
Diffstat (limited to 'clang/lib/Parse/ParseOpenMP.cpp')
-rw-r--r-- | clang/lib/Parse/ParseOpenMP.cpp | 525 |
1 files changed, 211 insertions, 314 deletions
diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 76d1854..00f9ebb 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -24,10 +24,10 @@ #include "clang/Sema/SemaAMDGPU.h" #include "clang/Sema/SemaCodeCompletion.h" #include "clang/Sema/SemaOpenMP.h" +#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" #include "llvm/Frontend/OpenMP/OMPContext.h" -#include <bitset> #include <optional> using namespace clang; @@ -2146,7 +2146,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_requires: { SourceLocation StartLoc = ConsumeToken(); SmallVector<OMPClause *, 5> Clauses; - std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses; + llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); if (Tok.is(tok::annot_pragma_openmp_end)) { Diag(Tok, diag::err_omp_expected_clause) << getOpenMPDirectiveName(OMPD_requires); @@ -2374,81 +2374,19 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_unknown: Diag(Tok, diag::err_omp_unknown_directive); break; - case OMPD_parallel: - case OMPD_simd: - case OMPD_tile: - case OMPD_unroll: - case OMPD_task: - case OMPD_taskyield: - case OMPD_barrier: - case OMPD_taskwait: - case OMPD_taskgroup: - case OMPD_flush: - case OMPD_depobj: - case OMPD_scan: - case OMPD_for: - case OMPD_for_simd: - case OMPD_sections: - case OMPD_section: - case OMPD_single: - case OMPD_master: - case OMPD_ordered: - case OMPD_critical: - case OMPD_parallel_for: - case OMPD_parallel_for_simd: - case OMPD_parallel_sections: - case OMPD_parallel_master: - case OMPD_parallel_masked: - case OMPD_atomic: - case OMPD_target: - case OMPD_teams: - case OMPD_cancellation_point: - case OMPD_cancel: - case OMPD_target_data: - case OMPD_target_enter_data: - case OMPD_target_exit_data: - case OMPD_target_parallel: - case OMPD_target_parallel_for: - case OMPD_taskloop: - case OMPD_taskloop_simd: - case OMPD_master_taskloop: - case OMPD_master_taskloop_simd: - case OMPD_parallel_master_taskloop: - case OMPD_parallel_master_taskloop_simd: - case OMPD_masked_taskloop: - case OMPD_masked_taskloop_simd: - case OMPD_parallel_masked_taskloop: - case OMPD_parallel_masked_taskloop_simd: - case OMPD_distribute: - case OMPD_target_update: - case OMPD_distribute_parallel_for: - case OMPD_distribute_parallel_for_simd: - case OMPD_distribute_simd: - case OMPD_target_parallel_for_simd: - case OMPD_target_simd: - case OMPD_scope: - case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: - case OMPD_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_target_teams: - case OMPD_target_teams_distribute: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: - case OMPD_dispatch: - case OMPD_masked: - case OMPD_metadirective: - case OMPD_loop: - case OMPD_teams_loop: - case OMPD_target_teams_loop: - case OMPD_parallel_loop: - case OMPD_target_parallel_loop: - Diag(Tok, diag::err_omp_unexpected_directive) - << 1 << getOpenMPDirectiveName(DKind); - break; default: - break; + switch (getDirectiveCategory(DKind)) { + case Category::Executable: + case Category::Meta: + case Category::Subsidiary: + case Category::Utility: + Diag(Tok, diag::err_omp_unexpected_directive) + << 1 << getOpenMPDirectiveName(DKind); + break; + case Category::Declarative: + case Category::Informational: + break; + } } while (Tok.isNot(tok::annot_pragma_openmp_end)) ConsumeAnyToken(); @@ -2456,6 +2394,186 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( return nullptr; } +StmtResult Parser::ParseOpenMPExecutableDirective( + ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc, + bool ReadDirectiveWithinMetadirective) { + assert((DKind == OMPD_error || + getDirectiveCategory(DKind) == Category::Executable || + getDirectiveCategory(DKind) == Category::Subsidiary) && + "Directive with an unexpected category"); + bool HasAssociatedStatement = true; + Association Assoc = getDirectiveAssociation(DKind); + + // OMPD_ordered has None as association, but it comes in two variants, + // the second of which is associated with a block. + // OMPD_scan and OMPD_section are both "separating", but section is treated + // as if it was associated with a statement, while scan is not. + if (DKind != OMPD_ordered && DKind != OMPD_section && + (Assoc == Association::None || Assoc == Association::Separating)) { + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == + ParsedStmtContext()) { + Diag(Tok, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind) << 0; + if (DKind == OMPD_error) { + SkipUntil(tok::annot_pragma_openmp_end); + return StmtError(); + } + } + HasAssociatedStatement = false; + } + + SourceLocation EndLoc; + SmallVector<OMPClause *, 5> Clauses; + llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); + DeclarationNameInfo DirName; + OpenMPDirectiveKind CancelRegion = OMPD_unknown; + unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | + Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; + + // Special processing for flush and depobj clauses. + Token ImplicitTok; + bool ImplicitClauseAllowed = false; + if (DKind == OMPD_flush || DKind == OMPD_depobj) { + ImplicitTok = Tok; + ImplicitClauseAllowed = true; + } + ConsumeToken(); + // Parse directive name of the 'critical' directive if any. + if (DKind == OMPD_critical) { + BalancedDelimiterTracker T(*this, tok::l_paren, + tok::annot_pragma_openmp_end); + if (!T.consumeOpen()) { + if (Tok.isAnyIdentifier()) { + DirName = + DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation()); + ConsumeAnyToken(); + } else { + Diag(Tok, diag::err_omp_expected_identifier_for_critical); + } + T.consumeClose(); + } + } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) { + CancelRegion = parseOpenMPDirectiveKind(*this); + if (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeToken(); + } + + if (isOpenMPLoopDirective(DKind)) + ScopeFlags |= Scope::OpenMPLoopDirectiveScope; + if (isOpenMPSimdDirective(DKind)) + ScopeFlags |= Scope::OpenMPSimdDirectiveScope; + ParseScope OMPDirectiveScope(this, ScopeFlags); + Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), + Loc); + + while (Tok.isNot(tok::annot_pragma_openmp_end)) { + // If we are parsing for a directive within a metadirective, the directive + // ends with a ')'. + if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) { + while (Tok.isNot(tok::annot_pragma_openmp_end)) + ConsumeAnyToken(); + break; + } + bool HasImplicitClause = false; + if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) { + HasImplicitClause = true; + // Push copy of the current token back to stream to properly parse + // pseudo-clause OMPFlushClause or OMPDepobjClause. + PP.EnterToken(Tok, /*IsReinject*/ true); + PP.EnterToken(ImplicitTok, /*IsReinject*/ true); + ConsumeAnyToken(); + } + OpenMPClauseKind CKind = Tok.isAnnotation() + ? OMPC_unknown + : getOpenMPClauseKind(PP.getSpelling(Tok)); + if (HasImplicitClause) { + assert(CKind == OMPC_unknown && "Must be unknown implicit clause."); + if (DKind == OMPD_flush) { + CKind = OMPC_flush; + } else { + assert(DKind == OMPD_depobj && "Expected flush or depobj directives."); + CKind = OMPC_depobj; + } + } + // No more implicit clauses allowed. + ImplicitClauseAllowed = false; + Actions.OpenMP().StartOpenMPClause(CKind); + HasImplicitClause = false; + OMPClause *Clause = + ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); + SeenClauses[unsigned(CKind)] = true; + if (Clause) + Clauses.push_back(Clause); + + // Skip ',' if any. + if (Tok.is(tok::comma)) + ConsumeToken(); + Actions.OpenMP().EndOpenMPClause(); + } + // End location of the directive. + EndLoc = Tok.getLocation(); + // Consume final annot_pragma_openmp_end. + ConsumeAnnotationToken(); + + if (DKind == OMPD_ordered) { + // If the depend or doacross clause is specified, the ordered construct + // is a stand-alone directive. + for (auto CK : {OMPC_depend, OMPC_doacross}) { + if (SeenClauses[unsigned(CK)]) { + if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == + ParsedStmtContext()) { + Diag(Loc, diag::err_omp_immediate_directive) + << getOpenMPDirectiveName(DKind) << 1 << getOpenMPClauseName(CK); + } + HasAssociatedStatement = false; + } + } + } + + if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) { + Diag(Loc, diag::err_omp_required_clause) + << getOpenMPDirectiveName(OMPD_tile) << "sizes"; + } + + StmtResult AssociatedStmt; + if (HasAssociatedStatement) { + // The body is a block scope like in Lambdas and Blocks. + Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); + // FIXME: We create a bogus CompoundStmt scope to hold the contents of + // the captured region. Code elsewhere assumes that any FunctionScopeInfo + // should have at least one compound statement scope within it. + ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); + { + Sema::CompoundScopeRAII Scope(Actions); + AssociatedStmt = ParseStatement(); + + if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && + getLangOpts().OpenMPIRBuilder) + AssociatedStmt = + Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get()); + } + AssociatedStmt = + Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); + } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || + DKind == OMPD_target_exit_data) { + Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); + AssociatedStmt = (Sema::CompoundScopeRAII(Actions), + Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt, + /*isStmtExpr=*/false)); + AssociatedStmt = + Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); + } + + StmtResult Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective( + DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, EndLoc); + + // Exit scope. + Actions.OpenMP().EndOpenMPDSABlock(Directive.get()); + OMPDirectiveScope.Exit(); + + return Directive; +} + /// Parsing of declarative or executable OpenMP directives. /// /// threadprivate-directive: @@ -2503,24 +2621,30 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( "Not an OpenMP directive!"); ParsingOpenMPDirectiveRAII DirScope(*this); ParenBraceBracketBalancer BalancerRAIIObj(*this); - SmallVector<OMPClause *, 5> Clauses; - std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses; - unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope | - Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope; SourceLocation Loc = ReadDirectiveWithinMetadirective ? Tok.getLocation() - : ConsumeAnnotationToken(), - EndLoc; + : ConsumeAnnotationToken(); OpenMPDirectiveKind DKind = parseOpenMPDirectiveKind(*this); if (ReadDirectiveWithinMetadirective && DKind == OMPD_unknown) { Diag(Tok, diag::err_omp_unknown_directive); return StmtError(); } - OpenMPDirectiveKind CancelRegion = OMPD_unknown; - // Name of critical directive. - DeclarationNameInfo DirName; + StmtResult Directive = StmtError(); - bool HasAssociatedStatement = true; + + bool IsExecutable = [&]() { + if (DKind == OMPD_error) // OMPD_error is handled as executable + return true; + auto Res = getDirectiveCategory(DKind); + return Res == Category::Executable || Res == Category::Subsidiary; + }(); + + if (IsExecutable) { + Directive = ParseOpenMPExecutableDirective( + StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective); + assert(!Directive.isUnset() && "Executable directive remained unprocessed"); + return Directive; + } switch (DKind) { case OMPD_nothing: @@ -2709,7 +2833,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( /*AllowScopeSpecifier=*/false)) { SmallVector<OMPClause *, 1> Clauses; if (Tok.isNot(tok::annot_pragma_openmp_end)) { - std::bitset<llvm::omp::Clause_enumSize + 1> SeenClauses; + llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1); while (Tok.isNot(tok::annot_pragma_openmp_end)) { OpenMPClauseKind CKind = Tok.isAnnotation() ? OMPC_unknown @@ -2763,233 +2887,6 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( } break; } - case OMPD_flush: - case OMPD_depobj: - case OMPD_scan: - case OMPD_taskyield: - case OMPD_error: - case OMPD_barrier: - case OMPD_taskwait: - case OMPD_cancellation_point: - case OMPD_cancel: - case OMPD_target_enter_data: - case OMPD_target_exit_data: - case OMPD_target_update: - case OMPD_interop: - if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == - ParsedStmtContext()) { - Diag(Tok, diag::err_omp_immediate_directive) - << getOpenMPDirectiveName(DKind) << 0; - if (DKind == OMPD_error) { - SkipUntil(tok::annot_pragma_openmp_end); - break; - } - } - HasAssociatedStatement = false; - // Fall through for further analysis. - [[fallthrough]]; - case OMPD_parallel: - case OMPD_simd: - case OMPD_tile: - case OMPD_unroll: - case OMPD_for: - case OMPD_for_simd: - case OMPD_sections: - case OMPD_single: - case OMPD_section: - case OMPD_master: - case OMPD_critical: - case OMPD_parallel_for: - case OMPD_parallel_for_simd: - case OMPD_parallel_sections: - case OMPD_parallel_master: - case OMPD_parallel_masked: - case OMPD_task: - case OMPD_ordered: - case OMPD_atomic: - case OMPD_target: - case OMPD_teams: - case OMPD_taskgroup: - case OMPD_target_data: - case OMPD_target_parallel: - case OMPD_target_parallel_for: - case OMPD_loop: - case OMPD_teams_loop: - case OMPD_target_teams_loop: - case OMPD_parallel_loop: - case OMPD_target_parallel_loop: - case OMPD_scope: - case OMPD_taskloop: - case OMPD_taskloop_simd: - case OMPD_master_taskloop: - case OMPD_masked_taskloop: - case OMPD_master_taskloop_simd: - case OMPD_masked_taskloop_simd: - case OMPD_parallel_master_taskloop: - case OMPD_parallel_masked_taskloop: - case OMPD_parallel_master_taskloop_simd: - case OMPD_parallel_masked_taskloop_simd: - case OMPD_distribute: - case OMPD_distribute_parallel_for: - case OMPD_distribute_parallel_for_simd: - case OMPD_distribute_simd: - case OMPD_target_parallel_for_simd: - case OMPD_target_simd: - case OMPD_teams_distribute: - case OMPD_teams_distribute_simd: - case OMPD_teams_distribute_parallel_for_simd: - case OMPD_teams_distribute_parallel_for: - case OMPD_target_teams: - case OMPD_target_teams_distribute: - case OMPD_target_teams_distribute_parallel_for: - case OMPD_target_teams_distribute_parallel_for_simd: - case OMPD_target_teams_distribute_simd: - case OMPD_dispatch: - case OMPD_masked: { - // Special processing for flush and depobj clauses. - Token ImplicitTok; - bool ImplicitClauseAllowed = false; - if (DKind == OMPD_flush || DKind == OMPD_depobj) { - ImplicitTok = Tok; - ImplicitClauseAllowed = true; - } - ConsumeToken(); - // Parse directive name of the 'critical' directive if any. - if (DKind == OMPD_critical) { - BalancedDelimiterTracker T(*this, tok::l_paren, - tok::annot_pragma_openmp_end); - if (!T.consumeOpen()) { - if (Tok.isAnyIdentifier()) { - DirName = - DeclarationNameInfo(Tok.getIdentifierInfo(), Tok.getLocation()); - ConsumeAnyToken(); - } else { - Diag(Tok, diag::err_omp_expected_identifier_for_critical); - } - T.consumeClose(); - } - } else if (DKind == OMPD_cancellation_point || DKind == OMPD_cancel) { - CancelRegion = parseOpenMPDirectiveKind(*this); - if (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeToken(); - } - - if (isOpenMPLoopDirective(DKind)) - ScopeFlags |= Scope::OpenMPLoopDirectiveScope; - if (isOpenMPSimdDirective(DKind)) - ScopeFlags |= Scope::OpenMPSimdDirectiveScope; - ParseScope OMPDirectiveScope(this, ScopeFlags); - Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(), - Loc); - - while (Tok.isNot(tok::annot_pragma_openmp_end)) { - // If we are parsing for a directive within a metadirective, the directive - // ends with a ')'. - if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) { - while (Tok.isNot(tok::annot_pragma_openmp_end)) - ConsumeAnyToken(); - break; - } - bool HasImplicitClause = false; - if (ImplicitClauseAllowed && Tok.is(tok::l_paren)) { - HasImplicitClause = true; - // Push copy of the current token back to stream to properly parse - // pseudo-clause OMPFlushClause or OMPDepobjClause. - PP.EnterToken(Tok, /*IsReinject*/ true); - PP.EnterToken(ImplicitTok, /*IsReinject*/ true); - ConsumeAnyToken(); - } - OpenMPClauseKind CKind = Tok.isAnnotation() - ? OMPC_unknown - : getOpenMPClauseKind(PP.getSpelling(Tok)); - if (HasImplicitClause) { - assert(CKind == OMPC_unknown && "Must be unknown implicit clause."); - if (DKind == OMPD_flush) { - CKind = OMPC_flush; - } else { - assert(DKind == OMPD_depobj && - "Expected flush or depobj directives."); - CKind = OMPC_depobj; - } - } - // No more implicit clauses allowed. - ImplicitClauseAllowed = false; - Actions.OpenMP().StartOpenMPClause(CKind); - HasImplicitClause = false; - OMPClause *Clause = - ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]); - SeenClauses[unsigned(CKind)] = true; - if (Clause) - Clauses.push_back(Clause); - - // Skip ',' if any. - if (Tok.is(tok::comma)) - ConsumeToken(); - Actions.OpenMP().EndOpenMPClause(); - } - // End location of the directive. - EndLoc = Tok.getLocation(); - // Consume final annot_pragma_openmp_end. - ConsumeAnnotationToken(); - - if (DKind == OMPD_ordered) { - // If the depend or doacross clause is specified, the ordered construct - // is a stand-alone directive. - for (auto CK : {OMPC_depend, OMPC_doacross}) { - if (SeenClauses[unsigned(CK)]) { - if ((StmtCtx & ParsedStmtContext::AllowStandaloneOpenMPDirectives) == - ParsedStmtContext()) { - Diag(Loc, diag::err_omp_immediate_directive) - << getOpenMPDirectiveName(DKind) << 1 - << getOpenMPClauseName(CK); - } - HasAssociatedStatement = false; - } - } - } - - if (DKind == OMPD_tile && !SeenClauses[unsigned(OMPC_sizes)]) { - Diag(Loc, diag::err_omp_required_clause) - << getOpenMPDirectiveName(OMPD_tile) << "sizes"; - } - - StmtResult AssociatedStmt; - if (HasAssociatedStatement) { - // The body is a block scope like in Lambdas and Blocks. - Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); - // FIXME: We create a bogus CompoundStmt scope to hold the contents of - // the captured region. Code elsewhere assumes that any FunctionScopeInfo - // should have at least one compound statement scope within it. - ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false); - { - Sema::CompoundScopeRAII Scope(Actions); - AssociatedStmt = ParseStatement(); - - if (AssociatedStmt.isUsable() && isOpenMPLoopDirective(DKind) && - getLangOpts().OpenMPIRBuilder) - AssociatedStmt = - Actions.OpenMP().ActOnOpenMPLoopnest(AssociatedStmt.get()); - } - AssociatedStmt = - Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); - } else if (DKind == OMPD_target_update || DKind == OMPD_target_enter_data || - DKind == OMPD_target_exit_data) { - Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope()); - AssociatedStmt = (Sema::CompoundScopeRAII(Actions), - Actions.ActOnCompoundStmt(Loc, Loc, std::nullopt, - /*isStmtExpr=*/false)); - AssociatedStmt = - Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses); - } - Directive = Actions.OpenMP().ActOnOpenMPExecutableDirective( - DKind, DirName, CancelRegion, Clauses, AssociatedStmt.get(), Loc, - EndLoc); - - // Exit scope. - Actions.OpenMP().EndOpenMPDSABlock(Directive.get()); - OMPDirectiveScope.Exit(); - break; - } case OMPD_declare_target: { SourceLocation DTLoc = ConsumeAnyToken(); bool HasClauses = Tok.isNot(tok::annot_pragma_openmp_end); |