Skip to content

Commit

Permalink
[OpenMP] OpenMP 5.1 "assume" directive parsing support (#92731)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
jtb20 authored Aug 5, 2024
1 parent 8370ba4 commit a42e515
Show file tree
Hide file tree
Showing 36 changed files with 1,315 additions and 2 deletions.
2 changes: 1 addition & 1 deletion clang/docs/OpenMPSupport.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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 |
+------------------------------+--------------------------------------------------------------+--------------------------+-----------------------------------------------------------------------+
Expand Down
1 change: 1 addition & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ Python Binding Changes

OpenMP Support
--------------
- Added support for 'omp assume' directive.

Improvements
^^^^^^^^^^^^
Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -2154,6 +2154,10 @@ enum CXCursorKind {
*/
CXCursor_OMPInterchangeDirective = 308,

/** OpenMP assume directive.
*/
CXCursor_OMPAssumeDirective = 309,

/** OpenACC Compute Construct.
*/
CXCursor_OpenACCComputeConstruct = 320,
Expand Down
238 changes: 238 additions & 0 deletions clang/include/clang/AST/OpenMPClause.h
Original file line number Diff line number Diff line change
Expand Up @@ -342,6 +342,66 @@ template <class T> class OMPVarListClause : public OMPClause {
}
};

/// 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.
///
Expand Down Expand Up @@ -2013,6 +2073,184 @@ class OMPMergeableClause : public OMPClause {
}
};

/// 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
Expand Down
35 changes: 35 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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)); })

Expand Down Expand Up @@ -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;
Expand Down
30 changes: 30 additions & 0 deletions clang/include/clang/AST/StmtOpenMP.h
Original file line number Diff line number Diff line change
Expand Up @@ -6468,6 +6468,36 @@ class OMPErrorDirective final : public OMPExecutableDirective {
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
5 changes: 5 additions & 0 deletions clang/include/clang/Basic/OpenMPKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Loading

0 comments on commit a42e515

Please sign in to comment.