[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:
parent
8370ba4d15
commit
a42e515e3a
@ -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 |
|
||||
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
|
||||
|
||||
@ -323,6 +323,7 @@ Python Binding Changes
|
||||
|
||||
OpenMP Support
|
||||
--------------
|
||||
- Added support for 'omp assume' directive.
|
||||
|
||||
Improvements
|
||||
^^^^^^^^^^^^
|
||||
|
||||
@ -2154,6 +2154,10 @@ enum CXCursorKind {
|
||||
*/
|
||||
CXCursor_OMPInterchangeDirective = 308,
|
||||
|
||||
/** OpenMP assume directive.
|
||||
*/
|
||||
CXCursor_OMPAssumeDirective = 309,
|
||||
|
||||
/** OpenACC Compute Construct.
|
||||
*/
|
||||
CXCursor_OpenACCComputeConstruct = 320,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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";
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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 *) {}
|
||||
|
||||
@ -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]);
|
||||
|
||||
@ -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 *) {}
|
||||
|
||||
@ -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());
|
||||
|
||||
31
clang/test/OpenMP/assume_lambda.cpp
Normal file
31
clang/test/OpenMP/assume_lambda.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
30
clang/test/OpenMP/assume_messages.c
Normal file
30
clang/test/OpenMP/assume_messages.c
Normal 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}}
|
||||
{}
|
||||
}
|
||||
30
clang/test/OpenMP/assume_messages_attr.c
Normal file
30
clang/test/OpenMP/assume_messages_attr.c
Normal 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}}
|
||||
{}
|
||||
}
|
||||
53
clang/test/OpenMP/assume_nesting.cpp
Normal file
53
clang/test/OpenMP/assume_nesting.cpp
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
59
clang/test/OpenMP/assume_nesting_tmpl.cpp
Normal file
59
clang/test/OpenMP/assume_nesting_tmpl.cpp
Normal 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;
|
||||
}
|
||||
31
clang/test/OpenMP/assume_serialize_deserialize.cpp
Normal file
31
clang/test/OpenMP/assume_serialize_deserialize.cpp
Normal 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;
|
||||
}
|
||||
72
clang/test/OpenMP/assume_serialize_deserialize_tmpl.cpp
Normal file
72
clang/test/OpenMP/assume_serialize_deserialize_tmpl.cpp
Normal 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;
|
||||
}
|
||||
42
clang/test/OpenMP/assume_template.cpp
Normal file
42
clang/test/OpenMP/assume_template.cpp
Normal 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
|
||||
@ -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:
|
||||
|
||||
@ -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>,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user