[OpenMP] OpenMP 5.1 "assume" directive parsing support (#92731)

This is a minimal patch to support parsing for "omp assume" directives.
These are meant to be hints to a compiler's optimisers: as such, it is
legitimate (if not very useful) to ignore them. The patch builds on top
of the existing support for "omp assumes" directives (note spelling!).

Unlike the "omp [begin/end] assumes" directives, "omp assume" is
associated with a compound statement, i.e. it can appear within a
function. The "holds" assumption could (theoretically) be mapped onto
the existing builtin "__builtin_assume", though the latter applies to a
single point in the program, and the former to a range (i.e. the whole
of the associated compound statement).

This patch fixes sollve's OpenMP 5.1 "omp assume"-based tests.
This commit is contained in:
Julian Brown 2024-08-05 12:37:07 +01:00 committed by GitHub
parent 8370ba4d15
commit a42e515e3a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
36 changed files with 1315 additions and 2 deletions

View File

@ -314,7 +314,7 @@ implementation.
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | assumes directives | :part:`worked on` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | assume directive | :part:`worked on` | |
| misc | assume directive | :good:`done` | |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
| misc | nothing directive | :good:`done` | D123286 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+

View File

@ -323,6 +323,7 @@ Python Binding Changes
OpenMP Support
--------------
- Added support for 'omp assume' directive.
Improvements
^^^^^^^^^^^^

View File

@ -2154,6 +2154,10 @@ enum CXCursorKind {
*/
CXCursor_OMPInterchangeDirective = 308,
/** OpenMP assume directive.
*/
CXCursor_OMPAssumeDirective = 309,
/** OpenACC Compute Construct.
*/
CXCursor_OpenACCComputeConstruct = 320,

View File

@ -342,6 +342,66 @@ public:
}
};
/// Class that represents a list of directive kinds (parallel, target, etc.)
/// as used in \c absent, \c contains clauses.
template <class T> class OMPDirectiveListClause : public OMPClause {
/// Location of '('.
SourceLocation LParenLoc;
protected:
/// Number of directive kinds listed in the clause
unsigned NumKinds;
public:
/// Build a clause with \a NumKinds directive kinds.
///
/// \param K The clause kind.
/// \param StartLoc Starting location of the clause (the clause keyword).
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param NumKinds Number of directive kinds listed in the clause.
OMPDirectiveListClause(OpenMPClauseKind K, SourceLocation StartLoc,
SourceLocation LParenLoc, SourceLocation EndLoc,
unsigned NumKinds)
: OMPClause(K, StartLoc, EndLoc), LParenLoc(LParenLoc),
NumKinds(NumKinds) {}
child_range children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
child_range used_children() {
return child_range(child_iterator(), child_iterator());
}
const_child_range used_children() const {
return const_child_range(const_child_iterator(), const_child_iterator());
}
MutableArrayRef<OpenMPDirectiveKind> getDirectiveKinds() {
return MutableArrayRef<OpenMPDirectiveKind>(
static_cast<T *>(this)
->template getTrailingObjects<OpenMPDirectiveKind>(),
NumKinds);
}
void setDirectiveKinds(ArrayRef<OpenMPDirectiveKind> DK) {
assert(
DK.size() == NumKinds &&
"Number of directive kinds is not the same as the preallocated buffer");
std::copy(DK.begin(), DK.end(),
static_cast<T *>(this)
->template getTrailingObjects<OpenMPDirectiveKind>());
}
SourceLocation getLParenLoc() { return LParenLoc; }
void setLParenLoc(SourceLocation S) { LParenLoc = S; }
};
/// This represents 'allocator' clause in the '#pragma omp ...'
/// directive.
///
@ -2013,6 +2073,184 @@ public:
}
};
/// This represents the 'absent' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume absent(<directive-name list>)
/// \endcode
/// In this example directive '#pragma omp assume' has an 'absent' clause.
class OMPAbsentClause final
: public OMPDirectiveListClause<OMPAbsentClause>,
private llvm::TrailingObjects<OMPAbsentClause, OpenMPDirectiveKind> {
friend OMPDirectiveListClause;
friend TrailingObjects;
/// Build 'absent' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param NumKinds Number of directive kinds listed in the clause.
OMPAbsentClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, unsigned NumKinds)
: OMPDirectiveListClause<OMPAbsentClause>(
llvm::omp::OMPC_absent, StartLoc, LParenLoc, EndLoc, NumKinds) {}
/// Build an empty clause.
OMPAbsentClause(unsigned NumKinds)
: OMPDirectiveListClause<OMPAbsentClause>(
llvm::omp::OMPC_absent, SourceLocation(), SourceLocation(),
SourceLocation(), NumKinds) {}
public:
static OMPAbsentClause *Create(const ASTContext &C,
ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc, SourceLocation LLoc,
SourceLocation RLoc);
static OMPAbsentClause *CreateEmpty(const ASTContext &C, unsigned NumKinds);
static bool classof(const OMPClause *C) {
return C->getClauseKind() == llvm::omp::OMPC_absent;
}
};
/// This represents the 'contains' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume contains(<directive-name list>)
/// \endcode
/// In this example directive '#pragma omp assume' has a 'contains' clause.
class OMPContainsClause final
: public OMPDirectiveListClause<OMPContainsClause>,
private llvm::TrailingObjects<OMPContainsClause, OpenMPDirectiveKind> {
friend OMPDirectiveListClause;
friend TrailingObjects;
/// Build 'contains' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param LParenLoc Location of '('.
/// \param EndLoc Ending location of the clause.
/// \param NumKinds Number of directive kinds listed in the clause.
OMPContainsClause(SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, unsigned NumKinds)
: OMPDirectiveListClause<OMPContainsClause>(
llvm::omp::OMPC_contains, StartLoc, LParenLoc, EndLoc, NumKinds) {}
/// Build an empty clause.
OMPContainsClause(unsigned NumKinds)
: OMPDirectiveListClause<OMPContainsClause>(
llvm::omp::OMPC_contains, SourceLocation(), SourceLocation(),
SourceLocation(), NumKinds) {}
public:
static OMPContainsClause *Create(const ASTContext &C,
ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc, SourceLocation LLoc,
SourceLocation RLoc);
static OMPContainsClause *CreateEmpty(const ASTContext &C, unsigned NumKinds);
static bool classof(const OMPClause *C) {
return C->getClauseKind() == llvm::omp::OMPC_contains;
}
};
/// This represents the 'holds' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume holds(<expr>)
/// \endcode
/// In this example directive '#pragma omp assume' has a 'holds' clause.
class OMPHoldsClause final
: public OMPOneStmtClause<llvm::omp::OMPC_holds, OMPClause> {
friend class OMPClauseReader;
public:
/// Build 'holds' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPHoldsClause(Expr *E, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc)
: OMPOneStmtClause(E, StartLoc, LParenLoc, EndLoc) {}
/// Build an empty clause.
OMPHoldsClause() : OMPOneStmtClause() {}
Expr *getExpr() const { return getStmtAs<Expr>(); }
void setExpr(Expr *E) { setStmt(E); }
};
/// This represents the 'no_openmp' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume no_openmp
/// \endcode
/// In this example directive '#pragma omp assume' has a 'no_openmp' clause.
class OMPNoOpenMPClause final
: public OMPNoChildClause<llvm::omp::OMPC_no_openmp> {
public:
/// Build 'no_openmp' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPNoOpenMPClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPNoChildClause(StartLoc, EndLoc) {}
/// Build an empty clause.
OMPNoOpenMPClause() : OMPNoChildClause() {}
};
/// This represents the 'no_openmp_routines' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume no_openmp_routines
/// \endcode
/// In this example directive '#pragma omp assume' has a 'no_openmp_routines'
/// clause.
class OMPNoOpenMPRoutinesClause final
: public OMPNoChildClause<llvm::omp::OMPC_no_openmp_routines> {
public:
/// Build 'no_openmp_routines' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPNoOpenMPRoutinesClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPNoChildClause(StartLoc, EndLoc) {}
/// Build an empty clause.
OMPNoOpenMPRoutinesClause() : OMPNoChildClause() {}
};
/// This represents the 'no_parallelism' clause in the '#pragma omp assume'
/// directive.
///
/// \code
/// #pragma omp assume no_parallelism
/// \endcode
/// In this example directive '#pragma omp assume' has a 'no_parallelism'
/// clause.
class OMPNoParallelismClause final
: public OMPNoChildClause<llvm::omp::OMPC_no_parallelism> {
public:
/// Build 'no_parallelism' clause.
///
/// \param StartLoc Starting location of the clause.
/// \param EndLoc Ending location of the clause.
OMPNoParallelismClause(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPNoChildClause(StartLoc, EndLoc) {}
/// Build an empty clause.
OMPNoParallelismClause() : OMPNoChildClause() {}
};
/// This represents 'read' clause in the '#pragma omp atomic' directive.
///
/// \code

View File

@ -3238,6 +3238,9 @@ DEF_TRAVERSE_STMT(OMPParallelGenericLoopDirective,
DEF_TRAVERSE_STMT(OMPTargetParallelGenericLoopDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPAssumeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
DEF_TRAVERSE_STMT(OMPErrorDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })
@ -3480,6 +3483,38 @@ bool RecursiveASTVisitor<Derived>::VisitOMPAcqRelClause(OMPAcqRelClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPAbsentClause(OMPAbsentClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPHoldsClause(OMPHoldsClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPContainsClause(OMPContainsClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNoOpenMPRoutinesClause(
OMPNoOpenMPRoutinesClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPNoParallelismClause(
OMPNoParallelismClause *) {
return true;
}
template <typename Derived>
bool RecursiveASTVisitor<Derived>::VisitOMPAcquireClause(OMPAcquireClause *) {
return true;

View File

@ -6468,6 +6468,36 @@ public:
return T->getStmtClass() == OMPErrorDirectiveClass;
}
};
// It's not really an executable directive, but it seems convenient to use
// that as the parent class.
class OMPAssumeDirective final : public OMPExecutableDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
private:
OMPAssumeDirective(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPExecutableDirective(OMPAssumeDirectiveClass, llvm::omp::OMPD_assume,
StartLoc, EndLoc) {}
explicit OMPAssumeDirective()
: OMPExecutableDirective(OMPAssumeDirectiveClass, llvm::omp::OMPD_assume,
SourceLocation(), SourceLocation()) {}
public:
static OMPAssumeDirective *Create(const ASTContext &Ctx,
SourceLocation StartLoc,
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AStmt);
static OMPAssumeDirective *CreateEmpty(const ASTContext &C,
unsigned NumClauses, EmptyShell);
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPAssumeDirectiveClass;
}
};
} // end namespace clang
#endif

View File

@ -377,6 +377,11 @@ bool checkFailClauseParameter(OpenMPClauseKind FailClauseParameter);
/// otherwise - false.
bool isOpenMPExecutableDirective(OpenMPDirectiveKind DKind);
/// Checks if the specified directive is considered as "informational".
/// \param DKind Specified directive.
/// \return true if it is an informational directive, false otherwise.
bool isOpenMPInformationalDirective(OpenMPDirectiveKind DKind);
/// Checks if the specified directive can capture variables.
/// \param DKind Specified directive.
/// \return true - if the above condition is met for this directive

View File

@ -298,6 +298,7 @@ def OMPTeamsGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPTargetTeamsGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPParallelGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPTargetParallelGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPAssumeDirective : StmtNode<OMPExecutableDirective>;
def OMPErrorDirective : StmtNode<OMPExecutableDirective>;
// OpenACC Constructs.

View File

@ -3532,6 +3532,17 @@ private:
OpenMPDirectiveKind DKind, SourceLocation Loc,
bool ReadDirectiveWithinMetadirective);
/// Parses informational directive.
///
/// \param StmtCtx The context in which we're parsing the directive.
/// \param DKind The kind of the informational directive.
/// \param Loc Source location of the beginning of the directive.
/// \param ReadDirectiveWithinMetadirective true if directive is within a
/// metadirective and therefore ends on the closing paren.
StmtResult ParseOpenMPInformationalDirective(
ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
bool ReadDirectiveWithinMetadirective);
/// Parses clause of kind \a CKind for directive of a kind \a Kind.
///
/// \param DKind Kind of current directive.

View File

@ -399,6 +399,28 @@ public:
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
OpenMPDirectiveKind CancelRegion, ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc);
/// Process an OpenMP informational directive.
///
/// \param Kind The directive kind.
/// \param DirName Declaration name info.
/// \param Clauses Array of clauses for directive.
/// \param AStmt The associated statement.
/// \param StartLoc The start location.
/// \param EndLoc The end location.
StmtResult ActOnOpenMPInformationalDirective(
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
/// Process an OpenMP assume directive.
///
/// \param Clauses Array of clauses for directive.
/// \param AStmt The associated statement.
/// \param StartLoc The start location.
/// \param EndLoc The end location.
StmtResult ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc);
/// Called on well-formed '\#pragma omp parallel' after parsing
/// of the associated statement.
StmtResult ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
@ -940,6 +962,17 @@ public:
SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-formed 'holds' clause.
OMPClause *ActOnOpenMPHoldsClause(Expr *E, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc);
/// Called on well-formed 'absent' or 'contains' clauses.
OMPClause *ActOnOpenMPDirectivePresenceClause(
OpenMPClauseKind CK, llvm::ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc, SourceLocation LLoc, SourceLocation RLoc);
OMPClause *ActOnOpenMPNullaryAssumptionClause(OpenMPClauseKind CK,
SourceLocation Loc,
SourceLocation RLoc);
OMPClause *ActOnOpenMPSingleExprWithArgClause(
OpenMPClauseKind Kind, ArrayRef<unsigned> Arguments, Expr *Expr,

View File

@ -1964,6 +1964,7 @@ enum StmtCode {
STMT_OMP_TARGET_TEAMS_GENERIC_LOOP_DIRECTIVE,
STMT_OMP_PARALLEL_GENERIC_LOOP_DIRECTIVE,
STMT_OMP_TARGET_PARALLEL_GENERIC_LOOP_DIRECTIVE,
STMT_OMP_ASSUME_DIRECTIVE,
EXPR_ARRAY_SECTION,
EXPR_OMP_ARRAY_SHAPING,
EXPR_OMP_ITERATOR,

View File

@ -1720,6 +1720,41 @@ const Expr *OMPDoacrossClause::getLoopData(unsigned NumLoop) const {
return *It;
}
OMPAbsentClause *OMPAbsentClause::Create(const ASTContext &C,
ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc,
SourceLocation LLoc,
SourceLocation RLoc) {
void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(DKVec.size()),
alignof(OMPAbsentClause));
auto *AC = new (Mem) OMPAbsentClause(Loc, LLoc, RLoc, DKVec.size());
AC->setDirectiveKinds(DKVec);
return AC;
}
OMPAbsentClause *OMPAbsentClause::CreateEmpty(const ASTContext &C, unsigned K) {
void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(K),
alignof(OMPAbsentClause));
return new (Mem) OMPAbsentClause(K);
}
OMPContainsClause *OMPContainsClause::Create(
const ASTContext &C, ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc, SourceLocation LLoc, SourceLocation RLoc) {
void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(DKVec.size()),
alignof(OMPContainsClause));
auto *CC = new (Mem) OMPContainsClause(Loc, LLoc, RLoc, DKVec.size());
CC->setDirectiveKinds(DKVec);
return CC;
}
OMPContainsClause *OMPContainsClause::CreateEmpty(const ASTContext &C,
unsigned K) {
void *Mem = C.Allocate(totalSizeToAlloc<OpenMPDirectiveKind>(K),
alignof(OMPContainsClause));
return new (Mem) OMPContainsClause(K);
}
//===----------------------------------------------------------------------===//
// OpenMP clauses printing methods
//===----------------------------------------------------------------------===//
@ -1937,6 +1972,49 @@ void OMPClausePrinter::VisitOMPFailClause(OMPFailClause *Node) {
}
}
void OMPClausePrinter::VisitOMPAbsentClause(OMPAbsentClause *Node) {
OS << "absent(";
bool First = true;
for (auto &D : Node->getDirectiveKinds()) {
if (!First)
OS << ", ";
OS << getOpenMPDirectiveName(D);
First = false;
}
OS << ")";
}
void OMPClausePrinter::VisitOMPHoldsClause(OMPHoldsClause *Node) {
OS << "holds(";
Node->getExpr()->printPretty(OS, nullptr, Policy, 0);
OS << ")";
}
void OMPClausePrinter::VisitOMPContainsClause(OMPContainsClause *Node) {
OS << "contains(";
bool First = true;
for (auto &D : Node->getDirectiveKinds()) {
if (!First)
OS << ", ";
OS << getOpenMPDirectiveName(D);
First = false;
}
OS << ")";
}
void OMPClausePrinter::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {
OS << "no_openmp";
}
void OMPClausePrinter::VisitOMPNoOpenMPRoutinesClause(
OMPNoOpenMPRoutinesClause *) {
OS << "no_openmp_routines";
}
void OMPClausePrinter::VisitOMPNoParallelismClause(OMPNoParallelismClause *) {
OS << "no_parallelism";
}
void OMPClausePrinter::VisitOMPSeqCstClause(OMPSeqCstClause *) {
OS << "seq_cst";
}

