[Clang][OpenMP] Add interchange directive by Meinersbur · Pull Request #93022 · llvm/llvm-project (original) (raw)
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
[ Show hidden characters]({{ revealButtonHref }})
Add the interchange directive which will be introduced in the upcoming OpenMP 6.0 specification. A preview has been published in Technical Report 12.
… users/meinersbur/clang_openmp_reverse
@llvm/pr-subscribers-clang-codegen
@llvm/pr-subscribers-flang-openmp
Author: Michael Kruse (Meinersbur)
Changes
Add the interchange directive which will be introduced in the upcoming OpenMP 6.0 specification. A preview has been published in Technical Report 12.
Patch is 185.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93022.diff
30 Files Affected:
- (modified) clang/include/clang-c/Index.h (+4)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+3)
- (modified) clang/include/clang/AST/StmtOpenMP.h (+75-1)
- (modified) clang/include/clang/Basic/StmtNodes.td (+1)
- (modified) clang/include/clang/Sema/SemaOpenMP.h (+6)
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+1)
- (modified) clang/lib/AST/StmtOpenMP.cpp (+20)
- (modified) clang/lib/AST/StmtPrinter.cpp (+5)
- (modified) clang/lib/AST/StmtProfile.cpp (+5)
- (modified) clang/lib/Basic/OpenMPKinds.cpp (+3-1)
- (modified) clang/lib/CodeGen/CGStmt.cpp (+3)
- (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+10)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
- (modified) clang/lib/Parse/ParseOpenMP.cpp (+2)
- (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+1)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+162)
- (modified) clang/lib/Sema/TreeTransform.h (+11)
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+11)
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+5)
- (added) clang/test/OpenMP/interchange_ast_print.cpp (+135)
- (added) clang/test/OpenMP/interchange_codegen.cpp (+1990)
- (added) clang/test/OpenMP/interchange_messages.cpp (+77)
- (modified) clang/tools/libclang/CIndex.cpp (+8)
- (modified) clang/tools/libclang/CXCursor.cpp (+3)
- (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+3)
- (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)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index c7d63818ece23..a79aafbf20222 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2150,6 +2150,10 @@ enum CXCursorKind { */ CXCursor_OMPReverseDirective = 307,
- /** OpenMP interchange directive.
- */
- CXCursor_OMPInterchangeDirective = 308,
- /** OpenACC Compute Construct. */ CXCursor_OpenACCComputeConstruct = 320, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 06b29d59785f6..1bb167d7ddc3c 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3024,6 +3024,9 @@ DEF_TRAVERSE_STMT(OMPUnrollDirective, DEF_TRAVERSE_STMT(OMPReverseDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPInterchangeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })- DEF_TRAVERSE_STMT(OMPForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index fb7f413162fad..01c8b8e1a9f5e 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -1009,7 +1009,7 @@ class OMPLoopTransformationDirective : public OMPLoopBasedDirective { static bool classof(const Stmt *T) { Stmt::StmtClass C = T->getStmtClass(); return C == OMPTileDirectiveClass || C == OMPUnrollDirectiveClass ||
C == OMPReverseDirectiveClass;
} };C == OMPReverseDirectiveClass || C == OMPInterchangeDirectiveClass;
@@ -5777,6 +5777,80 @@ class OMPReverseDirective final : public OMPLoopTransformationDirective { } };
+/// 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 '#pragma omp scan' directive. /// /// \code diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index b2e2be5c998bb..b445ea225eac5 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -230,6 +230,7 @@ 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/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index ca91bffe24f6f..06376f173e8df 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -425,6 +425,12 @@ class SemaOpenMP : public SemaBase { /// Called on well-formed '#pragma omp reverse'. StmtResult ActOnOpenMPReverseDirective(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,
/// Called on well-formed '#pragma omp for' after parsing /// of the associated statement. StmtResult diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index dee0d073557cc..5fbdfd7a496fe 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1857,6 +1857,7 @@ enum StmtCode { STMT_OMP_TILE_DIRECTIVE, STMT_OMP_UNROLL_DIRECTIVE, STMT_OMP_REVERSE_DIRECTIVE,SourceLocation EndLoc);- STMT_OMP_INTERCHANGE_DIRECTIVE, STMT_OMP_FOR_DIRECTIVE, STMT_OMP_FOR_SIMD_DIRECTIVE, STMT_OMP_SECTIONS_DIRECTIVE, diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 83b8a08e9af73..24d8eb25c59ba 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -467,6 +467,26 @@ OMPReverseDirective *OMPReverseDirective::CreateEmpty(const ASTContext &C, 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, StartLoc, EndLoc,NumLoops);- Dir->setTransformedStmt(TransformedStmt);
- Dir->setPreInits(PreInits);
- return Dir; +}
- +OMPInterchangeDirective * +OMPInterchangeDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
unsigned NumLoops) {- return createEmptyDirective(
C, NumClauses, /*HasAssociatedStmt=*/true, TransformedStmtOffset + 1,SourceLocation(), SourceLocation(), NumLoops);
+} + OMPForSimdDirective * OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 64b481f680311..64bee75b205ae 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -768,6 +768,11 @@ void StmtPrinter::VisitOMPReverseDirective(OMPReverseDirective *Node) { PrintOMPExecutableDirective(Node); }
+void StmtPrinter::VisitOMPInterchangeDirective(OMPInterchangeDirective *Node) {
- Indent() << "#pragma omp interchange";
- PrintOMPExecutableDirective(Node); +}
- void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) { Indent() << "#pragma omp for"; PrintOMPExecutableDirective(Node); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 7445e5519b972..1ae99d43575a7 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -989,6 +989,11 @@ void StmtProfiler::VisitOMPReverseDirective(const OMPReverseDirective *S) { VisitOMPLoopTransformationDirective(S); }
+void StmtProfiler::VisitOMPInterchangeDirective(
const OMPInterchangeDirective *S) {
VisitOMPLoopTransformationDirective(S); +}
void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) { VisitOMPLoopDirective(S); } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 803808c38e2fe..ff5d5c8bdc981 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -684,7 +684,8 @@ bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) { }
bool clang::isOpenMPLoopTransformationDirective(OpenMPDirectiveKind DKind) {
- return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse;
- return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse ||
DKind == OMPD_interchange;
}
bool clang::isOpenMPCombinedParallelADirective(OpenMPDirectiveKind DKind) { @@ -809,6 +810,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: // loop transformations do not introduce captures. break; case OMPD_threadprivate: diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 93c2f8900dd12..ba7c52cc6ab7b 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -225,6 +225,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { case Stmt::OMPReverseDirectiveClass: EmitOMPReverseDirective(cast(*S)); break;
- case Stmt::OMPInterchangeDirectiveClass:
- EmitOMPInterchangeDirective(cast(*S));
- break;
case Stmt::OMPForDirectiveClass: EmitOMPForDirective(cast(*S)); break; diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index ad6c044aa483b..7a37e452fb559 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -189,6 +189,9 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { PreInits = Unroll->getPreInits(); } else if (const auto *Reverse = dyn_cast(&S)) { PreInits = Reverse->getPreInits();
- } else if (const auto *Interchange =
dyn_cast<OMPInterchangeDirective>(&S)) {
} else { llvm_unreachable("Unknown loop-based directive kind."); } @@ -2770,6 +2773,13 @@ void CodeGenFunction::EmitOMPReverseDirective(const OMPReverseDirective &S) { EmitStmt(S.getTransformedStmt()); }PreInits = Interchange->getPreInits();
+void CodeGenFunction::EmitOMPInterchangeDirective(
- const OMPInterchangeDirective &S) {
- // Emit the de-sugared statement.
- OMPTransformDirectiveScopeRAII InterchangeScope(*this, &S);
- EmitStmt(S.getTransformedStmt()); +}
- void CodeGenFunction::EmitOMPUnrollDirective(const OMPUnrollDirective &S) { bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder;
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index ac738e1e82886..c2a8e65ca2d0a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3808,6 +3808,7 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitOMPTileDirective(const OMPTileDirective &S); void EmitOMPUnrollDirective(const OMPUnrollDirective &S); void EmitOMPReverseDirective(const OMPReverseDirective &S);
- void EmitOMPInterchangeDirective(const OMPInterchangeDirective &S); void EmitOMPForDirective(const OMPForDirective &S); void EmitOMPForSimdDirective(const OMPForSimdDirective &S); void EmitOMPSectionsDirective(const OMPSectionsDirective &S); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 57fcf6ce520ac..0e3e604203c86 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2385,6 +2385,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: case OMPD_task: case OMPD_taskyield: case OMPD_barrier: @@ -2804,6 +2805,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: case OMPD_for: case OMPD_for_simd: case OMPD_sections: diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 4de7183cde281..5991f496d3a0f 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1487,6 +1487,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OMPTileDirectiveClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPReverseDirectiveClass:
- case Stmt::OMPInterchangeDirectiveClass: case Stmt::OMPSingleDirectiveClass: case Stmt::OMPTargetDataDirectiveClass: case Stmt::OMPTargetDirectiveClass: diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c2fd4de933ae4..ef141003b7d61 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -39,6 +39,7 @@
#include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" @@ -4335,6 +4336,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: break; case OMPD_loop: // TODO: 'loop' may require additional parameters depending on the binding. @@ -6552,6 +6554,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( "reverse directive does not support any clauses"); Res = ActOnOpenMPReverseDirective(AStmt, StartLoc, EndLoc); break;
- case OMPD_interchange:
- Res = ActOnOpenMPInterchangeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);- break;
case OMPD_for: Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -15139,6 +15145,8 @@ bool SemaOpenMP::checkTransformableLoopNest( DependentPreInits = Dir->getPreInits(); else if (auto *Dir = dyn_cast(Transform)) DependentPreInits = Dir->getPreInits();
else if (auto *Dir = dyn_cast<OMPInterchangeDirective>(Transform))DependentPreInits = Dir->getPreInits(); else llvm_unreachable("Unhandled loop transformation");
@@ -15937,6 +15945,160 @@ StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt, buildPreInits(Context, PreInits)); }
+StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
- ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
- SourceLocation EndLoc) {
- ASTContext &Context = getASTContext();
- DeclContext *CurContext = SemaRef.CurContext;
- Scope *CurScope = SemaRef.getCurScope();
- // Empty statement should only be possible if there already was an error.
- if (!AStmt)
- return StmtError();
- // interchange without permutation clause swaps two loops.
- constexpr size_t NumLoops = 2;
- // Verify and diagnose loop nest.
- SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
- Stmt *Body = nullptr;
- SmallVector<SmallVector<Stmt *, 0>, 2> OriginalInits;
- if (!checkTransformableLoopNest(OMPD_interchange, AStmt, NumLoops,
LoopHelpers, Body, OriginalInits))- return StmtError();
- // Delay interchange to when template is completely instantiated.
- if (CurContext->isDependentContext())
- return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
NumLoops, AStmt, nullptr, nullptr);- assert(LoopHelpers.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of ""affected loops");- assert(OriginalInits.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of ""affected loops");- // Decode the permutation clause.
- constexpr uint64_t Permutation[] = {1, 0};
- // Find the affected loops.
- SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
- collectLoopStmts(AStmt, LoopStmts);
- // Collect pre-init statements on the order before the permuation.
- SmallVector<Stmt *> PreInits;
- for (auto I : llvm::seq(NumLoops)) {
- OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
- assert(LoopHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");- auto *OrigCntVar = cast(LoopHelper.Counters.front());
- std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
- addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I],
PreInits);- }
- SmallVector<VarDecl *> PermutedIndVars;
- PermutedIndVars.resize(NumLoops);
- CaptureVars CopyTransformer(SemaRef);
- // Create the permuted loops from the inside to the outside of the
- // interchanged loop nest. Body of the innermost new loop is the original
- // innermost body.
- Stmt *Inner = Body;
- for (auto TargetIdx : llvm::reverse(llvm::seq(NumLoops))) {
- // Get the original loop that belongs to this new position.
- uint64_t SourceIdx = Permutation[TargetIdx];
- OMPLoopBasedDirective::HelperExprs &SourceHelper = LoopHelpers[SourceIdx];
- Stmt *SourceLoopStmt = LoopStmts[SourceIdx];
- assert(SourceHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");- auto *OrigCntVar = cast(SourceHelper.Counters.front());
- // Normalized loop counter variable: From 0 to n-1, always an integer type.
- DeclRefExpr *IterVarRef = cast(SourceHelper.IterationVarRef);
- QualType IVTy = IterVarRef->getType();
- assert(IVTy->isIntegerType() &&
"Expected the logical iteration counter to be an integer");- std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
- SourceLocation OrigVarLoc = IterVarRef->getExprLoc();
- // Make a copy of the NumIterations expression for each use: By the AST
- // constraints, every expression object in a DeclContext must be unique.
- auto MakeNumIterations = &CopyTransformer, &SourceHelper -> Expr * {
return AssertSuccess(CopyTransformer.TransformExpr(SourceHelper.NumIterations));- };
- // Iteration variable for the permuted loop. Reuse the one from
- // checkOpenMPLoop which will also be used to update the original loop
- // variable.
- std::string PermutedCntName =
(Twine(".permuted_") + llvm::utostr(TargetIdx) + ".iv." + OrigVarName).str();- auto *PermutedCntDecl = cast(IterVarRef->getDecl());
- PermutedCntDecl->setDeclName(
&SemaRef.P...
[truncated]
@llvm/pr-subscribers-clang-modules
Author: Michael Kruse (Meinersbur)
Changes
Add the interchange directive which will be introduced in the upcoming OpenMP 6.0 specification. A preview has been published in Technical Report 12.
Patch is 185.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93022.diff
30 Files Affected:
- (modified) clang/include/clang-c/Index.h (+4)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+3)
- (modified) clang/include/clang/AST/StmtOpenMP.h (+75-1)
- (modified) clang/include/clang/Basic/StmtNodes.td (+1)
- (modified) clang/include/clang/Sema/SemaOpenMP.h (+6)
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+1)
- (modified) clang/lib/AST/StmtOpenMP.cpp (+20)
- (modified) clang/lib/AST/StmtPrinter.cpp (+5)
- (modified) clang/lib/AST/StmtProfile.cpp (+5)
- (modified) clang/lib/Basic/OpenMPKinds.cpp (+3-1)
- (modified) clang/lib/CodeGen/CGStmt.cpp (+3)
- (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+10)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
- (modified) clang/lib/Parse/ParseOpenMP.cpp (+2)
- (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+1)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+162)
- (modified) clang/lib/Sema/TreeTransform.h (+11)
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+11)
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+5)
- (added) clang/test/OpenMP/interchange_ast_print.cpp (+135)
- (added) clang/test/OpenMP/interchange_codegen.cpp (+1990)
- (added) clang/test/OpenMP/interchange_messages.cpp (+77)
- (modified) clang/tools/libclang/CIndex.cpp (+8)
- (modified) clang/tools/libclang/CXCursor.cpp (+3)
- (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+3)
- (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)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index c7d63818ece23..a79aafbf20222 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2150,6 +2150,10 @@ enum CXCursorKind { */ CXCursor_OMPReverseDirective = 307,
- /** OpenMP interchange directive.
- */
- CXCursor_OMPInterchangeDirective = 308,
- /** OpenACC Compute Construct. */ CXCursor_OpenACCComputeConstruct = 320, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 06b29d59785f6..1bb167d7ddc3c 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3024,6 +3024,9 @@ DEF_TRAVERSE_STMT(OMPUnrollDirective, DEF_TRAVERSE_STMT(OMPReverseDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPInterchangeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })- DEF_TRAVERSE_STMT(OMPForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index fb7f413162fad..01c8b8e1a9f5e 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -1009,7 +1009,7 @@ class OMPLoopTransformationDirective : public OMPLoopBasedDirective { static bool classof(const Stmt *T) { Stmt::StmtClass C = T->getStmtClass(); return C == OMPTileDirectiveClass || C == OMPUnrollDirectiveClass ||
C == OMPReverseDirectiveClass;
} };C == OMPReverseDirectiveClass || C == OMPInterchangeDirectiveClass;
@@ -5777,6 +5777,80 @@ class OMPReverseDirective final : public OMPLoopTransformationDirective { } };
+/// 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 '#pragma omp scan' directive. /// /// \code diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index b2e2be5c998bb..b445ea225eac5 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -230,6 +230,7 @@ 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/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index ca91bffe24f6f..06376f173e8df 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -425,6 +425,12 @@ class SemaOpenMP : public SemaBase { /// Called on well-formed '#pragma omp reverse'. StmtResult ActOnOpenMPReverseDirective(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,
/// Called on well-formed '#pragma omp for' after parsing /// of the associated statement. StmtResult diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index dee0d073557cc..5fbdfd7a496fe 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1857,6 +1857,7 @@ enum StmtCode { STMT_OMP_TILE_DIRECTIVE, STMT_OMP_UNROLL_DIRECTIVE, STMT_OMP_REVERSE_DIRECTIVE,SourceLocation EndLoc);- STMT_OMP_INTERCHANGE_DIRECTIVE, STMT_OMP_FOR_DIRECTIVE, STMT_OMP_FOR_SIMD_DIRECTIVE, STMT_OMP_SECTIONS_DIRECTIVE, diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 83b8a08e9af73..24d8eb25c59ba 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -467,6 +467,26 @@ OMPReverseDirective *OMPReverseDirective::CreateEmpty(const ASTContext &C, 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, StartLoc, EndLoc,NumLoops);- Dir->setTransformedStmt(TransformedStmt);
- Dir->setPreInits(PreInits);
- return Dir; +}
- +OMPInterchangeDirective * +OMPInterchangeDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
unsigned NumLoops) {- return createEmptyDirective(
C, NumClauses, /*HasAssociatedStmt=*/true, TransformedStmtOffset + 1,SourceLocation(), SourceLocation(), NumLoops);
+} + OMPForSimdDirective * OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 64b481f680311..64bee75b205ae 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -768,6 +768,11 @@ void StmtPrinter::VisitOMPReverseDirective(OMPReverseDirective *Node) { PrintOMPExecutableDirective(Node); }
+void StmtPrinter::VisitOMPInterchangeDirective(OMPInterchangeDirective *Node) {
- Indent() << "#pragma omp interchange";
- PrintOMPExecutableDirective(Node); +}
- void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) { Indent() << "#pragma omp for"; PrintOMPExecutableDirective(Node); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 7445e5519b972..1ae99d43575a7 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -989,6 +989,11 @@ void StmtProfiler::VisitOMPReverseDirective(const OMPReverseDirective *S) { VisitOMPLoopTransformationDirective(S); }
+void StmtProfiler::VisitOMPInterchangeDirective(
const OMPInterchangeDirective *S) {
VisitOMPLoopTransformationDirective(S); +}
void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) { VisitOMPLoopDirective(S); } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 803808c38e2fe..ff5d5c8bdc981 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -684,7 +684,8 @@ bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) { }
bool clang::isOpenMPLoopTransformationDirective(OpenMPDirectiveKind DKind) {
- return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse;
- return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse ||
DKind == OMPD_interchange;
}
bool clang::isOpenMPCombinedParallelADirective(OpenMPDirectiveKind DKind) { @@ -809,6 +810,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: // loop transformations do not introduce captures. break; case OMPD_threadprivate: diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 93c2f8900dd12..ba7c52cc6ab7b 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -225,6 +225,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { case Stmt::OMPReverseDirectiveClass: EmitOMPReverseDirective(cast(*S)); break;
- case Stmt::OMPInterchangeDirectiveClass:
- EmitOMPInterchangeDirective(cast(*S));
- break;
case Stmt::OMPForDirectiveClass: EmitOMPForDirective(cast(*S)); break; diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index ad6c044aa483b..7a37e452fb559 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -189,6 +189,9 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { PreInits = Unroll->getPreInits(); } else if (const auto *Reverse = dyn_cast(&S)) { PreInits = Reverse->getPreInits();
- } else if (const auto *Interchange =
dyn_cast<OMPInterchangeDirective>(&S)) {
} else { llvm_unreachable("Unknown loop-based directive kind."); } @@ -2770,6 +2773,13 @@ void CodeGenFunction::EmitOMPReverseDirective(const OMPReverseDirective &S) { EmitStmt(S.getTransformedStmt()); }PreInits = Interchange->getPreInits();
+void CodeGenFunction::EmitOMPInterchangeDirective(
- const OMPInterchangeDirective &S) {
- // Emit the de-sugared statement.
- OMPTransformDirectiveScopeRAII InterchangeScope(*this, &S);
- EmitStmt(S.getTransformedStmt()); +}
- void CodeGenFunction::EmitOMPUnrollDirective(const OMPUnrollDirective &S) { bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder;
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index ac738e1e82886..c2a8e65ca2d0a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3808,6 +3808,7 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitOMPTileDirective(const OMPTileDirective &S); void EmitOMPUnrollDirective(const OMPUnrollDirective &S); void EmitOMPReverseDirective(const OMPReverseDirective &S);
- void EmitOMPInterchangeDirective(const OMPInterchangeDirective &S); void EmitOMPForDirective(const OMPForDirective &S); void EmitOMPForSimdDirective(const OMPForSimdDirective &S); void EmitOMPSectionsDirective(const OMPSectionsDirective &S); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 57fcf6ce520ac..0e3e604203c86 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2385,6 +2385,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: case OMPD_task: case OMPD_taskyield: case OMPD_barrier: @@ -2804,6 +2805,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: case OMPD_for: case OMPD_for_simd: case OMPD_sections: diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 4de7183cde281..5991f496d3a0f 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1487,6 +1487,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OMPTileDirectiveClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPReverseDirectiveClass:
- case Stmt::OMPInterchangeDirectiveClass: case Stmt::OMPSingleDirectiveClass: case Stmt::OMPTargetDataDirectiveClass: case Stmt::OMPTargetDirectiveClass: diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c2fd4de933ae4..ef141003b7d61 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -39,6 +39,7 @@
#include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" @@ -4335,6 +4336,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: break; case OMPD_loop: // TODO: 'loop' may require additional parameters depending on the binding. @@ -6552,6 +6554,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( "reverse directive does not support any clauses"); Res = ActOnOpenMPReverseDirective(AStmt, StartLoc, EndLoc); break;
- case OMPD_interchange:
- Res = ActOnOpenMPInterchangeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);- break;
case OMPD_for: Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -15139,6 +15145,8 @@ bool SemaOpenMP::checkTransformableLoopNest( DependentPreInits = Dir->getPreInits(); else if (auto *Dir = dyn_cast(Transform)) DependentPreInits = Dir->getPreInits();
else if (auto *Dir = dyn_cast<OMPInterchangeDirective>(Transform))DependentPreInits = Dir->getPreInits(); else llvm_unreachable("Unhandled loop transformation");
@@ -15937,6 +15945,160 @@ StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt, buildPreInits(Context, PreInits)); }
+StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
- ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
- SourceLocation EndLoc) {
- ASTContext &Context = getASTContext();
- DeclContext *CurContext = SemaRef.CurContext;
- Scope *CurScope = SemaRef.getCurScope();
- // Empty statement should only be possible if there already was an error.
- if (!AStmt)
- return StmtError();
- // interchange without permutation clause swaps two loops.
- constexpr size_t NumLoops = 2;
- // Verify and diagnose loop nest.
- SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
- Stmt *Body = nullptr;
- SmallVector<SmallVector<Stmt *, 0>, 2> OriginalInits;
- if (!checkTransformableLoopNest(OMPD_interchange, AStmt, NumLoops,
LoopHelpers, Body, OriginalInits))- return StmtError();
- // Delay interchange to when template is completely instantiated.
- if (CurContext->isDependentContext())
- return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
NumLoops, AStmt, nullptr, nullptr);- assert(LoopHelpers.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of ""affected loops");- assert(OriginalInits.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of ""affected loops");- // Decode the permutation clause.
- constexpr uint64_t Permutation[] = {1, 0};
- // Find the affected loops.
- SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
- collectLoopStmts(AStmt, LoopStmts);
- // Collect pre-init statements on the order before the permuation.
- SmallVector<Stmt *> PreInits;
- for (auto I : llvm::seq(NumLoops)) {
- OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
- assert(LoopHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");- auto *OrigCntVar = cast(LoopHelper.Counters.front());
- std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
- addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I],
PreInits);- }
- SmallVector<VarDecl *> PermutedIndVars;
- PermutedIndVars.resize(NumLoops);
- CaptureVars CopyTransformer(SemaRef);
- // Create the permuted loops from the inside to the outside of the
- // interchanged loop nest. Body of the innermost new loop is the original
- // innermost body.
- Stmt *Inner = Body;
- for (auto TargetIdx : llvm::reverse(llvm::seq(NumLoops))) {
- // Get the original loop that belongs to this new position.
- uint64_t SourceIdx = Permutation[TargetIdx];
- OMPLoopBasedDirective::HelperExprs &SourceHelper = LoopHelpers[SourceIdx];
- Stmt *SourceLoopStmt = LoopStmts[SourceIdx];
- assert(SourceHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");- auto *OrigCntVar = cast(SourceHelper.Counters.front());
- // Normalized loop counter variable: From 0 to n-1, always an integer type.
- DeclRefExpr *IterVarRef = cast(SourceHelper.IterationVarRef);
- QualType IVTy = IterVarRef->getType();
- assert(IVTy->isIntegerType() &&
"Expected the logical iteration counter to be an integer");- std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
- SourceLocation OrigVarLoc = IterVarRef->getExprLoc();
- // Make a copy of the NumIterations expression for each use: By the AST
- // constraints, every expression object in a DeclContext must be unique.
- auto MakeNumIterations = &CopyTransformer, &SourceHelper -> Expr * {
return AssertSuccess(CopyTransformer.TransformExpr(SourceHelper.NumIterations));- };
- // Iteration variable for the permuted loop. Reuse the one from
- // checkOpenMPLoop which will also be used to update the original loop
- // variable.
- std::string PermutedCntName =
(Twine(".permuted_") + llvm::utostr(TargetIdx) + ".iv." + OrigVarName).str();- auto *PermutedCntDecl = cast(IterVarRef->getDecl());
- PermutedCntDecl->setDeclName(
&SemaRef.P...
[truncated]
@llvm/pr-subscribers-clang
Author: Michael Kruse (Meinersbur)
Changes
Add the interchange directive which will be introduced in the upcoming OpenMP 6.0 specification. A preview has been published in Technical Report 12.
Patch is 185.81 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/93022.diff
30 Files Affected:
- (modified) clang/include/clang-c/Index.h (+4)
- (modified) clang/include/clang/AST/RecursiveASTVisitor.h (+3)
- (modified) clang/include/clang/AST/StmtOpenMP.h (+75-1)
- (modified) clang/include/clang/Basic/StmtNodes.td (+1)
- (modified) clang/include/clang/Sema/SemaOpenMP.h (+6)
- (modified) clang/include/clang/Serialization/ASTBitCodes.h (+1)
- (modified) clang/lib/AST/StmtOpenMP.cpp (+20)
- (modified) clang/lib/AST/StmtPrinter.cpp (+5)
- (modified) clang/lib/AST/StmtProfile.cpp (+5)
- (modified) clang/lib/Basic/OpenMPKinds.cpp (+3-1)
- (modified) clang/lib/CodeGen/CGStmt.cpp (+3)
- (modified) clang/lib/CodeGen/CGStmtOpenMP.cpp (+10)
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+1)
- (modified) clang/lib/Parse/ParseOpenMP.cpp (+2)
- (modified) clang/lib/Sema/SemaExceptionSpec.cpp (+1)
- (modified) clang/lib/Sema/SemaOpenMP.cpp (+162)
- (modified) clang/lib/Sema/TreeTransform.h (+11)
- (modified) clang/lib/Serialization/ASTReaderStmt.cpp (+11)
- (modified) clang/lib/Serialization/ASTWriterStmt.cpp (+5)
- (added) clang/test/OpenMP/interchange_ast_print.cpp (+135)
- (added) clang/test/OpenMP/interchange_codegen.cpp (+1990)
- (added) clang/test/OpenMP/interchange_messages.cpp (+77)
- (modified) clang/tools/libclang/CIndex.cpp (+8)
- (modified) clang/tools/libclang/CXCursor.cpp (+3)
- (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+3)
- (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)
diff --git a/clang/include/clang-c/Index.h b/clang/include/clang-c/Index.h index c7d63818ece23..a79aafbf20222 100644 --- a/clang/include/clang-c/Index.h +++ b/clang/include/clang-c/Index.h @@ -2150,6 +2150,10 @@ enum CXCursorKind { */ CXCursor_OMPReverseDirective = 307,
- /** OpenMP interchange directive.
- */
- CXCursor_OMPInterchangeDirective = 308,
- /** OpenACC Compute Construct. */ CXCursor_OpenACCComputeConstruct = 320, diff --git a/clang/include/clang/AST/RecursiveASTVisitor.h b/clang/include/clang/AST/RecursiveASTVisitor.h index 06b29d59785f6..1bb167d7ddc3c 100644 --- a/clang/include/clang/AST/RecursiveASTVisitor.h +++ b/clang/include/clang/AST/RecursiveASTVisitor.h @@ -3024,6 +3024,9 @@ DEF_TRAVERSE_STMT(OMPUnrollDirective, DEF_TRAVERSE_STMT(OMPReverseDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
+DEF_TRAVERSE_STMT(OMPInterchangeDirective,
{ TRY_TO(TraverseOMPExecutableDirective(S)); })- DEF_TRAVERSE_STMT(OMPForDirective, { TRY_TO(TraverseOMPExecutableDirective(S)); })
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h index fb7f413162fad..01c8b8e1a9f5e 100644 --- a/clang/include/clang/AST/StmtOpenMP.h +++ b/clang/include/clang/AST/StmtOpenMP.h @@ -1009,7 +1009,7 @@ class OMPLoopTransformationDirective : public OMPLoopBasedDirective { static bool classof(const Stmt *T) { Stmt::StmtClass C = T->getStmtClass(); return C == OMPTileDirectiveClass || C == OMPUnrollDirectiveClass ||
C == OMPReverseDirectiveClass;
} };C == OMPReverseDirectiveClass || C == OMPInterchangeDirectiveClass;
@@ -5777,6 +5777,80 @@ class OMPReverseDirective final : public OMPLoopTransformationDirective { } };
+/// 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 '#pragma omp scan' directive. /// /// \code diff --git a/clang/include/clang/Basic/StmtNodes.td b/clang/include/clang/Basic/StmtNodes.td index b2e2be5c998bb..b445ea225eac5 100644 --- a/clang/include/clang/Basic/StmtNodes.td +++ b/clang/include/clang/Basic/StmtNodes.td @@ -230,6 +230,7 @@ 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/Sema/SemaOpenMP.h b/clang/include/clang/Sema/SemaOpenMP.h index ca91bffe24f6f..06376f173e8df 100644 --- a/clang/include/clang/Sema/SemaOpenMP.h +++ b/clang/include/clang/Sema/SemaOpenMP.h @@ -425,6 +425,12 @@ class SemaOpenMP : public SemaBase { /// Called on well-formed '#pragma omp reverse'. StmtResult ActOnOpenMPReverseDirective(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,
/// Called on well-formed '#pragma omp for' after parsing /// of the associated statement. StmtResult diff --git a/clang/include/clang/Serialization/ASTBitCodes.h b/clang/include/clang/Serialization/ASTBitCodes.h index dee0d073557cc..5fbdfd7a496fe 100644 --- a/clang/include/clang/Serialization/ASTBitCodes.h +++ b/clang/include/clang/Serialization/ASTBitCodes.h @@ -1857,6 +1857,7 @@ enum StmtCode { STMT_OMP_TILE_DIRECTIVE, STMT_OMP_UNROLL_DIRECTIVE, STMT_OMP_REVERSE_DIRECTIVE,SourceLocation EndLoc);- STMT_OMP_INTERCHANGE_DIRECTIVE, STMT_OMP_FOR_DIRECTIVE, STMT_OMP_FOR_SIMD_DIRECTIVE, STMT_OMP_SECTIONS_DIRECTIVE, diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp index 83b8a08e9af73..24d8eb25c59ba 100644 --- a/clang/lib/AST/StmtOpenMP.cpp +++ b/clang/lib/AST/StmtOpenMP.cpp @@ -467,6 +467,26 @@ OMPReverseDirective *OMPReverseDirective::CreateEmpty(const ASTContext &C, 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, StartLoc, EndLoc,NumLoops);- Dir->setTransformedStmt(TransformedStmt);
- Dir->setPreInits(PreInits);
- return Dir; +}
- +OMPInterchangeDirective * +OMPInterchangeDirective::CreateEmpty(const ASTContext &C, unsigned NumClauses,
unsigned NumLoops) {- return createEmptyDirective(
C, NumClauses, /*HasAssociatedStmt=*/true, TransformedStmtOffset + 1,SourceLocation(), SourceLocation(), NumLoops);
+} + OMPForSimdDirective * OMPForSimdDirective::Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc, unsigned CollapsedNum, diff --git a/clang/lib/AST/StmtPrinter.cpp b/clang/lib/AST/StmtPrinter.cpp index 64b481f680311..64bee75b205ae 100644 --- a/clang/lib/AST/StmtPrinter.cpp +++ b/clang/lib/AST/StmtPrinter.cpp @@ -768,6 +768,11 @@ void StmtPrinter::VisitOMPReverseDirective(OMPReverseDirective *Node) { PrintOMPExecutableDirective(Node); }
+void StmtPrinter::VisitOMPInterchangeDirective(OMPInterchangeDirective *Node) {
- Indent() << "#pragma omp interchange";
- PrintOMPExecutableDirective(Node); +}
- void StmtPrinter::VisitOMPForDirective(OMPForDirective *Node) { Indent() << "#pragma omp for"; PrintOMPExecutableDirective(Node); diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index 7445e5519b972..1ae99d43575a7 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -989,6 +989,11 @@ void StmtProfiler::VisitOMPReverseDirective(const OMPReverseDirective *S) { VisitOMPLoopTransformationDirective(S); }
+void StmtProfiler::VisitOMPInterchangeDirective(
const OMPInterchangeDirective *S) {
VisitOMPLoopTransformationDirective(S); +}
void StmtProfiler::VisitOMPForDirective(const OMPForDirective *S) { VisitOMPLoopDirective(S); } diff --git a/clang/lib/Basic/OpenMPKinds.cpp b/clang/lib/Basic/OpenMPKinds.cpp index 803808c38e2fe..ff5d5c8bdc981 100644 --- a/clang/lib/Basic/OpenMPKinds.cpp +++ b/clang/lib/Basic/OpenMPKinds.cpp @@ -684,7 +684,8 @@ bool clang::isOpenMPLoopBoundSharingDirective(OpenMPDirectiveKind Kind) { }
bool clang::isOpenMPLoopTransformationDirective(OpenMPDirectiveKind DKind) {
- return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse;
- return DKind == OMPD_tile || DKind == OMPD_unroll || DKind == OMPD_reverse ||
DKind == OMPD_interchange;
}
bool clang::isOpenMPCombinedParallelADirective(OpenMPDirectiveKind DKind) { @@ -809,6 +810,7 @@ void clang::getOpenMPCaptureRegions( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: // loop transformations do not introduce captures. break; case OMPD_threadprivate: diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 93c2f8900dd12..ba7c52cc6ab7b 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -225,6 +225,9 @@ void CodeGenFunction::EmitStmt(const Stmt *S, ArrayRef<const Attr *> Attrs) { case Stmt::OMPReverseDirectiveClass: EmitOMPReverseDirective(cast(*S)); break;
- case Stmt::OMPInterchangeDirectiveClass:
- EmitOMPInterchangeDirective(cast(*S));
- break;
case Stmt::OMPForDirectiveClass: EmitOMPForDirective(cast(*S)); break; diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp index ad6c044aa483b..7a37e452fb559 100644 --- a/clang/lib/CodeGen/CGStmtOpenMP.cpp +++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp @@ -189,6 +189,9 @@ class OMPLoopScope : public CodeGenFunction::RunCleanupsScope { PreInits = Unroll->getPreInits(); } else if (const auto *Reverse = dyn_cast(&S)) { PreInits = Reverse->getPreInits();
- } else if (const auto *Interchange =
dyn_cast<OMPInterchangeDirective>(&S)) {
} else { llvm_unreachable("Unknown loop-based directive kind."); } @@ -2770,6 +2773,13 @@ void CodeGenFunction::EmitOMPReverseDirective(const OMPReverseDirective &S) { EmitStmt(S.getTransformedStmt()); }PreInits = Interchange->getPreInits();
+void CodeGenFunction::EmitOMPInterchangeDirective(
- const OMPInterchangeDirective &S) {
- // Emit the de-sugared statement.
- OMPTransformDirectiveScopeRAII InterchangeScope(*this, &S);
- EmitStmt(S.getTransformedStmt()); +}
- void CodeGenFunction::EmitOMPUnrollDirective(const OMPUnrollDirective &S) { bool UseOMPIRBuilder = CGM.getLangOpts().OpenMPIRBuilder;
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index ac738e1e82886..c2a8e65ca2d0a 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -3808,6 +3808,7 @@ class CodeGenFunction : public CodeGenTypeCache { void EmitOMPTileDirective(const OMPTileDirective &S); void EmitOMPUnrollDirective(const OMPUnrollDirective &S); void EmitOMPReverseDirective(const OMPReverseDirective &S);
- void EmitOMPInterchangeDirective(const OMPInterchangeDirective &S); void EmitOMPForDirective(const OMPForDirective &S); void EmitOMPForSimdDirective(const OMPForSimdDirective &S); void EmitOMPSectionsDirective(const OMPSectionsDirective &S); diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp index 57fcf6ce520ac..0e3e604203c86 100644 --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -2385,6 +2385,7 @@ Parser::DeclGroupPtrTy Parser::ParseOpenMPDeclarativeDirectiveWithExtDecl( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: case OMPD_task: case OMPD_taskyield: case OMPD_barrier: @@ -2804,6 +2805,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective( case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: case OMPD_for: case OMPD_for_simd: case OMPD_sections: diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 4de7183cde281..5991f496d3a0f 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -1487,6 +1487,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OMPTileDirectiveClass: case Stmt::OMPUnrollDirectiveClass: case Stmt::OMPReverseDirectiveClass:
- case Stmt::OMPInterchangeDirectiveClass: case Stmt::OMPSingleDirectiveClass: case Stmt::OMPTargetDataDirectiveClass: case Stmt::OMPTargetDirectiveClass: diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index c2fd4de933ae4..ef141003b7d61 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -39,6 +39,7 @@
#include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/PointerEmbeddedInt.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Sequence.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Frontend/OpenMP/OMPAssume.h" @@ -4335,6 +4336,7 @@ void SemaOpenMP::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, case OMPD_tile: case OMPD_unroll: case OMPD_reverse:
- case OMPD_interchange: break; case OMPD_loop: // TODO: 'loop' may require additional parameters depending on the binding. @@ -6552,6 +6554,10 @@ StmtResult SemaOpenMP::ActOnOpenMPExecutableDirective( "reverse directive does not support any clauses"); Res = ActOnOpenMPReverseDirective(AStmt, StartLoc, EndLoc); break;
- case OMPD_interchange:
- Res = ActOnOpenMPInterchangeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc);- break;
case OMPD_for: Res = ActOnOpenMPForDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -15139,6 +15145,8 @@ bool SemaOpenMP::checkTransformableLoopNest( DependentPreInits = Dir->getPreInits(); else if (auto *Dir = dyn_cast(Transform)) DependentPreInits = Dir->getPreInits();
else if (auto *Dir = dyn_cast<OMPInterchangeDirective>(Transform))DependentPreInits = Dir->getPreInits(); else llvm_unreachable("Unhandled loop transformation");
@@ -15937,6 +15945,160 @@ StmtResult SemaOpenMP::ActOnOpenMPReverseDirective(Stmt *AStmt, buildPreInits(Context, PreInits)); }
+StmtResult SemaOpenMP::ActOnOpenMPInterchangeDirective(
- ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
- SourceLocation EndLoc) {
- ASTContext &Context = getASTContext();
- DeclContext *CurContext = SemaRef.CurContext;
- Scope *CurScope = SemaRef.getCurScope();
- // Empty statement should only be possible if there already was an error.
- if (!AStmt)
- return StmtError();
- // interchange without permutation clause swaps two loops.
- constexpr size_t NumLoops = 2;
- // Verify and diagnose loop nest.
- SmallVector<OMPLoopBasedDirective::HelperExprs, 4> LoopHelpers(NumLoops);
- Stmt *Body = nullptr;
- SmallVector<SmallVector<Stmt *, 0>, 2> OriginalInits;
- if (!checkTransformableLoopNest(OMPD_interchange, AStmt, NumLoops,
LoopHelpers, Body, OriginalInits))- return StmtError();
- // Delay interchange to when template is completely instantiated.
- if (CurContext->isDependentContext())
- return OMPInterchangeDirective::Create(Context, StartLoc, EndLoc, Clauses,
NumLoops, AStmt, nullptr, nullptr);- assert(LoopHelpers.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of ""affected loops");- assert(OriginalInits.size() == NumLoops &&
"Expecting loop iteration space dimensionaly to match number of ""affected loops");- // Decode the permutation clause.
- constexpr uint64_t Permutation[] = {1, 0};
- // Find the affected loops.
- SmallVector<Stmt *> LoopStmts(NumLoops, nullptr);
- collectLoopStmts(AStmt, LoopStmts);
- // Collect pre-init statements on the order before the permuation.
- SmallVector<Stmt *> PreInits;
- for (auto I : llvm::seq(NumLoops)) {
- OMPLoopBasedDirective::HelperExprs &LoopHelper = LoopHelpers[I];
- assert(LoopHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");- auto *OrigCntVar = cast(LoopHelper.Counters.front());
- std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
- addLoopPreInits(Context, LoopHelper, LoopStmts[I], OriginalInits[I],
PreInits);- }
- SmallVector<VarDecl *> PermutedIndVars;
- PermutedIndVars.resize(NumLoops);
- CaptureVars CopyTransformer(SemaRef);
- // Create the permuted loops from the inside to the outside of the
- // interchanged loop nest. Body of the innermost new loop is the original
- // innermost body.
- Stmt *Inner = Body;
- for (auto TargetIdx : llvm::reverse(llvm::seq(NumLoops))) {
- // Get the original loop that belongs to this new position.
- uint64_t SourceIdx = Permutation[TargetIdx];
- OMPLoopBasedDirective::HelperExprs &SourceHelper = LoopHelpers[SourceIdx];
- Stmt *SourceLoopStmt = LoopStmts[SourceIdx];
- assert(SourceHelper.Counters.size() == 1 &&
"Single-dimensional loop iteration space expected");- auto *OrigCntVar = cast(SourceHelper.Counters.front());
- // Normalized loop counter variable: From 0 to n-1, always an integer type.
- DeclRefExpr *IterVarRef = cast(SourceHelper.IterationVarRef);
- QualType IVTy = IterVarRef->getType();
- assert(IVTy->isIntegerType() &&
"Expected the logical iteration counter to be an integer");- std::string OrigVarName = OrigCntVar->getNameInfo().getAsString();
- SourceLocation OrigVarLoc = IterVarRef->getExprLoc();
- // Make a copy of the NumIterations expression for each use: By the AST
- // constraints, every expression object in a DeclContext must be unique.
- auto MakeNumIterations = &CopyTransformer, &SourceHelper -> Expr * {
return AssertSuccess(CopyTransformer.TransformExpr(SourceHelper.NumIterations));- };
- // Iteration variable for the permuted loop. Reuse the one from
- // checkOpenMPLoop which will also be used to update the original loop
- // variable.
- std::string PermutedCntName =
(Twine(".permuted_") + llvm::utostr(TargetIdx) + ".iv." + OrigVarName).str();- auto *PermutedCntDecl = cast(IterVarRef->getDecl());
- PermutedCntDecl->setDeclName(
&SemaRef.P...
[truncated]
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG with a nit
…rsbur/clang_openmp_interchange
Base automatically changed from users/meinersbur/clang_openmp_reverse to main
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LG with some nits
| "Single-dimensional loop iteration space expected"); |
|---|
| auto *OrigCntVar = cast(LoopHelper.Counters.front()); |
| std::string OrigVarName = OrigCntVar->getNameInfo().getAsString(); |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SmallString
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get this. getAsString returns an std::string r-value. Assigning it to a SmallString will unpack that std::string and copy it over to SmallString's buffer, compared to RVO where no copy happens other than the initial construction of the std::string inside getAsString().
Furthermore, contemporary implementations of std::string are already using a small-size buffer.
I guess I could call OrigCntVar->getNameInfo().operator<<, and pass a raw_svector_ostream instantiated using a SmallString. This would enable us to choose a larger small buffer size ourselves. Is that what you are asking? If so, what should the small buffer size be?
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just saying, that better to use SmallString where possible. If you think, std::string is good enough here, I'm fine with it. It was just a suggestion.
| assert(IVTy->isIntegerType() && |
|---|
| "Expected the logical iteration counter to be an integer"); |
| std::string OrigVarName = OrigCntVar->getNameInfo().getAsString(); |
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SmallString
Meinersbur deleted the users/meinersbur/clang_openmp_interchange branch
Meinersbur restored the users/meinersbur/clang_openmp_interchange branch