[Clang][OpenMP] Add permutation clause by Meinersbur · Pull Request #92030 · llvm/llvm-project (original) (raw)
@llvm/pr-subscribers-flang-parser
@llvm/pr-subscribers-flang-openmp
@llvm/pr-subscribers-flang-fir-hlfir
@llvm/pr-subscribers-flang-semantics
@llvm/pr-subscribers-clang
Author: Michael Kruse (Meinersbur)
Changes
Add the reverse and interchange directives which will be introduced in the upcoming OpenMP 6.0 specification. A preview has been published in Technical Report 12.
The boilerplate code of the new directives largely overlaps. Having both in a single PR should be easier to review and avoids confects when inevitably one is committed before the other.
Patch is 561.80 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/92030.diff
47 Files Affected:
- (modified) clang/include/clang-c/Index.h (+8)
- (modified) clang/include/clang/AST/OpenMPClause.h (+100)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+14)
- (modified) clang/include/clang/AST/StmtOpenMP.h (+144-2)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+4)
- (modified) clang/include/clang/Basic/StmtNodes.td (+2)
- (modified) clang/include/clang/Parse/Parser.h (+3)
- (modified) clang/include/clang/Sema/SemaOpenMP.h (+16)
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+2)
- (modified) clang/lib/AST/OpenMPClause.cpp (+31)
- (modified) clang/lib/AST/StmtOpenMP.cpp (+39)
- (modified) clang/lib/AST/StmtPrinter.cpp (+10)
- (modified) clang/lib/AST/StmtProfile.cpp (+16)
- (modified) clang/lib/Basic/OpenMPKinds.cpp (+6-1)
- (modified) clang/lib/CodeGen/CGStmt.cpp (+6)
- (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+18)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+2)
- (modified) clang/lib/Parse/ParseOpenMP.cpp (+24)
- (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+2)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+435)
- (modified) clang/lib/Sema/TreeTransform.h (+57)
- (modified) clang/lib/Serialization/ASTReader.cpp (+11)
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+23)
- (modified) clang/lib/Serialization/ASTWriter.cpp (+7)
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+10)
- (added) clang/test/OpenMP/interchange_ast_print.cpp (+233)
- (added) clang/test/OpenMP/interchange_codegen.cpp (+5323)
- (added) clang/test/OpenMP/interchange_messages.cpp (+231)
- (added) clang/test/OpenMP/reverse_ast_print.cpp (+159)
- (added) clang/test/OpenMP/reverse_codegen.cpp (+1554)
- (added) clang/test/OpenMP/reverse_messages.cpp (+40)
- (modified) clang/tools/libclang/CIndex.cpp (+21)
- (modified) clang/tools/libclang/CXCursor.cpp (+6)
- (modified) flang/lib/Lower/OpenMP/Clauses.cpp (+6)
- (modified) flang/lib/Semantics/check-omp-structure.cpp (+1)
- (modified) llvm/include/llvm/Frontend/OpenMP/ClauseT.h (+11-3)
- (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+15)
- (added) openmp/runtime/test/transform/interchange/foreach.cpp (+216)
- (added) openmp/runtime/test/transform/interchange/intfor.c (+38)
- (added) openmp/runtime/test/transform/interchange/iterfor.cpp (+222)
- (added) openmp/runtime/test/transform/interchange/parallel-wsloop-collapse-foreach.cpp (+340)
- (added) openmp/runtime/test/transform/interchange/parallel-wsloop-collapse-intfor.cpp (+106)
- (added) openmp/runtime/test/transform/reverse/foreach.cpp (+162)
- (added) openmp/runtime/test/transform/reverse/intfor.c (+25)
- (added) openmp/runtime/test/transform/reverse/iterfor.cpp (+164)
- (added) openmp/runtime/test/transform/reverse/parallel-wsloop-collapse-foreach.cpp (+285)
- (added) openmp/runtime/test/transform/reverse/parallel-wsloop-collapse-intfor.cpp (+51)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index 365b607c74117..a79aafbf20222 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2146,6 +2146,14 @@ enum CXCursorKind { */ CXCursor_OMPScopeDirective = 306,
- /** OpenMP reverse directive.
- */
- CXCursor_OMPReverseDirective = 307,
- /** OpenMP interchange directive.
- */
- CXCursor_OMPInterchangeDirective = 308,
- /** OpenACC Compute Construct. */ CXCursor_OpenACCComputeConstruct = 320, diff --git a/clang/include/clang/AST/OpenMPClause.h b/clang/include/clang/AST/OpenMPClause.h index 325a1baa44614..c381bbde9eb11 100644 --- a/clang/include/clang/AST/OpenMPClause.h +++ b/clang/include/clang/AST/OpenMPClause.h @@ -870,6 +870,106 @@ class OMPSizesClause final } };
+/// This class represents the 'permutation' clause in the +/// '#pragma omp interchange' directive. +/// +/// \code{c} +/// #pragma omp interchange permutation(2,1) +/// for (int i = 0; i < 64; ++i) +/// for (int j = 0; j < 64; ++j) +/// \endcode +class OMPPermutationClause final
- : public OMPClause,
private llvm::TrailingObjects<OMPSizesClause, Expr *> {- friend class OMPClauseReader;
- friend class llvm::TrailingObjects<OMPSizesClause, Expr *>;
- /// Location of '('.
- SourceLocation LParenLoc;
- /// Number of arguments in the clause, and hence also the number of loops to
- /// be permuted.
- unsigned NumLoops;
- /// Build an empty clause.
- explicit OMPPermutationClause(int NumLoops)
: OMPClause(llvm::omp::OMPC_permutation, SourceLocation(),SourceLocation()),NumLoops(NumLoops) {}- +public:
- /// Build a 'permutation' clause AST node.
- ///
- /// \param C Context of the AST.
- /// \param StartLoc Location of the 'permutation' identifier.
- /// \param LParenLoc Location of '('.
- /// \param EndLoc Location of ')'.
- /// \param Args Content of the clause.
- static OMPPermutationClause *
- Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation EndLoc, ArrayRef<Expr *> Args);- /// Build an empty 'permutation' AST node for deserialization.
- ///
- /// \param C Context of the AST.
- /// \param NumLoops Number of arguments in the clause.
- static OMPPermutationClause *CreateEmpty(const ASTContext &C,
unsigned NumLoops);- /// Sets the location of '('.
- void setLParenLoc(SourceLocation Loc) { LParenLoc = Loc; }
- /// Returns the location of '('.
- SourceLocation getLParenLoc() const { return LParenLoc; }
- /// Returns the number of list items.
- unsigned getNumLoops() const { return NumLoops; }
- /// Returns the permutation index expressions.
- ///@{
- MutableArrayRef<Expr *> getArgsRefs() {
- return MutableArrayRef<Expr *>(static_cast<OMPPermutationClause *>(this)
->template getTrailingObjects<Expr *>(),NumLoops);- }
- ArrayRef<Expr *> getArgsRefs() const {
- return ArrayRef<Expr *>(static_cast<const OMPPermutationClause *>(this)
->template getTrailingObjects<Expr *>(),NumLoops);- }
- ///@}
- /// Sets the permutation index expressions.
- void setArgRefs(ArrayRef<Expr *> VL) {
- assert(VL.size() == NumLoops);
- std::copy(VL.begin(), VL.end(),
static_cast<OMPPermutationClause *>(this)->template getTrailingObjects<Expr *>());- }
- child_range children() {
- MutableArrayRef<Expr *> Args = getArgsRefs();
- return child_range(reinterpret_cast<Stmt **>(Args.begin()),
reinterpret_cast<Stmt **>(Args.end()));- }
- const_child_range children() const {
- ArrayRef<Expr *> Args = getArgsRefs();
- return const_child_range(reinterpret_cast<Stmt *const *>(Args.begin()),
reinterpret_cast<Stmt *const *>(Args.end()));- }
- 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());
- }
- static bool classof(const OMPClause *T) {
- return T->getClauseKind() == llvm::omp::OMPC_permutation;
- } +};
- /// Representation of the 'full' clause of the '#pragma omp unroll' directive. /// /// \code diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index f9b145b4e86a5..7596b78c94f1c 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3004,6 +3004,12 @@ DEF_TRAVERSE_STMT(OMPTileDirective, DEF_TRAVERSE_STMT(OMPUnrollDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPReverseDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })- +DEF_TRAVERSE_STMT(OMPInterchangeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })- DEF_TRAVERSE_STMT(OMPForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
@@ -3302,6 +3308,14 @@ bool RecursiveASTVisitor::VisitOMPSizesClause(OMPSizesClause *C) { return true; }
+template +bool RecursiveASTVisitor::VisitOMPPermutationClause(
OMPPermutationClause *C) {
for (Expr *E : C->getArgsRefs())
TRY_TO(TraverseStmt(E));
return true; +}
template bool RecursiveASTVisitor::VisitOMPFullClause(OMPFullClause *C) { return true; diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index f735fa5643aec..df6c485117c80 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -1007,8 +1007,9 @@ class OMPLoopTransformationDirective : public OMPLoopBasedDirective { Stmt *getPreInits() const;
static bool classof(const Stmt *T) {
- return T->getStmtClass() == OMPTileDirectiveClass ||
T->getStmtClass() == OMPUnrollDirectiveClass;
- Stmt::StmtClass C = T->getStmtClass();
- return C == OMPTileDirectiveClass || C == OMPUnrollDirectiveClass ||
} };C == OMPReverseDirectiveClass || C == OMPInterchangeDirectiveClass;
@@ -5638,6 +5639,147 @@ class OMPTileDirective final : public OMPLoopTransformationDirective { } };
+/// Represents the '#pragma omp reverse' loop transformation directive. +/// +/// \code +/// #pragma omp reverse +/// for (int i = 0; i < n; ++i) +/// ... +/// \endcode +class OMPReverseDirective final : public OMPLoopTransformationDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
/// Offsets of child members.
enum {
PreInitsOffset = 0,
TransformedStmtOffset,
};
explicit OMPReverseDirective(SourceLocation StartLoc, SourceLocation EndLoc)
: OMPLoopTransformationDirective(OMPReverseDirectiveClass,llvm::omp::OMPD_reverse, StartLoc,EndLoc, 1) {}void setPreInits(Stmt *PreInits) {
Data->getChildren()[PreInitsOffset] = PreInits;
}
void setTransformedStmt(Stmt *S) {
Data->getChildren()[TransformedStmtOffset] = S;
}
+public:
/// Create a new AST node representation for '#pragma omp reverse'.
///
/// \param C Context of the AST.
/// \param StartLoc Location of the introducer (e.g. the 'omp' token).
/// \param EndLoc Location of the directive's end (e.g. the tok::eod).
/// \param Clauses The directive's clauses.
/// \param AssociatedStmt The outermost associated loop.
/// \param TransformedStmt The loop nest after tiling, or nullptr in
/// dependent contexts.
/// \param PreInits Helper preinits statements for the loop nest.
static OMPReverseDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,Stmt *TransformedStmt, Stmt *PreInits);/// Build an empty '#pragma omp reverse' AST node for deserialization.
///
/// \param C Context of the AST.
/// \param NumClauses Number of clauses to allocate.
static OMPReverseDirective *CreateEmpty(const ASTContext &C,
unsigned NumClauses);/// Gets/sets the associated loops after the transformation, i.e. after
/// de-sugaring.
Stmt *getTransformedStmt() const {
return Data->getChildren()[TransformedStmtOffset];
}
/// Return preinits statement.
Stmt *getPreInits() const { return Data->getChildren()[PreInitsOffset]; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPReverseDirectiveClass;
} +};
+/// Represents the '#pragma omp interchange' loop transformation directive. +/// +/// \code{c} +/// #pragma omp interchange +/// for (int i = 0; i < m; ++i) +/// for (int j = 0; j < n; ++j) +/// .. +/// \endcode +class OMPInterchangeDirective final : public OMPLoopTransformationDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
/// Offsets of child members.
enum {
PreInitsOffset = 0,
TransformedStmtOffset,
};
explicit OMPInterchangeDirective(SourceLocation StartLoc,
SourceLocation EndLoc, unsigned NumLoops): OMPLoopTransformationDirective(OMPInterchangeDirectiveClass,llvm::omp::OMPD_interchange, StartLoc,EndLoc, NumLoops) {setNumGeneratedLoops(3 * NumLoops);
}
void setPreInits(Stmt *PreInits) {
Data->getChildren()[PreInitsOffset] = PreInits;
}
void setTransformedStmt(Stmt *S) {
Data->getChildren()[TransformedStmtOffset] = S;
}
+public:
/// Create a new AST node representation for '#pragma omp interchange'.
///
/// \param C Context of the AST.
/// \param StartLoc Location of the introducer (e.g. the 'omp' token).
/// \param EndLoc Location of the directive's end (e.g. the tok::eod).
/// \param Clauses The directive's clauses.
/// \param NumLoops Number of affected loops
/// (number of items in the 'permutation' clause if present).
/// \param AssociatedStmt The outermost associated loop.
/// \param TransformedStmt The loop nest after tiling, or nullptr in
/// dependent contexts.
/// \param PreInits Helper preinits statements for the loop nest.
static OMPInterchangeDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, unsigned NumLoops, Stmt *AssociatedStmt,Stmt *TransformedStmt, Stmt *PreInits);/// Build an empty '#pragma omp interchange' AST node for deserialization.
///
/// \param C Context of the AST.
/// \param NumClauses Number of clauses to allocate.
/// \param NumLoops Number of associated loops to allocate.
static OMPInterchangeDirective *
CreateEmpty(const ASTContext &C, unsigned NumClauses, unsigned NumLoops);
/// Gets the associated loops after the transformation. This is the de-sugared
/// replacement or nullptr in dependent contexts.
Stmt *getTransformedStmt() const {
return Data->getChildren()[TransformedStmtOffset];
}
/// Return preinits statement.
Stmt *getPreInits() const { return Data->getChildren()[PreInitsOffset]; }
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPInterchangeDirectiveClass;
} +};
/// This represents the '#pragma omp unroll' loop transformation directive. /// /// \code diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 9e82130c93609..690912060f723 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -11494,6 +11494,10 @@ def err_omp_dispatch_statement_call " to a target function or an assignment to one">; def err_omp_unroll_full_variable_trip_count : Error< "loop to be fully unrolled must have a constant trip count">; +def err_omp_interchange_permutation_value_range : Error<
"permutation index must be at least 1 and at most %0">; +def err_omp_interchange_permutation_value_repeated : Error<
"index %0 must appear exactly once in the permutation clause">; def note_omp_directive_here : Note<"'%0' directive found here">; def err_omp_instantiation_not_supported : Error<"instantiation of '%0' not supported yet">; diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index 305f19daa4a92..b445ea225eac5 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -229,6 +229,8 @@ def OMPSimdDirective : StmtNode; def OMPLoopTransformationDirective : StmtNode<OMPLoopBasedDirective, 1>; def OMPTileDirective : StmtNode; def OMPUnrollDirective : StmtNode; +def OMPReverseDirective : StmtNode; +def OMPInterchangeDirective : StmtNode; def OMPForDirective : StmtNode; def OMPForSimdDirective : StmtNode; def OMPSectionsDirective : StmtNode; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 61589fb7766f4..aea53673721bd 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -3537,6 +3537,9 @@ class Parser : public CodeCompletionHandler { /// Parses the 'sizes' clause of a '#pragma omp tile' directive. OMPClause *ParseOpenMPSizesClause();
/// Parses the 'permutation' clause of a '#pragma omp interchange' directive.
OMPClause *ParseOpenMPPermutationClause();
/// Parses clause without any additional arguments. /// /// \param Kind Kind of current clause. diff --git a/clang/include/clang/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index 51981e1c9a8b9..fe9d702b7af03 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -422,6 +422,17 @@ class SemaOpenMP : public SemaBase { StmtResult ActOnOpenMPUnrollDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc);
/// Called on well-formed '#pragma omp reverse' after parsing of its clauses
/// and the associated statement.
StmtResult ActOnOpenMPReverseDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,SourceLocation EndLoc);/// Called on well-formed '#pragma omp interchange' after parsing of its
/// clauses and the associated statement.
StmtResult ActOnOpenMPInterchangeDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,SourceLocation StartLoc,SourceLocation EndLoc);/// Called on well-formed '#pragma omp for' after parsing /// of the associated statement. StmtResult @@ -859,6 +870,11 @@ class SemaOpenMP : public SemaBase { SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc);
/// Called on well-form 'permutation' clause after parsing its arguments.
OMPClause *ActOnOpenMPPermutationClause(ArrayRef<Expr *> PermExprs,
SourceLocation StartLoc,SourceLocation LParenLoc,SourceLocation EndLoc);/// Called on well-form 'full' clauses. OMPClause *ActOnOpenMPFullClause(SourceLocation StartLoc, SourceLocation EndLoc);
diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index d3538e43d3d78..f488d1eca35c2 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1856,6 +1856,8 @@ enum StmtCode { STMT_OMP_SIMD_DIRECTIVE, STMT_OMP_TILE_DIRECTIVE, STMT_OMP_UNROLL_DIRECTIVE,
- STMT_OMP_REVERSE_DIRECTIVE,
- STMT_OMP_INTERCHANGE_DIRECTIVE, STMT_OMP_FOR_DIRECTIVE, STMT_OMP_FOR_SIMD_DIRECTIVE, STMT_OMP_SECTIONS_DIRECTIVE, diff --git a/clang/lib/AST/OpenMPClause.cpp b/clang/lib/AST/OpenMPClause.cpp index 042a5df5906ca..c94310769ed9e 100644 --- a/clang/lib/AST/OpenMPClause.cpp +++ b/clang/lib/AST/OpenMPClause.cpp @@ -971,6 +971,25 @@ OMPSizesClause *OMPSizesClause::CreateEmpty(const ASTContext &C, return new (Mem) OMPSizesClause(NumSizes); }
+OMPPermutationClause *OMPPermutationClause::Create(const ASTContext &C,
SourceLocation StartLoc,SourceLocation LParenLoc,SourceLocation EndLoc,ArrayRef<Expr *> Args) {- OMPPermutationClause *Clause = CreateEmpty(C, Args.size());
- Clause->setLocStart(StartLoc);
- Clause->setLParenLoc(LParenLoc);
- Clause->setLocEnd(EndLoc);
- Clause->setArgRefs(Args);
- return Clause; +}
- +OMPPermutationClause *OMPPermutationClause::CreateEmpty(const ASTContext &C,
unsigned NumLoops) {- void *Mem = C.Allocate(totalSizeToAlloc<Expr *>(NumLoops));
- return new (Mem) OMPPermutationClause(NumLoops); +}
- OMPFullClause *OMPFullClause::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc) {
@@ -1774,6 +1793,18 @@ void OMPClausePrinter::VisitOMPSizesClause(OMPSizesClause *Node) { OS << ")"; }
+void OMPClausePrinter::VisitOMPPermutationClause(OMPPermutationClause *Node) {
OS << "permutation(";
bool First = true;
for (Expr *Size : Node->getArgsRefs()) {
if (!First)
OS << ", ";Size->printPretty(OS, nullptr, Policy, 0);
First = false;
}
OS << ")"; +}
void OMPClausePrinter::VisitOMPFullClause(OMPFullClause *Node) { OS << "full"; }
void OMPClausePrinter::VisitOMPPartialClause(OMPPartialClause *Node) {
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index d8519b2071e6d..8a4a736263920 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -449,6 +449,45 @@ OMPUnrollDirective *OMPUnrollDirective::CreateEmpty(const ASTContext &C, SourceLocation(), SourceLocation()); }
+OMPReverseDirective * +OMPReverseDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc,ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,Stmt *TransformedStmt, Stmt *PreInits) {- OMPReverseDirective *Dir = createDirective(
C, Clauses, AssociatedStmt, TransformedStmtOffset + 1, StartLoc, EndLoc);- Dir->setTransformedStmt(TransformedStmt);
- Dir->setPreInits(PreInits);
- return Dir; +}
- +OMPReverseDirective *OMPReverseDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses) {- return createEmptyDirective(
C, NumClauses, /*HasAssociatedStmt=*/true, TransformedStmtOffset + 1,SourceLocation(), SourceLocation());
+} + +OMPInterchangeDirective *OMPInterchangeDirective::Create(
- const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
- ArrayRef<OMPClause *> Clauses, unsigned NumLoops, Stmt *AssociatedStmt,
- Stmt *TransformedStmt, Stmt *PreInits) {
- OMPInterchangeDirective *Dir = createDirective(
C, Clauses, AssociatedStmt, TransformedStmtOffset + 1, StartLo...
[truncated]