View File

@ -799,6 +799,23 @@ OMPTaskyieldDirective *OMPTaskyieldDirective::CreateEmpty(const ASTContext &C,
return new (C) OMPTaskyieldDirective();
}
OMPAssumeDirective *OMPAssumeDirective::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses,
Stmt *AStmt) {
return createDirective<OMPAssumeDirective>(C, Clauses, AStmt,
/*NumChildren=*/0, StartLoc,
EndLoc);
}
OMPAssumeDirective *OMPAssumeDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
return createEmptyDirective<OMPAssumeDirective>(C, NumClauses,
/*HasAssociatedStmt=*/true);
}
OMPErrorDirective *OMPErrorDirective::Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc,

View File

@ -867,6 +867,11 @@ void StmtPrinter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *Node) {
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPAssumeDirective(OMPAssumeDirective *Node) {
Indent() << "#pragma omp assume";
PrintOMPExecutableDirective(Node);
}
void StmtPrinter::VisitOMPErrorDirective(OMPErrorDirective *Node) {
Indent() << "#pragma omp error";
PrintOMPExecutableDirective(Node);

View File

@ -584,6 +584,20 @@ void OMPClauseProfiler::VisitOMPCompareClause(const OMPCompareClause *) {}
void OMPClauseProfiler::VisitOMPFailClause(const OMPFailClause *) {}
void OMPClauseProfiler::VisitOMPAbsentClause(const OMPAbsentClause *) {}
void OMPClauseProfiler::VisitOMPHoldsClause(const OMPHoldsClause *) {}
void OMPClauseProfiler::VisitOMPContainsClause(const OMPContainsClause *) {}
void OMPClauseProfiler::VisitOMPNoOpenMPClause(const OMPNoOpenMPClause *) {}
void OMPClauseProfiler::VisitOMPNoOpenMPRoutinesClause(
const OMPNoOpenMPRoutinesClause *) {}
void OMPClauseProfiler::VisitOMPNoParallelismClause(
const OMPNoParallelismClause *) {}
void OMPClauseProfiler::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
void OMPClauseProfiler::VisitOMPAcqRelClause(const OMPAcqRelClause *) {}
@ -1068,6 +1082,10 @@ void StmtProfiler::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *S) {
VisitOMPExecutableDirective(S);
}
void StmtProfiler::VisitOMPAssumeDirective(const OMPAssumeDirective *S) {
VisitOMPExecutableDirective(S);
}
void StmtProfiler::VisitOMPErrorDirective(const OMPErrorDirective *S) {
VisitOMPExecutableDirective(S);
}

View File

@ -710,6 +710,13 @@ bool clang::isOpenMPExecutableDirective(OpenMPDirectiveKind DKind) {
return Cat == Category::Executable || Cat == Category::Subsidiary;
}
bool clang::isOpenMPInformationalDirective(OpenMPDirectiveKind DKind) {
if (DKind == OMPD_error)
return true;
Category Cat = getDirectiveCategory(DKind);
return Cat == Category::Informational;
}
bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind) {
if (isOpenMPExecutableDirective(DKind)) {
switch (DKind) {
@ -726,6 +733,7 @@ bool clang::isOpenMPCapturingDirective(OpenMPDirectiveKind DKind) {
case OMPD_section:
case OMPD_taskwait:
case OMPD_taskyield:
case OMPD_assume:
return false;
default:
return !isOpenMPLoopTransformationDirective(DKind);

View File

@ -446,6 +446,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) {
case Stmt::OMPParallelMaskedDirectiveClass:
EmitOMPParallelMaskedDirective(cast<OMPParallelMaskedDirective>(*S));
break;
case Stmt::OMPAssumeDirectiveClass:
EmitOMPAssumeDirective(cast<OMPAssumeDirective>(*S));
break;
case Stmt::OpenACCComputeConstructClass:
EmitOpenACCComputeConstruct(cast<OpenACCComputeConstruct>(*S));
break;

View File

@ -8288,7 +8288,8 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective(
D.getDirectiveKind() == OMPD_section ||
D.getDirectiveKind() == OMPD_master ||
D.getDirectiveKind() == OMPD_masked ||
D.getDirectiveKind() == OMPD_unroll) {
D.getDirectiveKind() == OMPD_unroll ||
D.getDirectiveKind() == OMPD_assume) {
EmitStmt(D.getAssociatedStmt());
} else {
auto LPCRegion =
@ -8303,3 +8304,7 @@ void CodeGenFunction::EmitSimpleOMPExecutableDirective(
// Check for outer lastprivate conditional update.
checkForLastprivateConditionalUpdate(*this, D);
}
void CodeGenFunction::EmitOMPAssumeDirective(const OMPAssumeDirective &S) {
EmitStmt(S.getAssociatedStmt());
}

View File

@ -3904,6 +3904,7 @@ public:
void EmitOMPTeamsGenericLoopDirective(const OMPTeamsGenericLoopDirective &S);
void EmitOMPInteropDirective(const OMPInteropDirective &S);
void EmitOMPParallelMaskedDirective(const OMPParallelMaskedDirective &S);
void EmitOMPAssumeDirective(const OMPAssumeDirective &S);
/// Emit device code for the target directive.
static void EmitOMPTargetDeviceFunction(CodeGenModule &CGM,

View File

@ -2371,6 +2371,11 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl(
ParseOMPEndDeclareTargetDirective(DTCI.Kind, DKind, DTCI.Loc);
return nullptr;
}
case OMPD_assume: {
Diag(Tok, diag::err_omp_unexpected_directive)
<< 1 << getOpenMPDirectiveName(DKind);
break;
}
case OMPD_unknown:
Diag(Tok, diag::err_omp_unknown_directive);
break;
@ -2572,6 +2577,71 @@ StmtResult Parser::ParseOpenMPExecutableDirective(
return Directive;
}
StmtResult Parser::ParseOpenMPInformationalDirective(
ParsedStmtContext StmtCtx, OpenMPDirectiveKind DKind, SourceLocation Loc,
bool ReadDirectiveWithinMetadirective) {
assert(isOpenMPInformationalDirective(DKind) &&
"Unexpected directive category");
bool HasAssociatedStatement = true;
Association Assoc = getDirectiveAssociation(DKind);
SmallVector<OMPClause *, 5> Clauses;
llvm::SmallBitVector SeenClauses(llvm::omp::Clause_enumSize + 1);
DeclarationNameInfo DirName;
unsigned ScopeFlags = Scope::FnScope | Scope::DeclScope |
Scope::CompoundStmtScope | Scope::OpenMPDirectiveScope;
ParseScope OMPDirectiveScope(this, ScopeFlags);
Actions.OpenMP().StartOpenMPDSABlock(DKind, DirName, Actions.getCurScope(),
Loc);
while (Tok.isNot(tok::annot_pragma_openmp_end)) {
if (ReadDirectiveWithinMetadirective && Tok.is(tok::r_paren)) {
while (Tok.isNot(tok::annot_pragma_openmp_end))
ConsumeAnyToken();
break;
}
OpenMPClauseKind CKind = Tok.isAnnotation()
? OMPC_unknown
: getOpenMPClauseKind(PP.getSpelling(Tok));
Actions.OpenMP().StartOpenMPClause(CKind);
OMPClause *Clause =
ParseOpenMPClause(DKind, CKind, !SeenClauses[unsigned(CKind)]);
SeenClauses[unsigned(CKind)] = true;
if (Clause)
Clauses.push_back(Clause);
if (Tok.is(tok::comma))
ConsumeToken();
Actions.OpenMP().EndOpenMPClause();
}
SourceLocation EndLoc = Tok.getLocation();
ConsumeAnnotationToken();
StmtResult AssociatedStmt;
if (HasAssociatedStatement) {
Actions.OpenMP().ActOnOpenMPRegionStart(DKind, getCurScope());
ParsingOpenMPDirectiveRAII NormalScope(*this, /*Value=*/false);
{
Sema::CompoundScopeRAII Scope(Actions);
AssociatedStmt = ParseStatement();
}
AssociatedStmt =
Actions.OpenMP().ActOnOpenMPRegionEnd(AssociatedStmt, Clauses);
}
StmtResult Directive = Actions.OpenMP().ActOnOpenMPInformationalDirective(
DKind, DirName, Clauses, AssociatedStmt.get(), Loc, EndLoc);
Actions.OpenMP().EndOpenMPDSABlock(Directive.get());
OMPDirectiveScope.Exit();
return Directive;
}
/// Parsing of declarative or executable OpenMP directives.
///
/// threadprivate-directive:
@ -2920,6 +2990,14 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective(
<< 1 << getOpenMPDirectiveName(DKind);
SkipUntil(tok::annot_pragma_openmp_end);
break;
case OMPD_assume: {
ConsumeToken();
Directive = ParseOpenMPInformationalDirective(
StmtCtx, DKind, Loc, ReadDirectiveWithinMetadirective);
assert(!Directive.isUnset() &&
"Informational directive remains unprocessed");
return Directive;
}
case OMPD_unknown:
default:
Diag(Tok, diag::err_omp_unknown_directive);
@ -3206,6 +3284,9 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
case OMPC_if:
Clause = ParseOpenMPSingleExprWithArgClause(DKind, CKind, WrongDirective);
break;
case OMPC_holds:
Clause = ParseOpenMPSingleExprClause(CKind, WrongDirective);
break;
case OMPC_nowait:
case OMPC_untied:
case OMPC_mergeable:
@ -3323,6 +3404,49 @@ OMPClause *Parser::ParseOpenMPClause(OpenMPDirectiveKind DKind,
<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
SkipUntil(tok::comma, tok::annot_pragma_openmp_end, StopBeforeMatch);
break;
case OMPC_absent:
case OMPC_contains: {
SourceLocation Loc = ConsumeToken();
SourceLocation LLoc = Tok.getLocation();
SourceLocation RLoc;
llvm::SmallVector<OpenMPDirectiveKind, 4> DKVec;
BalancedDelimiterTracker T(*this, tok::l_paren);
T.consumeOpen();
do {
OpenMPDirectiveKind DK = getOpenMPDirectiveKind(PP.getSpelling(Tok));
if (DK == OMPD_unknown) {
skipUntilPragmaOpenMPEnd(OMPD_assume);
Diag(Tok, diag::err_omp_unexpected_clause)
<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
break;
}
if (isOpenMPExecutableDirective(DK)) {
DKVec.push_back(DK);
ConsumeToken();
} else {
Diag(Tok, diag::err_omp_unexpected_clause)
<< getOpenMPClauseName(CKind) << getOpenMPDirectiveName(DKind);
}
} while (TryConsumeToken(tok::comma));
RLoc = Tok.getLocation();
T.consumeClose();
Clause = Actions.OpenMP().ActOnOpenMPDirectivePresenceClause(
CKind, DKVec, Loc, LLoc, RLoc);
break;
}
case OMPC_no_openmp:
case OMPC_no_openmp_routines:
case OMPC_no_parallelism: {
if (!FirstClause) {
Diag(Tok, diag::err_omp_more_one_clause)
<< getOpenMPDirectiveName(DKind) << getOpenMPClauseName(CKind) << 0;
ErrorFound = true;
}
SourceLocation Loc = ConsumeToken();
Clause = Actions.OpenMP().ActOnOpenMPNullaryAssumptionClause(
CKind, Loc, Tok.getLocation());
break;
}
case OMPC_ompx_attribute:
Clause = ParseOpenMPOMPXAttributesClause(WrongDirective);
break;
@ -3408,6 +3532,9 @@ ExprResult Parser::ParseOpenMPParensExpr(StringRef ClauseName,
/// align-clause
/// 'align' '(' positive-integer-constant ')'
///
/// holds-clause
/// 'holds' '(' expression ')'
///
OMPClause *Parser::ParseOpenMPSingleExprClause(OpenMPClauseKind Kind,
bool ParseOnly) {
SourceLocation Loc = ConsumeToken();

View File

@ -3563,6 +3563,17 @@ void SemaOpenMP::ActOnOpenMPEndAssumesDirective() {
OMPAssumeScoped.pop_back();
}
StmtResult SemaOpenMP::ActOnOpenMPAssumeDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
if (!AStmt)
return StmtError();
return OMPAssumeDirective::Create(getASTContext(), StartLoc, EndLoc, Clauses,
AStmt);
}
OMPRequiresDecl *
SemaOpenMP::CheckOMPRequiresDecl(SourceLocation Loc,
ArrayRef<OMPClause *> ClauseList) {
@ -3728,6 +3739,7 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> {
S->getDirectiveKind() == OMPD_master ||
S->getDirectiveKind() == OMPD_masked ||
S->getDirectiveKind() == OMPD_scope ||
S->getDirectiveKind() == OMPD_assume ||
isOpenMPLoopTransformationDirective(S->getDirectiveKind())) {
Visit(S->getAssociatedStmt());
return;
@ -4387,6 +4399,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind,
case OMPD_unroll:
case OMPD_reverse:
case OMPD_interchange:
case OMPD_assume:
break;
default:
processCapturedRegions(SemaRef, DKind, CurScope,
@ -6928,6 +6941,26 @@ SemaOpenMP::DeclGroupPtrTy SemaOpenMP::ActOnOpenMPDeclareSimdDirective(
return DG;
}
StmtResult SemaOpenMP::ActOnOpenMPInformationalDirective(
OpenMPDirectiveKind Kind, const DeclarationNameInfo &DirName,
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
assert(isOpenMPInformationalDirective(Kind) &&
"Unexpected directive category");
StmtResult Res = StmtError();
switch (Kind) {
case OMPD_assume:
Res = ActOnOpenMPAssumeDirective(Clauses, AStmt, StartLoc, EndLoc);
break;
default:
llvm_unreachable("Unknown OpenMP directive");
}
return Res;
}
static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto,
QualType NewType) {
assert(NewType->isFunctionProtoType() &&
@ -14961,6 +14994,9 @@ OMPClause *SemaOpenMP::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind,
case OMPC_ompx_dyn_cgroup_mem:
Res = ActOnOpenMPXDynCGroupMemClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_holds:
Res = ActOnOpenMPHoldsClause(Expr, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_grainsize:
case OMPC_num_tasks:
case OMPC_device:
@ -23337,6 +23373,40 @@ OMPClause *SemaOpenMP::ActOnOpenMPXBareClause(SourceLocation StartLoc,
return new (getASTContext()) OMPXBareClause(StartLoc, EndLoc);
}
OMPClause *SemaOpenMP::ActOnOpenMPHoldsClause(Expr *E, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return new (getASTContext()) OMPHoldsClause(E, StartLoc, LParenLoc, EndLoc);
}
OMPClause *SemaOpenMP::ActOnOpenMPDirectivePresenceClause(
OpenMPClauseKind CK, llvm::ArrayRef<OpenMPDirectiveKind> DKVec,
SourceLocation Loc, SourceLocation LLoc, SourceLocation RLoc) {
switch (CK) {
case OMPC_absent:
return OMPAbsentClause::Create(getASTContext(), DKVec, Loc, LLoc, RLoc);
case OMPC_contains:
return OMPContainsClause::Create(getASTContext(), DKVec, Loc, LLoc, RLoc);
default:
llvm_unreachable("Unexpected OpenMP clause");
}
}
OMPClause *SemaOpenMP::ActOnOpenMPNullaryAssumptionClause(OpenMPClauseKind CK,
SourceLocation Loc,
SourceLocation RLoc) {
switch (CK) {
case OMPC_no_openmp:
return new (getASTContext()) OMPNoOpenMPClause(Loc, RLoc);
case OMPC_no_openmp_routines:
return new (getASTContext()) OMPNoOpenMPRoutinesClause(Loc, RLoc);
case OMPC_no_parallelism:
return new (getASTContext()) OMPNoParallelismClause(Loc, RLoc);
default:
llvm_unreachable("Unexpected OpenMP clause");
}
}
ExprResult SemaOpenMP::ActOnOMPArraySectionExpr(
Expr *Base, SourceLocation LBLoc, Expr *LowerBound,
SourceLocation ColonLocFirst, SourceLocation ColonLocSecond, Expr *Length,

View File

@ -803,6 +803,8 @@ public:
StmtResult TransformOMPExecutableDirective(OMPExecutableDirective *S);
StmtResult TransformOMPInformationalDirective(OMPExecutableDirective *S);
// FIXME: We use LLVM_ATTRIBUTE_NOINLINE because inlining causes a ridiculous
// amount of stack usage with clang.
#define STMT(Node, Parent) \
@ -1678,6 +1680,18 @@ public:
Kind, DirName, CancelRegion, Clauses, AStmt, StartLoc, EndLoc);
}
/// Build a new OpenMP informational directive.
StmtResult RebuildOMPInformationalDirective(OpenMPDirectiveKind Kind,
DeclarationNameInfo DirName,
ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
SourceLocation EndLoc) {
return getSema().OpenMP().ActOnOpenMPInformationalDirective(
Kind, DirName, Clauses, AStmt, StartLoc, EndLoc);
}
/// Build a new OpenMP 'if' clause.
///
/// By default, performs semantic analysis to build the new OpenMP clause.
@ -2486,6 +2500,14 @@ public:
DepType, DepLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc);
}
/// Build a new OpenMP 'holds' clause.
OMPClause *RebuildOMPHoldsClause(Expr *A, SourceLocation StartLoc,
SourceLocation LParenLoc,
SourceLocation EndLoc) {
return getSema().OpenMP().ActOnOpenMPHoldsClause(A, StartLoc, LParenLoc,
EndLoc);
}
/// Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@ -9185,6 +9207,58 @@ StmtResult TreeTransform<Derived>::TransformOMPExecutableDirective(
AssociatedStmt.get(), D->getBeginLoc(), D->getEndLoc());
}
/// This is mostly the same as above, but allows 'informational' class
/// directives when rebuilding the stmt. It still takes an
/// OMPExecutableDirective-type argument because we're reusing that as the
/// superclass for the 'assume' directive at present, instead of defining a
/// mostly-identical OMPInformationalDirective parent class.
template <typename Derived>
StmtResult TreeTransform<Derived>::TransformOMPInformationalDirective(
OMPExecutableDirective *D) {
// Transform the clauses
llvm::SmallVector<OMPClause *, 16> TClauses;
ArrayRef<OMPClause *> Clauses = D->clauses();
TClauses.reserve(Clauses.size());
for (OMPClause *C : Clauses) {
if (C) {
getDerived().getSema().OpenMP().StartOpenMPClause(C->getClauseKind());
OMPClause *Clause = getDerived().TransformOMPClause(C);
getDerived().getSema().OpenMP().EndOpenMPClause();
if (Clause)
TClauses.push_back(Clause);
} else {
TClauses.push_back(nullptr);
}
}
StmtResult AssociatedStmt;
if (D->hasAssociatedStmt() && D->getAssociatedStmt()) {
getDerived().getSema().OpenMP().ActOnOpenMPRegionStart(
D->getDirectiveKind(),
/*CurScope=*/nullptr);
StmtResult Body;
{
Sema::CompoundScopeRAII CompoundScope(getSema());
assert(D->getDirectiveKind() == OMPD_assume &&
"Unexpected informational directive");
Stmt *CS = D->getAssociatedStmt();
Body = getDerived().TransformStmt(CS);
}
AssociatedStmt =
getDerived().getSema().OpenMP().ActOnOpenMPRegionEnd(Body, TClauses);
if (AssociatedStmt.isInvalid())
return StmtError();
}
if (TClauses.size() != Clauses.size())
return StmtError();
DeclarationNameInfo DirName;
return getDerived().RebuildOMPInformationalDirective(
D->getDirectiveKind(), DirName, TClauses, AssociatedStmt.get(),
D->getBeginLoc(), D->getEndLoc());
}
template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPMetaDirective(OMPMetaDirective *D) {
@ -9446,6 +9520,17 @@ TreeTransform<Derived>::TransformOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
return Res;
}
template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPAssumeDirective(OMPAssumeDirective *D) {
DeclarationNameInfo DirName;
getDerived().getSema().OpenMP().StartOpenMPDSABlock(
OMPD_assume, DirName, nullptr, D->getBeginLoc());
StmtResult Res = getDerived().TransformOMPInformationalDirective(D);
getDerived().getSema().OpenMP().EndOpenMPDSABlock(Res.get());
return Res;
}
template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPErrorDirective(OMPErrorDirective *D) {
@ -10240,6 +10325,43 @@ OMPClause *TreeTransform<Derived>::TransformOMPFailClause(OMPFailClause *C) {
return C;
}
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPAbsentClause(OMPAbsentClause *C) {
return C;
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPHoldsClause(OMPHoldsClause *C) {
ExprResult E = getDerived().TransformExpr(C->getExpr());
if (E.isInvalid())
return nullptr;
return getDerived().RebuildOMPHoldsClause(E.get(), C->getBeginLoc(),
C->getLParenLoc(), C->getEndLoc());
}
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPContainsClause(OMPContainsClause *C) {
return C;
}
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPNoOpenMPClause(OMPNoOpenMPClause *C) {
return C;
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPNoOpenMPRoutinesClause(
OMPNoOpenMPRoutinesClause *C) {
return C;
}
template <typename Derived>
OMPClause *TreeTransform<Derived>::TransformOMPNoParallelismClause(
OMPNoParallelismClause *C) {
return C;
}
template <typename Derived>
OMPClause *
TreeTransform<Derived>::TransformOMPSeqCstClause(OMPSeqCstClause *C) {

View File

@ -10463,6 +10463,28 @@ OMPClause *OMPClauseReader::readClause() {
case llvm::omp::OMPC_acq_rel:
C = new (Context) OMPAcqRelClause();
break;
case llvm::omp::OMPC_absent: {
unsigned NumKinds = Record.readInt();
C = OMPAbsentClause::CreateEmpty(Context, NumKinds);
break;
}
case llvm::omp::OMPC_holds:
C = new (Context) OMPHoldsClause();
break;
case llvm::omp::OMPC_contains: {
unsigned NumKinds = Record.readInt();
C = OMPContainsClause::CreateEmpty(Context, NumKinds);
break;
}
case llvm::omp::OMPC_no_openmp:
C = new (Context) OMPNoOpenMPClause();
break;
case llvm::omp::OMPC_no_openmp_routines:
C = new (Context) OMPNoOpenMPRoutinesClause();
break;
case llvm::omp::OMPC_no_parallelism:
C = new (Context) OMPNoParallelismClause();
break;
case llvm::omp::OMPC_acquire:
C = new (Context) OMPAcquireClause();
break;
@ -10863,6 +10885,40 @@ void OMPClauseReader::VisitOMPFailClause(OMPFailClause *C) {
C->setFailParameter(CKind);
}
void OMPClauseReader::VisitOMPAbsentClause(OMPAbsentClause *C) {
unsigned Count = C->getDirectiveKinds().size();
C->setLParenLoc(Record.readSourceLocation());
llvm::SmallVector<OpenMPDirectiveKind, 4> DKVec;
DKVec.reserve(Count);
for (unsigned I = 0; I < Count; I++) {
DKVec.push_back(Record.readEnum<OpenMPDirectiveKind>());
}
C->setDirectiveKinds(DKVec);
}
void OMPClauseReader::VisitOMPHoldsClause(OMPHoldsClause *C) {
C->setExpr(Record.readExpr());
C->setLParenLoc(Record.readSourceLocation());
}
void OMPClauseReader::VisitOMPContainsClause(OMPContainsClause *C) {
unsigned Count = C->getDirectiveKinds().size();
C->setLParenLoc(Record.readSourceLocation());
llvm::SmallVector<OpenMPDirectiveKind, 4> DKVec;
DKVec.reserve(Count);
for (unsigned I = 0; I < Count; I++) {
DKVec.push_back(Record.readEnum<OpenMPDirectiveKind>());
}
C->setDirectiveKinds(DKVec);
}
void OMPClauseReader::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {}
void OMPClauseReader::VisitOMPNoOpenMPRoutinesClause(
OMPNoOpenMPRoutinesClause *) {}
void OMPClauseReader::VisitOMPNoParallelismClause(OMPNoParallelismClause *) {}
void OMPClauseReader::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
void OMPClauseReader::VisitOMPAcqRelClause(OMPAcqRelClause *) {}

View File

@ -2536,6 +2536,11 @@ void ASTStmtReader::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
VisitOMPExecutableDirective(D);
}
void ASTStmtReader::VisitOMPAssumeDirective(OMPAssumeDirective *D) {
VisitStmt(D);
VisitOMPExecutableDirective(D);
}
void ASTStmtReader::VisitOMPErrorDirective(OMPErrorDirective *D) {
VisitStmt(D);
// The NumClauses field was read in ReadStmtFromStream.
@ -3913,6 +3918,12 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
}
case STMT_OMP_ASSUME_DIRECTIVE: {
unsigned NumClauses = Record[ASTStmtReader::NumStmtFields];
S = OMPAssumeDirective::CreateEmpty(Context, NumClauses, Empty);
break;
}
case EXPR_CXX_OPERATOR_CALL: {
auto NumArgs = Record[ASTStmtReader::NumExprFields];
BitsUnpacker CallExprBits(Record[ASTStmtReader::NumExprFields + 1]);

View File

@ -7204,6 +7204,34 @@ void OMPClauseWriter::VisitOMPSeqCstClause(OMPSeqCstClause *) {}
void OMPClauseWriter::VisitOMPAcqRelClause(OMPAcqRelClause *) {}
void OMPClauseWriter::VisitOMPAbsentClause(OMPAbsentClause *C) {
Record.push_back(static_cast<uint64_t>(C->getDirectiveKinds().size()));
Record.AddSourceLocation(C->getLParenLoc());
for (auto K : C->getDirectiveKinds()) {
Record.writeEnum(K);
}
}
void OMPClauseWriter::VisitOMPHoldsClause(OMPHoldsClause *C) {
Record.AddStmt(C->getExpr());
Record.AddSourceLocation(C->getLParenLoc());
}
void OMPClauseWriter::VisitOMPContainsClause(OMPContainsClause *C) {
Record.push_back(static_cast<uint64_t>(C->getDirectiveKinds().size()));
Record.AddSourceLocation(C->getLParenLoc());
for (auto K : C->getDirectiveKinds()) {
Record.writeEnum(K);
}
}
void OMPClauseWriter::VisitOMPNoOpenMPClause(OMPNoOpenMPClause *) {}
void OMPClauseWriter::VisitOMPNoOpenMPRoutinesClause(
OMPNoOpenMPRoutinesClause *) {}
void OMPClauseWriter::VisitOMPNoParallelismClause(OMPNoParallelismClause *) {}
void OMPClauseWriter::VisitOMPAcquireClause(OMPAcquireClause *) {}
void OMPClauseWriter::VisitOMPReleaseClause(OMPReleaseClause *) {}

View File

@ -2606,6 +2606,12 @@ void ASTStmtWriter::VisitOMPTaskwaitDirective(OMPTaskwaitDirective *D) {
Code = serialization::STMT_OMP_TASKWAIT_DIRECTIVE;
}
void ASTStmtWriter::VisitOMPAssumeDirective(OMPAssumeDirective *D) {
VisitStmt(D);
VisitOMPExecutableDirective(D);
Code = serialization::STMT_OMP_ASSUME_DIRECTIVE;
}
void ASTStmtWriter::VisitOMPErrorDirective(OMPErrorDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());

View File

@ -0,0 +1,31 @@
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s
// expected-no-diagnostics
extern int bar(int);
int foo(int arg)
{
#pragma omp assume no_openmp_routines
{
auto fn = [](int x) { return bar(x); };
// CHECK: auto fn = [](int x) {
return fn(5);
}
}
class C {
public:
int foo(int a);
};
// We're really just checking that this parses. All the assumptions are thrown
// away immediately for now.
int C::foo(int a)
{
#pragma omp assume holds(sizeof(void*) == 8) absent(parallel)
{
auto fn = [](int x) { return bar(x); };
// CHECK: auto fn = [](int x) {
return fn(5);
}
}

View File

@ -0,0 +1,30 @@
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp -x c -std=c99 %s
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp-simd -x c -std=c99 %s
#pragma omp assume no_openmp // expected-error {{unexpected OpenMP directive '#pragma omp assume'}}
void foo(void) {
#pragma omp assume hold(1==1) // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
{}
}
void bar(void) {
#pragma omp assume absent(target)
} // expected-error {{expected statement}}
void qux(void) {
#pragma omp assume extra_bits // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
{}
}
void quux(void) {
// This form of spelling for assumption clauses is supported for
// "omp assumes" (as a non-standard extension), but not here.
#pragma omp assume ext_spelled_like_this // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
{}
}
void dups(void) {
#pragma omp assume no_openmp no_openmp // // expected-error {{directive '#pragma omp assume' cannot contain more than one 'no_openmp' clause}}
{}
}

View File

@ -0,0 +1,30 @@
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp -x c -std=c99 %s
// RUN: %clang_cc1 -triple=x86_64-linux-gnu -verify -fopenmp-simd -x c -std=c99 %s
[[omp::directive(assume no_openmp)]] // expected-error {{unexpected OpenMP directive '#pragma omp assume'}}
void foo(void) {
[[omp::directive(assume hold(1==1))]] // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
{}
}
void bar(void) {
[[omp::directive(assume absent(target))]]
} // expected-error {{expected statement}}
void qux(void) {
[[omp::directive(assume extra_bits)]] // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
{}
}
void quux(void) {
// This form of spelling for assumption clauses is supported for
// "omp assumes" (as a non-standard extension), but not here.
[[omp::directive(assume ext_spelled_like_this)]] // expected-warning {{extra tokens at the end of '#pragma omp assume' are ignored}}
{}
}
void dups(void) {
[[omp::directive(assume no_openmp no_openmp)]] // expected-error {{directive '#pragma omp assume' cannot contain more than one 'no_openmp' clause}}
{}
}

View File

@ -0,0 +1,53 @@
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s
// expected-no-diagnostics
extern void bar();
void foo()
{
#pragma omp assume no_openmp_routines
// CHECK: omp assume no_openmp_routines
{
#pragma omp assume no_parallelism
// CHECK: omp assume no_parallelism
{}
}
#pragma omp target
// CHECK: omp target
{
#pragma omp assume holds(1==1)
// CHECK: omp assume holds(1 == 1)
{}
}
#pragma omp assume no_parallelism
// CHECK: omp assume no_parallelism
{
#pragma omp target
// CHECK: omp target
{}
}
#pragma omp assume absent(parallel)
// CHECK: omp assume absent(parallel)
{
#pragma omp assume contains(target, loop)
// CHECK: omp assume contains(target, loop)
{
#pragma omp assume holds(1==1)
// CHECK: omp assume holds(1 == 1)
{
#pragma omp assume absent(teams)
// CHECK: omp assume absent(teams)
{
#pragma omp assume no_openmp_routines
// CHECK: omp assume no_openmp_routines
{
bar();
}
}
}
}
}
}

View File

@ -0,0 +1,59 @@
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -ast-print %s | FileCheck %s
// expected-no-diagnostics
extern void bar();
template<int N>
void foo()
{
#pragma omp assume no_openmp_routines
// CHECK: omp assume no_openmp_routines
{
#pragma omp assume no_parallelism
// CHECK: omp assume no_parallelism
{}
}
#pragma omp target
// CHECK: omp target
{
#pragma omp assume holds(1==N)
// CHECK: omp assume holds(1 == N)
{}
}
#pragma omp assume no_parallelism
// CHECK: omp assume no_parallelism
{
#pragma omp target
// CHECK: omp target
{}
}
#pragma omp assume absent(parallel)
// CHECK: omp assume absent(parallel)
{
#pragma omp assume contains(target, loop)
// CHECK: omp assume contains(target, loop)
{
#pragma omp assume holds(1==N)
// CHECK: omp assume holds(1 == N)
{
#pragma omp assume absent(teams)
// CHECK: omp assume absent(teams)
{
#pragma omp assume no_openmp_routines
// CHECK: omp assume no_openmp_routines
{
bar();
}
}
}
}
}
}
int main() {
foo<5>();
return 0;
}

View File

@ -0,0 +1,31 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: cd %t
// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/AssumeMod.cppm -emit-module-interface -o %t/AssumeMod.pcm
// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/UseAssumeMod.cpp -fmodule-file=AssumeMod=%t/AssumeMod.pcm -ast-dump-all | FileCheck %t/AssumeMod.cppm
// expected-no-diagnostics
//--- AssumeMod.cppm
module;
export module AssumeMod;
export int foo(int y) {
int x = -1;
#pragma omp assume holds(y == 5)
// CHECK: OMPAssumeDirective 0x{{.*}} <line:5:1, col:33>
// CHECK-NEXT: OMPHoldsClause 0x{{.*}} <col:20, col:32>
{
x = y;
}
return x;
}
//--- UseAssumeMod.cpp
import AssumeMod;
extern "C" int printf(const char* fmt, ...);
int main() {
printf ("foo(5)=%d\n", foo (5));
return 0;
}

View File

@ -0,0 +1,72 @@
// RUN: rm -rf %t
// RUN: split-file %s %t
// RUN: cd %t
// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/AssumeMod.cppm -emit-module-interface -o %t/AssumeMod.pcm
// RUN: %clang_cc1 -std=c++20 -fopenmp -triple x86_64-unknown-linux-gnu %t/UseAssumeMod.cpp -fmodule-file=AssumeMod=%t/AssumeMod.pcm -ast-dump-all | FileCheck %t/AssumeMod.cppm
// expected-no-diagnostics
//--- AssumeMod.cppm
module;
export module AssumeMod;
export template<int N> int foo(int y) {
int x = -1;
#pragma omp assume holds(y == N)
{
x = y;
}
return x;
}
export template<bool B> void bar(int *z) {
if constexpr (B) {
#pragma omp assume no_openmp
{
z[0]++;
}
} else {
#pragma omp assume contains(target, parallel) absent(loop)
{
z[1] += 2;
}
}
}
// CHECK: FunctionTemplateDecl 0x{{.*}}
// CHECK: OMPAssumeDirective 0x{{.*}} <line:5:1, col:33>
// CHECK-NEXT: OMPHoldsClause 0x{{.*}} <col:20, col:32>
// CHECK: FunctionDecl 0x{{.*}} implicit_instantiation
// CHECK: OMPAssumeDirective 0x{{.*}} <line:5:1, col:33>
// CHECK-NEXT: OMPHoldsClause 0x{{.*}} <col:20, col:32>
// CHECK: FunctionTemplateDecl 0x{{.*}}
// CHECK: OMPAssumeDirective 0x{{.*}} <line:14:1, col:29>
// CHECK-NEXT: OMPNo_openmpClause 0x{{.*}} <col:20, col:29>
// CHECK: OMPAssumeDirective 0x{{.*}} <line:19:1, col:59>
// CHECK-NEXT: OMPContainsClause 0x{{.*}} <col:20, col:45>
// CHECK-NEXT: OMPAbsentClause 0x{{.*}} <col:47, col:58>
// CHECK: FunctionDecl 0x{{.*}} implicit_instantiation
// CHECK: OMPAssumeDirective 0x{{.*}} <line:14:1, col:29>
// CHECK-NEXT: OMPNo_openmpClause 0x{{.*}} <col:20, col:29>
// CHECK: FunctionDecl 0x{{.*}} implicit_instantiation
// CHECK: OMPAssumeDirective 0x{{.*}} <line:19:1, col:59>
// CHECK-NEXT: OMPContainsClause 0x{{.*}} <col:20, col:45>
// CHECK-NEXT: OMPAbsentClause 0x{{.*}} <col:47, col:58>
//--- UseAssumeMod.cpp
import AssumeMod;
extern "C" int printf(const char* fmt, ...);
int main() {
printf ("foo(5)=%d\n", foo<5> (5));
int arr[2] = { 0, 0 };
bar<true>(arr);
bar<false>(arr);
printf ("arr[0]=%d, arr[1]=%d\n", arr[0], arr[1]);
return 0;
}

View File

@ -0,0 +1,42 @@
// RUN: %clang_cc1 -verify -fopenmp -ast-print %s | FileCheck %s
// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -emit-pch -o %t %s
// RUN: %clang_cc1 -fopenmp -std=c++11 -include-pch %t -verify %s -ast-print | FileCheck %s
// expected-no-diagnostics
#ifndef HEADER
#define HEADER
extern int qux(int);
template<typename T>
int foo(T arg)
{
#pragma omp assume no_openmp_routines
{
auto fn = [](int x) { return qux(x); };
// CHECK: auto fn = [](int x) {
return fn(5);
}
}
template<typename T>
class C {
T m;
public:
T bar(T a);
};
// We're really just checking this parses. All the assumptions are thrown
// away immediately for now.
template<typename T>
T C<T>::bar(T a)
{
#pragma omp assume holds(sizeof(T) == 8) absent(parallel)
{
return (T)qux((int)a);
// CHECK: return (T)qux((int)a);
}
}
#endif

View File

@ -2200,6 +2200,7 @@ public:
void VisitOMPTaskyieldDirective(const OMPTaskyieldDirective *D);
void VisitOMPBarrierDirective(const OMPBarrierDirective *D);
void VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D);
void VisitOMPAssumeDirective(const OMPAssumeDirective *D);
void VisitOMPErrorDirective(const OMPErrorDirective *D);
void VisitOMPTaskgroupDirective(const OMPTaskgroupDirective *D);
void
@ -2425,6 +2426,20 @@ void OMPClauseEnqueue::VisitOMPCompareClause(const OMPCompareClause *) {}
void OMPClauseEnqueue::VisitOMPFailClause(const OMPFailClause *) {}
void OMPClauseEnqueue::VisitOMPAbsentClause(const OMPAbsentClause *) {}
void OMPClauseEnqueue::VisitOMPHoldsClause(const OMPHoldsClause *) {}
void OMPClauseEnqueue::VisitOMPContainsClause(const OMPContainsClause *) {}
void OMPClauseEnqueue::VisitOMPNoOpenMPClause(const OMPNoOpenMPClause *) {}
void OMPClauseEnqueue::VisitOMPNoOpenMPRoutinesClause(
const OMPNoOpenMPRoutinesClause *) {}
void OMPClauseEnqueue::VisitOMPNoParallelismClause(
const OMPNoParallelismClause *) {}
void OMPClauseEnqueue::VisitOMPSeqCstClause(const OMPSeqCstClause *) {}
void OMPClauseEnqueue::VisitOMPAcqRelClause(const OMPAcqRelClause *) {}
@ -3310,6 +3325,10 @@ void EnqueueVisitor::VisitOMPTaskwaitDirective(const OMPTaskwaitDirective *D) {
VisitOMPExecutableDirective(D);
}
void EnqueueVisitor::VisitOMPAssumeDirective(const OMPAssumeDirective *D) {
VisitOMPAssumeDirective(D);
}
void EnqueueVisitor::VisitOMPErrorDirective(const OMPErrorDirective *D) {
VisitOMPExecutableDirective(D);
}
@ -6146,6 +6165,8 @@ CXString clang_getCursorKindSpelling(enum CXCursorKind Kind) {
return cxstring::createRef("OMPBarrierDirective");
case CXCursor_OMPTaskwaitDirective:
return cxstring::createRef("OMPTaskwaitDirective");
case CXCursor_OMPAssumeDirective:
return cxstring::createRef("OMPAssumeDirective");
case CXCursor_OMPErrorDirective:
return cxstring::createRef("OMPErrorDirective");
case CXCursor_OMPTaskgroupDirective:

View File

@ -32,6 +32,9 @@ def OpenMP : DirectiveLanguage {
// Sorted alphabetically wrt clause spelling.
//===----------------------------------------------------------------------===//
def OMPC_Absent : Clause<"absent"> {
let clangClass = "OMPAbsentClause";
}
def OMPC_Acquire : Clause<"acquire"> {
let clangClass = "OMPAcquireClause";
}
@ -87,6 +90,9 @@ def OMPC_CancellationConstructType : Clause<"cancellation_construct_type"> {
OMP_CANCELLATION_CONSTRUCT_None
];
}
def OMPC_Contains : Clause<"contains"> {
let clangClass = "OMPContainsClause";
}
def OMPC_Capture : Clause<"capture"> {
let clangClass = "OMPCaptureClause";
}
@ -196,6 +202,9 @@ def OMPC_Hint : Clause<"hint"> {
let clangClass = "OMPHintClause";
let flangClass = "ConstantExpr";
}
def OMPC_Holds : Clause<"holds"> {
let clangClass = "OMPHoldsClause";
}
def OMPC_If : Clause<"if"> {
let clangClass = "OMPIfClause";
let flangClass = "OmpIfClause";
@ -260,6 +269,15 @@ def OMPC_Mergeable : Clause<"mergeable"> {
def OMPC_Message : Clause<"message"> {
let clangClass = "OMPMessageClause";
}
def OMPC_NoOpenMP : Clause<"no_openmp"> {
let clangClass = "OMPNoOpenMPClause";
}
def OMPC_NoOpenMPRoutines : Clause<"no_openmp_routines"> {
let clangClass = "OMPNoOpenMPRoutinesClause";
}
def OMPC_NoParallelism : Clause<"no_parallelism"> {
let clangClass = "OMPNoParallelismClause";
}
def OMPC_Nocontext : Clause<"nocontext"> {
let clangClass = "OMPNocontextClause";
let flangClass = "ScalarLogicalExpr";
@ -510,6 +528,18 @@ def OMP_EndAssumes : Directive<"end assumes"> {
let association = AS_Delimited;
let category = OMP_Assumes.category;
}
def OMP_Assume : Directive<"assume"> {
let association = AS_Block;
let category = CA_Informational;
let allowedOnceClauses = [
VersionedClause<OMPC_Absent, 51>,
VersionedClause<OMPC_Contains, 51>,
VersionedClause<OMPC_Holds, 51>,
VersionedClause<OMPC_NoOpenMP, 51>,
VersionedClause<OMPC_NoOpenMPRoutines, 51>,
VersionedClause<OMPC_NoParallelism, 51>,
];
}
def OMP_Atomic : Directive<"atomic"> {
let allowedClauses = [
VersionedClause<OMPC_Capture>,