|
21 | 21 | #include "clang/Parse/RAIIObjectsForParser.h" |
22 | 22 | #include "clang/Sema/Scope.h" |
23 | 23 | #include "llvm/ADT/PointerIntPair.h" |
| 24 | +#include "llvm/ADT/StringSwitch.h" |
24 | 25 | #include "llvm/ADT/UniqueVector.h" |
25 | 26 | #include "llvm/Frontend/OpenMP/OMPContext.h" |
26 | 27 |
|
@@ -115,7 +116,9 @@ static OpenMPDirectiveKindExWrapper parseOpenMPDirectiveKind(Parser &P) { |
115 | 116 | // TODO: add other combined directives in topological order. |
116 | 117 | static const OpenMPDirectiveKindExWrapper F[][3] = { |
117 | 118 | {OMPD_begin, OMPD_declare, OMPD_begin_declare}, |
| 119 | + {OMPD_begin, OMPD_assumes, OMPD_begin_assumes}, |
118 | 120 | {OMPD_end, OMPD_declare, OMPD_end_declare}, |
| 121 | + {OMPD_end, OMPD_assumes, OMPD_end_assumes}, |
119 | 122 | {OMPD_cancellation, OMPD_point, OMPD_cancellation_point}, |
120 | 123 | {OMPD_declare, OMPD_reduction, OMPD_declare_reduction}, |
121 | 124 | {OMPD_declare, OMPD_mapper, OMPD_declare_mapper}, |
@@ -1508,6 +1511,103 @@ bool Parser::parseOMPDeclareVariantMatchClause(SourceLocation Loc, |
1508 | 1511 | return false; |
1509 | 1512 | } |
1510 | 1513 |
|
| 1514 | +/// `omp assumes` or `omp begin/end assumes` <clause> [[,]<clause>]... |
| 1515 | +/// where |
| 1516 | +/// |
| 1517 | +/// clause: |
| 1518 | +/// 'ext_IMPL_DEFINED' |
| 1519 | +/// 'absent' '(' directive-name [, directive-name]* ')' |
| 1520 | +/// 'contains' '(' directive-name [, directive-name]* ')' |
| 1521 | +/// 'holds' '(' scalar-expression ')' |
| 1522 | +/// 'no_openmp' |
| 1523 | +/// 'no_openmp_routines' |
| 1524 | +/// 'no_parallelism' |
| 1525 | +/// |
| 1526 | +void Parser::ParseOpenMPAssumesDirective(OpenMPDirectiveKind DKind, |
| 1527 | + SourceLocation Loc) { |
| 1528 | + SmallVector<StringRef, 4> Assumptions; |
| 1529 | + bool SkippedClauses = false; |
| 1530 | + |
| 1531 | + auto SkipBraces = [&](llvm::StringRef Spelling, bool IssueNote) { |
| 1532 | + BalancedDelimiterTracker T(*this, tok::l_paren, |
| 1533 | + tok::annot_pragma_openmp_end); |
| 1534 | + if (T.expectAndConsume(diag::err_expected_lparen_after, Spelling.data())) |
| 1535 | + return; |
| 1536 | + T.skipToEnd(); |
| 1537 | + if (IssueNote && T.getCloseLocation().isValid()) |
| 1538 | + Diag(T.getCloseLocation(), |
| 1539 | + diag::note_omp_assumption_clause_continue_here); |
| 1540 | + }; |
| 1541 | + |
| 1542 | + /// Helper to determine which AssumptionClauseMapping (ACM) in the |
| 1543 | + /// AssumptionClauseMappings table matches \p RawString. The return value is |
| 1544 | + /// the index of the matching ACM into the table or -1 if there was no match. |
| 1545 | + auto MatchACMClause = [&](StringRef RawString) { |
| 1546 | + llvm::StringSwitch<int> SS(RawString); |
| 1547 | + unsigned ACMIdx = 0; |
| 1548 | + for (const AssumptionClauseMappingInfo &ACMI : AssumptionClauseMappings) { |
| 1549 | + if (ACMI.StartsWith) |
| 1550 | + SS.StartsWith(ACMI.Identifier, ACMIdx++); |
| 1551 | + else |
| 1552 | + SS.Case(ACMI.Identifier, ACMIdx++); |
| 1553 | + } |
| 1554 | + return SS.Default(-1); |
| 1555 | + }; |
| 1556 | + |
| 1557 | + while (Tok.isNot(tok::annot_pragma_openmp_end)) { |
| 1558 | + IdentifierInfo *II = nullptr; |
| 1559 | + SourceLocation StartLoc = Tok.getLocation(); |
| 1560 | + int Idx = -1; |
| 1561 | + if (Tok.isAnyIdentifier()) { |
| 1562 | + II = Tok.getIdentifierInfo(); |
| 1563 | + Idx = MatchACMClause(II->getName()); |
| 1564 | + } |
| 1565 | + ConsumeAnyToken(); |
| 1566 | + |
| 1567 | + bool NextIsLPar = Tok.is(tok::l_paren); |
| 1568 | + // Handle unknown clauses by skipping them. |
| 1569 | + if (Idx == -1) { |
| 1570 | + Diag(StartLoc, diag::warn_omp_unknown_assumption_clause_missing_id) |
| 1571 | + << llvm::omp::getOpenMPDirectiveName(DKind) |
| 1572 | + << llvm::omp::getAllAssumeClauseOptions() << NextIsLPar; |
| 1573 | + if (NextIsLPar) |
| 1574 | + SkipBraces(II ? II->getName() : "", /* IssueNote */ true); |
| 1575 | + SkippedClauses = true; |
| 1576 | + continue; |
| 1577 | + } |
| 1578 | + const AssumptionClauseMappingInfo &ACMI = AssumptionClauseMappings[Idx]; |
| 1579 | + if (ACMI.HasDirectiveList || ACMI.HasExpression) { |
| 1580 | + // TODO: We ignore absent, contains, and holds assumptions for now. We |
| 1581 | + // also do not verify the content in the parenthesis at all. |
| 1582 | + SkippedClauses = true; |
| 1583 | + SkipBraces(II->getName(), /* IssueNote */ false); |
| 1584 | + continue; |
| 1585 | + } |
| 1586 | + |
| 1587 | + if (NextIsLPar) { |
| 1588 | + Diag(Tok.getLocation(), |
| 1589 | + diag::warn_omp_unknown_assumption_clause_without_args) |
| 1590 | + << II; |
| 1591 | + SkipBraces(II->getName(), /* IssueNote */ true); |
| 1592 | + } |
| 1593 | + |
| 1594 | + assert(II && "Expected an identifier clause!"); |
| 1595 | + StringRef Assumption = II->getName(); |
| 1596 | + if (ACMI.StartsWith) |
| 1597 | + Assumption = Assumption.substr(ACMI.Identifier.size()); |
| 1598 | + Assumptions.push_back(Assumption); |
| 1599 | + } |
| 1600 | + |
| 1601 | + Actions.ActOnOpenMPAssumesDirective(Loc, DKind, Assumptions, SkippedClauses); |
| 1602 | +} |
| 1603 | + |
| 1604 | +void Parser::ParseOpenMPEndAssumesDirective(SourceLocation Loc) { |
| 1605 | + if (Actions.isInOpenMPAssumeScope()) |
| 1606 | + Actions.ActOnOpenMPEndAssumesDirective(); |
| 1607 | + else |
| 1608 | + Diag(Loc, diag::err_expected_begin_assumes); |
| 1609 | +} |
| 1610 | + |
1511 | 1611 | /// Parsing of simple OpenMP clauses like 'default' or 'proc_bind'. |
1512 | 1612 | /// |
1513 | 1613 | /// default-clause: |
@@ -1716,6 +1816,14 @@ void Parser::ParseOMPEndDeclareTargetDirective(OpenMPDirectiveKind DKind, |
1716 | 1816 | /// annot_pragma_openmp 'requires' <clause> [[[,] <clause>] ... ] |
1717 | 1817 | /// annot_pragma_openmp_end |
1718 | 1818 | /// |
| 1819 | +/// assumes directive: |
| 1820 | +/// annot_pragma_openmp 'assumes' <clause> [[[,] <clause>] ... ] |
| 1821 | +/// annot_pragma_openmp_end |
| 1822 | +/// or |
| 1823 | +/// annot_pragma_openmp 'begin assumes' <clause> [[[,] <clause>] ... ] |
| 1824 | +/// annot_pragma_openmp 'end assumes' |
| 1825 | +/// annot_pragma_openmp_end |
| 1826 | +/// |
1719 | 1827 | Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( |
1720 | 1828 | AccessSpecifier &AS, ParsedAttributesWithRange &Attrs, bool Delayed, |
1721 | 1829 | DeclSpec::TST TagType, Decl *Tag) { |
@@ -1853,6 +1961,13 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( |
1853 | 1961 | ConsumeAnnotationToken(); |
1854 | 1962 | return Actions.ActOnOpenMPRequiresDirective(StartLoc, Clauses); |
1855 | 1963 | } |
| 1964 | + case OMPD_assumes: |
| 1965 | + case OMPD_begin_assumes: |
| 1966 | + ParseOpenMPAssumesDirective(DKind, ConsumeToken()); |
| 1967 | + break; |
| 1968 | + case OMPD_end_assumes: |
| 1969 | + ParseOpenMPEndAssumesDirective(ConsumeToken()); |
| 1970 | + break; |
1856 | 1971 | case OMPD_declare_reduction: |
1857 | 1972 | ConsumeToken(); |
1858 | 1973 | if (DeclGroupPtrTy Res = ParseOpenMPDeclareReductionDirective(AS)) { |
|
0 commit comments