================
@@ -2662,91 +2664,215 @@ StmtResult
Parser::ParseOpenMPDeclarativeOrExecutableDirective(
TI.getAsVariantMatchInfo(ASTContext, VMI);
VMIs.push_back(VMI);
+ TraitInfos.push_back(&TI);
+ ClauseKinds.push_back(CKind);
}
TPA.Revert();
// End of the first iteration. Parser is reset to the start of
metadirective
- std::function<void(StringRef)> DiagUnknownTrait =
- [this, Loc](StringRef ISATrait) {
- // TODO Track the selector locations in a way that is accessible here
- // to improve the diagnostic location.
- Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) << ISATrait;
- };
- TargetOMPContext OMPCtx(ASTContext, std::move(DiagUnknownTrait),
- /* CurrentFunctionDecl */ nullptr,
- ArrayRef<llvm::omp::TraitProperty>(),
- Actions.OpenMP().getOpenMPDeviceNum());
-
- // A single match is returned for OpenMP 5.0
- int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
-
- int Idx = 0;
- // In OpenMP 5.0 metadirective is either replaced by another directive or
- // ignored.
- // TODO: In OpenMP 5.1 generate multiple directives based upon the matches
- // found by getBestWhenMatchForContext.
- while (Tok.isNot(tok::annot_pragma_openmp_end)) {
- // OpenMP 5.0 implementation - Skip to the best index found.
- if (Idx++ != BestIdx) {
- ConsumeToken(); // Consume clause name
- T.consumeOpen(); // Consume '('
- int paren = 0;
- // Skip everything inside the clause
- while (Tok.isNot(tok::r_paren) || paren != 0) {
- if (Tok.is(tok::l_paren))
- paren++;
+ // Detect non-constant user conditions.
+ bool NeedsRuntimeSelection = false;
+ for (unsigned I = 0; I < TraitInfos.size(); ++I) {
+ if (ClauseKinds[I] != OMPC_when)
+ continue;
+ TraitInfos[I]->anyScoreOrCondition([&](Expr *&E, bool IsScore) {
+ if (!IsScore && E && !E->isIntegerConstantExpr(ASTContext)) {
+ NeedsRuntimeSelection = true;
+ return true;
+ }
+ return false;
+ });
+ if (NeedsRuntimeSelection)
+ break;
+ }
+
+ if (!NeedsRuntimeSelection) {
+ std::function<void(StringRef)> DiagUnknownTrait =
+ [this, Loc](StringRef ISATrait) {
+ // TODO Track the selector locations in a way that is accessible
+ // here to improve the diagnostic location.
+ Diag(Loc, diag::warn_unknown_declare_variant_isa_trait) <<
ISATrait;
+ };
+ TargetOMPContext OMPCtx(ASTContext, std::move(DiagUnknownTrait),
+ /* CurrentFunctionDecl */ nullptr,
+ ArrayRef<llvm::omp::TraitProperty>(),
+ Actions.OpenMP().getOpenMPDeviceNum());
+
+ // A single match is returned for OpenMP 5.0
+ int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx);
+
+ int Idx = 0;
+ // In OpenMP 5.0 metadirective is either replaced by another directive or
+ // ignored.
+ // TODO: In OpenMP 5.1 generate multiple directives based upon the
matches
+ // found by getBestWhenMatchForContext.
+ while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ // OpenMP 5.0 implementation - Skip to the best index found.
+ if (Idx++ != BestIdx) {
+ ConsumeToken(); // Consume clause name
+ T.consumeOpen(); // Consume '('
+ int paren = 0;
+ // Skip everything inside the clause
+ while (Tok.isNot(tok::r_paren) || paren != 0) {
+ if (Tok.is(tok::l_paren))
+ paren++;
+ if (Tok.is(tok::r_paren))
+ paren--;
+ ConsumeAnyToken();
+ }
+ // Parse ')'
if (Tok.is(tok::r_paren))
- paren--;
+ T.consumeClose();
+ continue;
+ }
+
+ OpenMPClauseKind CKind = Tok.isAnnotation()
+ ? OMPC_unknown
+ :
getOpenMPClauseKind(PP.getSpelling(Tok));
+ SourceLocation Loc = ConsumeToken();
+
+ // Parse '('.
+ T.consumeOpen();
+
+ // Skip ContextSelectors for when clause
+ if (CKind == OMPC_when) {
+ OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
+ // parse and skip the ContextSelectors
+ parseOMPContextSelectors(Loc, TI);
+
+ // Parse ':'
ConsumeAnyToken();
}
- // Parse ')'
- if (Tok.is(tok::r_paren))
- T.consumeClose();
- continue;
+
+ // If no directive is passed, skip in OpenMP 5.0.
+ // TODO: Generate nothing directive from OpenMP 5.1.
+ if (Tok.is(tok::r_paren)) {
+ SkipUntil(tok::annot_pragma_openmp_end);
+ break;
+ }
+
+ // Parse Directive
+ Directive = ParseOpenMPDeclarativeOrExecutableDirective(
+ StmtCtx,
+ /*ReadDirectiveWithinMetadirective=*/true);
+ break;
+ }
+ // If no match is found and no otherwise clause is present, skip
+ // OMP5.2 Chapter 7.4: If no otherwise clause is specified the effect is
+ // as if one was specified without an associated directive variant.
+ if (BestIdx == -1 && Idx > 0) {
+ assert(Tok.is(tok::annot_pragma_openmp_end) &&
+ "Expecting the end of the pragma here");
+ ConsumeAnnotationToken();
+ return StmtEmpty();
}
+ break;
+ }
- OpenMPClauseKind CKind = Tok.isAnnotation()
- ? OMPC_unknown
- : getOpenMPClauseKind(PP.getSpelling(Tok));
- SourceLocation Loc = ConsumeToken();
+ // Runtime path: NeedsRuntimeSelection == true.
+ // For each clause, do a separate tentative parse to extract its
+ // sub-directive. This is needed because
+ // ParseOpenMPDeclarativeOrExecutableDirective consumes the pragma
+ // end on each call, so we can't parse multiple clauses in one
+ // linear pass.
+ SmallVector<Expr *, 4> Conditions;
+ SmallVector<Stmt *, 4> SubDirectives;
- // Parse '('.
- T.consumeOpen();
+ for (unsigned TargetIdx = 0; TargetIdx < TraitInfos.size(); ++TargetIdx) {
+ // Revert to the start of the clause list for each iteration.
+ TentativeParsingAction TPA2(*this);
+ BalancedDelimiterTracker T2(*this, tok::l_paren,
+ tok::annot_pragma_openmp_end);
+ unsigned Idx = 0;
+ Expr *Condition = nullptr;
+ Stmt *SubStmt = nullptr;
- // Skip ContextSelectors for when clause
- if (CKind == OMPC_when) {
- OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
- // parse and skip the ContextSelectors
- parseOMPContextSelectors(Loc, TI);
+ while (Tok.isNot(tok::annot_pragma_openmp_end)) {
+ if (Tok.isAnnotation())
+ break;
+ OpenMPClauseKind CKind = getOpenMPClauseKind(PP.getSpelling(Tok));
+ if (CKind == OMPC_unknown)
+ break;
- // Parse ':'
- ConsumeAnyToken();
- }
+ SourceLocation ClauseLoc = ConsumeToken();
+ T2.consumeOpen();
+
+ if (Idx != TargetIdx) {
+ int paren = 0;
+ while (Tok.isNot(tok::r_paren) || paren != 0) {
+ if (Tok.is(tok::l_paren))
+ paren++;
+ if (Tok.is(tok::r_paren))
+ paren--;
+ if (Tok.is(tok::annot_pragma_openmp_end))
+ break;
+ ConsumeAnyToken();
+ }
+ if (Tok.is(tok::r_paren))
+ T2.consumeClose();
+ ++Idx;
+ continue;
+ }
- // If no directive is passed, skip in OpenMP 5.0.
- // TODO: Generate nothing directive from OpenMP 5.1.
- if (Tok.is(tok::r_paren)) {
- SkipUntil(tok::annot_pragma_openmp_end);
+ // This is the target clause. Parse it fully.
+ if (CKind == OMPC_when) {
+ OMPTraitInfo &TI = Actions.getASTContext().getNewOMPTraitInfo();
+ parseOMPContextSelectors(ClauseLoc, TI);
+ TI.anyScoreOrCondition([&](Expr *&E, bool IsScore) {
+ if (!IsScore && E) {
+ Condition = E;
+ return true;
+ }
+ return false;
+ });
+ if (Tok.is(tok::colon))
+ ConsumeAnyToken();
+ }
+ // For 'otherwise'/'default', Condition stays nullptr.
+
+ if (Tok.is(tok::r_paren)) {
+ T2.consumeClose();
+ SubStmt = nullptr;
+ } else {
+ StmtResult SR = ParseOpenMPDeclarativeOrExecutableDirective(
+ StmtCtx, /*ReadDirectiveWithinMetadirective=*/true);
+ if (SR.isInvalid()) {
+ TPA2.Commit();
+ SkipUntil(tok::annot_pragma_openmp_end);
+ return StmtError();
+ }
+ SubStmt = SR.get();
+ if (isa_and_nonnull<NullStmt>(SubStmt))
+ SubStmt = nullptr;
+ }
break;
}
- // Parse Directive
- Directive = ParseOpenMPDeclarativeOrExecutableDirective(
- StmtCtx,
- /*ReadDirectiveWithinMetadirective=*/true);
- break;
+ // Revert token stream for the next iteration.
+ TPA2.Revert();
----------------
alexey-bataev wrote:
This code does not rever sema, only lexer/preprocessor. Use my previous
suggestion
https://github.com/llvm/llvm-project/pull/192455
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits